From d7144731e089dcde8ff8ecc33af55642652ac803 Mon Sep 17 00:00:00 2001 From: Rene Fichtmueller Date: Mon, 27 Apr 2026 00:00:14 +0200 Subject: [PATCH] feat(scraper): add 100+ OEM seed scrapers + tip-llm-guided inference layer MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit New OEM transceiver seed scrapers (94 cron-scheduled, 24/7): - Media/Broadcast: Evertz, Grass Valley, Haivision, Viasat - Asian Optical: FiberHome, Oplink, Accelink, Hisense Broadband - Optical Mfrs: Lumentum, II-VI/Coherent, Source Photonics, O-Net, InnoLight, AOI, Sumitomo Electric, NeoPhotonics - Industrial: GE Grid, Schweitzer, Moxa Industrial, Cisco IE, Phoenix Contact, Beckhoff, Omron, ABB, Siemens, Schneider, Rockwell, Belden - Enterprise/DC: Arista, Pica8, Pluribus, DriveNets, Cisco (Meraki/Catalyst/Nexus/ASR) - Cloud: AWS, Azure, Google Cloud, Meta - Storage: NetApp, Pure Storage, HPE Storage, IBM Storage, Dell Storage, Hitachi Vantara - 5G/RAN: Samsung Networks, Nokia AirScale, Ericsson RAN, Mavenir - Security: Check Point, Barracuda, Fortinet, Palo Alto - Telecom Optical: ADVA, PacketLight, FiberHome, Accelink, Hisense API: tip-llm-guided inference layer (strict schema + repair-retry + safe fallback) - POST /api/tip-llm/infer|research-plan|extract|finding|health - Hard JSON schema enforcement, create_finding=false on empty evidence - Confidence gate (>= 0.4), validation with consistency check Build: added incremental=true to scraper tsconfig (OOM prevention) Scheduler: 87 → 94 registered workers --- packages/api/src/index.ts | 3 + packages/api/src/llm/client.ts | 6 +- packages/api/src/llm/fo-blog-pipeline.ts | 2 +- packages/api/src/llm/tip-llm-guided.ts | 421 +++++++ packages/api/src/routes/tip-llm.ts | 130 ++ packages/scraper/src/scheduler.ts | 1121 ++++++++++++++++- packages/scraper/src/scrapers/abb-oem.ts | 118 ++ packages/scraper/src/scrapers/accelink-oem.ts | 131 ++ packages/scraper/src/scrapers/adtran-oem.ts | 131 ++ .../scraper/src/scrapers/adtran-ta-oem.ts | 146 +++ packages/scraper/src/scrapers/adva-oem.ts | 137 ++ .../scraper/src/scrapers/adva-optical-oem.ts | 248 ++++ .../scraper/src/scrapers/advantech-oem.ts | 117 ++ packages/scraper/src/scrapers/ale-oem.ts | 123 ++ .../src/scrapers/allied-telesis-oem.ts | 127 ++ packages/scraper/src/scrapers/antaira-oem.ts | 116 ++ packages/scraper/src/scrapers/aoi-oem.ts | 137 ++ .../scraper/src/scrapers/arista-7000-oem.ts | 126 ++ packages/scraper/src/scrapers/arris-oem.ts | 123 ++ packages/scraper/src/scrapers/aruba-cx-oem.ts | 121 ++ packages/scraper/src/scrapers/aws-oem.ts | 330 +++++ packages/scraper/src/scrapers/azure-oem.ts | 331 +++++ .../scraper/src/scrapers/barracuda-oem.ts | 121 ++ packages/scraper/src/scrapers/beckhoff-oem.ts | 118 ++ packages/scraper/src/scrapers/belden-oem.ts | 121 ++ packages/scraper/src/scrapers/blackbox-oem.ts | 127 ++ packages/scraper/src/scrapers/broadcom-oem.ts | 129 ++ packages/scraper/src/scrapers/brocade-oem.ts | 138 ++ .../scraper/src/scrapers/calix-access-oem.ts | 127 ++ .../src/scrapers/calix-gigapoint-oem.ts | 140 ++ packages/scraper/src/scrapers/calix-oem.ts | 119 ++ packages/scraper/src/scrapers/cambium-oem.ts | 121 ++ .../scraper/src/scrapers/casa-systems-oem.ts | 126 ++ packages/scraper/src/scrapers/centec-oem.ts | 118 ++ packages/scraper/src/scrapers/ceragon-oem.ts | 123 ++ .../scraper/src/scrapers/checkpoint-oem.ts | 133 ++ packages/scraper/src/scrapers/ciena-oem.ts | 141 +++ .../src/scrapers/ciena-waveserver-oem.ts | 150 +++ packages/scraper/src/scrapers/cimc-oem.ts | 138 ++ .../scraper/src/scrapers/cisco-asr-oem.ts | 130 ++ .../src/scrapers/cisco-catalyst-oem.ts | 122 ++ packages/scraper/src/scrapers/cisco-ie-oem.ts | 119 ++ .../scraper/src/scrapers/cisco-meraki-oem.ts | 120 ++ .../scraper/src/scrapers/cisco-nexus-oem.ts | 125 ++ packages/scraper/src/scrapers/coherent-oem.ts | 153 +++ .../scraper/src/scrapers/commscope-oem.ts | 133 ++ packages/scraper/src/scrapers/comnet-oem.ts | 116 ++ packages/scraper/src/scrapers/comtrend-oem.ts | 147 +++ packages/scraper/src/scrapers/coriant-oem.ts | 139 ++ packages/scraper/src/scrapers/corning-oem.ts | 123 ++ .../scraper/src/scrapers/cradlepoint-oem.ts | 117 ++ .../src/scrapers/cumulus-networks-oem.ts | 120 ++ packages/scraper/src/scrapers/datang-oem.ts | 148 +++ .../scraper/src/scrapers/dell-storage-oem.ts | 341 +++++ packages/scraper/src/scrapers/dlink-oem.ts | 125 ++ .../scraper/src/scrapers/drivenets-oem.ts | 128 ++ packages/scraper/src/scrapers/dzs-oem.ts | 129 ++ .../src/scrapers/edgewater-networks-oem.ts | 139 ++ packages/scraper/src/scrapers/ekinops-oem.ts | 132 ++ packages/scraper/src/scrapers/emulex-oem.ts | 342 +++++ packages/scraper/src/scrapers/ericsson-oem.ts | 138 ++ .../scraper/src/scrapers/ericsson-ran-oem.ts | 135 ++ .../src/scrapers/ericsson-transport-oem.ts | 155 +++ packages/scraper/src/scrapers/etherwan-oem.ts | 116 ++ packages/scraper/src/scrapers/evertz-oem.ts | 139 ++ .../scraper/src/scrapers/exfo-network-oem.ts | 135 ++ packages/scraper/src/scrapers/exfo-oem.ts | 144 +++ .../src/scrapers/extreme-campus-oem.ts | 122 ++ packages/scraper/src/scrapers/f5-oem.ts | 120 ++ .../scraper/src/scrapers/fiberhome-oem.ts | 144 +++ packages/scraper/src/scrapers/fortinet-oem.ts | 121 ++ packages/scraper/src/scrapers/fujitsu-oem.ts | 134 ++ packages/scraper/src/scrapers/ge-grid-oem.ts | 118 ++ .../scraper/src/scrapers/google-cloud-oem.ts | 333 +++++ .../scraper/src/scrapers/grass-valley-oem.ts | 133 ++ packages/scraper/src/scrapers/h3c-oem.ts | 122 ++ .../scraper/src/scrapers/haivision-oem.ts | 120 ++ packages/scraper/src/scrapers/harmonic-oem.ts | 146 +++ .../scraper/src/scrapers/hillstone-oem.ts | 120 ++ .../scraper/src/scrapers/hirschmann-oem.ts | 130 ++ .../src/scrapers/hisense-broadband-oem.ts | 131 ++ .../src/scrapers/hitachi-vantara-oem.ts | 315 +++++ .../scraper/src/scrapers/hpe-storage-oem.ts | 365 ++++++ .../scraper/src/scrapers/huawei-access-oem.ts | 147 +++ .../scraper/src/scrapers/ibm-storage-oem.ts | 368 ++++++ packages/scraper/src/scrapers/ii-vi-oem.ts | 141 +++ .../src/scrapers/infinera-groove-oem.ts | 135 ++ packages/scraper/src/scrapers/infinera-oem.ts | 130 ++ .../scraper/src/scrapers/innolight-oem.ts | 137 ++ packages/scraper/src/scrapers/intel-oem.ts | 131 ++ .../scraper/src/scrapers/ipinfusion-oem.ts | 129 ++ packages/scraper/src/scrapers/isolan-oem.ts | 141 +++ packages/scraper/src/scrapers/ixia-oem.ts | 132 ++ .../scraper/src/scrapers/juniper-mx-oem.ts | 132 ++ .../scraper/src/scrapers/juniper-qfx-oem.ts | 123 ++ packages/scraper/src/scrapers/keysight-oem.ts | 130 ++ packages/scraper/src/scrapers/kontron-oem.ts | 131 ++ packages/scraper/src/scrapers/korenix-oem.ts | 115 ++ packages/scraper/src/scrapers/lancom-oem.ts | 126 ++ packages/scraper/src/scrapers/lumentum-oem.ts | 135 ++ packages/scraper/src/scrapers/marvell-oem.ts | 133 ++ packages/scraper/src/scrapers/mavenir-oem.ts | 123 ++ packages/scraper/src/scrapers/mellanox-oem.ts | 136 ++ packages/scraper/src/scrapers/meta-oem.ts | 314 +++++ packages/scraper/src/scrapers/mikrotik-oem.ts | 127 ++ .../src/scrapers/moxa-industrial-oem.ts | 123 ++ packages/scraper/src/scrapers/moxa-oem.ts | 111 ++ packages/scraper/src/scrapers/nec-oem.ts | 122 ++ .../scraper/src/scrapers/neophotonics-oem.ts | 140 ++ packages/scraper/src/scrapers/netapp-oem.ts | 358 ++++++ packages/scraper/src/scrapers/netgear-oem.ts | 124 ++ .../scraper/src/scrapers/nokia-access-oem.ts | 148 +++ .../src/scrapers/nokia-airscale-oem.ts | 133 ++ packages/scraper/src/scrapers/nokia-oem.ts | 119 +- packages/scraper/src/scrapers/o-net-oem.ts | 145 +++ packages/scraper/src/scrapers/ofs-oem.ts | 127 ++ packages/scraper/src/scrapers/omron-oem.ts | 116 ++ packages/scraper/src/scrapers/oplink-oem.ts | 134 ++ .../scraper/src/scrapers/packetfront-oem.ts | 138 ++ .../scraper/src/scrapers/packetlight-oem.ts | 130 ++ .../scraper/src/scrapers/palo-alto-oem.ts | 129 ++ packages/scraper/src/scrapers/perle-oem.ts | 116 ++ .../src/scrapers/phoenix-contact-oem.ts | 113 ++ packages/scraper/src/scrapers/pica8-oem.ts | 120 ++ packages/scraper/src/scrapers/pluribus-oem.ts | 118 ++ .../scraper/src/scrapers/pure-storage-oem.ts | 312 +++++ packages/scraper/src/scrapers/qlogic-oem.ts | 369 ++++++ packages/scraper/src/scrapers/rad-oem.ts | 156 +++ packages/scraper/src/scrapers/redlion-oem.ts | 118 ++ .../scraper/src/scrapers/ribbon-comms-oem.ts | 127 ++ packages/scraper/src/scrapers/ribbon-oem.ts | 129 ++ packages/scraper/src/scrapers/rockwell-oem.ts | 119 ++ .../scraper/src/scrapers/ruggedcom-oem.ts | 127 ++ packages/scraper/src/scrapers/ruijie-oem.ts | 119 ++ .../src/scrapers/samsung-networks-oem.ts | 123 ++ .../scraper/src/scrapers/schneider-oem.ts | 119 ++ .../scraper/src/scrapers/schweitzer-oem.ts | 118 ++ packages/scraper/src/scrapers/siemens-oem.ts | 121 ++ packages/scraper/src/scrapers/siklu-oem.ts | 120 ++ .../scraper/src/scrapers/solarflare-oem.ts | 131 ++ packages/scraper/src/scrapers/sonic-oem.ts | 123 ++ .../scraper/src/scrapers/sonicwall-oem.ts | 123 ++ packages/scraper/src/scrapers/sophos-oem.ts | 122 ++ .../src/scrapers/source-photonics-oem.ts | 144 +++ packages/scraper/src/scrapers/spirent-oem.ts | 134 ++ packages/scraper/src/scrapers/stordis-oem.ts | 124 ++ .../src/scrapers/sumitomo-electric-oem.ts | 139 ++ .../scraper/src/scrapers/supermicro-oem.ts | 123 ++ packages/scraper/src/scrapers/sycamore-oem.ts | 128 ++ .../src/scrapers/tejas-networks-oem.ts | 141 +++ .../scraper/src/scrapers/telco-systems-oem.ts | 145 +++ packages/scraper/src/scrapers/teleste-oem.ts | 139 ++ packages/scraper/src/scrapers/telrad-oem.ts | 122 ++ packages/scraper/src/scrapers/tplink-oem.ts | 119 ++ .../src/scrapers/transition-networks-oem.ts | 334 +++++ packages/scraper/src/scrapers/ubiquiti-oem.ts | 121 ++ packages/scraper/src/scrapers/vecima-oem.ts | 116 ++ .../src/scrapers/versa-networks-oem.ts | 117 ++ packages/scraper/src/scrapers/viasat-oem.ts | 118 ++ packages/scraper/src/scrapers/viavi-oem.ts | 144 +++ packages/scraper/src/scrapers/viptela-oem.ts | 117 ++ packages/scraper/src/scrapers/vmware-oem.ts | 117 ++ .../scraper/src/scrapers/watchguard-oem.ts | 120 ++ packages/scraper/src/scrapers/westermo-oem.ts | 117 ++ .../scraper/src/scrapers/zte-access-oem.ts | 141 +++ packages/scraper/src/scrapers/zte-oem.ts | 146 +++ packages/scraper/src/scrapers/zyxel-oem.ts | 122 ++ packages/scraper/tsconfig.json | 3 +- 168 files changed, 25201 insertions(+), 65 deletions(-) create mode 100644 packages/api/src/llm/tip-llm-guided.ts create mode 100644 packages/api/src/routes/tip-llm.ts create mode 100644 packages/scraper/src/scrapers/abb-oem.ts create mode 100644 packages/scraper/src/scrapers/accelink-oem.ts create mode 100644 packages/scraper/src/scrapers/adtran-oem.ts create mode 100644 packages/scraper/src/scrapers/adtran-ta-oem.ts create mode 100644 packages/scraper/src/scrapers/adva-oem.ts create mode 100644 packages/scraper/src/scrapers/adva-optical-oem.ts create mode 100644 packages/scraper/src/scrapers/advantech-oem.ts create mode 100644 packages/scraper/src/scrapers/ale-oem.ts create mode 100644 packages/scraper/src/scrapers/allied-telesis-oem.ts create mode 100644 packages/scraper/src/scrapers/antaira-oem.ts create mode 100644 packages/scraper/src/scrapers/aoi-oem.ts create mode 100644 packages/scraper/src/scrapers/arista-7000-oem.ts create mode 100644 packages/scraper/src/scrapers/arris-oem.ts create mode 100644 packages/scraper/src/scrapers/aruba-cx-oem.ts create mode 100644 packages/scraper/src/scrapers/aws-oem.ts create mode 100644 packages/scraper/src/scrapers/azure-oem.ts create mode 100644 packages/scraper/src/scrapers/barracuda-oem.ts create mode 100644 packages/scraper/src/scrapers/beckhoff-oem.ts create mode 100644 packages/scraper/src/scrapers/belden-oem.ts create mode 100644 packages/scraper/src/scrapers/blackbox-oem.ts create mode 100644 packages/scraper/src/scrapers/broadcom-oem.ts create mode 100644 packages/scraper/src/scrapers/brocade-oem.ts create mode 100644 packages/scraper/src/scrapers/calix-access-oem.ts create mode 100644 packages/scraper/src/scrapers/calix-gigapoint-oem.ts create mode 100644 packages/scraper/src/scrapers/calix-oem.ts create mode 100644 packages/scraper/src/scrapers/cambium-oem.ts create mode 100644 packages/scraper/src/scrapers/casa-systems-oem.ts create mode 100644 packages/scraper/src/scrapers/centec-oem.ts create mode 100644 packages/scraper/src/scrapers/ceragon-oem.ts create mode 100644 packages/scraper/src/scrapers/checkpoint-oem.ts create mode 100644 packages/scraper/src/scrapers/ciena-oem.ts create mode 100644 packages/scraper/src/scrapers/ciena-waveserver-oem.ts create mode 100644 packages/scraper/src/scrapers/cimc-oem.ts create mode 100644 packages/scraper/src/scrapers/cisco-asr-oem.ts create mode 100644 packages/scraper/src/scrapers/cisco-catalyst-oem.ts create mode 100644 packages/scraper/src/scrapers/cisco-ie-oem.ts create mode 100644 packages/scraper/src/scrapers/cisco-meraki-oem.ts create mode 100644 packages/scraper/src/scrapers/cisco-nexus-oem.ts create mode 100644 packages/scraper/src/scrapers/coherent-oem.ts create mode 100644 packages/scraper/src/scrapers/commscope-oem.ts create mode 100644 packages/scraper/src/scrapers/comnet-oem.ts create mode 100644 packages/scraper/src/scrapers/comtrend-oem.ts create mode 100644 packages/scraper/src/scrapers/coriant-oem.ts create mode 100644 packages/scraper/src/scrapers/corning-oem.ts create mode 100644 packages/scraper/src/scrapers/cradlepoint-oem.ts create mode 100644 packages/scraper/src/scrapers/cumulus-networks-oem.ts create mode 100644 packages/scraper/src/scrapers/datang-oem.ts create mode 100644 packages/scraper/src/scrapers/dell-storage-oem.ts create mode 100644 packages/scraper/src/scrapers/dlink-oem.ts create mode 100644 packages/scraper/src/scrapers/drivenets-oem.ts create mode 100644 packages/scraper/src/scrapers/dzs-oem.ts create mode 100644 packages/scraper/src/scrapers/edgewater-networks-oem.ts create mode 100644 packages/scraper/src/scrapers/ekinops-oem.ts create mode 100644 packages/scraper/src/scrapers/emulex-oem.ts create mode 100644 packages/scraper/src/scrapers/ericsson-oem.ts create mode 100644 packages/scraper/src/scrapers/ericsson-ran-oem.ts create mode 100644 packages/scraper/src/scrapers/ericsson-transport-oem.ts create mode 100644 packages/scraper/src/scrapers/etherwan-oem.ts create mode 100644 packages/scraper/src/scrapers/evertz-oem.ts create mode 100644 packages/scraper/src/scrapers/exfo-network-oem.ts create mode 100644 packages/scraper/src/scrapers/exfo-oem.ts create mode 100644 packages/scraper/src/scrapers/extreme-campus-oem.ts create mode 100644 packages/scraper/src/scrapers/f5-oem.ts create mode 100644 packages/scraper/src/scrapers/fiberhome-oem.ts create mode 100644 packages/scraper/src/scrapers/fortinet-oem.ts create mode 100644 packages/scraper/src/scrapers/fujitsu-oem.ts create mode 100644 packages/scraper/src/scrapers/ge-grid-oem.ts create mode 100644 packages/scraper/src/scrapers/google-cloud-oem.ts create mode 100644 packages/scraper/src/scrapers/grass-valley-oem.ts create mode 100644 packages/scraper/src/scrapers/h3c-oem.ts create mode 100644 packages/scraper/src/scrapers/haivision-oem.ts create mode 100644 packages/scraper/src/scrapers/harmonic-oem.ts create mode 100644 packages/scraper/src/scrapers/hillstone-oem.ts create mode 100644 packages/scraper/src/scrapers/hirschmann-oem.ts create mode 100644 packages/scraper/src/scrapers/hisense-broadband-oem.ts create mode 100644 packages/scraper/src/scrapers/hitachi-vantara-oem.ts create mode 100644 packages/scraper/src/scrapers/hpe-storage-oem.ts create mode 100644 packages/scraper/src/scrapers/huawei-access-oem.ts create mode 100644 packages/scraper/src/scrapers/ibm-storage-oem.ts create mode 100644 packages/scraper/src/scrapers/ii-vi-oem.ts create mode 100644 packages/scraper/src/scrapers/infinera-groove-oem.ts create mode 100644 packages/scraper/src/scrapers/infinera-oem.ts create mode 100644 packages/scraper/src/scrapers/innolight-oem.ts create mode 100644 packages/scraper/src/scrapers/intel-oem.ts create mode 100644 packages/scraper/src/scrapers/ipinfusion-oem.ts create mode 100644 packages/scraper/src/scrapers/isolan-oem.ts create mode 100644 packages/scraper/src/scrapers/ixia-oem.ts create mode 100644 packages/scraper/src/scrapers/juniper-mx-oem.ts create mode 100644 packages/scraper/src/scrapers/juniper-qfx-oem.ts create mode 100644 packages/scraper/src/scrapers/keysight-oem.ts create mode 100644 packages/scraper/src/scrapers/kontron-oem.ts create mode 100644 packages/scraper/src/scrapers/korenix-oem.ts create mode 100644 packages/scraper/src/scrapers/lancom-oem.ts create mode 100644 packages/scraper/src/scrapers/lumentum-oem.ts create mode 100644 packages/scraper/src/scrapers/marvell-oem.ts create mode 100644 packages/scraper/src/scrapers/mavenir-oem.ts create mode 100644 packages/scraper/src/scrapers/mellanox-oem.ts create mode 100644 packages/scraper/src/scrapers/meta-oem.ts create mode 100644 packages/scraper/src/scrapers/mikrotik-oem.ts create mode 100644 packages/scraper/src/scrapers/moxa-industrial-oem.ts create mode 100644 packages/scraper/src/scrapers/moxa-oem.ts create mode 100644 packages/scraper/src/scrapers/nec-oem.ts create mode 100644 packages/scraper/src/scrapers/neophotonics-oem.ts create mode 100644 packages/scraper/src/scrapers/netapp-oem.ts create mode 100644 packages/scraper/src/scrapers/netgear-oem.ts create mode 100644 packages/scraper/src/scrapers/nokia-access-oem.ts create mode 100644 packages/scraper/src/scrapers/nokia-airscale-oem.ts create mode 100644 packages/scraper/src/scrapers/o-net-oem.ts create mode 100644 packages/scraper/src/scrapers/ofs-oem.ts create mode 100644 packages/scraper/src/scrapers/omron-oem.ts create mode 100644 packages/scraper/src/scrapers/oplink-oem.ts create mode 100644 packages/scraper/src/scrapers/packetfront-oem.ts create mode 100644 packages/scraper/src/scrapers/packetlight-oem.ts create mode 100644 packages/scraper/src/scrapers/palo-alto-oem.ts create mode 100644 packages/scraper/src/scrapers/perle-oem.ts create mode 100644 packages/scraper/src/scrapers/phoenix-contact-oem.ts create mode 100644 packages/scraper/src/scrapers/pica8-oem.ts create mode 100644 packages/scraper/src/scrapers/pluribus-oem.ts create mode 100644 packages/scraper/src/scrapers/pure-storage-oem.ts create mode 100644 packages/scraper/src/scrapers/qlogic-oem.ts create mode 100644 packages/scraper/src/scrapers/rad-oem.ts create mode 100644 packages/scraper/src/scrapers/redlion-oem.ts create mode 100644 packages/scraper/src/scrapers/ribbon-comms-oem.ts create mode 100644 packages/scraper/src/scrapers/ribbon-oem.ts create mode 100644 packages/scraper/src/scrapers/rockwell-oem.ts create mode 100644 packages/scraper/src/scrapers/ruggedcom-oem.ts create mode 100644 packages/scraper/src/scrapers/ruijie-oem.ts create mode 100644 packages/scraper/src/scrapers/samsung-networks-oem.ts create mode 100644 packages/scraper/src/scrapers/schneider-oem.ts create mode 100644 packages/scraper/src/scrapers/schweitzer-oem.ts create mode 100644 packages/scraper/src/scrapers/siemens-oem.ts create mode 100644 packages/scraper/src/scrapers/siklu-oem.ts create mode 100644 packages/scraper/src/scrapers/solarflare-oem.ts create mode 100644 packages/scraper/src/scrapers/sonic-oem.ts create mode 100644 packages/scraper/src/scrapers/sonicwall-oem.ts create mode 100644 packages/scraper/src/scrapers/sophos-oem.ts create mode 100644 packages/scraper/src/scrapers/source-photonics-oem.ts create mode 100644 packages/scraper/src/scrapers/spirent-oem.ts create mode 100644 packages/scraper/src/scrapers/stordis-oem.ts create mode 100644 packages/scraper/src/scrapers/sumitomo-electric-oem.ts create mode 100644 packages/scraper/src/scrapers/supermicro-oem.ts create mode 100644 packages/scraper/src/scrapers/sycamore-oem.ts create mode 100644 packages/scraper/src/scrapers/tejas-networks-oem.ts create mode 100644 packages/scraper/src/scrapers/telco-systems-oem.ts create mode 100644 packages/scraper/src/scrapers/teleste-oem.ts create mode 100644 packages/scraper/src/scrapers/telrad-oem.ts create mode 100644 packages/scraper/src/scrapers/tplink-oem.ts create mode 100644 packages/scraper/src/scrapers/transition-networks-oem.ts create mode 100644 packages/scraper/src/scrapers/ubiquiti-oem.ts create mode 100644 packages/scraper/src/scrapers/vecima-oem.ts create mode 100644 packages/scraper/src/scrapers/versa-networks-oem.ts create mode 100644 packages/scraper/src/scrapers/viasat-oem.ts create mode 100644 packages/scraper/src/scrapers/viavi-oem.ts create mode 100644 packages/scraper/src/scrapers/viptela-oem.ts create mode 100644 packages/scraper/src/scrapers/vmware-oem.ts create mode 100644 packages/scraper/src/scrapers/watchguard-oem.ts create mode 100644 packages/scraper/src/scrapers/westermo-oem.ts create mode 100644 packages/scraper/src/scrapers/zte-access-oem.ts create mode 100644 packages/scraper/src/scrapers/zte-oem.ts create mode 100644 packages/scraper/src/scrapers/zyxel-oem.ts diff --git a/packages/api/src/index.ts b/packages/api/src/index.ts index 153b511..191cf6a 100644 --- a/packages/api/src/index.ts +++ b/packages/api/src/index.ts @@ -34,6 +34,7 @@ import { priceComparisonRouter } from "./routes/price-comparison"; import { selflearningRouter } from "./routes/selflearning"; import { internalDemandRouter } from "./routes/internal-demand"; import { formFactorsRouter } from "./routes/form-factors"; +import { tipLlmRouter } from "./routes/tip-llm"; const app = express(); @@ -99,6 +100,8 @@ app.use("/api/selflearning", selflearningRouter); app.use("/api/form-factors", formFactorsRouter); // Internal-only — restricted to localhost / LAN by the router itself app.use("/api/internal/demand", internalDemandRouter); +// tip-llm-v1 guided inference +app.use("/api/tip-llm", tipLlmRouter); // Dashboard (static HTML) app.use("/dashboard", express.static(join(__dirname, "..", "..", "dashboard"))); diff --git a/packages/api/src/llm/client.ts b/packages/api/src/llm/client.ts index 827462a..b5059a3 100644 --- a/packages/api/src/llm/client.ts +++ b/packages/api/src/llm/client.ts @@ -5,14 +5,14 @@ * Provider selection: * BLOG_LLM_PROVIDER=claude-code → Claude via claude-bridge (flat-rate, recommended) * BLOG_LLM_PROVIDER=anthropic → Claude Sonnet/Haiku via Anthropic API - * BLOG_LLM_PROVIDER=ollama → fine-tuned fo-blog-v5 on local Ollama (default) + * BLOG_LLM_PROVIDER=ollama → local adapter bridge / Ollama-compatible endpoint (default) * * Claude-code is preferred: uses Claude Code subscription (flat-rate), no API costs. - * Ollama fo-blog-v5 is the fallback for offline/local usage. + * The default local blog model is the latest RunPod-trained FO_BlogLLM adapter. */ const OLLAMA_URL = process.env.OLLAMA_URL || "http://localhost:11434"; -const LLM_MODEL = process.env.OLLAMA_LLM_MODEL || "fo-blog-v5"; +const LLM_MODEL = process.env.OLLAMA_LLM_MODEL || "fo-blog-v7"; const ANTHROPIC_API_KEY = process.env.ANTHROPIC_API_KEY || ""; const ANTHROPIC_MODEL = process.env.ANTHROPIC_MODEL || "claude-sonnet-4-20250514"; diff --git a/packages/api/src/llm/fo-blog-pipeline.ts b/packages/api/src/llm/fo-blog-pipeline.ts index 16c2572..31a9517 100644 --- a/packages/api/src/llm/fo-blog-pipeline.ts +++ b/packages/api/src/llm/fo-blog-pipeline.ts @@ -27,7 +27,7 @@ * - Core principle: "Your content gets better the more you delete" * * Dedicated FO_Blog_LLM: - * - Model: qwen2.5:14b on .213 (or override via FO_BLOG_MODEL env) + * - Model: fo-blog-v7 via local adapter bridge (or override via FO_BLOG_MODEL env) * - System prompt loaded with accumulated feedback * - Feedback loop: every blog gets rated, feedback trains next generation */ diff --git a/packages/api/src/llm/tip-llm-guided.ts b/packages/api/src/llm/tip-llm-guided.ts new file mode 100644 index 0000000..8f1efbe --- /dev/null +++ b/packages/api/src/llm/tip-llm-guided.ts @@ -0,0 +1,421 @@ +/** + * tip-llm-guided.ts — Structured Inference Engine for tip-llm-v1 + * + * DESIGN PRINCIPLE: tip-llm-v1 must NEVER think freely. + * Every call goes through: + * 1. Hard system prompt that locks the output format + * 2. Schema validation of the response + * 3. Repair retry (max 2x) with diff showing what was wrong + * 4. Fallback to safe default (create_finding=false) on persistent failure + * + * Input: source text/HTML + context (vendor, product, URL) + * Output: validated TipLlmOutput JSON — always, never throws + */ + +import { generate } from "./client"; + +// ─── Model config ───────────────────────────────────────────────────────────── + +const TIP_LLM_MODEL = process.env.TIP_LLM_MODEL || "tip-llm-v1"; +const TIP_OLLAMA_URL = process.env.TIP_OLLAMA_URL || process.env.OLLAMA_URL || "http://localhost:11434"; +const TIP_LLM_TIMEOUT = parseInt(process.env.TIP_LLM_TIMEOUT_MS || "30000"); +const TIP_LLM_MAX_RETRY = 2; + +// ─── Schema ─────────────────────────────────────────────────────────────────── + +export type TipLlmTask = + | "research_plan" // produce a crawl/search plan for a vendor/product + | "extract" // extract structured facts from provided HTML/text + | "finding"; // produce a finding ticket from pre-gathered evidence + +export interface TipLlmInput { + task: TipLlmTask; + /** Raw text or HTML snippet to analyse (max ~4000 chars recommended) */ + text?: string; + /** Source URL the text was fetched from */ + url?: string; + /** Vendor name context */ + vendor?: string; + /** Product name / PID context */ + product?: string; + /** Extra context string for the model */ + context?: string; +} + +export interface EvidenceItem { + /** Verbatim quote or data point found in the source */ + quote: string; + /** Source URL or description (must be from the provided input, not invented) */ + source: string; + /** How confident this item is: 0.0–1.0 */ + confidence: number; +} + +export interface TipLlmOutput { + /** Task that was executed */ + task: TipLlmTask; + /** For research_plan: search queries to execute */ + search_patterns: string[]; + /** For extract: field names + XPath/CSS selectors or regex patterns */ + extraction_fields: Array<{ + field: string; + selector_or_pattern: string; + example?: string; + }>; + /** Rules for what counts as relevant vs noise */ + relevance_rules: string[]; + /** Concrete evidence items from the provided source text — EMPTY if nothing found */ + evidence: EvidenceItem[]; + /** Aggregate confidence 0.0–1.0. Must be 0 if evidence is empty. */ + confidence: number; + /** True ONLY if evidence is non-empty AND confidence >= 0.4 */ + create_finding: boolean; + /** Human-readable summary — one sentence max */ + summary: string; + /** Raw sources referenced (URLs or "provided_text") */ + sources: string[]; +} + +// ─── Validation ─────────────────────────────────────────────────────────────── + +interface ValidationError { + field: string; + issue: string; +} + +function validateOutput(raw: unknown): { ok: true; data: TipLlmOutput } | { ok: false; errors: ValidationError[] } { + const errors: ValidationError[] = []; + + if (typeof raw !== "object" || raw === null) { + return { ok: false, errors: [{ field: "root", issue: "Response is not a JSON object" }] }; + } + + const obj = raw as Record; + + // task + const validTasks: TipLlmTask[] = ["research_plan", "extract", "finding"]; + if (!validTasks.includes(obj.task as TipLlmTask)) { + errors.push({ field: "task", issue: `Must be one of: ${validTasks.join(", ")}` }); + } + + // search_patterns + if (!Array.isArray(obj.search_patterns)) { + errors.push({ field: "search_patterns", issue: "Must be an array of strings" }); + } else if (obj.search_patterns.some((x) => typeof x !== "string")) { + errors.push({ field: "search_patterns", issue: "All items must be strings" }); + } + + // extraction_fields + if (!Array.isArray(obj.extraction_fields)) { + errors.push({ field: "extraction_fields", issue: "Must be an array" }); + } else { + for (const [i, ef] of obj.extraction_fields.entries()) { + if (typeof ef !== "object" || ef === null) { + errors.push({ field: `extraction_fields[${i}]`, issue: "Must be an object" }); + continue; + } + const e = ef as Record; + if (typeof e.field !== "string") errors.push({ field: `extraction_fields[${i}].field`, issue: "Must be a string" }); + if (typeof e.selector_or_pattern !== "string") errors.push({ field: `extraction_fields[${i}].selector_or_pattern`, issue: "Must be a string" }); + } + } + + // relevance_rules + if (!Array.isArray(obj.relevance_rules)) { + errors.push({ field: "relevance_rules", issue: "Must be an array of strings" }); + } + + // evidence + if (!Array.isArray(obj.evidence)) { + errors.push({ field: "evidence", issue: "Must be an array" }); + } else { + for (const [i, ev] of obj.evidence.entries()) { + if (typeof ev !== "object" || ev === null) { + errors.push({ field: `evidence[${i}]`, issue: "Must be an object" }); + continue; + } + const e = ev as Record; + if (typeof e.quote !== "string" || e.quote.trim().length === 0) { + errors.push({ field: `evidence[${i}].quote`, issue: "Must be a non-empty string" }); + } + if (typeof e.source !== "string" || e.source.trim().length === 0) { + errors.push({ field: `evidence[${i}].source`, issue: "Must be a non-empty string" }); + } + if (typeof e.confidence !== "number" || e.confidence < 0 || e.confidence > 1) { + errors.push({ field: `evidence[${i}].confidence`, issue: "Must be a number between 0 and 1" }); + } + } + } + + // confidence + if (typeof obj.confidence !== "number" || obj.confidence < 0 || obj.confidence > 1) { + errors.push({ field: "confidence", issue: "Must be a number between 0.0 and 1.0" }); + } + + // create_finding consistency check + if (typeof obj.create_finding !== "boolean") { + errors.push({ field: "create_finding", issue: "Must be a boolean" }); + } else { + const evidence = Array.isArray(obj.evidence) ? obj.evidence : []; + const confidence = typeof obj.confidence === "number" ? obj.confidence : 0; + if (obj.create_finding === true && (evidence.length === 0 || confidence < 0.4)) { + errors.push({ + field: "create_finding", + issue: "Cannot be true when evidence is empty or confidence < 0.4 — set to false", + }); + } + } + + // summary + if (typeof obj.summary !== "string") { + errors.push({ field: "summary", issue: "Must be a string" }); + } + + // sources + if (!Array.isArray(obj.sources)) { + errors.push({ field: "sources", issue: "Must be an array of strings" }); + } + + if (errors.length > 0) return { ok: false, errors }; + + return { ok: true, data: obj as unknown as TipLlmOutput }; +} + +// ─── Safe fallback ──────────────────────────────────────────────────────────── + +function safeDefault(input: TipLlmInput, reason: string): TipLlmOutput { + console.warn(`[tip-llm] Returning safe default — reason: ${reason}`); + return { + task: input.task, + search_patterns: [], + extraction_fields: [], + relevance_rules: [], + evidence: [], + confidence: 0, + create_finding: false, + summary: `No reliable output could be produced: ${reason}`, + sources: input.url ? [input.url] : ["provided_text"], + }; +} + +// ─── Prompts ────────────────────────────────────────────────────────────────── + +const SYSTEM_PROMPT = `You are a structured data extraction engine for the Transceiver Intelligence Platform (TIP). + +STRICT RULES — violating ANY of these results in your output being discarded: +1. You MUST respond with ONLY valid JSON. No markdown. No explanation. No code blocks. +2. The JSON MUST contain ALL of these fields: task, search_patterns, extraction_fields, relevance_rules, evidence, confidence, create_finding, summary, sources. +3. evidence MUST only contain information that is EXPLICITLY present in the provided source text. If the text does not contain the information, evidence MUST be an empty array []. +4. DO NOT invent, hallucinate, or assume any vendor details, lead times, pricing, specs, or availability without direct textual evidence. +5. create_finding MUST be false if evidence is empty or confidence < 0.4. +6. confidence MUST be 0.0 if evidence is empty. +7. Every evidence item MUST have a non-empty quote (verbatim from source), a source, and a confidence value between 0.0 and 1.0. +8. summary MUST be one sentence, maximum 150 characters. + +JSON SCHEMA: +{ + "task": "research_plan" | "extract" | "finding", + "search_patterns": ["string"], + "extraction_fields": [{"field": "string", "selector_or_pattern": "string", "example": "string (optional)"}], + "relevance_rules": ["string"], + "evidence": [{"quote": "string", "source": "string", "confidence": 0.0-1.0}], + "confidence": 0.0-1.0, + "create_finding": true | false, + "summary": "string (max 150 chars)", + "sources": ["string"] +}`; + +function buildUserPrompt(input: TipLlmInput): string { + const parts: string[] = []; + + parts.push(`TASK: ${input.task}`); + if (input.vendor) parts.push(`VENDOR: ${input.vendor}`); + if (input.product) parts.push(`PRODUCT: ${input.product}`); + if (input.url) parts.push(`URL: ${input.url}`); + if (input.context) parts.push(`CONTEXT: ${input.context}`); + + if (input.text) { + // Truncate to 4000 chars to stay within tip-llm-v1 context window + const truncated = input.text.length > 4000 + ? input.text.slice(0, 4000) + "\n[... truncated]" + : input.text; + parts.push(`\nSOURCE TEXT:\n${truncated}`); + } else { + parts.push("\nSOURCE TEXT: (none provided — generate search plan only)"); + } + + parts.push("\nRespond with ONLY the JSON object. No other text."); + return parts.join("\n"); +} + +function buildRepairPrompt(input: TipLlmInput, previousOutput: string, errors: ValidationError[]): string { + const errorList = errors.map((e) => `- ${e.field}: ${e.issue}`).join("\n"); + return `Your previous response had schema errors. Fix them and return ONLY corrected JSON. + +ERRORS: +${errorList} + +PREVIOUS RESPONSE (first 500 chars): +${previousOutput.slice(0, 500)} + +${buildUserPrompt(input)}`; +} + +// ─── Raw Ollama call (bypasses blog LLM routing, hits tip-llm-v1 directly) ──── + +async function callTipLlm( + systemPrompt: string, + userPrompt: string, + attempt: number, +): Promise { + // Override model env vars temporarily by calling Ollama API directly + // This ensures tip-llm-v1 is used, not fo-blog-v7 + const resp = await fetch(`${TIP_OLLAMA_URL}/api/generate`, { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ + model: TIP_LLM_MODEL, + prompt: userPrompt, + system: systemPrompt, + stream: false, + options: { + temperature: attempt === 0 ? 0.1 : 0.05, // lower temp on retry + num_predict: 1500, + stop: ["\n\n\n"], // prevent runaway output + }, + }), + signal: AbortSignal.timeout(TIP_LLM_TIMEOUT), + }); + + if (!resp.ok) { + const errText = await resp.text(); + throw new Error(`tip-llm-v1 call failed: ${resp.status} ${errText.slice(0, 200)}`); + } + + const data = await resp.json() as { response: string; model: string; total_duration: number }; + const durationMs = Math.round(data.total_duration / 1_000_000); + console.log(`[tip-llm] ${data.model} attempt=${attempt} duration=${durationMs}ms chars=${data.response.length}`); + return data.response; +} + +// ─── JSON extraction ────────────────────────────────────────────────────────── + +function extractJson(raw: string): unknown { + // Strip markdown code blocks if model wrapped output despite instructions + let text = raw.trim(); + const codeBlock = text.match(/```(?:json)?\s*([\s\S]*?)```/); + if (codeBlock) text = codeBlock[1].trim(); + + // Find the first complete JSON object + const start = text.indexOf("{"); + const end = text.lastIndexOf("}"); + if (start === -1 || end === -1) throw new Error("No JSON object found in response"); + + return JSON.parse(text.slice(start, end + 1)); +} + +// ─── Main entry point ───────────────────────────────────────────────────────── + +/** + * Run tip-llm-v1 with strict guided inference. + * Never throws — returns a safe default on persistent failure. + */ +export async function tipLlmInfer(input: TipLlmInput): Promise { + const startTime = Date.now(); + let lastRaw = ""; + let lastErrors: ValidationError[] = []; + + for (let attempt = 0; attempt <= TIP_LLM_MAX_RETRY; attempt++) { + try { + const userPrompt = attempt === 0 + ? buildUserPrompt(input) + : buildRepairPrompt(input, lastRaw, lastErrors); + + lastRaw = await callTipLlm(SYSTEM_PROMPT, userPrompt, attempt); + + let parsed: unknown; + try { + parsed = extractJson(lastRaw); + } catch (parseErr) { + lastErrors = [{ field: "root", issue: `JSON parse error: ${(parseErr as Error).message}` }]; + console.warn(`[tip-llm] attempt=${attempt} parse failed: ${(parseErr as Error).message}`); + continue; + } + + const result = validateOutput(parsed); + if (result.ok) { + const totalMs = Date.now() - startTime; + console.log(`[tip-llm] SUCCESS attempt=${attempt} create_finding=${result.data.create_finding} evidence=${result.data.evidence.length} total=${totalMs}ms`); + return result.data; + } + + lastErrors = result.errors; + console.warn(`[tip-llm] attempt=${attempt} validation failed (${result.errors.length} errors):`, result.errors); + + } catch (err) { + const msg = (err as Error).message; + console.error(`[tip-llm] attempt=${attempt} call error: ${msg}`); + lastErrors = [{ field: "root", issue: msg }]; + } + } + + // All retries exhausted — return safe default + const errorSummary = lastErrors.map((e) => `${e.field}: ${e.issue}`).slice(0, 3).join("; "); + return safeDefault(input, `schema validation failed after ${TIP_LLM_MAX_RETRY + 1} attempts: ${errorSummary}`); +} + +// ─── Convenience wrappers ───────────────────────────────────────────────────── + +/** Generate a search/crawl plan for a vendor+product without any source text */ +export async function tipLlmResearchPlan( + vendor: string, + product: string, + context?: string, +): Promise { + return tipLlmInfer({ task: "research_plan", vendor, product, context }); +} + +/** Extract structured facts from scraped HTML/text */ +export async function tipLlmExtract( + text: string, + url: string, + vendor?: string, + product?: string, +): Promise { + return tipLlmInfer({ task: "extract", text, url, vendor, product }); +} + +/** Produce a finding from pre-gathered evidence text */ +export async function tipLlmFinding( + text: string, + vendor: string, + product: string, + url?: string, +): Promise { + return tipLlmInfer({ task: "finding", text, url, vendor, product }); +} + +/** Health check — verifies tip-llm-v1 is loaded in Ollama */ +export async function checkTipLlmHealth(): Promise<{ + ok: boolean; + model: string; + error?: string; +}> { + try { + const resp = await fetch(`${TIP_OLLAMA_URL}/api/tags`, { + signal: AbortSignal.timeout(5000), + }); + if (!resp.ok) { + return { ok: false, model: TIP_LLM_MODEL, error: `Ollama HTTP ${resp.status}` }; + } + const data = await resp.json() as { models: Array<{ name: string }> }; + const hasModel = data.models.some((m) => m.name.startsWith(TIP_LLM_MODEL.split(":")[0])); + return { + ok: hasModel, + model: TIP_LLM_MODEL, + error: hasModel ? undefined : `Model "${TIP_LLM_MODEL}" not found in Ollama`, + }; + } catch (err) { + return { ok: false, model: TIP_LLM_MODEL, error: (err as Error).message }; + } +} diff --git a/packages/api/src/routes/tip-llm.ts b/packages/api/src/routes/tip-llm.ts new file mode 100644 index 0000000..4bab525 --- /dev/null +++ b/packages/api/src/routes/tip-llm.ts @@ -0,0 +1,130 @@ +/** + * /api/tip-llm — Guided Inference API for tip-llm-v1 + * + * Endpoints: + * POST /api/tip-llm/infer — general inference (any task) + * POST /api/tip-llm/research-plan — generate search/crawl plan + * POST /api/tip-llm/extract — extract facts from HTML/text + * POST /api/tip-llm/finding — produce a finding from evidence + * GET /api/tip-llm/health — model health check + */ + +import { Router, type Request, type Response } from "express"; +import { + tipLlmInfer, + tipLlmResearchPlan, + tipLlmExtract, + tipLlmFinding, + checkTipLlmHealth, + type TipLlmInput, + type TipLlmTask, +} from "../llm/tip-llm-guided"; + +export const tipLlmRouter = Router(); + +const VALID_TASKS: TipLlmTask[] = ["research_plan", "extract", "finding"]; + +// ── Health ───────────────────────────────────────────────────────────────── + +tipLlmRouter.get("/health", async (_req: Request, res: Response) => { + const result = await checkTipLlmHealth(); + res.status(result.ok ? 200 : 503).json(result); +}); + +// ── General infer ────────────────────────────────────────────────────────── + +tipLlmRouter.post("/infer", async (req: Request, res: Response) => { + const { task, text, url, vendor, product, context } = req.body as { + task?: string; + text?: string; + url?: string; + vendor?: string; + product?: string; + context?: string; + }; + + if (!task || !VALID_TASKS.includes(task as TipLlmTask)) { + res.status(400).json({ error: `task is required and must be one of: ${VALID_TASKS.join(", ")}` }); + return; + } + if (text && text.length > 8000) { + res.status(400).json({ error: "text must be <= 8000 characters" }); + return; + } + + const input: TipLlmInput = { + task: task as TipLlmTask, + text, + url, + vendor, + product, + context, + }; + + const result = await tipLlmInfer(input); + res.json({ success: true, data: result }); +}); + +// ── Research plan ────────────────────────────────────────────────────────── + +tipLlmRouter.post("/research-plan", async (req: Request, res: Response) => { + const { vendor, product, context } = req.body as { + vendor?: string; + product?: string; + context?: string; + }; + + if (!vendor || !product) { + res.status(400).json({ error: "vendor and product are required" }); + return; + } + + const result = await tipLlmResearchPlan(vendor, product, context); + res.json({ success: true, data: result }); +}); + +// ── Extract ──────────────────────────────────────────────────────────────── + +tipLlmRouter.post("/extract", async (req: Request, res: Response) => { + const { text, url, vendor, product } = req.body as { + text?: string; + url?: string; + vendor?: string; + product?: string; + }; + + if (!text || !url) { + res.status(400).json({ error: "text and url are required" }); + return; + } + if (text.length > 8000) { + res.status(400).json({ error: "text must be <= 8000 characters" }); + return; + } + + const result = await tipLlmExtract(text, url, vendor, product); + res.json({ success: true, data: result }); +}); + +// ── Finding ──────────────────────────────────────────────────────────────── + +tipLlmRouter.post("/finding", async (req: Request, res: Response) => { + const { text, vendor, product, url } = req.body as { + text?: string; + vendor?: string; + product?: string; + url?: string; + }; + + if (!text || !vendor || !product) { + res.status(400).json({ error: "text, vendor and product are required" }); + return; + } + if (text.length > 8000) { + res.status(400).json({ error: "text must be <= 8000 characters" }); + return; + } + + const result = await tipLlmFinding(text, vendor, product, url); + res.json({ success: true, data: result }); +}); diff --git a/packages/scraper/src/scheduler.ts b/packages/scraper/src/scheduler.ts index 1c7066c..d755bb5 100644 --- a/packages/scraper/src/scheduler.ts +++ b/packages/scraper/src/scheduler.ts @@ -228,6 +228,168 @@ export async function registerSchedules(boss: PgBoss): Promise { await boss.schedule("scrape:catalog:extreme-oem", "30 5 * * *", {}, { retryLimit: 2, expireInSeconds: 3600 }); await boss.schedule("scrape:catalog:nvidia-mellanox-oem","45 5 * * *", {}, { retryLimit: 2, expireInSeconds: 3600 }); await boss.schedule("scrape:catalog:brocade-ruckus-oem","0 6 * * *", {}, { retryLimit: 2, expireInSeconds: 3600 }); + await boss.schedule("scrape:catalog:zte-oem", "15 6 * * *", {}, { retryLimit: 2, expireInSeconds: 3600 }); + await boss.schedule("scrape:catalog:ciena-oem", "30 6 * * *", {}, { retryLimit: 2, expireInSeconds: 3600 }); + await boss.schedule("scrape:catalog:ericsson-oem", "45 6 * * *", {}, { retryLimit: 2, expireInSeconds: 3600 }); + await boss.schedule("scrape:catalog:fortinet-oem", "0 7 * * *", {}, { retryLimit: 2, expireInSeconds: 3600 }); + await boss.schedule("scrape:catalog:palo-alto-oem", "15 7 * * *", {}, { retryLimit: 2, expireInSeconds: 3600 }); + await boss.schedule("scrape:catalog:f5-oem", "30 7 * * *", {}, { retryLimit: 2, expireInSeconds: 3600 }); + await boss.schedule("scrape:catalog:ubiquiti-oem", "45 7 * * *", {}, { retryLimit: 2, expireInSeconds: 3600 }); + await boss.schedule("scrape:catalog:mikrotik-oem", "0 8 * * *", {}, { retryLimit: 2, expireInSeconds: 3600 }); + await boss.schedule("scrape:catalog:netgear-oem", "15 8 * * *", {}, { retryLimit: 2, expireInSeconds: 3600 }); + await boss.schedule("scrape:catalog:adtran-oem", "30 8 * * *", {}, { retryLimit: 2, expireInSeconds: 3600 }); + await boss.schedule("scrape:catalog:calix-oem", "45 8 * * *", {}, { retryLimit: 2, expireInSeconds: 3600 }); + await boss.schedule("scrape:catalog:checkpoint-oem", "0 9 * * *", {}, { retryLimit: 2, expireInSeconds: 3600 }); + await boss.schedule("scrape:catalog:allied-telesis-oem","15 9 * * *", {}, { retryLimit: 2, expireInSeconds: 3600 }); + await boss.schedule("scrape:catalog:zyxel-oem", "30 9 * * *", {}, { retryLimit: 2, expireInSeconds: 3600 }); + await boss.schedule("scrape:catalog:dlink-oem", "45 9 * * *", {}, { retryLimit: 2, expireInSeconds: 3600 }); + await boss.schedule("scrape:catalog:ale-oem", "0 10 * * *", {}, { retryLimit: 2, expireInSeconds: 3600 }); + await boss.schedule("scrape:catalog:ribbon-oem", "15 10 * * *", {}, { retryLimit: 2, expireInSeconds: 3600 }); + await boss.schedule("scrape:catalog:infinera-oem", "30 10 * * *", {}, { retryLimit: 2, expireInSeconds: 3600 }); + await boss.schedule("scrape:catalog:tplink-oem", "45 10 * * *", {}, { retryLimit: 2, expireInSeconds: 3600 }); + await boss.schedule("scrape:catalog:cambium-oem", "0 11 * * *", {}, { retryLimit: 2, expireInSeconds: 3600 }); + await boss.schedule("scrape:catalog:moxa-oem", "15 11 * * *", {}, { retryLimit: 2, expireInSeconds: 3600 }); + await boss.schedule("scrape:catalog:lumentum-oem", "30 11 * * *", {}, { retryLimit: 2, expireInSeconds: 3600 }); + await boss.schedule("scrape:catalog:coherent-oem", "45 11 * * *", {}, { retryLimit: 2, expireInSeconds: 3600 }); + await boss.schedule("scrape:catalog:brocade-oem", "0 12 * * *", {}, { retryLimit: 2, expireInSeconds: 3600 }); + await boss.schedule("scrape:catalog:ruggedcom-oem", "15 12 * * *", {}, { retryLimit: 2, expireInSeconds: 3600 }); + await boss.schedule("scrape:catalog:hirschmann-oem", "30 12 * * *", {}, { retryLimit: 2, expireInSeconds: 3600 }); + await boss.schedule("scrape:catalog:viavi-oem", "45 12 * * *", {}, { retryLimit: 2, expireInSeconds: 3600 }); + await boss.schedule("scrape:catalog:westermo-oem", "0 13 * * *", {}, { retryLimit: 2, expireInSeconds: 3600 }); + await boss.schedule("scrape:catalog:lancom-oem", "15 13 * * *", {}, { retryLimit: 2, expireInSeconds: 3600 }); + await boss.schedule("scrape:catalog:dzs-oem", "30 13 * * *", {}, { retryLimit: 2, expireInSeconds: 3600 }); + await boss.schedule("scrape:catalog:watchguard-oem", "45 13 * * *", {}, { retryLimit: 2, expireInSeconds: 3600 }); + await boss.schedule("scrape:catalog:sonicwall-oem", "0 14 * * *", {}, { retryLimit: 2, expireInSeconds: 3600 }); + await boss.schedule("scrape:catalog:advantech-oem", "15 14 * * *", {}, { retryLimit: 2, expireInSeconds: 3600 }); + await boss.schedule("scrape:catalog:redlion-oem", "30 14 * * *", {}, { retryLimit: 2, expireInSeconds: 3600 }); + await boss.schedule("scrape:catalog:exfo-oem", "45 14 * * *", {}, { retryLimit: 2, expireInSeconds: 3600 }); + await boss.schedule("scrape:catalog:mellanox-oem", "0 15 * * *", {}, { retryLimit: 2, expireInSeconds: 3600 }); + await boss.schedule("scrape:catalog:intel-oem", "15 15 * * *", {}, { retryLimit: 2, expireInSeconds: 3600 }); + await boss.schedule("scrape:catalog:antaira-oem", "30 15 * * *", {}, { retryLimit: 2, expireInSeconds: 3600 }); + await boss.schedule("scrape:catalog:transition-networks-oem", "45 15 * * *", {}, { retryLimit: 2, expireInSeconds: 3600 }); + await boss.schedule("scrape:catalog:perle-oem", "0 16 * * *", {}, { retryLimit: 2, expireInSeconds: 3600 }); + await boss.schedule("scrape:catalog:barracuda-oem", "15 16 * * *", {}, { retryLimit: 2, expireInSeconds: 3600 }); + await boss.schedule("scrape:catalog:etherwan-oem", "30 16 * * *", {}, { retryLimit: 2, expireInSeconds: 3600 }); + await boss.schedule("scrape:catalog:blackbox-oem", "45 16 * * *", {}, { retryLimit: 2, expireInSeconds: 3600 }); + await boss.schedule("scrape:catalog:packetlight-oem", "0 17 * * *", {}, { retryLimit: 2, expireInSeconds: 3600 }); + await boss.schedule("scrape:catalog:spirent-oem", "15 17 * * *", {}, { retryLimit: 2, expireInSeconds: 3600 }); + await boss.schedule("scrape:catalog:comnet-oem", "30 17 * * *", {}, { retryLimit: 2, expireInSeconds: 3600 }); + await boss.schedule("scrape:catalog:korenix-oem", "45 17 * * *", {}, { retryLimit: 2, expireInSeconds: 3600 }); + await boss.schedule("scrape:catalog:sophos-oem", "0 18 * * *", {}, { retryLimit: 2, expireInSeconds: 3600 }); + await boss.schedule("scrape:catalog:cradlepoint-oem", "15 18 * * *", {}, { retryLimit: 2, expireInSeconds: 3600 }); + await boss.schedule("scrape:catalog:fujitsu-oem", "30 18 * * *", {}, { retryLimit: 2, expireInSeconds: 3600 }); + await boss.schedule("scrape:catalog:nec-oem", "45 18 * * *", {}, { retryLimit: 2, expireInSeconds: 3600 }); + await boss.schedule("scrape:catalog:arris-oem", "0 19 * * *", {}, { retryLimit: 2, expireInSeconds: 3600 }); + await boss.schedule("scrape:catalog:hillstone-oem", "15 19 * * *", {}, { retryLimit: 2, expireInSeconds: 3600 }); + await boss.schedule("scrape:catalog:vecima-oem", "30 19 * * *", {}, { retryLimit: 2, expireInSeconds: 3600 }); + await boss.schedule("scrape:catalog:stordis-oem", "45 19 * * *", {}, { retryLimit: 2, expireInSeconds: 3600 }); + await boss.schedule("scrape:catalog:keysight-oem", "0 20 * * *", {}, { retryLimit: 2, expireInSeconds: 3600 }); + await boss.schedule("scrape:catalog:sycamore-oem", "15 20 * * *", {}, { retryLimit: 2, expireInSeconds: 3600 }); + await boss.schedule("scrape:catalog:ekinops-oem", "30 20 * * *", {}, { retryLimit: 2, expireInSeconds: 3600 }); + await boss.schedule("scrape:catalog:adva-oem", "45 20 * * *", {}, { retryLimit: 2, expireInSeconds: 3600 }); + await boss.schedule("scrape:catalog:coriant-oem", "0 21 * * *", {}, { retryLimit: 2, expireInSeconds: 3600 }); + await boss.schedule("scrape:catalog:casa-systems-oem", "15 21 * * *", {}, { retryLimit: 2, expireInSeconds: 3600 }); + await boss.schedule("scrape:catalog:harmonic-oem", "30 21 * * *", {}, { retryLimit: 2, expireInSeconds: 3600 }); + await boss.schedule("scrape:catalog:solarflare-oem", "45 21 * * *", {}, { retryLimit: 2, expireInSeconds: 3600 }); + await boss.schedule("scrape:catalog:marvell-oem", "0 22 * * *", {}, { retryLimit: 2, expireInSeconds: 3600 }); + await boss.schedule("scrape:catalog:broadcom-oem", "15 22 * * *", {}, { retryLimit: 2, expireInSeconds: 3600 }); + await boss.schedule("scrape:catalog:calix-access-oem", "30 22 * * *", {}, { retryLimit: 2, expireInSeconds: 3600 }); + await boss.schedule("scrape:catalog:ribbon-comms-oem", "45 22 * * *", {}, { retryLimit: 2, expireInSeconds: 3600 }); + await boss.schedule("scrape:catalog:infinera-groove-oem", "0 23 * * *", {}, { retryLimit: 2, expireInSeconds: 3600 }); + await boss.schedule("scrape:catalog:ciena-waveserver-oem","15 23 * * *", {}, { retryLimit: 2, expireInSeconds: 3600 }); + await boss.schedule("scrape:catalog:commscope-oem", "30 23 * * *", {}, { retryLimit: 2, expireInSeconds: 3600 }); + await boss.schedule("scrape:catalog:teleste-oem", "45 23 * * *", {}, { retryLimit: 2, expireInSeconds: 3600 }); + await boss.schedule("scrape:catalog:tejas-networks-oem", "0 0 * * *", {}, { retryLimit: 2, expireInSeconds: 3600 }); + await boss.schedule("scrape:catalog:ericsson-transport-oem","15 0 * * *",{}, { retryLimit: 2, expireInSeconds: 3600 }); + await boss.schedule("scrape:catalog:adtran-ta-oem", "30 0 * * *", {}, { retryLimit: 2, expireInSeconds: 3600 }); + await boss.schedule("scrape:catalog:isolan-oem", "45 0 * * *", {}, { retryLimit: 2, expireInSeconds: 3600 }); + await boss.schedule("scrape:catalog:telco-systems-oem", "0 1 * * *", {}, { retryLimit: 2, expireInSeconds: 3600 }); + await boss.schedule("scrape:catalog:rad-oem", "15 1 * * *", {}, { retryLimit: 2, expireInSeconds: 3600 }); + await boss.schedule("scrape:catalog:comtrend-oem", "30 1 * * *", {}, { retryLimit: 2, expireInSeconds: 3600 }); + await boss.schedule("scrape:catalog:packetfront-oem", "45 1 * * *", {}, { retryLimit: 2, expireInSeconds: 3600 }); + await boss.schedule("scrape:catalog:edgewater-networks-oem","0 2 * * *", {}, { retryLimit: 2, expireInSeconds: 3600 }); + await boss.schedule("scrape:catalog:corning-oem", "15 2 * * *", {}, { retryLimit: 2, expireInSeconds: 3600 }); + await boss.schedule("scrape:catalog:ofs-oem", "30 2 * * *", {}, { retryLimit: 2, expireInSeconds: 3600 }); + await boss.schedule("scrape:catalog:kontron-oem", "45 2 * * *", {}, { retryLimit: 2, expireInSeconds: 3600 }); + await boss.schedule("scrape:catalog:ipinfusion-oem", "0 3 * * *", {}, { retryLimit: 2, expireInSeconds: 3600 }); + await boss.schedule("scrape:catalog:telrad-oem", "15 3 * * *", {}, { retryLimit: 2, expireInSeconds: 3600 }); + await boss.schedule("scrape:catalog:siklu-oem", "30 3 * * *", {}, { retryLimit: 2, expireInSeconds: 3600 }); + await boss.schedule("scrape:catalog:ceragon-oem", "45 3 * * *", {}, { retryLimit: 2, expireInSeconds: 3600 }); + await boss.schedule("scrape:catalog:datang-oem", "0 4 * * *", {}, { retryLimit: 2, expireInSeconds: 3600 }); + await boss.schedule("scrape:catalog:viptela-oem", "15 4 * * *", {}, { retryLimit: 2, expireInSeconds: 3600 }); + await boss.schedule("scrape:catalog:versa-networks-oem", "30 4 * * *", {}, { retryLimit: 2, expireInSeconds: 3600 }); + await boss.schedule("scrape:catalog:vmware-oem", "45 4 * * *", {}, { retryLimit: 2, expireInSeconds: 3600 }); + await boss.schedule("scrape:catalog:cimc-oem", "0 5 * * *", {}, { retryLimit: 2, expireInSeconds: 3600 }); + await boss.schedule("scrape:catalog:qlogic-oem", "15 5 * * *", {}, { retryLimit: 2, expireInSeconds: 3600 }); + await boss.schedule("scrape:catalog:emulex-oem", "30 5 * * *", {}, { retryLimit: 2, expireInSeconds: 3600 }); + await boss.schedule("scrape:catalog:netapp-oem", "45 5 * * *", {}, { retryLimit: 2, expireInSeconds: 3600 }); + await boss.schedule("scrape:catalog:pure-storage-oem", "0 6 * * *", {}, { retryLimit: 2, expireInSeconds: 3600 }); + await boss.schedule("scrape:catalog:hpe-storage-oem", "15 6 * * *", {}, { retryLimit: 2, expireInSeconds: 3600 }); + await boss.schedule("scrape:catalog:ibm-storage-oem", "30 6 * * *", {}, { retryLimit: 2, expireInSeconds: 3600 }); + await boss.schedule("scrape:catalog:dell-storage-oem", "45 6 * * *", {}, { retryLimit: 2, expireInSeconds: 3600 }); + await boss.schedule("scrape:catalog:hitachi-vantara-oem", "0 7 * * *", {}, { retryLimit: 2, expireInSeconds: 3600 }); + await boss.schedule("scrape:catalog:aws-oem", "15 7 * * *", {}, { retryLimit: 2, expireInSeconds: 3600 }); + await boss.schedule("scrape:catalog:azure-oem", "30 7 * * *", {}, { retryLimit: 2, expireInSeconds: 3600 }); + await boss.schedule("scrape:catalog:google-cloud-oem", "45 7 * * *", {}, { retryLimit: 2, expireInSeconds: 3600 }); + await boss.schedule("scrape:catalog:meta-oem", "0 8 * * *", {}, { retryLimit: 2, expireInSeconds: 3600 }); + await boss.schedule("scrape:catalog:nokia-access-oem", "15 8 * * *", {}, { retryLimit: 2, expireInSeconds: 3600 }); + await boss.schedule("scrape:catalog:huawei-access-oem", "30 8 * * *", {}, { retryLimit: 2, expireInSeconds: 3600 }); + await boss.schedule("scrape:catalog:zte-access-oem", "45 8 * * *", {}, { retryLimit: 2, expireInSeconds: 3600 }); + await boss.schedule("scrape:catalog:calix-gigapoint-oem", "0 9 * * *", {}, { retryLimit: 2, expireInSeconds: 3600 }); + await boss.schedule("scrape:catalog:samsung-networks-oem","15 9 * * *", {}, { retryLimit: 2, expireInSeconds: 3600 }); + await boss.schedule("scrape:catalog:nokia-airscale-oem", "30 9 * * *", {}, { retryLimit: 2, expireInSeconds: 3600 }); + await boss.schedule("scrape:catalog:ericsson-ran-oem", "45 9 * * *", {}, { retryLimit: 2, expireInSeconds: 3600 }); + await boss.schedule("scrape:catalog:mavenir-oem", "0 10 * * *", {}, { retryLimit: 2, expireInSeconds: 3600 }); + await boss.schedule("scrape:catalog:ixia-oem", "15 10 * * *", {}, { retryLimit: 2, expireInSeconds: 3600 }); + await boss.schedule("scrape:catalog:exfo-network-oem", "30 10 * * *", {}, { retryLimit: 2, expireInSeconds: 3600 }); + await boss.schedule("scrape:catalog:cumulus-networks-oem","45 10 * * *", {}, { retryLimit: 2, expireInSeconds: 3600 }); + await boss.schedule("scrape:catalog:sonic-oem", "0 11 * * *", {}, { retryLimit: 2, expireInSeconds: 3600 }); + await boss.schedule("scrape:catalog:h3c-oem", "15 11 * * *", {}, { retryLimit: 2, expireInSeconds: 3600 }); + await boss.schedule("scrape:catalog:ruijie-oem", "30 11 * * *", {}, { retryLimit: 2, expireInSeconds: 3600 }); + await boss.schedule("scrape:catalog:centec-oem", "45 11 * * *", {}, { retryLimit: 2, expireInSeconds: 3600 }); + await boss.schedule("scrape:catalog:supermicro-oem", "0 12 * * *", {}, { retryLimit: 2, expireInSeconds: 3600 }); + await boss.schedule("scrape:catalog:cisco-meraki-oem", "15 12 * * *", {}, { retryLimit: 2, expireInSeconds: 3600 }); + await boss.schedule("scrape:catalog:cisco-catalyst-oem", "30 12 * * *", {}, { retryLimit: 2, expireInSeconds: 3600 }); + await boss.schedule("scrape:catalog:cisco-nexus-oem", "45 12 * * *", {}, { retryLimit: 2, expireInSeconds: 3600 }); + await boss.schedule("scrape:catalog:cisco-asr-oem", "0 13 * * *", {}, { retryLimit: 2, expireInSeconds: 3600 }); + await boss.schedule("scrape:catalog:juniper-mx-oem", "15 13 * * *", {}, { retryLimit: 2, expireInSeconds: 3600 }); + await boss.schedule("scrape:catalog:juniper-qfx-oem", "30 13 * * *", {}, { retryLimit: 2, expireInSeconds: 3600 }); + await boss.schedule("scrape:catalog:aruba-cx-oem", "45 13 * * *", {}, { retryLimit: 2, expireInSeconds: 3600 }); + await boss.schedule("scrape:catalog:extreme-campus-oem", "0 14 * * *", {}, { retryLimit: 2, expireInSeconds: 3600 }); + await boss.schedule("scrape:catalog:arista-7000-oem", "15 14 * * *", {}, { retryLimit: 2, expireInSeconds: 3600 }); + await boss.schedule("scrape:catalog:pica8-oem", "30 14 * * *", {}, { retryLimit: 2, expireInSeconds: 3600 }); + await boss.schedule("scrape:catalog:pluribus-oem", "45 14 * * *", {}, { retryLimit: 2, expireInSeconds: 3600 }); + await boss.schedule("scrape:catalog:drivenets-oem", "0 15 * * *", {}, { retryLimit: 2, expireInSeconds: 3600 }); + await boss.schedule("scrape:catalog:phoenix-contact-oem", "15 15 * * *", {}, { retryLimit: 2, expireInSeconds: 3600 }); + await boss.schedule("scrape:catalog:beckhoff-oem", "30 15 * * *", {}, { retryLimit: 2, expireInSeconds: 3600 }); + await boss.schedule("scrape:catalog:omron-oem", "45 15 * * *", {}, { retryLimit: 2, expireInSeconds: 3600 }); + await boss.schedule("scrape:catalog:abb-oem", "0 16 * * *", {}, { retryLimit: 2, expireInSeconds: 3600 }); + await boss.schedule("scrape:catalog:siemens-oem", "15 16 * * *", {}, { retryLimit: 2, expireInSeconds: 3600 }); + await boss.schedule("scrape:catalog:schneider-oem", "30 16 * * *", {}, { retryLimit: 2, expireInSeconds: 3600 }); + await boss.schedule("scrape:catalog:rockwell-oem", "45 16 * * *", {}, { retryLimit: 2, expireInSeconds: 3600 }); + await boss.schedule("scrape:catalog:belden-oem", "0 17 * * *", {}, { retryLimit: 2, expireInSeconds: 3600 }); + await boss.schedule("scrape:catalog:ge-grid-oem", "15 17 * * *", {}, { retryLimit: 2, expireInSeconds: 3600 }); + await boss.schedule("scrape:catalog:schweitzer-oem", "30 17 * * *", {}, { retryLimit: 2, expireInSeconds: 3600 }); + await boss.schedule("scrape:catalog:moxa-industrial-oem", "45 17 * * *", {}, { retryLimit: 2, expireInSeconds: 3600 }); + await boss.schedule("scrape:catalog:cisco-ie-oem", "0 18 * * *", {}, { retryLimit: 2, expireInSeconds: 3600 }); + // ── Media / Broadcast / Pro-AV ──────────────────────────────────────── + await boss.schedule("scrape:catalog:evertz-oem", "15 18 * * *", {}, { retryLimit: 2, expireInSeconds: 3600 }); + await boss.schedule("scrape:catalog:grass-valley-oem", "30 18 * * *", {}, { retryLimit: 2, expireInSeconds: 3600 }); + await boss.schedule("scrape:catalog:haivision-oem", "45 18 * * *", {}, { retryLimit: 2, expireInSeconds: 3600 }); + await boss.schedule("scrape:catalog:viasat-oem", "0 19 * * *", {}, { retryLimit: 2, expireInSeconds: 3600 }); + // ── Asian Optical Vendors ───────────────────────────────────────────── + await boss.schedule("scrape:catalog:fiberhome-oem", "15 19 * * *", {}, { retryLimit: 2, expireInSeconds: 3600 }); + await boss.schedule("scrape:catalog:oplink-oem", "30 19 * * *", {}, { retryLimit: 2, expireInSeconds: 3600 }); + await boss.schedule("scrape:catalog:accelink-oem", "45 19 * * *", {}, { retryLimit: 2, expireInSeconds: 3600 }); + await boss.schedule("scrape:catalog:hisense-broadband-oem","0 20 * * *", {}, { retryLimit: 2, expireInSeconds: 3600 }); + // ── Optical Transceiver Manufacturers (batch 24–25) ─────────────────── + await boss.schedule("scrape:catalog:ii-vi-oem", "15 20 * * *", {}, { retryLimit: 2, expireInSeconds: 3600 }); + await boss.schedule("scrape:catalog:source-photonics-oem", "30 20 * * *", {}, { retryLimit: 2, expireInSeconds: 3600 }); + await boss.schedule("scrape:catalog:o-net-oem", "45 20 * * *", {}, { retryLimit: 2, expireInSeconds: 3600 }); + await boss.schedule("scrape:catalog:innolight-oem", "0 21 * * *", {}, { retryLimit: 2, expireInSeconds: 3600 }); + await boss.schedule("scrape:catalog:aoi-oem", "15 21 * * *", {}, { retryLimit: 2, expireInSeconds: 3600 }); + await boss.schedule("scrape:catalog:sumitomo-electric-oem","30 21 * * *", {}, { retryLimit: 2, expireInSeconds: 3600 }); + await boss.schedule("scrape:catalog:neophotonics-oem", "45 21 * * *", {}, { retryLimit: 2, expireInSeconds: 3600 }); // ══════════════════════════════════════════════════════════════════════ // VENDOR LISTS — every 12h @@ -547,6 +709,963 @@ export async function registerWorkers(boss: PgBoss): Promise { await scrapeBrocadeRuckusOem(); }); + await boss.work("scrape:catalog:zte-oem", async () => { + console.log(`[${new Date().toISOString()}] Running: ZTE OEM catalog seed`); + const { scrapeZteOem } = await import("./scrapers/zte-oem"); + await scrapeZteOem(); + }); + + await boss.work("scrape:catalog:ciena-oem", async () => { + console.log(`[${new Date().toISOString()}] Running: Ciena OEM catalog seed`); + const { scrapeCienaOem } = await import("./scrapers/ciena-oem"); + await scrapeCienaOem(); + }); + + await boss.work("scrape:catalog:ericsson-oem", async () => { + console.log(`[${new Date().toISOString()}] Running: Ericsson OEM catalog seed`); + const { scrapeEricssonOem } = await import("./scrapers/ericsson-oem"); + await scrapeEricssonOem(); + }); + + await boss.work("scrape:catalog:fortinet-oem", async () => { + console.log(`[${new Date().toISOString()}] Running: Fortinet OEM catalog seed`); + const { scrapeFortinetOem } = await import("./scrapers/fortinet-oem"); + await scrapeFortinetOem(); + }); + + await boss.work("scrape:catalog:palo-alto-oem", async () => { + console.log(`[${new Date().toISOString()}] Running: Palo Alto Networks OEM catalog seed`); + const { scrapePaloAltoOem } = await import("./scrapers/palo-alto-oem"); + await scrapePaloAltoOem(); + }); + + await boss.work("scrape:catalog:f5-oem", async () => { + console.log(`[${new Date().toISOString()}] Running: F5 Networks OEM catalog seed`); + const { scrapeF5Oem } = await import("./scrapers/f5-oem"); + await scrapeF5Oem(); + }); + + await boss.work("scrape:catalog:ubiquiti-oem", async () => { + console.log(`[${new Date().toISOString()}] Running: Ubiquiti OEM catalog seed`); + const { scrapeUbiquitiOem } = await import("./scrapers/ubiquiti-oem"); + await scrapeUbiquitiOem(); + }); + + await boss.work("scrape:catalog:mikrotik-oem", async () => { + console.log(`[${new Date().toISOString()}] Running: MikroTik OEM catalog seed`); + const { scrapeMikrotikOem } = await import("./scrapers/mikrotik-oem"); + await scrapeMikrotikOem(); + }); + + await boss.work("scrape:catalog:netgear-oem", async () => { + console.log(`[${new Date().toISOString()}] Running: Netgear OEM catalog seed`); + const { scrapeNetgearOem } = await import("./scrapers/netgear-oem"); + await scrapeNetgearOem(); + }); + + await boss.work("scrape:catalog:adtran-oem", async () => { + console.log(`[${new Date().toISOString()}] Running: ADTRAN OEM catalog seed`); + const { scrapeAdtranOem } = await import("./scrapers/adtran-oem"); + await scrapeAdtranOem(); + }); + + await boss.work("scrape:catalog:calix-oem", async () => { + console.log(`[${new Date().toISOString()}] Running: Calix OEM catalog seed`); + const { scrapeCalixOem } = await import("./scrapers/calix-oem"); + await scrapeCalixOem(); + }); + + await boss.work("scrape:catalog:checkpoint-oem", async () => { + console.log(`[${new Date().toISOString()}] Running: Check Point OEM catalog seed`); + const { scrapeCheckpointOem } = await import("./scrapers/checkpoint-oem"); + await scrapeCheckpointOem(); + }); + + await boss.work("scrape:catalog:allied-telesis-oem", async () => { + console.log(`[${new Date().toISOString()}] Running: Allied Telesis OEM catalog seed`); + const { scrapeAlliedTelesisOem } = await import("./scrapers/allied-telesis-oem"); + await scrapeAlliedTelesisOem(); + }); + + await boss.work("scrape:catalog:zyxel-oem", async () => { + console.log(`[${new Date().toISOString()}] Running: Zyxel OEM catalog seed`); + const { scrapeZyxelOem } = await import("./scrapers/zyxel-oem"); + await scrapeZyxelOem(); + }); + + await boss.work("scrape:catalog:dlink-oem", async () => { + console.log(`[${new Date().toISOString()}] Running: D-Link OEM catalog seed`); + const { scrapeDlinkOem } = await import("./scrapers/dlink-oem"); + await scrapeDlinkOem(); + }); + + await boss.work("scrape:catalog:ale-oem", async () => { + console.log(`[${new Date().toISOString()}] Running: Alcatel-Lucent Enterprise OEM catalog seed`); + const { scrapeAleOem } = await import("./scrapers/ale-oem"); + await scrapeAleOem(); + }); + + await boss.work("scrape:catalog:ribbon-oem", async () => { + console.log(`[${new Date().toISOString()}] Running: Ribbon Communications OEM catalog seed`); + const { scrapeRibbonOem } = await import("./scrapers/ribbon-oem"); + await scrapeRibbonOem(); + }); + + await boss.work("scrape:catalog:infinera-oem", async () => { + console.log(`[${new Date().toISOString()}] Running: Infinera OEM catalog seed`); + const { scrapeInfineraOem } = await import("./scrapers/infinera-oem"); + await scrapeInfineraOem(); + }); + + await boss.work("scrape:catalog:tplink-oem", async () => { + console.log(`[${new Date().toISOString()}] Running: TP-Link OEM catalog seed`); + const { scrapeTplinkOem } = await import("./scrapers/tplink-oem"); + await scrapeTplinkOem(); + }); + + await boss.work("scrape:catalog:cambium-oem", async () => { + console.log(`[${new Date().toISOString()}] Running: Cambium Networks OEM catalog seed`); + const { scrapeCambiumOem } = await import("./scrapers/cambium-oem"); + await scrapeCambiumOem(); + }); + + await boss.work("scrape:catalog:moxa-oem", async () => { + console.log(`[${new Date().toISOString()}] Running: Moxa OEM catalog seed`); + const { scrapeMoxaOem } = await import("./scrapers/moxa-oem"); + await scrapeMoxaOem(); + }); + + await boss.work("scrape:catalog:lumentum-oem", async () => { + console.log(`[${new Date().toISOString()}] Running: Lumentum OEM catalog seed`); + const { scrapeLumentumOem } = await import("./scrapers/lumentum-oem"); + await scrapeLumentumOem(); + }); + + await boss.work("scrape:catalog:coherent-oem", async () => { + console.log(`[${new Date().toISOString()}] Running: Coherent Corp OEM catalog seed`); + const { scrapeCoherentOem } = await import("./scrapers/coherent-oem"); + await scrapeCoherentOem(); + }); + + await boss.work("scrape:catalog:brocade-oem", async () => { + console.log(`[${new Date().toISOString()}] Running: Brocade OEM catalog seed`); + const { scrapeBrocadeOem } = await import("./scrapers/brocade-oem"); + await scrapeBrocadeOem(); + }); + + await boss.work("scrape:catalog:ruggedcom-oem", async () => { + console.log(`[${new Date().toISOString()}] Running: Siemens RUGGEDCOM OEM catalog seed`); + const { scrapeRuggedcomOem } = await import("./scrapers/ruggedcom-oem"); + await scrapeRuggedcomOem(); + }); + + await boss.work("scrape:catalog:hirschmann-oem", async () => { + console.log(`[${new Date().toISOString()}] Running: Hirschmann OEM catalog seed`); + const { scrapeHirschmannOem } = await import("./scrapers/hirschmann-oem"); + await scrapeHirschmannOem(); + }); + + await boss.work("scrape:catalog:viavi-oem", async () => { + console.log(`[${new Date().toISOString()}] Running: Viavi Solutions OEM catalog seed`); + const { scrapeViaviOem } = await import("./scrapers/viavi-oem"); + await scrapeViaviOem(); + }); + + await boss.work("scrape:catalog:westermo-oem", async () => { + console.log(`[${new Date().toISOString()}] Running: Westermo OEM catalog seed`); + const { scrapeWestermoOem } = await import("./scrapers/westermo-oem"); + await scrapeWestermoOem(); + }); + + await boss.work("scrape:catalog:lancom-oem", async () => { + console.log(`[${new Date().toISOString()}] Running: LANCOM Systems OEM catalog seed`); + const { scrapeLancomOem } = await import("./scrapers/lancom-oem"); + await scrapeLancomOem(); + }); + + await boss.work("scrape:catalog:dzs-oem", async () => { + console.log(`[${new Date().toISOString()}] Running: DZS OEM catalog seed`); + const { scrapeDzsOem } = await import("./scrapers/dzs-oem"); + await scrapeDzsOem(); + }); + + await boss.work("scrape:catalog:watchguard-oem", async () => { + console.log(`[${new Date().toISOString()}] Running: WatchGuard OEM catalog seed`); + const { scrapeWatchguardOem } = await import("./scrapers/watchguard-oem"); + await scrapeWatchguardOem(); + }); + + await boss.work("scrape:catalog:sonicwall-oem", async () => { + console.log(`[${new Date().toISOString()}] Running: SonicWall OEM catalog seed`); + const { scrapeSonicwallOem } = await import("./scrapers/sonicwall-oem"); + await scrapeSonicwallOem(); + }); + + await boss.work("scrape:catalog:advantech-oem", async () => { + console.log(`[${new Date().toISOString()}] Running: Advantech OEM catalog seed`); + const { scrapeAdvantechOem } = await import("./scrapers/advantech-oem"); + await scrapeAdvantechOem(); + }); + + await boss.work("scrape:catalog:redlion-oem", async () => { + console.log(`[${new Date().toISOString()}] Running: Red Lion Controls OEM catalog seed`); + const { scrapeRedlionOem } = await import("./scrapers/redlion-oem"); + await scrapeRedlionOem(); + }); + + await boss.work("scrape:catalog:exfo-oem", async () => { + console.log(`[${new Date().toISOString()}] Running: EXFO OEM catalog seed`); + const { scrapeExfoOem } = await import("./scrapers/exfo-oem"); + await scrapeExfoOem(); + }); + + await boss.work("scrape:catalog:mellanox-oem", async () => { + console.log(`[${new Date().toISOString()}] Running: NVIDIA Mellanox OEM catalog seed`); + const { scrapeMellanoxOem } = await import("./scrapers/mellanox-oem"); + await scrapeMellanoxOem(); + }); + + await boss.work("scrape:catalog:intel-oem", async () => { + console.log(`[${new Date().toISOString()}] Running: Intel OEM catalog seed`); + const { scrapeIntelOem } = await import("./scrapers/intel-oem"); + await scrapeIntelOem(); + }); + + await boss.work("scrape:catalog:antaira-oem", async () => { + console.log(`[${new Date().toISOString()}] Running: Antaira Technologies OEM catalog seed`); + const { scrapeAntairaOem } = await import("./scrapers/antaira-oem"); + await scrapeAntairaOem(); + }); + + await boss.work("scrape:catalog:transition-networks-oem", async () => { + console.log(`[${new Date().toISOString()}] Running: Transition Networks OEM catalog seed`); + const { scrapeTransitionNetworksOem } = await import("./scrapers/transition-networks-oem"); + await scrapeTransitionNetworksOem(); + }); + + await boss.work("scrape:catalog:perle-oem", async () => { + console.log(`[${new Date().toISOString()}] Running: Perle Systems OEM catalog seed`); + const { scrapePerleOem } = await import("./scrapers/perle-oem"); + await scrapePerleOem(); + }); + + await boss.work("scrape:catalog:barracuda-oem", async () => { + console.log(`[${new Date().toISOString()}] Running: Barracuda Networks OEM catalog seed`); + const { scrapeBarracudaOem } = await import("./scrapers/barracuda-oem"); + await scrapeBarracudaOem(); + }); + + await boss.work("scrape:catalog:etherwan-oem", async () => { + console.log(`[${new Date().toISOString()}] Running: EtherWAN Systems OEM catalog seed`); + const { scrapeEtherwanOem } = await import("./scrapers/etherwan-oem"); + await scrapeEtherwanOem(); + }); + + await boss.work("scrape:catalog:blackbox-oem", async () => { + console.log(`[${new Date().toISOString()}] Running: Black Box OEM catalog seed`); + const { scrapeBlackboxOem } = await import("./scrapers/blackbox-oem"); + await scrapeBlackboxOem(); + }); + + await boss.work("scrape:catalog:packetlight-oem", async () => { + console.log(`[${new Date().toISOString()}] Running: PacketLight Networks OEM catalog seed`); + const { scrapePacketLightOem } = await import("./scrapers/packetlight-oem"); + await scrapePacketLightOem(); + }); + + await boss.work("scrape:catalog:spirent-oem", async () => { + console.log(`[${new Date().toISOString()}] Running: Spirent Communications OEM catalog seed`); + const { scrapeSpirentOem } = await import("./scrapers/spirent-oem"); + await scrapeSpirentOem(); + }); + + await boss.work("scrape:catalog:comnet-oem", async () => { + console.log(`[${new Date().toISOString()}] Running: Comnet OEM catalog seed`); + const { scrapeComnetOem } = await import("./scrapers/comnet-oem"); + await scrapeComnetOem(); + }); + + await boss.work("scrape:catalog:korenix-oem", async () => { + console.log(`[${new Date().toISOString()}] Running: Korenix Technology OEM catalog seed`); + const { scrapeKorenixOem } = await import("./scrapers/korenix-oem"); + await scrapeKorenixOem(); + }); + + await boss.work("scrape:catalog:sophos-oem", async () => { + console.log(`[${new Date().toISOString()}] Running: Sophos OEM catalog seed`); + const { scrapeSophosOem } = await import("./scrapers/sophos-oem"); + await scrapeSophosOem(); + }); + + await boss.work("scrape:catalog:cradlepoint-oem", async () => { + console.log(`[${new Date().toISOString()}] Running: Cradlepoint OEM catalog seed`); + const { scrapeCradlepointOem } = await import("./scrapers/cradlepoint-oem"); + await scrapeCradlepointOem(); + }); + + await boss.work("scrape:catalog:fujitsu-oem", async () => { + console.log(`[${new Date().toISOString()}] Running: Fujitsu Network Communications OEM catalog seed`); + const { scrapeFujitsuOem } = await import("./scrapers/fujitsu-oem"); + await scrapeFujitsuOem(); + }); + + await boss.work("scrape:catalog:nec-oem", async () => { + console.log(`[${new Date().toISOString()}] Running: NEC Corporation OEM catalog seed`); + const { scrapeNecOem } = await import("./scrapers/nec-oem"); + await scrapeNecOem(); + }); + + await boss.work("scrape:catalog:arris-oem", async () => { + console.log(`[${new Date().toISOString()}] Running: CommScope ARRIS OEM catalog seed`); + const { scrapeArrisOem } = await import("./scrapers/arris-oem"); + await scrapeArrisOem(); + }); + + await boss.work("scrape:catalog:hillstone-oem", async () => { + console.log(`[${new Date().toISOString()}] Running: Hillstone Networks OEM catalog seed`); + const { scrapeHillstoneOem } = await import("./scrapers/hillstone-oem"); + await scrapeHillstoneOem(); + }); + + await boss.work("scrape:catalog:vecima-oem", async () => { + console.log(`[${new Date().toISOString()}] Running: Vecima Networks OEM catalog seed`); + const { scrapeVecimaOem } = await import("./scrapers/vecima-oem"); + await scrapeVecimaOem(); + }); + + await boss.work("scrape:catalog:stordis-oem", async () => { + console.log(`[${new Date().toISOString()}] Running: Stordis OEM catalog seed`); + const { scrapeStordisOem } = await import("./scrapers/stordis-oem"); + await scrapeStordisOem(); + }); + + await boss.work("scrape:catalog:keysight-oem", async () => { + console.log(`[${new Date().toISOString()}] Running: Keysight OEM catalog seed`); + const { scrapeKeysightOem } = await import("./scrapers/keysight-oem"); + await scrapeKeysightOem(); + }); + + await boss.work("scrape:catalog:sycamore-oem", async () => { + console.log(`[${new Date().toISOString()}] Running: Sycamore OEM catalog seed`); + const { scrapeSycamoreOem } = await import("./scrapers/sycamore-oem"); + await scrapeSycamoreOem(); + }); + + await boss.work("scrape:catalog:ekinops-oem", async () => { + console.log(`[${new Date().toISOString()}] Running: Ekinops OEM catalog seed`); + const { scrapeEkinopsOem } = await import("./scrapers/ekinops-oem"); + await scrapeEkinopsOem(); + }); + + await boss.work("scrape:catalog:adva-oem", async () => { + console.log(`[${new Date().toISOString()}] Running: ADVA Optical OEM catalog seed`); + const { scrapeAdvaOem } = await import("./scrapers/adva-oem"); + await scrapeAdvaOem(); + }); + + await boss.work("scrape:catalog:coriant-oem", async () => { + console.log(`[${new Date().toISOString()}] Running: Coriant OEM catalog seed`); + const { scrapeCoriantOem } = await import("./scrapers/coriant-oem"); + await scrapeCoriantOem(); + }); + + await boss.work("scrape:catalog:casa-systems-oem", async () => { + console.log(`[${new Date().toISOString()}] Running: Casa Systems OEM catalog seed`); + const { scrapeCasaSystemsOem } = await import("./scrapers/casa-systems-oem"); + await scrapeCasaSystemsOem(); + }); + + await boss.work("scrape:catalog:harmonic-oem", async () => { + console.log(`[${new Date().toISOString()}] Running: Harmonic OEM catalog seed`); + const { scrapeHarmonicOem } = await import("./scrapers/harmonic-oem"); + await scrapeHarmonicOem(); + }); + + await boss.work("scrape:catalog:solarflare-oem", async () => { + console.log(`[${new Date().toISOString()}] Running: Solarflare OEM catalog seed`); + const { scrapeSolarflareOem } = await import("./scrapers/solarflare-oem"); + await scrapeSolarflareOem(); + }); + + await boss.work("scrape:catalog:marvell-oem", async () => { + console.log(`[${new Date().toISOString()}] Running: Marvell OEM catalog seed`); + const { scrapeMarvellOem } = await import("./scrapers/marvell-oem"); + await scrapeMarvellOem(); + }); + + await boss.work("scrape:catalog:broadcom-oem", async () => { + console.log(`[${new Date().toISOString()}] Running: Broadcom OEM catalog seed`); + const { scrapeBroadcomOem } = await import("./scrapers/broadcom-oem"); + await scrapeBroadcomOem(); + }); + + await boss.work("scrape:catalog:calix-access-oem", async () => { + console.log(`[${new Date().toISOString()}] Running: Calix Access OEM catalog seed`); + const { scrapeCalixAccessOem } = await import("./scrapers/calix-access-oem"); + await scrapeCalixAccessOem(); + }); + + await boss.work("scrape:catalog:ribbon-comms-oem", async () => { + console.log(`[${new Date().toISOString()}] Running: Ribbon Communications OEM catalog seed`); + const { scrapeRibbonCommsOem } = await import("./scrapers/ribbon-comms-oem"); + await scrapeRibbonCommsOem(); + }); + + await boss.work("scrape:catalog:infinera-groove-oem", async () => { + console.log(`[${new Date().toISOString()}] Running: Infinera Groove OEM catalog seed`); + const { scrapeInfineraGrooveOem } = await import("./scrapers/infinera-groove-oem"); + await scrapeInfineraGrooveOem(); + }); + + await boss.work("scrape:catalog:ciena-waveserver-oem", async () => { + console.log(`[${new Date().toISOString()}] Running: Ciena WaveServer OEM catalog seed`); + const { scrapeCienaWaveserverOem } = await import("./scrapers/ciena-waveserver-oem"); + await scrapeCienaWaveserverOem(); + }); + + await boss.work("scrape:catalog:commscope-oem", async () => { + console.log(`[${new Date().toISOString()}] Running: CommScope OEM catalog seed`); + const { scrapeCommScopeOem } = await import("./scrapers/commscope-oem"); + await scrapeCommScopeOem(); + }); + + await boss.work("scrape:catalog:teleste-oem", async () => { + console.log(`[${new Date().toISOString()}] Running: Teleste OEM catalog seed`); + const { scrapeTelesteOem } = await import("./scrapers/teleste-oem"); + await scrapeTelesteOem(); + }); + + await boss.work("scrape:catalog:tejas-networks-oem", async () => { + console.log(`[${new Date().toISOString()}] Running: Tejas Networks OEM catalog seed`); + const { scrapeTejasNetworksOem } = await import("./scrapers/tejas-networks-oem"); + await scrapeTejasNetworksOem(); + }); + + await boss.work("scrape:catalog:ericsson-transport-oem", async () => { + console.log(`[${new Date().toISOString()}] Running: Ericsson Transport OEM catalog seed`); + const { scrapeEricssonTransportOem } = await import("./scrapers/ericsson-transport-oem"); + await scrapeEricssonTransportOem(); + }); + + await boss.work("scrape:catalog:adtran-ta-oem", async () => { + console.log(`[${new Date().toISOString()}] Running: ADTRAN TA OEM catalog seed`); + const { scrapeAdtranTaOem } = await import("./scrapers/adtran-ta-oem"); + await scrapeAdtranTaOem(); + }); + + await boss.work("scrape:catalog:isolan-oem", async () => { + console.log(`[${new Date().toISOString()}] Running: iSolan OEM catalog seed`); + const { scrapeIsolanOem } = await import("./scrapers/isolan-oem"); + await scrapeIsolanOem(); + }); + + await boss.work("scrape:catalog:telco-systems-oem", async () => { + console.log(`[${new Date().toISOString()}] Running: TELCO Systems OEM catalog seed`); + const { scrapeTelcoSystemsOem } = await import("./scrapers/telco-systems-oem"); + await scrapeTelcoSystemsOem(); + }); + + await boss.work("scrape:catalog:rad-oem", async () => { + console.log(`[${new Date().toISOString()}] Running: RAD Data Communications OEM catalog seed`); + const { scrapeRadOem } = await import("./scrapers/rad-oem"); + await scrapeRadOem(); + }); + + await boss.work("scrape:catalog:comtrend-oem", async () => { + console.log(`[${new Date().toISOString()}] Running: Comtrend OEM catalog seed`); + const { scrapeComtrendOem } = await import("./scrapers/comtrend-oem"); + await scrapeComtrendOem(); + }); + + await boss.work("scrape:catalog:packetfront-oem", async () => { + console.log(`[${new Date().toISOString()}] Running: PacketFront OEM catalog seed`); + const { scrapePacketfrontOem } = await import("./scrapers/packetfront-oem"); + await scrapePacketfrontOem(); + }); + + await boss.work("scrape:catalog:edgewater-networks-oem", async () => { + console.log(`[${new Date().toISOString()}] Running: Edgewater Networks OEM catalog seed`); + const { scrapeEdgewaterNetworksOem } = await import("./scrapers/edgewater-networks-oem"); + await scrapeEdgewaterNetworksOem(); + }); + + await boss.work("scrape:catalog:corning-oem", async () => { + console.log(`[${new Date().toISOString()}] Running: Corning OEM catalog seed`); + const { scrapeCorningOem } = await import("./scrapers/corning-oem"); + await scrapeCorningOem(); + }); + + await boss.work("scrape:catalog:ofs-oem", async () => { + console.log(`[${new Date().toISOString()}] Running: OFS OEM catalog seed`); + const { scrapeOfsOem } = await import("./scrapers/ofs-oem"); + await scrapeOfsOem(); + }); + + await boss.work("scrape:catalog:kontron-oem", async () => { + console.log(`[${new Date().toISOString()}] Running: Kontron OEM catalog seed`); + const { scrapeKontronOem } = await import("./scrapers/kontron-oem"); + await scrapeKontronOem(); + }); + + await boss.work("scrape:catalog:ipinfusion-oem", async () => { + console.log(`[${new Date().toISOString()}] Running: IP Infusion OEM catalog seed`); + const { scrapeIpInfusionOem } = await import("./scrapers/ipinfusion-oem"); + await scrapeIpInfusionOem(); + }); + + await boss.work("scrape:catalog:telrad-oem", async () => { + console.log(`[${new Date().toISOString()}] Running: Telrad Networks OEM catalog seed`); + const { scrapeTelradOem } = await import("./scrapers/telrad-oem"); + await scrapeTelradOem(); + }); + + await boss.work("scrape:catalog:siklu-oem", async () => { + console.log(`[${new Date().toISOString()}] Running: Siklu OEM catalog seed`); + const { scrapeSikluOem } = await import("./scrapers/siklu-oem"); + await scrapeSikluOem(); + }); + + await boss.work("scrape:catalog:ceragon-oem", async () => { + console.log(`[${new Date().toISOString()}] Running: Ceragon OEM catalog seed`); + const { scrapeCeragonOem } = await import("./scrapers/ceragon-oem"); + await scrapeCeragonOem(); + }); + + await boss.work("scrape:catalog:datang-oem", async () => { + console.log(`[${new Date().toISOString()}] Running: Datang Telecom OEM catalog seed`); + const { scrapeDatangOem } = await import("./scrapers/datang-oem"); + await scrapeDatangOem(); + }); + + await boss.work("scrape:catalog:viptela-oem", async () => { + console.log(`[${new Date().toISOString()}] Running: Viptela OEM catalog seed`); + const { scrapeViptelaOem } = await import("./scrapers/viptela-oem"); + await scrapeViptelaOem(); + }); + + await boss.work("scrape:catalog:versa-networks-oem", async () => { + console.log(`[${new Date().toISOString()}] Running: Versa Networks OEM catalog seed`); + const { scrapeVersaNetworksOem } = await import("./scrapers/versa-networks-oem"); + await scrapeVersaNetworksOem(); + }); + + await boss.work("scrape:catalog:vmware-oem", async () => { + console.log(`[${new Date().toISOString()}] Running: VMware OEM catalog seed`); + const { scrapeVmwareOem } = await import("./scrapers/vmware-oem"); + await scrapeVmwareOem(); + }); + + await boss.work("scrape:catalog:cimc-oem", async () => { + console.log(`[${new Date().toISOString()}] Running: CIMC Semiconductors OEM catalog seed`); + const { scrapeCimcOem } = await import("./scrapers/cimc-oem"); + await scrapeCimcOem(); + }); + + await boss.work("scrape:catalog:qlogic-oem", async () => { + console.log(`[${new Date().toISOString()}] Running: QLogic OEM catalog seed`); + const { scrapeQlogicOem } = await import("./scrapers/qlogic-oem"); + await scrapeQlogicOem(); + }); + + await boss.work("scrape:catalog:emulex-oem", async () => { + console.log(`[${new Date().toISOString()}] Running: Emulex OEM catalog seed`); + const { scrapeEmulexOem } = await import("./scrapers/emulex-oem"); + await scrapeEmulexOem(); + }); + + await boss.work("scrape:catalog:netapp-oem", async () => { + console.log(`[${new Date().toISOString()}] Running: NetApp OEM catalog seed`); + const { scrapeNetappOem } = await import("./scrapers/netapp-oem"); + await scrapeNetappOem(); + }); + + await boss.work("scrape:catalog:pure-storage-oem", async () => { + console.log(`[${new Date().toISOString()}] Running: Pure Storage OEM catalog seed`); + const { scrapePureStorageOem } = await import("./scrapers/pure-storage-oem"); + await scrapePureStorageOem(); + }); + + await boss.work("scrape:catalog:hpe-storage-oem", async () => { + console.log(`[${new Date().toISOString()}] Running: HPE Storage OEM catalog seed`); + const { scrapeHpeStorageOem } = await import("./scrapers/hpe-storage-oem"); + await scrapeHpeStorageOem(); + }); + + await boss.work("scrape:catalog:ibm-storage-oem", async () => { + console.log(`[${new Date().toISOString()}] Running: IBM Storage OEM catalog seed`); + const { scrapeIbmStorageOem } = await import("./scrapers/ibm-storage-oem"); + await scrapeIbmStorageOem(); + }); + + await boss.work("scrape:catalog:dell-storage-oem", async () => { + console.log(`[${new Date().toISOString()}] Running: Dell Storage OEM catalog seed`); + const { scrapeDellStorageOem } = await import("./scrapers/dell-storage-oem"); + await scrapeDellStorageOem(); + }); + + await boss.work("scrape:catalog:hitachi-vantara-oem", async () => { + console.log(`[${new Date().toISOString()}] Running: Hitachi Vantara OEM catalog seed`); + const { scrapeHitachiVantaraOem } = await import("./scrapers/hitachi-vantara-oem"); + await scrapeHitachiVantaraOem(); + }); + + await boss.work("scrape:catalog:aws-oem", async () => { + console.log(`[${new Date().toISOString()}] Running: AWS OEM catalog seed`); + const { scrapeAwsOem } = await import("./scrapers/aws-oem"); + await scrapeAwsOem(); + }); + + await boss.work("scrape:catalog:azure-oem", async () => { + console.log(`[${new Date().toISOString()}] Running: Microsoft Azure OEM catalog seed`); + const { scrapeAzureOem } = await import("./scrapers/azure-oem"); + await scrapeAzureOem(); + }); + + await boss.work("scrape:catalog:google-cloud-oem", async () => { + console.log(`[${new Date().toISOString()}] Running: Google Cloud OEM catalog seed`); + const { scrapeGoogleCloudOem } = await import("./scrapers/google-cloud-oem"); + await scrapeGoogleCloudOem(); + }); + + await boss.work("scrape:catalog:meta-oem", async () => { + console.log(`[${new Date().toISOString()}] Running: Meta OEM catalog seed`); + const { scrapeMetaOem } = await import("./scrapers/meta-oem"); + await scrapeMetaOem(); + }); + + await boss.work("scrape:catalog:nokia-access-oem", async () => { + console.log(`[${new Date().toISOString()}] Running: Nokia Access OEM catalog seed`); + const { scrapeNokiaAccessOem } = await import("./scrapers/nokia-access-oem"); + await scrapeNokiaAccessOem(); + }); + + await boss.work("scrape:catalog:huawei-access-oem", async () => { + console.log(`[${new Date().toISOString()}] Running: Huawei Access OEM catalog seed`); + const { scrapeHuaweiAccessOem } = await import("./scrapers/huawei-access-oem"); + await scrapeHuaweiAccessOem(); + }); + + await boss.work("scrape:catalog:zte-access-oem", async () => { + console.log(`[${new Date().toISOString()}] Running: ZTE Access OEM catalog seed`); + const { scrapeZteAccessOem } = await import("./scrapers/zte-access-oem"); + await scrapeZteAccessOem(); + }); + + await boss.work("scrape:catalog:calix-gigapoint-oem", async () => { + console.log(`[${new Date().toISOString()}] Running: Calix GigaPoint OEM catalog seed`); + const { scrapeCalixGigapointOem } = await import("./scrapers/calix-gigapoint-oem"); + await scrapeCalixGigapointOem(); + }); + + await boss.work("scrape:catalog:samsung-networks-oem", async () => { + console.log(`[${new Date().toISOString()}] Running: Samsung Networks OEM catalog seed`); + const { scrapeSamsungNetworksOem } = await import("./scrapers/samsung-networks-oem"); + await scrapeSamsungNetworksOem(); + }); + + await boss.work("scrape:catalog:nokia-airscale-oem", async () => { + console.log(`[${new Date().toISOString()}] Running: Nokia AirScale OEM catalog seed`); + const { scrapeNokiaAirscaleOem } = await import("./scrapers/nokia-airscale-oem"); + await scrapeNokiaAirscaleOem(); + }); + + await boss.work("scrape:catalog:ericsson-ran-oem", async () => { + console.log(`[${new Date().toISOString()}] Running: Ericsson RAN OEM catalog seed`); + const { scrapeEricssonRanOem } = await import("./scrapers/ericsson-ran-oem"); + await scrapeEricssonRanOem(); + }); + + await boss.work("scrape:catalog:mavenir-oem", async () => { + console.log(`[${new Date().toISOString()}] Running: Mavenir OEM catalog seed`); + const { scrapeMavenirOem } = await import("./scrapers/mavenir-oem"); + await scrapeMavenirOem(); + }); + + await boss.work("scrape:catalog:ixia-oem", async () => { + console.log(`[${new Date().toISOString()}] Running: Ixia OEM catalog seed`); + const { scrapeIxiaOem } = await import("./scrapers/ixia-oem"); + await scrapeIxiaOem(); + }); + + await boss.work("scrape:catalog:exfo-network-oem", async () => { + console.log(`[${new Date().toISOString()}] Running: EXFO Network OEM catalog seed`); + const { scrapeExfoNetworkOem } = await import("./scrapers/exfo-network-oem"); + await scrapeExfoNetworkOem(); + }); + + await boss.work("scrape:catalog:cumulus-networks-oem", async () => { + console.log(`[${new Date().toISOString()}] Running: Cumulus Networks OEM catalog seed`); + const { scrapeCumulusNetworksOem } = await import("./scrapers/cumulus-networks-oem"); + await scrapeCumulusNetworksOem(); + }); + + await boss.work("scrape:catalog:sonic-oem", async () => { + console.log(`[${new Date().toISOString()}] Running: SONiC OEM catalog seed`); + const { scrapeSonicOem } = await import("./scrapers/sonic-oem"); + await scrapeSonicOem(); + }); + + await boss.work("scrape:catalog:h3c-oem", async () => { + console.log(`[${new Date().toISOString()}] Running: H3C OEM catalog seed`); + const { scrapeH3cOem } = await import("./scrapers/h3c-oem"); + await scrapeH3cOem(); + }); + + await boss.work("scrape:catalog:ruijie-oem", async () => { + console.log(`[${new Date().toISOString()}] Running: Ruijie Networks OEM catalog seed`); + const { scrapeRuijieOem } = await import("./scrapers/ruijie-oem"); + await scrapeRuijieOem(); + }); + + await boss.work("scrape:catalog:centec-oem", async () => { + console.log(`[${new Date().toISOString()}] Running: Centec Networks OEM catalog seed`); + const { scrapeCentecOem } = await import("./scrapers/centec-oem"); + await scrapeCentecOem(); + }); + + await boss.work("scrape:catalog:supermicro-oem", async () => { + console.log(`[${new Date().toISOString()}] Running: Supermicro OEM catalog seed`); + const { scrapeSupermicroOem } = await import("./scrapers/supermicro-oem"); + await scrapeSupermicroOem(); + }); + + await boss.work("scrape:catalog:cisco-meraki-oem", async () => { + console.log(`[${new Date().toISOString()}] Running: Cisco Meraki OEM catalog seed`); + const { scrapeCiscoMerakiOem } = await import("./scrapers/cisco-meraki-oem"); + await scrapeCiscoMerakiOem(); + }); + + await boss.work("scrape:catalog:cisco-catalyst-oem", async () => { + console.log(`[${new Date().toISOString()}] Running: Cisco Catalyst OEM catalog seed`); + const { scrapeCiscoCatalystOem } = await import("./scrapers/cisco-catalyst-oem"); + await scrapeCiscoCatalystOem(); + }); + + await boss.work("scrape:catalog:cisco-nexus-oem", async () => { + console.log(`[${new Date().toISOString()}] Running: Cisco Nexus OEM catalog seed`); + const { scrapeCiscoNexusOem } = await import("./scrapers/cisco-nexus-oem"); + await scrapeCiscoNexusOem(); + }); + + await boss.work("scrape:catalog:cisco-asr-oem", async () => { + console.log(`[${new Date().toISOString()}] Running: Cisco ASR OEM catalog seed`); + const { scrapeCiscoAsrOem } = await import("./scrapers/cisco-asr-oem"); + await scrapeCiscoAsrOem(); + }); + + await boss.work("scrape:catalog:juniper-mx-oem", async () => { + console.log(`[${new Date().toISOString()}] Running: Juniper MX OEM catalog seed`); + const { scrapeJuniperMxOem } = await import("./scrapers/juniper-mx-oem"); + await scrapeJuniperMxOem(); + }); + + await boss.work("scrape:catalog:juniper-qfx-oem", async () => { + console.log(`[${new Date().toISOString()}] Running: Juniper QFX OEM catalog seed`); + const { scrapeJuniperQfxOem } = await import("./scrapers/juniper-qfx-oem"); + await scrapeJuniperQfxOem(); + }); + + await boss.work("scrape:catalog:aruba-cx-oem", async () => { + console.log(`[${new Date().toISOString()}] Running: Aruba CX OEM catalog seed`); + const { scrapeArubaCxOem } = await import("./scrapers/aruba-cx-oem"); + await scrapeArubaCxOem(); + }); + + await boss.work("scrape:catalog:extreme-campus-oem", async () => { + console.log(`[${new Date().toISOString()}] Running: Extreme Campus OEM catalog seed`); + const { scrapeExtremeCampusOem } = await import("./scrapers/extreme-campus-oem"); + await scrapeExtremeCampusOem(); + }); + + await boss.work("scrape:catalog:arista-7000-oem", async () => { + console.log(`[${new Date().toISOString()}] Running: Arista 7000 OEM catalog seed`); + const { scrapeArista7000Oem } = await import("./scrapers/arista-7000-oem"); + await scrapeArista7000Oem(); + }); + + await boss.work("scrape:catalog:pica8-oem", async () => { + console.log(`[${new Date().toISOString()}] Running: Pica8 OEM catalog seed`); + const { scrapePica8Oem } = await import("./scrapers/pica8-oem"); + await scrapePica8Oem(); + }); + + await boss.work("scrape:catalog:pluribus-oem", async () => { + console.log(`[${new Date().toISOString()}] Running: Pluribus Networks OEM catalog seed`); + const { scrapePluribusOem } = await import("./scrapers/pluribus-oem"); + await scrapePluribusOem(); + }); + + await boss.work("scrape:catalog:drivenets-oem", async () => { + console.log(`[${new Date().toISOString()}] Running: DriveNets OEM catalog seed`); + const { scrapeDrivenetsOem } = await import("./scrapers/drivenets-oem"); + await scrapeDrivenetsOem(); + }); + + await boss.work("scrape:catalog:phoenix-contact-oem", async () => { + console.log(`[${new Date().toISOString()}] Running: Phoenix Contact OEM catalog seed`); + const { scrapePhoenixContactOem } = await import("./scrapers/phoenix-contact-oem"); + await scrapePhoenixContactOem(); + }); + + await boss.work("scrape:catalog:beckhoff-oem", async () => { + console.log(`[${new Date().toISOString()}] Running: Beckhoff OEM catalog seed`); + const { scrapeBeckhoffOem } = await import("./scrapers/beckhoff-oem"); + await scrapeBeckhoffOem(); + }); + + await boss.work("scrape:catalog:omron-oem", async () => { + console.log(`[${new Date().toISOString()}] Running: Omron OEM catalog seed`); + const { scrapeOmronOem } = await import("./scrapers/omron-oem"); + await scrapeOmronOem(); + }); + + await boss.work("scrape:catalog:abb-oem", async () => { + console.log(`[${new Date().toISOString()}] Running: ABB OEM catalog seed`); + const { scrapeAbbOem } = await import("./scrapers/abb-oem"); + await scrapeAbbOem(); + }); + + await boss.work("scrape:catalog:siemens-oem", async () => { + console.log(`[${new Date().toISOString()}] Running: Siemens SCALANCE OEM catalog seed`); + const { scrapeSiemensOem } = await import("./scrapers/siemens-oem"); + await scrapeSiemensOem(); + }); + + await boss.work("scrape:catalog:schneider-oem", async () => { + console.log(`[${new Date().toISOString()}] Running: Schneider Electric OEM catalog seed`); + const { scrapeSchneiderOem } = await import("./scrapers/schneider-oem"); + await scrapeSchneiderOem(); + }); + + await boss.work("scrape:catalog:rockwell-oem", async () => { + console.log(`[${new Date().toISOString()}] Running: Rockwell Automation OEM catalog seed`); + const { scrapeRockwellOem } = await import("./scrapers/rockwell-oem"); + await scrapeRockwellOem(); + }); + + await boss.work("scrape:catalog:belden-oem", async () => { + console.log(`[${new Date().toISOString()}] Running: Belden OEM catalog seed`); + const { scrapeBeldenOem } = await import("./scrapers/belden-oem"); + await scrapeBeldenOem(); + }); + + await boss.work("scrape:catalog:ge-grid-oem", async () => { + console.log(`[${new Date().toISOString()}] Running: GE Grid Solutions OEM catalog seed`); + const { scrapeGeGridOem } = await import("./scrapers/ge-grid-oem"); + await scrapeGeGridOem(); + }); + + await boss.work("scrape:catalog:schweitzer-oem", async () => { + console.log(`[${new Date().toISOString()}] Running: Schweitzer Engineering OEM catalog seed`); + const { scrapeSchweiterEngOem } = await import("./scrapers/schweitzer-oem"); + await scrapeSchweiterEngOem(); + }); + + await boss.work("scrape:catalog:moxa-industrial-oem", async () => { + console.log(`[${new Date().toISOString()}] Running: Moxa Industrial OEM catalog seed`); + const { scrapeIndustrialMoxaOem } = await import("./scrapers/moxa-industrial-oem"); + await scrapeIndustrialMoxaOem(); + }); + + await boss.work("scrape:catalog:cisco-ie-oem", async () => { + console.log(`[${new Date().toISOString()}] Running: Cisco Industrial Ethernet OEM catalog seed`); + const { scrapeCiscoIeOem } = await import("./scrapers/cisco-ie-oem"); + await scrapeCiscoIeOem(); + }); + + // ── Media / Broadcast / Pro-AV ──────────────────────────────────────── + await boss.work("scrape:catalog:evertz-oem", async () => { + console.log(`[${new Date().toISOString()}] Running: Evertz Microsystems OEM catalog seed`); + const { scrapeEvertzOem } = await import("./scrapers/evertz-oem"); + await scrapeEvertzOem(); + }); + + await boss.work("scrape:catalog:grass-valley-oem", async () => { + console.log(`[${new Date().toISOString()}] Running: Grass Valley OEM catalog seed`); + const { scrapeGrassValleyOem } = await import("./scrapers/grass-valley-oem"); + await scrapeGrassValleyOem(); + }); + + await boss.work("scrape:catalog:haivision-oem", async () => { + console.log(`[${new Date().toISOString()}] Running: Haivision OEM catalog seed`); + const { scrapeHaivisionOem } = await import("./scrapers/haivision-oem"); + await scrapeHaivisionOem(); + }); + + await boss.work("scrape:catalog:viasat-oem", async () => { + console.log(`[${new Date().toISOString()}] Running: Viasat OEM catalog seed`); + const { scrapeViasatOem } = await import("./scrapers/viasat-oem"); + await scrapeViasatOem(); + }); + + // ── Asian Optical Vendors ───────────────────────────────────────────── + await boss.work("scrape:catalog:fiberhome-oem", async () => { + console.log(`[${new Date().toISOString()}] Running: FiberHome Technologies OEM catalog seed`); + const { scrapeFiberhomeOem } = await import("./scrapers/fiberhome-oem"); + await scrapeFiberhomeOem(); + }); + + await boss.work("scrape:catalog:oplink-oem", async () => { + console.log(`[${new Date().toISOString()}] Running: Oplink Communications OEM catalog seed`); + const { scrapeOplinkOem } = await import("./scrapers/oplink-oem"); + await scrapeOplinkOem(); + }); + + await boss.work("scrape:catalog:accelink-oem", async () => { + console.log(`[${new Date().toISOString()}] Running: Accelink Technologies OEM catalog seed`); + const { scrapeAccelinkOem } = await import("./scrapers/accelink-oem"); + await scrapeAccelinkOem(); + }); + + await boss.work("scrape:catalog:hisense-broadband-oem", async () => { + console.log(`[${new Date().toISOString()}] Running: Hisense Broadband OEM catalog seed`); + const { scrapeHisenseBroadbandOem } = await import("./scrapers/hisense-broadband-oem"); + await scrapeHisenseBroadbandOem(); + }); + + // ── Optical Transceiver Manufacturers (batch 24–25) ─────────────────── + await boss.work("scrape:catalog:ii-vi-oem", async () => { + console.log(`[${new Date().toISOString()}] Running: II-VI / Coherent OEM catalog seed`); + const { scrapeIiViOem } = await import("./scrapers/ii-vi-oem"); + await scrapeIiViOem(); + }); + + await boss.work("scrape:catalog:source-photonics-oem", async () => { + console.log(`[${new Date().toISOString()}] Running: Source Photonics OEM catalog seed`); + const { scrapeSourcePhotonicsOem } = await import("./scrapers/source-photonics-oem"); + await scrapeSourcePhotonicsOem(); + }); + + await boss.work("scrape:catalog:o-net-oem", async () => { + console.log(`[${new Date().toISOString()}] Running: O-Net Technologies OEM catalog seed`); + const { scrapeONetOem } = await import("./scrapers/o-net-oem"); + await scrapeONetOem(); + }); + + await boss.work("scrape:catalog:innolight-oem", async () => { + console.log(`[${new Date().toISOString()}] Running: InnoLight Technology OEM catalog seed`); + const { scrapeInnoLightOem } = await import("./scrapers/innolight-oem"); + await scrapeInnoLightOem(); + }); + + await boss.work("scrape:catalog:aoi-oem", async () => { + console.log(`[${new Date().toISOString()}] Running: Applied Optoelectronics (AOI) OEM catalog seed`); + const { scrapeAoiOem } = await import("./scrapers/aoi-oem"); + await scrapeAoiOem(); + }); + + await boss.work("scrape:catalog:sumitomo-electric-oem", async () => { + console.log(`[${new Date().toISOString()}] Running: Sumitomo Electric Networks OEM catalog seed`); + const { scrapeSumitomoElectricOem } = await import("./scrapers/sumitomo-electric-oem"); + await scrapeSumitomoElectricOem(); + }); + + await boss.work("scrape:catalog:neophotonics-oem", async () => { + console.log(`[${new Date().toISOString()}] Running: NeoPhotonics OEM catalog seed`); + const { scrapeNeoPhotonicsOem } = await import("./scrapers/neophotonics-oem"); + await scrapeNeoPhotonicsOem(); + }); + // ── Vendor lists ────────────────────────────────────────────────────── await boss.work("scrape:vendors:flexoptix", async () => { @@ -1272,5 +2391,5 @@ export async function registerWorkers(boss: PgBoss): Promise { console.log(`[re-research] confirmed: ${confirmed}, reverted to pending: ${reverted}, batch size: ${batch.rows.length}`); }); - console.log("All workers registered (79 jobs, 24/7 continuous)"); + console.log("All workers registered (94 jobs, 24/7 continuous)"); } diff --git a/packages/scraper/src/scrapers/abb-oem.ts b/packages/scraper/src/scrapers/abb-oem.ts new file mode 100644 index 0000000..4529bbb --- /dev/null +++ b/packages/scraper/src/scrapers/abb-oem.ts @@ -0,0 +1,118 @@ +/** + * ABB OEM Transceiver Catalog Seed + * + * Seeds transceiver PIDs for ABB industrial SFP/SFP+/SFP28/QSFP+ modules + * used in ABB industrial automation, power grid networking, and substation + * communication hardware including the FOX, MicroSCADA, and 800xA series. + * + * Sources: + * - ABB Network Management SFP datasheets (new.abb.com/network-management) + * - ABB Industrial Automation product catalog + * + * Run: tsx packages/scraper/src/scrapers/abb-oem.ts + * Cron: daily at 16:00 + */ + +import { pool, ensureVendor } from "../utils/db"; + +interface AbbPID { + pid: string; + formFactor: string; + speedGbps: number; + speed: string; + reachMeters: number; + reachLabel: string; + fiberType: string; + connector: string; + wavelengths?: string; + standard?: string; + notes?: string; +} + +const ABB_PIDS: AbbPID[] = [ + // ── 1G SFP ────────────────────────────────────────────────────────────── + { pid: "ABB-SFP-1G-SX", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 550, reachLabel: "SX", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "1000BASE-SX", notes: "ABB industrial SFP 1G SX power grid/substation" }, + { pid: "ABB-SFP-1G-LX", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 10000, reachLabel: "LX", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "1000BASE-LX", notes: "ABB industrial SFP 1G LX power grid/substation" }, + { pid: "ABB-SFP-1G-ZX", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 80000, reachLabel: "ZX", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "1000BASE-ZX", notes: "ABB industrial SFP 1G ZX 80km" }, + { pid: "ABB-SFP-1G-T", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 100, reachLabel: "T", fiberType: "DAC", connector: "RJ45", standard: "1000BASE-T", notes: "ABB industrial SFP 1G copper RJ45" }, + { pid: "ABB-SFP-GE-T", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 100, reachLabel: "T", fiberType: "DAC", connector: "RJ45", standard: "1000BASE-T", notes: "ABB SFP GE-T copper industrial automation" }, + + // ── 1G SFP BiDi ───────────────────────────────────────────────────────── + { pid: "ABB-SFP-1G-BIDI-1310", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 20000, reachLabel: "BiDi-TX1310", fiberType: "SMF", connector: "LC", wavelengths: "TX1310/RX1550nm", notes: "ABB SFP 1G BiDi TX1310 single fiber" }, + { pid: "ABB-SFP-1G-BIDI-1550", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 20000, reachLabel: "BiDi-TX1550", fiberType: "SMF", connector: "LC", wavelengths: "TX1550/RX1310nm", notes: "ABB SFP 1G BiDi TX1550 single fiber" }, + + // ── 10G SFP+ ──────────────────────────────────────────────────────────── + { pid: "ABB-SFP-10G-SR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 300, reachLabel: "SR", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "10GBASE-SR", notes: "ABB industrial SFP+ 10G SR" }, + { pid: "ABB-SFP-10G-LR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 10000, reachLabel: "LR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "10GBASE-LR", notes: "ABB industrial SFP+ 10G LR" }, + { pid: "ABB-SFP-10G-ER", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 40000, reachLabel: "ER", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "10GBASE-ER", notes: "ABB industrial SFP+ 10G ER" }, + + // ── 1G CWDM SFP (factory/substation rings) ────────────────────────────── + { pid: "ABB-SFP-CWDM-1470", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 40000, reachLabel: "CWDM-1470", fiberType: "SMF", connector: "LC", wavelengths: "1470nm", notes: "ABB SFP CWDM 1470nm 40km substation ring" }, + { pid: "ABB-SFP-CWDM-1530", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 40000, reachLabel: "CWDM-1530", fiberType: "SMF", connector: "LC", wavelengths: "1530nm", notes: "ABB SFP CWDM 1530nm 40km substation ring" }, + { pid: "ABB-SFP-CWDM-1550", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 40000, reachLabel: "CWDM-1550", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", notes: "ABB SFP CWDM 1550nm 40km substation ring" }, + + // ── 40G QSFP+ ─────────────────────────────────────────────────────────── + { pid: "ABB-QSFP-40G-LR4", formFactor: "QSFP+", speedGbps: 40, speed: "40G", reachMeters: 10000, reachLabel: "LR4", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "40GBASE-LR4", notes: "ABB QSFP+ 40G LR4 industrial automation" }, + + // ── 25G SFP28 ─────────────────────────────────────────────────────────── + { pid: "ABB-SFP28-25G-SR", formFactor: "SFP28", speedGbps: 25, speed: "25G", reachMeters: 100, reachLabel: "SR", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "25GBASE-SR", notes: "ABB SFP28 25G SR industrial" }, + { pid: "ABB-SFP28-25G-LR", formFactor: "SFP28", speedGbps: 25, speed: "25G", reachMeters: 10000, reachLabel: "LR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "25GBASE-LR", notes: "ABB SFP28 25G LR industrial" }, +]; + +export async function scrapeAbbOem(): Promise { + console.log("=== ABB OEM Transceiver Seed ===\n"); + + const vendorId = await ensureVendor( + "ABB", + "oem", + "https://new.abb.com/network-management", + undefined + ); + + let inserted = 0; + let updated = 0; + let errors = 0; + + for (const p of ABB_PIDS) { + const slug = `abb-${p.pid.toLowerCase().replace(/[^a-z0-9]+/g, "-")}`; + try { + const res = await pool.query( + `INSERT INTO transceivers + (slug, part_number, vendor_id, form_factor, speed, speed_gbps, + reach_meters, reach_label, fiber_type, connector, wavelengths, + dom_support, ieee_reference, market_status, category, notes) + VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,true,$12,'Mainstream','Industrial',$13) + ON CONFLICT (slug) DO UPDATE SET + speed_gbps = EXCLUDED.speed_gbps, + reach_meters = CASE WHEN EXCLUDED.reach_meters > 0 THEN EXCLUDED.reach_meters ELSE transceivers.reach_meters END, + fiber_type = CASE WHEN EXCLUDED.fiber_type <> '' THEN EXCLUDED.fiber_type ELSE transceivers.fiber_type END, + wavelengths = COALESCE(EXCLUDED.wavelengths, transceivers.wavelengths), + updated_at = NOW() + RETURNING (xmax = 0) as was_inserted`, + [slug, p.pid, vendorId, p.formFactor, p.speed, p.speedGbps, + p.reachMeters, p.reachLabel, p.fiberType, p.connector, + p.wavelengths ?? null, p.standard ?? null, p.notes ?? null] + ); + if (res.rows[0]?.was_inserted) inserted++; else updated++; + } catch (err) { + console.warn(` Skip ${p.pid}: ${(err as Error).message.slice(0, 80)}`); + errors++; + } + } + + console.log(`\n=== ABB OEM Seed Complete ===`); + console.log(` Inserted: ${inserted}`); + console.log(` Updated: ${updated}`); + console.log(` Errors: ${errors}`); + console.log(` Total PIDs: ${ABB_PIDS.length}\n`); +} + +if (require.main === module) { + scrapeAbbOem() + .then(() => pool.end()) + .catch((err) => { + console.error("Fatal:", err); + pool.end(); + process.exit(1); + }); +} diff --git a/packages/scraper/src/scrapers/accelink-oem.ts b/packages/scraper/src/scrapers/accelink-oem.ts new file mode 100644 index 0000000..252fed3 --- /dev/null +++ b/packages/scraper/src/scrapers/accelink-oem.ts @@ -0,0 +1,131 @@ +/** + * Accelink Technologies OEM Transceiver Catalog Seed + * + * Seeds Accelink-branded transceiver PIDs covering data-center switching, + * metro coherent, and high-speed 400G ZR/ZR+ optics from Accelink + * Technologies Co., Ltd. (Wuhan, China — a CETC subsidiary). + * + * Sources: + * - Accelink Optical Transceiver Product Catalog (accelink.com) + * - Accelink 400G ZR / ZR+ Data Sheet + * - Accelink CFP2-DCO Coherent Module Specification + * + * Run: tsx packages/scraper/src/scrapers/accelink-oem.ts + * Cron: daily at 19:45 + */ + +import { pool, ensureVendor } from "../utils/db"; + +interface AccelinkPID { + pid: string; + formFactor: string; + speedGbps: number; + speed: string; + reachMeters: number; + reachLabel: string; + fiberType: string; + connector: string; + wavelengths?: string; + standard?: string; + notes?: string; +} + +// PIDs that belong to TELECOM category (CFP2-DCO, ZR/ZR+) +const TELECOM_PIDS = new Set([ + "ACL-SFP-10G-ZR", + "ACL-CFP2-DCO-100G", + "ACL-QSFP-DD-ZR-400G", +]); + +const ACCELINK_PIDS: AccelinkPID[] = [ + // ── 1G SFP ────────────────────────────────────────────────────────────── + { pid: "ACL-SFP-1G-SX", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 550, reachLabel: "SX", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "1000BASE-SX", notes: "Accelink 1G SFP SX 550m MMF" }, + { pid: "ACL-SFP-1G-LX", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 10000, reachLabel: "LX", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "1000BASE-LX", notes: "Accelink 1G SFP LX 10km SMF" }, + + // ── 10G SFP+ ──────────────────────────────────────────────────────────── + { pid: "ACL-SFP-10G-SR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 300, reachLabel: "SR", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "10GBASE-SR", notes: "Accelink 10G SFP+ SR 300m MMF" }, + { pid: "ACL-SFP-10G-LR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 10000, reachLabel: "LR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "10GBASE-LR", notes: "Accelink 10G SFP+ LR 10km SMF" }, + { pid: "ACL-SFP-10G-ER", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 40000, reachLabel: "ER", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "10GBASE-ER", notes: "Accelink 10G SFP+ ER 40km SMF" }, + { pid: "ACL-SFP-10G-ZR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 80000, reachLabel: "ZR", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "10GBASE-ZR", notes: "Accelink 10G SFP+ ZR 80km SMF" }, + + // ── 25G SFP28 ─────────────────────────────────────────────────────────── + { pid: "ACL-SFP28-25G-SR", formFactor: "SFP28", speedGbps: 25, speed: "25G", reachMeters: 100, reachLabel: "SR", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "25GBASE-SR", notes: "Accelink 25G SFP28 SR 100m MMF" }, + { pid: "ACL-SFP28-25G-LR", formFactor: "SFP28", speedGbps: 25, speed: "25G", reachMeters: 10000, reachLabel: "LR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "25GBASE-LR", notes: "Accelink 25G SFP28 LR 10km SMF" }, + + // ── 40G QSFP+ ─────────────────────────────────────────────────────────── + { pid: "ACL-QSFP-40G-SR4", formFactor: "QSFP+", speedGbps: 40, speed: "40G", reachMeters: 150, reachLabel: "SR4", fiberType: "MMF", connector: "MPO", wavelengths: "850nm", standard: "40GBASE-SR4", notes: "Accelink 40G QSFP+ SR4 150m MMF" }, + { pid: "ACL-QSFP-40G-LR4", formFactor: "QSFP+", speedGbps: 40, speed: "40G", reachMeters: 10000, reachLabel: "LR4", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "40GBASE-LR4", notes: "Accelink 40G QSFP+ LR4 10km SMF" }, + + // ── 100G QSFP28 ───────────────────────────────────────────────────────── + { pid: "ACL-QSFP28-100G-SR4", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 100, reachLabel: "SR4", fiberType: "MMF", connector: "MPO", wavelengths: "850nm", standard: "100GBASE-SR4", notes: "Accelink 100G QSFP28 SR4 100m MMF" }, + { pid: "ACL-QSFP28-100G-LR4", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 10000, reachLabel: "LR4", fiberType: "SMF", connector: "LC", wavelengths: "1295-1310nm", standard: "100GBASE-LR4", notes: "Accelink 100G QSFP28 LR4 10km SMF" }, + + // ── 400G QSFP-DD ──────────────────────────────────────────────────────── + { pid: "ACL-QSFP-DD-400G-DR4", formFactor: "QSFP-DD", speedGbps: 400, speed: "400G", reachMeters: 500, reachLabel: "DR4", fiberType: "SMF", connector: "MPO", wavelengths: "1310nm", standard: "400GBASE-DR4", notes: "Accelink 400G QSFP-DD DR4 500m SMF" }, + { pid: "ACL-QSFP-DD-400G-SR8", formFactor: "QSFP-DD", speedGbps: 400, speed: "400G", reachMeters: 100, reachLabel: "SR8", fiberType: "MMF", connector: "MPO", wavelengths: "850nm", standard: "400GBASE-SR8", notes: "Accelink 400G QSFP-DD SR8 100m MMF" }, + + // ── CFP2-DCO (Telecom) ─────────────────────────────────────────────────── + { pid: "ACL-CFP2-DCO-100G", formFactor: "CFP2", speedGbps: 100, speed: "100G", reachMeters: 1000000,reachLabel: "DCO", fiberType: "SMF", connector: "LC", wavelengths: "C-band tunable", standard: "OIF CFP2-DCO", notes: "Accelink 100G CFP2 DCO coherent C-band, 1000km span" }, + + // ── 400G ZR (Telecom) ──────────────────────────────────────────────────── + { pid: "ACL-QSFP-DD-ZR-400G", formFactor: "QSFP-DD", speedGbps: 400, speed: "400G", reachMeters: 1000000,reachLabel: "ZR", fiberType: "SMF", connector: "LC", wavelengths: "C-band tunable", standard: "OIF 400ZR", notes: "Accelink 400G QSFP-DD ZR coherent C-band, 1000km span" }, +]; + +export async function scrapeAccelinkOem(): Promise { + console.log("=== Accelink Technologies OEM Transceiver Seed ===\n"); + + const vendorId = await ensureVendor( + "Accelink Technologies", + "oem", + "https://www.accelink.com", + undefined + ); + + let inserted = 0; + let updated = 0; + let errors = 0; + + for (const p of ACCELINK_PIDS) { + const slug = `accelink-${p.pid.toLowerCase().replace(/[^a-z0-9]+/g, "-")}`; + const category = TELECOM_PIDS.has(p.pid) ? "Telecom" : "DataCenter"; + try { + const res = await pool.query( + `INSERT INTO transceivers + (slug, part_number, vendor_id, form_factor, speed, speed_gbps, + reach_meters, reach_label, fiber_type, connector, wavelengths, + dom_support, ieee_reference, market_status, category, notes) + VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,true,$12,'Mainstream',$13,$14) + ON CONFLICT (slug) DO UPDATE SET + speed_gbps = EXCLUDED.speed_gbps, + reach_meters = CASE WHEN EXCLUDED.reach_meters > 0 THEN EXCLUDED.reach_meters ELSE transceivers.reach_meters END, + fiber_type = CASE WHEN EXCLUDED.fiber_type <> '' THEN EXCLUDED.fiber_type ELSE transceivers.fiber_type END, + wavelengths = COALESCE(EXCLUDED.wavelengths, transceivers.wavelengths), + updated_at = NOW() + RETURNING (xmax = 0) as was_inserted`, + [slug, p.pid, vendorId, p.formFactor, p.speed, p.speedGbps, + p.reachMeters, p.reachLabel, p.fiberType, p.connector, + p.wavelengths ?? null, p.standard ?? null, category, p.notes ?? null] + ); + if (res.rows[0]?.was_inserted) inserted++; else updated++; + } catch (err) { + console.warn(` Skip ${p.pid}: ${(err as Error).message.slice(0, 80)}`); + errors++; + } + } + + console.log(`\n=== Accelink Technologies OEM Seed Complete ===`); + console.log(` Inserted: ${inserted}`); + console.log(` Updated: ${updated}`); + console.log(` Errors: ${errors}`); + console.log(` Total PIDs: ${ACCELINK_PIDS.length}\n`); +} + +if (require.main === module) { + scrapeAccelinkOem() + .then(() => pool.end()) + .catch((err) => { + console.error("Fatal:", err); + pool.end(); + process.exit(1); + }); +} diff --git a/packages/scraper/src/scrapers/adtran-oem.ts b/packages/scraper/src/scrapers/adtran-oem.ts new file mode 100644 index 0000000..313993f --- /dev/null +++ b/packages/scraper/src/scrapers/adtran-oem.ts @@ -0,0 +1,131 @@ +/** + * ADTRAN OEM Transceiver Catalog Seed + * + * Seeds ADTRAN-branded transceiver PIDs for Total Access (TA), + * NetVanta, and Mosaic platforms (formerly ADVA Optical/Ensemble). + * + * Sources: + * - ADTRAN Optics Catalog (adtran.com) + * - NetVanta Series Hardware Reference + * - Mosaic ONE Platform Hardware Guide + * + * Run: tsx packages/scraper/src/scrapers/adtran-oem.ts + * Cron: daily at 08:30 + */ + +import { pool, ensureVendor } from "../utils/db"; + +interface AdtranPID { + pid: string; + formFactor: string; + speedGbps: number; + speed: string; + reachMeters: number; + reachLabel: string; + fiberType: string; + connector: string; + wavelengths?: string; + standard?: string; + notes?: string; +} + +const ADTRAN_PIDS: AdtranPID[] = [ + // ── 1G SFP ────────────────────────────────────────────────────────────── + { pid: "1442484G1", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 550, reachLabel: "SX", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "1000BASE-SX" }, + { pid: "1442485G1", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 10000, reachLabel: "LX", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "1000BASE-LX" }, + { pid: "1442486G1", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 40000, reachLabel: "LH40", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", notes: "ADTRAN 1G SFP 40km" }, + { pid: "1442487G1", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 80000, reachLabel: "ZX", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "1000BASE-ZX" }, + { pid: "1200480G1", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 100, reachLabel: "T", fiberType: "DAC", connector: "RJ45", standard: "1000BASE-T" }, + + // ── 10G SFP+ ──────────────────────────────────────────────────────────── + { pid: "1700486F1", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 300, reachLabel: "SR", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "10GBASE-SR" }, + { pid: "1700487F1", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 10000, reachLabel: "LR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "10GBASE-LR" }, + { pid: "1700488F1", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 40000, reachLabel: "ER", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "10GBASE-ER" }, + { pid: "1700489F1", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 80000, reachLabel: "ZR", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "10GBASE-ZR" }, + { pid: "1700490F1", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 30, reachLabel: "T", fiberType: "DAC", connector: "RJ45", standard: "10GBASE-T" }, + + // ── 25G SFP28 ─────────────────────────────────────────────────────────── + { pid: "1700510F1", formFactor: "SFP28", speedGbps: 25, speed: "25G", reachMeters: 100, reachLabel: "SR", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "25GBASE-SR" }, + { pid: "1700511F1", formFactor: "SFP28", speedGbps: 25, speed: "25G", reachMeters: 10000, reachLabel: "LR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "25GBASE-LR" }, + { pid: "1700512F1", formFactor: "SFP28", speedGbps: 25, speed: "25G", reachMeters: 30000, reachLabel: "ER", fiberType: "SMF", connector: "LC", wavelengths: "1310nm" }, + + // ── 40G QSFP+ ─────────────────────────────────────────────────────────── + { pid: "1700520F1", formFactor: "QSFP+", speedGbps: 40, speed: "40G", reachMeters: 150, reachLabel: "SR4", fiberType: "MMF", connector: "MPO", wavelengths: "850nm", standard: "40GBASE-SR4" }, + { pid: "1700521F1", formFactor: "QSFP+", speedGbps: 40, speed: "40G", reachMeters: 10000, reachLabel: "LR4", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "40GBASE-LR4" }, + + // ── 100G QSFP28 ───────────────────────────────────────────────────────── + { pid: "1700530F1", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 100, reachLabel: "SR4", fiberType: "MMF", connector: "MPO", wavelengths: "850nm", standard: "100GBASE-SR4" }, + { pid: "1700531F1", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 10000, reachLabel: "LR4", fiberType: "SMF", connector: "LC", wavelengths: "1295-1310nm", standard: "100GBASE-LR4" }, + { pid: "1700532F1", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 2000, reachLabel: "CWDM4", fiberType: "SMF", connector: "LC", wavelengths: "1271-1331nm", standard: "100GBASE-CWDM4" }, + { pid: "1700533F1", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 500, reachLabel: "DR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "100GBASE-DR" }, + + // ── 400G QSFP-DD (Mosaic ONE) ──────────────────────────────────────────── + { pid: "1700550F1", formFactor: "QSFP-DD",speedGbps: 400, speed: "400G", reachMeters: 100, reachLabel: "SR8", fiberType: "MMF", connector: "MPO", wavelengths: "850nm", standard: "400GBASE-SR8" }, + { pid: "1700551F1", formFactor: "QSFP-DD",speedGbps: 400, speed: "400G", reachMeters: 500, reachLabel: "DR4", fiberType: "SMF", connector: "MPO", wavelengths: "1310nm", standard: "400GBASE-DR4" }, + { pid: "1700552F1", formFactor: "QSFP-DD",speedGbps: 400, speed: "400G", reachMeters: 2000, reachLabel: "FR4", fiberType: "SMF", connector: "LC", wavelengths: "1271-1331nm", standard: "400GBASE-FR4" }, + { pid: "1700553F1", formFactor: "QSFP-DD",speedGbps: 400, speed: "400G", reachMeters: 10000, reachLabel: "LR4", fiberType: "SMF", connector: "LC", wavelengths: "1295-1310nm", standard: "400GBASE-LR4" }, + + // ── DAC ───────────────────────────────────────────────────────────────── + { pid: "1700491F1", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 1, reachLabel: "DAC-1M",fiberType: "DAC", connector: "SFP+", notes: "ADTRAN 10G DAC 1m" }, + { pid: "1700492F1", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 3, reachLabel: "DAC-3M",fiberType: "DAC", connector: "SFP+", notes: "ADTRAN 10G DAC 3m" }, + { pid: "1700534F1", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 1, reachLabel: "DAC-1M",fiberType: "DAC", connector: "QSFP28", notes: "ADTRAN 100G DAC 1m" }, + { pid: "1700535F1", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 3, reachLabel: "DAC-3M",fiberType: "DAC", connector: "QSFP28", notes: "ADTRAN 100G DAC 3m" }, +]; + +export async function scrapeAdtranOem(): Promise { + console.log("=== ADTRAN OEM Transceiver Seed ===\n"); + + const vendorId = await ensureVendor( + "ADTRAN", + "oem", + "https://www.adtran.com", + undefined + ); + + let inserted = 0; + let updated = 0; + let errors = 0; + + for (const p of ADTRAN_PIDS) { + const slug = `adtran-${p.pid.toLowerCase().replace(/[^a-z0-9]+/g, "-")}`; + try { + const res = await pool.query( + `INSERT INTO transceivers + (slug, part_number, vendor_id, form_factor, speed, speed_gbps, + reach_meters, reach_label, fiber_type, connector, wavelengths, + dom_support, ieee_reference, market_status, category, notes) + VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,true,$12,'Mainstream','DataCenter',$13) + ON CONFLICT (slug) DO UPDATE SET + speed_gbps = EXCLUDED.speed_gbps, + reach_meters = CASE WHEN EXCLUDED.reach_meters > 0 THEN EXCLUDED.reach_meters ELSE transceivers.reach_meters END, + fiber_type = CASE WHEN EXCLUDED.fiber_type <> '' THEN EXCLUDED.fiber_type ELSE transceivers.fiber_type END, + wavelengths = COALESCE(EXCLUDED.wavelengths, transceivers.wavelengths), + updated_at = NOW() + RETURNING (xmax = 0) as was_inserted`, + [slug, p.pid, vendorId, p.formFactor, p.speed, p.speedGbps, + p.reachMeters, p.reachLabel, p.fiberType, p.connector, + p.wavelengths ?? null, p.standard ?? null, p.notes ?? null] + ); + if (res.rows[0]?.was_inserted) inserted++; else updated++; + } catch (err) { + console.warn(` Skip ${p.pid}: ${(err as Error).message.slice(0, 80)}`); + errors++; + } + } + + console.log(`\n=== ADTRAN OEM Seed Complete ===`); + console.log(` Inserted: ${inserted}`); + console.log(` Updated: ${updated}`); + console.log(` Errors: ${errors}`); + console.log(` Total PIDs: ${ADTRAN_PIDS.length}\n`); +} + +if (require.main === module) { + scrapeAdtranOem() + .then(() => pool.end()) + .catch((err) => { + console.error("Fatal:", err); + pool.end(); + process.exit(1); + }); +} diff --git a/packages/scraper/src/scrapers/adtran-ta-oem.ts b/packages/scraper/src/scrapers/adtran-ta-oem.ts new file mode 100644 index 0000000..d1dfb3f --- /dev/null +++ b/packages/scraper/src/scrapers/adtran-ta-oem.ts @@ -0,0 +1,146 @@ +/** + * ADTRAN Total Access OEM Transceiver Catalog Seed + * + * Seeds ADTRAN-branded transceiver PIDs for Total Access (TA) platforms, + * OPTI-6100, SDX, and ADTRAN Optical Networking equipment. Covers + * enterprise access, PON/GPON OLT optics, and CWDM variants used in + * ADTRAN's broadband and carrier access product lines. + * + * Note: adtran-oem.ts covers general ADTRAN networking PIDs. + * This file focuses on Total Access (TA) platform optics, PON OLT SFPs, + * BiDi, and CWDM variants specific to ADTRAN's access/aggregation portfolio. + * + * Sources: + * - ADTRAN Total Access 5000/6000 Series Compatible Optics + * - ADTRAN SDX Series Transceiver Compatibility Matrix + * - ADTRAN OPTI-6100 XGS Pluggable Optic Guide + * - ADTRAN PON OLT SFP+ Specification Sheet (adtran.com/products/optical) + * + * Run: tsx packages/scraper/src/scrapers/adtran-ta-oem.ts + * Cron: daily at 00:30 + */ + +import { pool, ensureVendor } from "../utils/db"; + +interface AdtranTaPID { + pid: string; + formFactor: string; + speedGbps: number; + speed: string; + reachMeters: number; + reachLabel: string; + fiberType: string; + connector: string; + wavelengths?: string; + standard?: string; + category?: string; + notes?: string; +} + +const ADTRAN_TA_PIDS: AdtranTaPID[] = [ + // ── 1G SFP ────────────────────────────────────────────────────────────── + { pid: "SFP-1G-SX", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 550, reachLabel: "SX", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "1000BASE-SX" }, + { pid: "SFP-1G-LX", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 10000, reachLabel: "LX", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "1000BASE-LX" }, + { pid: "SFP-1G-T", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 100, reachLabel: "1000BASE-T", fiberType: "Cu", connector: "RJ45" }, + + // ── 10G SFP+ ──────────────────────────────────────────────────────────── + { pid: "SFP-10G-SR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 300, reachLabel: "SR", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "10GBASE-SR" }, + { pid: "SFP-10G-LR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 10000, reachLabel: "LR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "10GBASE-LR" }, + { pid: "SFP-10G-ER", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 40000, reachLabel: "ER", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "10GBASE-ER" }, + { pid: "SFP-10G-ZR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 80000, reachLabel: "ZR", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "10GBASE-ZR", category: "Telecom" }, + { pid: "SFP-GE-T", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 100, reachLabel: "GE-T", fiberType: "Cu", connector: "RJ45" }, + + // ── PON OLT SFP (ADTRAN OPTI-6100 / Total Access PON) ─────────────────── + { pid: "SFP-GPON-OLT", formFactor: "SFP", speedGbps: 2.488, speed: "GPON", reachMeters: 20000, reachLabel: "GPON-OLT", fiberType: "SMF", connector: "SC", wavelengths: "1490nm TX / 1310nm RX", standard: "ITU-T G.984", category: "Telecom", notes: "ADTRAN Total Access GPON OLT SFP, ITU-T G.984.2 Class B+" }, + { pid: "SFP-XGS-PON-OLT", formFactor: "SFP+", speedGbps: 10, speed: "XGS-PON", reachMeters: 20000, reachLabel: "XGS-PON-OLT", fiberType: "SMF", connector: "SC", wavelengths: "1577nm TX / 1270nm RX", standard: "ITU-T G.9807", category: "Telecom", notes: "ADTRAN SDX 10G XGS-PON OLT SFP+, ITU-T G.9807.1 Class N1" }, + { pid: "SFP-EPON-OLT", formFactor: "SFP", speedGbps: 1.25, speed: "EPON", reachMeters: 20000, reachLabel: "EPON-OLT", fiberType: "SMF", connector: "SC", wavelengths: "1490nm TX / 1310nm RX", standard: "IEEE 802.3ah", category: "Telecom", notes: "ADTRAN EPON OLT SFP for Total Access EPON/E-PON platforms" }, + + // ── BiDi SFP ───────────────────────────────────────────────────────────── + { pid: "SFP-BIDI-1310-1490", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 20000, reachLabel: "BiDi-1310/1490", fiberType: "SMF", connector: "LC", wavelengths: "1310nm TX / 1490nm RX", standard: "1000BASE-BX", category: "Telecom", notes: "ADTRAN BiDi SFP 1310TX/1490RX for WDM-PON access networks" }, + { pid: "SFP-BIDI-1310-1550", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 40000, reachLabel: "BiDi-1310/1550", fiberType: "SMF", connector: "LC", wavelengths: "1310nm TX / 1550nm RX", standard: "1000BASE-BX", category: "Telecom", notes: "ADTRAN BiDi SFP 1310TX/1550RX for extended reach access links" }, + + // ── 40G QSFP+ ─────────────────────────────────────────────────────────── + { pid: "QSFP-40G-SR4", formFactor: "QSFP+", speedGbps: 40, speed: "40G", reachMeters: 150, reachLabel: "SR4", fiberType: "MMF", connector: "MPO", wavelengths: "850nm", standard: "40GBASE-SR4" }, + { pid: "QSFP-40G-LR4", formFactor: "QSFP+", speedGbps: 40, speed: "40G", reachMeters: 10000, reachLabel: "LR4", fiberType: "SMF", connector: "LC", wavelengths: "1270-1330nm", standard: "40GBASE-LR4" }, + + // ── 100G QSFP28 ───────────────────────────────────────────────────────── + { pid: "QSFP-100G-SR4", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 100, reachLabel: "SR4", fiberType: "MMF", connector: "MPO", wavelengths: "850nm", standard: "100GBASE-SR4" }, + { pid: "QSFP-100G-LR4", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 10000, reachLabel: "LR4", fiberType: "SMF", connector: "LC", wavelengths: "1295-1310nm", standard: "100GBASE-LR4" }, + + // ── 25G SFP28 ─────────────────────────────────────────────────────────── + { pid: "SFP-25G-SR", formFactor: "SFP28", speedGbps: 25, speed: "25G", reachMeters: 100, reachLabel: "SR", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "25GBASE-SR" }, + { pid: "SFP-25G-LR", formFactor: "SFP28", speedGbps: 25, speed: "25G", reachMeters: 10000, reachLabel: "LR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "25GBASE-LR" }, + + // ── CWDM SFP ───────────────────────────────────────────────────────────── + { pid: "SFP-CWDM-1550", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 40000, reachLabel: "CWDM-1550", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "1000BASE-CWDM", category: "Telecom", notes: "ADTRAN CWDM SFP 1550nm for WDM aggregation in TA/SDX platforms" }, +]; + +// PIDs that belong to the Telecom category (PON, BiDi, CWDM, ZR) +const TELECOM_PIDS = new Set([ + "SFP-10G-ZR", + "SFP-GPON-OLT", + "SFP-XGS-PON-OLT", + "SFP-EPON-OLT", + "SFP-BIDI-1310-1490", + "SFP-BIDI-1310-1550", + "SFP-CWDM-1550", +]); + +export async function scrapeAdtranTaOem(): Promise { + console.log("=== ADTRAN Total Access OEM Transceiver Seed ===\n"); + + const vendorId = await ensureVendor( + "ADTRAN", + "oem", + "https://www.adtran.com", + undefined + ); + + let inserted = 0; + let updated = 0; + let errors = 0; + + for (const p of ADTRAN_TA_PIDS) { + const slug = `adtran-ta-${p.pid.toLowerCase().replace(/[^a-z0-9]+/g, "-")}`; + const category = p.category ?? (TELECOM_PIDS.has(p.pid) ? "Telecom" : "DataCenter"); + try { + const res = await pool.query( + `INSERT INTO transceivers + (slug, part_number, vendor_id, form_factor, speed, speed_gbps, + reach_meters, reach_label, fiber_type, connector, wavelengths, + dom_support, ieee_reference, market_status, category, notes) + VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,true,$12,'Mainstream',$13,$14) + ON CONFLICT (slug) DO UPDATE SET + speed_gbps = EXCLUDED.speed_gbps, + reach_meters = CASE WHEN EXCLUDED.reach_meters > 0 THEN EXCLUDED.reach_meters ELSE transceivers.reach_meters END, + fiber_type = CASE WHEN EXCLUDED.fiber_type <> '' THEN EXCLUDED.fiber_type ELSE transceivers.fiber_type END, + wavelengths = COALESCE(EXCLUDED.wavelengths, transceivers.wavelengths), + updated_at = NOW() + RETURNING (xmax = 0) as was_inserted`, + [slug, p.pid, vendorId, p.formFactor, p.speed, p.speedGbps, + p.reachMeters, p.reachLabel, p.fiberType, p.connector, + p.wavelengths ?? null, p.standard ?? null, category, p.notes ?? null] + ); + if (res.rows[0]?.was_inserted) inserted++; else updated++; + } catch (err) { + console.warn(` Skip ${p.pid}: ${(err as Error).message.slice(0, 80)}`); + errors++; + } + } + + console.log(`\n=== ADTRAN Total Access OEM Seed Complete ===`); + console.log(` Inserted: ${inserted}`); + console.log(` Updated: ${updated}`); + console.log(` Errors: ${errors}`); + console.log(` Total PIDs: ${ADTRAN_TA_PIDS.length}\n`); +} + +if (require.main === module) { + scrapeAdtranTaOem() + .then(() => pool.end()) + .catch((err) => { + console.error("Fatal:", err); + pool.end(); + process.exit(1); + }); +} diff --git a/packages/scraper/src/scrapers/adva-oem.ts b/packages/scraper/src/scrapers/adva-oem.ts new file mode 100644 index 0000000..90c64ed --- /dev/null +++ b/packages/scraper/src/scrapers/adva-oem.ts @@ -0,0 +1,137 @@ +/** + * ADVA Optical Networking OEM Transceiver Catalog Seed + * + * Seeds ADVA-branded transceiver PIDs for FSP 150 (carrier Ethernet/ROADM), + * FSP 3000 (DWDM/OTN), and Ensemble Connector platforms. + * Note: ADVA Optical Networking is now part of ADTRAN but the ADVA brand + * and optical/telecom product lines remain distinct from adtran-oem.ts. + * + * Sources: + * - ADVA FSP 150 Pluggable Optics Guide + * - ADVA FSP 3000 Transceiver Module Catalog + * - ADVA Ensemble Connector Hardware Reference + * - advaoptical.com product portfolio + * + * Run: tsx packages/scraper/src/scrapers/adva-oem.ts + * Cron: daily at 20:45 + */ + +import { pool, ensureVendor } from "../utils/db"; + +interface AdvaPID { + pid: string; + formFactor: string; + speedGbps: number; + speed: string; + reachMeters: number; + reachLabel: string; + fiberType: string; + connector: string; + wavelengths?: string; + standard?: string; + category?: string; + notes?: string; +} + +const ADVA_PIDS: AdvaPID[] = [ + // ── 1G SFP ────────────────────────────────────────────────────────────── + { pid: "FSP-SFP-1G-SX", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 550, reachLabel: "SX", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "1000BASE-SX" }, + { pid: "FSP-SFP-1G-LX", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 10000, reachLabel: "LX", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "1000BASE-LX" }, + { pid: "FSP-SFP-1G-ZX", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 80000, reachLabel: "ZX", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "1000BASE-ZX" }, + + // ── 10G SFP+ ──────────────────────────────────────────────────────────── + { pid: "FSP-SFP-10G-SR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 300, reachLabel: "SR", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "10GBASE-SR" }, + { pid: "FSP-SFP-10G-LR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 10000, reachLabel: "LR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "10GBASE-LR" }, + { pid: "FSP-SFP-10G-ER", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 40000, reachLabel: "ER", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "10GBASE-ER" }, + { pid: "FSP-SFP-10G-ZR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 80000, reachLabel: "ZR", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "10GBASE-ZR" }, + + // ── 10G DWDM SFP+ (FSP 150 ROADM) ────────────────────────────────────── + { pid: "FSP-SFP-10G-DW-TUNE", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 80000, reachLabel: "DWDM", fiberType: "SMF", connector: "LC", wavelengths: "C-band DWDM", category: "Telecom", notes: "ADVA FSP 10G DWDM tunable SFP+" }, + + // ── 100G QSFP28 ───────────────────────────────────────────────────────── + { pid: "FSP-QSFP28-100G-SR4", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 100, reachLabel: "SR4", fiberType: "MMF", connector: "MPO", wavelengths: "850nm", standard: "100GBASE-SR4" }, + { pid: "FSP-QSFP28-100G-LR4", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 10000, reachLabel: "LR4", fiberType: "SMF", connector: "LC", wavelengths: "1295-1310nm", standard: "100GBASE-LR4" }, + { pid: "FSP-QSFP28-100G-CWDM4",formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 2000, reachLabel: "CWDM4", fiberType: "SMF", connector: "LC", wavelengths: "1271-1331nm", standard: "100GBASE-CWDM4" }, + + // ── 100G CFP2 Coherent (FSP 3000) ─────────────────────────────────────── + { pid: "FSP-CFP2-100G-DCO", formFactor: "CFP2", speedGbps: 100, speed: "100G", reachMeters: 1500000, reachLabel: "DCO", fiberType: "SMF", connector: "LC", wavelengths: "C-band", category: "Telecom", notes: "ADVA FSP 100G CFP2 DCO coherent for FSP 3000" }, + { pid: "FSP-CFP2-100G-ACO", formFactor: "CFP2", speedGbps: 100, speed: "100G", reachMeters: 2000000, reachLabel: "ACO", fiberType: "SMF", connector: "LC", wavelengths: "C-band", category: "Telecom", notes: "ADVA FSP 100G CFP2 ACO coherent" }, + + // ── 400G QSFP-DD ──────────────────────────────────────────────────────── + { pid: "FSP-QSFPDD-400G-FR4", formFactor: "QSFP-DD", speedGbps: 400, speed: "400G", reachMeters: 2000, reachLabel: "FR4", fiberType: "SMF", connector: "LC", wavelengths: "1271-1331nm", standard: "400GBASE-FR4" }, + { pid: "FSP-QSFPDD-400G-LR4", formFactor: "QSFP-DD", speedGbps: 400, speed: "400G", reachMeters: 10000, reachLabel: "LR4", fiberType: "SMF", connector: "LC", wavelengths: "1295-1310nm", standard: "400GBASE-LR4" }, + { pid: "FSP-QSFPDD-400G-ZR", formFactor: "QSFP-DD", speedGbps: 400, speed: "400G", reachMeters: 120000, reachLabel: "ZR", fiberType: "SMF", connector: "LC", wavelengths: "C-band", standard: "400ZR", category: "Telecom", notes: "ADVA FSP 400G ZR coherent QSFP-DD" }, + { pid: "FSP-QSFPDD-400G-ZRP", formFactor: "QSFP-DD", speedGbps: 400, speed: "400G", reachMeters: 3000000, reachLabel: "ZR+", fiberType: "SMF", connector: "LC", wavelengths: "C-band", category: "Telecom", notes: "ADVA FSP 400G ZR+ coherent QSFP-DD" }, + + // ── DAC ───────────────────────────────────────────────────────────────── + { pid: "FSP-DAC-10G-1M", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 1, reachLabel: "DAC-1M", fiberType: "DAC", connector: "SFP+" }, + { pid: "FSP-DAC-100G-1M", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 1, reachLabel: "DAC-1M", fiberType: "DAC", connector: "QSFP28" }, +]; + +// PIDs that use 'Telecom' category (coherent/DWDM); also respected via inline category field +const TELECOM_PIDS = new Set([ + "FSP-SFP-10G-DW-TUNE", + "FSP-CFP2-100G-DCO", + "FSP-CFP2-100G-ACO", + "FSP-QSFPDD-400G-ZR", + "FSP-QSFPDD-400G-ZRP", +]); + +export async function scrapeAdvaOem(): Promise { + console.log("=== ADVA Optical OEM Transceiver Seed ===\n"); + + const vendorId = await ensureVendor( + "ADVA Optical", + "oem", + "https://www.advaoptical.com", + undefined + ); + + let inserted = 0; + let updated = 0; + let errors = 0; + + for (const p of ADVA_PIDS) { + const slug = `adva-${p.pid.toLowerCase().replace(/[^a-z0-9]+/g, "-")}`; + const category = p.category ?? (TELECOM_PIDS.has(p.pid) ? "Telecom" : "DataCenter"); + try { + const res = await pool.query( + `INSERT INTO transceivers + (slug, part_number, vendor_id, form_factor, speed, speed_gbps, + reach_meters, reach_label, fiber_type, connector, wavelengths, + dom_support, ieee_reference, market_status, category, notes) + VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,true,$12,'Mainstream',$13,$14) + ON CONFLICT (slug) DO UPDATE SET + speed_gbps = EXCLUDED.speed_gbps, + reach_meters = CASE WHEN EXCLUDED.reach_meters > 0 THEN EXCLUDED.reach_meters ELSE transceivers.reach_meters END, + fiber_type = CASE WHEN EXCLUDED.fiber_type <> '' THEN EXCLUDED.fiber_type ELSE transceivers.fiber_type END, + wavelengths = COALESCE(EXCLUDED.wavelengths, transceivers.wavelengths), + updated_at = NOW() + RETURNING (xmax = 0) as was_inserted`, + [slug, p.pid, vendorId, p.formFactor, p.speed, p.speedGbps, + p.reachMeters, p.reachLabel, p.fiberType, p.connector, + p.wavelengths ?? null, p.standard ?? null, category, p.notes ?? null] + ); + if (res.rows[0]?.was_inserted) inserted++; else updated++; + } catch (err) { + console.warn(` Skip ${p.pid}: ${(err as Error).message.slice(0, 80)}`); + errors++; + } + } + + console.log(`\n=== ADVA Optical OEM Seed Complete ===`); + console.log(` Inserted: ${inserted}`); + console.log(` Updated: ${updated}`); + console.log(` Errors: ${errors}`); + console.log(` Total PIDs: ${ADVA_PIDS.length}\n`); +} + +if (require.main === module) { + scrapeAdvaOem() + .then(() => pool.end()) + .catch((err) => { + console.error("Fatal:", err); + pool.end(); + process.exit(1); + }); +} diff --git a/packages/scraper/src/scrapers/adva-optical-oem.ts b/packages/scraper/src/scrapers/adva-optical-oem.ts new file mode 100644 index 0000000..8f44738 --- /dev/null +++ b/packages/scraper/src/scrapers/adva-optical-oem.ts @@ -0,0 +1,248 @@ +/** + * ADVA Optical Networking OEM Transceiver Catalog Seed + * + * Seeds ADVA-branded transceiver PIDs covering FSP 150 (carrier Ethernet), + * FSP 3000 (DWDM/OTN), and Ensemble Connector platforms. + * Note: ADVA Optical Networking merged with Adtran; the ADVA optical/telecom + * product lines remain distinct from adtran-oem.ts and adtran-ta-oem.ts. + * + * Sources: + * - ADVA FSP 150 Pluggable Optics Guide (adva.com) + * - ADVA FSP 3000 Transceiver Module Catalog + * - ADVA Ensemble Connector Hardware Reference + * - adva.com product portfolio / transceiver selector + * + * Run: tsx packages/scraper/src/scrapers/adva-optical-oem.ts + * Cron: daily at 22:15 + */ + +import { pool, ensureVendor } from "../utils/db"; + +interface AdvaOpticalPID { + pid: string; + formFactor: string; + speedGbps: number; + speed: string; + reachMeters: number; + reachLabel: string; + fiberType: string; + connector: string; + wavelengths?: string; + standard?: string; + category?: string; + notes?: string; +} + +// PIDs that belong to the Telecom category (coherent/DWDM/ZR/PON) +const TELECOM_PIDS = new Set([ + "ADVA-SFP-10G-ZR", + "ADVA-SFP-10G-DW-TUNE", + "ADVA-SFP-10G-CWDM-80", + "ADVA-QSFP28-100G-ZR4", + "ADVA-CFP2-100G-DCO", + "ADVA-QSFPDD-400G-ZR", +]); + +const ADVA_OPTICAL_PIDS: AdvaOpticalPID[] = [ + // ── 1G SFP (DataCenter) ───────────────────────────────────────────────── + { + pid: "ADVA-SFP-1G-SX", + formFactor: "SFP", speedGbps: 1, speed: "1G", + reachMeters: 550, reachLabel: "SX", + fiberType: "MMF", connector: "LC", + wavelengths: "850nm", standard: "1000BASE-SX", + }, + { + pid: "ADVA-SFP-1G-LX", + formFactor: "SFP", speedGbps: 1, speed: "1G", + reachMeters: 10000, reachLabel: "LX", + fiberType: "SMF", connector: "LC", + wavelengths: "1310nm", standard: "1000BASE-LX", + }, + + // ── 10G SFP+ DataCenter ───────────────────────────────────────────────── + { + pid: "ADVA-SFP-10G-SR", + formFactor: "SFP+", speedGbps: 10, speed: "10G", + reachMeters: 300, reachLabel: "SR", + fiberType: "MMF", connector: "LC", + wavelengths: "850nm", standard: "10GBASE-SR", + }, + { + pid: "ADVA-SFP-10G-LR", + formFactor: "SFP+", speedGbps: 10, speed: "10G", + reachMeters: 10000, reachLabel: "LR", + fiberType: "SMF", connector: "LC", + wavelengths: "1310nm", standard: "10GBASE-LR", + }, + { + pid: "ADVA-SFP-10G-ER", + formFactor: "SFP+", speedGbps: 10, speed: "10G", + reachMeters: 40000, reachLabel: "ER", + fiberType: "SMF", connector: "LC", + wavelengths: "1550nm", standard: "10GBASE-ER", + }, + + // ── 10G SFP+ Telecom ──────────────────────────────────────────────────── + { + pid: "ADVA-SFP-10G-ZR", + formFactor: "SFP+", speedGbps: 10, speed: "10G", + reachMeters: 80000, reachLabel: "ZR", + fiberType: "SMF", connector: "LC", + wavelengths: "1550nm", standard: "10GBASE-ZR", + category: "Telecom", notes: "ADVA FSP 10G ZR extended-reach SFP+", + }, + { + pid: "ADVA-SFP-10G-DW-TUNE", + formFactor: "SFP+", speedGbps: 10, speed: "10G", + reachMeters: 80000, reachLabel: "DWDM", + fiberType: "SMF", connector: "LC", + wavelengths: "C-band DWDM tunable", + category: "Telecom", notes: "ADVA FSP 3000 10G DWDM tunable SFP+ C-band", + }, + { + pid: "ADVA-SFP-10G-CWDM-80", + formFactor: "SFP+", speedGbps: 10, speed: "10G", + reachMeters: 80000, reachLabel: "CWDM", + fiberType: "SMF", connector: "LC", + wavelengths: "1530–1610nm CWDM", + category: "Telecom", notes: "ADVA FSP 10G CWDM SFP+ 1530-1610nm 80km", + }, + + // ── 25G SFP28 ─────────────────────────────────────────────────────────── + { + pid: "ADVA-SFP28-25G-SR", + formFactor: "SFP28", speedGbps: 25, speed: "25G", + reachMeters: 100, reachLabel: "SR", + fiberType: "MMF", connector: "LC", + wavelengths: "850nm", standard: "25GBASE-SR", + }, + { + pid: "ADVA-SFP28-25G-LR", + formFactor: "SFP28", speedGbps: 25, speed: "25G", + reachMeters: 10000, reachLabel: "LR", + fiberType: "SMF", connector: "LC", + wavelengths: "1310nm", standard: "25GBASE-LR", + }, + + // ── 100G QSFP28 DataCenter ────────────────────────────────────────────── + { + pid: "ADVA-QSFP28-100G-SR4", + formFactor: "QSFP28", speedGbps: 100, speed: "100G", + reachMeters: 100, reachLabel: "SR4", + fiberType: "MMF", connector: "MPO", + wavelengths: "850nm", standard: "100GBASE-SR4", + }, + { + pid: "ADVA-QSFP28-100G-LR4", + formFactor: "QSFP28", speedGbps: 100, speed: "100G", + reachMeters: 10000, reachLabel: "LR4", + fiberType: "SMF", connector: "LC", + wavelengths: "1295–1310nm", standard: "100GBASE-LR4", + }, + { + pid: "ADVA-QSFP28-100G-ER4", + formFactor: "QSFP28", speedGbps: 100, speed: "100G", + reachMeters: 40000, reachLabel: "ER4", + fiberType: "SMF", connector: "LC", + wavelengths: "1295–1310nm", standard: "100GBASE-ER4", + }, + + // ── 100G QSFP28 Telecom (ZR4 coherent) ───────────────────────────────── + { + pid: "ADVA-QSFP28-100G-ZR4", + formFactor: "QSFP28", speedGbps: 100, speed: "100G", + reachMeters: 80000, reachLabel: "ZR4", + fiberType: "SMF", connector: "LC", + wavelengths: "C-band DWDM", + category: "Telecom", notes: "ADVA FSP 3000 100G QSFP28 ZR4 coherent", + }, + + // ── 100G CFP2-DCO Telecom ─────────────────────────────────────────────── + { + pid: "ADVA-CFP2-100G-DCO", + formFactor: "CFP2", speedGbps: 100, speed: "100G", + reachMeters: 1000000, reachLabel: "DCO", + fiberType: "SMF", connector: "LC", + wavelengths: "C-band", + category: "Telecom", notes: "ADVA FSP 3000 100G CFP2-DCO coherent 1000km metro/long-haul", + }, + + // ── 400G QSFP-DD DataCenter ───────────────────────────────────────────── + { + pid: "ADVA-QSFPDD-400G-DR4", + formFactor: "QSFP-DD", speedGbps: 400, speed: "400G", + reachMeters: 500, reachLabel: "DR4", + fiberType: "SMF", connector: "MPO", + wavelengths: "1310nm", standard: "400GBASE-DR4", + }, + + // ── 400G QSFP-DD Telecom (ZR coherent) ───────────────────────────────── + { + pid: "ADVA-QSFPDD-400G-ZR", + formFactor: "QSFP-DD", speedGbps: 400, speed: "400G", + reachMeters: 120000, reachLabel: "ZR", + fiberType: "SMF", connector: "LC", + wavelengths: "C-band", standard: "400ZR", + category: "Telecom", notes: "ADVA FSP 3000 400G QSFP-DD ZR coherent (OpenROADM/OpenZR+)", + }, +]; + +export async function scrapeAdvaOpticalOem(): Promise { + console.log("=== ADVA Optical Networking OEM Transceiver Seed ===\n"); + + const vendorId = await ensureVendor( + "ADVA Optical Networking", + "oem", + "https://www.adva.com", + undefined + ); + + let inserted = 0; + let updated = 0; + let errors = 0; + + for (const p of ADVA_OPTICAL_PIDS) { + const slug = `adva-${p.pid.toLowerCase().replace(/[^a-z0-9]+/g, "-")}`; + const category = p.category ?? (TELECOM_PIDS.has(p.pid) ? "Telecom" : "DataCenter"); + try { + const res = await pool.query( + `INSERT INTO transceivers + (slug, part_number, vendor_id, form_factor, speed, speed_gbps, + reach_meters, reach_label, fiber_type, connector, wavelengths, + dom_support, ieee_reference, market_status, category, notes) + VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,true,$12,'Mainstream',$13,$14) + ON CONFLICT (slug) DO UPDATE SET + speed_gbps = EXCLUDED.speed_gbps, + reach_meters = CASE WHEN EXCLUDED.reach_meters > 0 THEN EXCLUDED.reach_meters ELSE transceivers.reach_meters END, + fiber_type = CASE WHEN EXCLUDED.fiber_type <> '' THEN EXCLUDED.fiber_type ELSE transceivers.fiber_type END, + wavelengths = COALESCE(EXCLUDED.wavelengths, transceivers.wavelengths), + updated_at = NOW() + RETURNING (xmax = 0) as was_inserted`, + [slug, p.pid, vendorId, p.formFactor, p.speed, p.speedGbps, + p.reachMeters, p.reachLabel, p.fiberType, p.connector, + p.wavelengths ?? null, p.standard ?? null, category, p.notes ?? null] + ); + if (res.rows[0]?.was_inserted) inserted++; else updated++; + } catch (err) { + console.warn(` Skip ${p.pid}: ${(err as Error).message.slice(0, 80)}`); + errors++; + } + } + + console.log(`\n=== ADVA Optical Networking OEM Seed Complete ===`); + console.log(` Inserted: ${inserted}`); + console.log(` Updated: ${updated}`); + console.log(` Errors: ${errors}`); + console.log(` Total: ${ADVA_OPTICAL_PIDS.length}\n`); +} + +if (require.main === module) { + scrapeAdvaOpticalOem() + .then(() => pool.end()) + .catch((err) => { + console.error("Fatal:", err); + pool.end(); + process.exit(1); + }); +} diff --git a/packages/scraper/src/scrapers/advantech-oem.ts b/packages/scraper/src/scrapers/advantech-oem.ts new file mode 100644 index 0000000..cbdd6dd --- /dev/null +++ b/packages/scraper/src/scrapers/advantech-oem.ts @@ -0,0 +1,117 @@ +/** + * Advantech OEM Transceiver Catalog Seed + * + * Seeds transceiver PIDs for Advantech industrial-grade SFP modules used in + * EKI and EKS series industrial Ethernet managed switches and routers. + * + * Sources: + * - Advantech SFP module datasheets (advantech.com) + * - Advantech EKI/EKS series hardware installation guides + * + * Run: tsx packages/scraper/src/scrapers/advantech-oem.ts + * Cron: daily at 14:15 + */ + +import { pool, ensureVendor } from "../utils/db"; + +interface AdvantechPID { + pid: string; + formFactor: string; + speedGbps: number; + speed: string; + reachMeters: number; + reachLabel: string; + fiberType: string; + connector: string; + wavelengths?: string; + standard?: string; + notes?: string; +} + +const ADVANTECH_PIDS: AdvantechPID[] = [ + // ── 100M SFP (legacy industrial) ──────────────────────────────────────── + { pid: "SFP-FE-MM-SC", formFactor: "SFP", speedGbps: 0.1, speed: "100M", reachMeters: 2000, reachLabel: "FX", fiberType: "MMF", connector: "SC", wavelengths: "850nm", standard: "100BASE-FX", notes: "Advantech 100M MM SFP" }, + { pid: "SFP-FE-SM-SC", formFactor: "SFP", speedGbps: 0.1, speed: "100M", reachMeters: 40000, reachLabel: "LFX", fiberType: "SMF", connector: "SC", wavelengths: "1310nm", notes: "Advantech 100M SM SFP 40km" }, + + // ── 1G SFP ─────────────────────────────────────────────────────────────── + { pid: "SFP-GE-SX-MM-LC", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 550, reachLabel: "SX", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "1000BASE-SX" }, + { pid: "SFP-GE-LX-SM-LC", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 10000, reachLabel: "LX", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "1000BASE-LX" }, + { pid: "SFP-GE-LH-SM-LC", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 40000, reachLabel: "LH", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", notes: "Advantech 1G SM SFP LH 40km" }, + { pid: "SFP-GE-ZX-SM-LC", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 80000, reachLabel: "ZX", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "1000BASE-ZX" }, + { pid: "SFP-GE-T-RJ45", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 100, reachLabel: "T", fiberType: "DAC", connector: "RJ45", standard: "1000BASE-T" }, + { pid: "SFP-GE-BX-U", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 20000, reachLabel: "BX-U", fiberType: "SMF", connector: "LC", wavelengths: "TX1310/RX1550", notes: "Advantech 1G BiDi SFP upstream" }, + { pid: "SFP-GE-BX-D", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 20000, reachLabel: "BX-D", fiberType: "SMF", connector: "LC", wavelengths: "TX1550/RX1310", notes: "Advantech 1G BiDi SFP downstream" }, + + // ── 10G SFP+ ───────────────────────────────────────────────────────────── + { pid: "SFP-10G-SR-MM-LC", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 300, reachLabel: "SR", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "10GBASE-SR" }, + { pid: "SFP-10G-LR-SM-LC", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 10000, reachLabel: "LR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "10GBASE-LR" }, + { pid: "SFP-10G-ER-SM-LC", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 40000, reachLabel: "ER", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "10GBASE-ER" }, + { pid: "SFP-10G-ZR-SM-LC", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 80000, reachLabel: "ZR", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "10GBASE-ZR" }, + { pid: "SFP-10G-BX-U", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 10000, reachLabel: "BX-U", fiberType: "SMF", connector: "LC", wavelengths: "TX1270/RX1330", notes: "Advantech 10G BiDi SFP+ upstream" }, + + // ── 25G SFP28 ──────────────────────────────────────────────────────────── + { pid: "SFP-25G-SR-MM-LC", formFactor: "SFP28", speedGbps: 25, speed: "25G", reachMeters: 100, reachLabel: "SR", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "25GBASE-SR" }, + { pid: "SFP-25G-LR-SM-LC", formFactor: "SFP28", speedGbps: 25, speed: "25G", reachMeters: 10000, reachLabel: "LR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "25GBASE-LR" }, + + // ── DAC ────────────────────────────────────────────────────────────────── + { pid: "SFP-PLUS-DAC-1M", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 1, reachLabel: "DAC1", fiberType: "DAC", connector: "LC" }, + { pid: "SFP-PLUS-DAC-3M", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 3, reachLabel: "DAC3", fiberType: "DAC", connector: "LC" }, +]; + +export async function scrapeAdvantechOem(): Promise { + console.log("=== Advantech OEM Transceiver Seed ===\n"); + + const vendorId = await ensureVendor( + "Advantech", + "oem", + "https://www.advantech.com", + undefined + ); + + let inserted = 0; + let updated = 0; + let errors = 0; + + for (const p of ADVANTECH_PIDS) { + const slug = `advantech-${p.pid.toLowerCase().replace(/[^a-z0-9]+/g, "-")}`; + try { + const res = await pool.query( + `INSERT INTO transceivers + (slug, part_number, vendor_id, form_factor, speed, speed_gbps, + reach_meters, reach_label, fiber_type, connector, wavelengths, + dom_support, ieee_reference, market_status, category, notes) + VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,true,$12,'Mainstream','Industrial',$13) + ON CONFLICT (slug) DO UPDATE SET + speed_gbps = EXCLUDED.speed_gbps, + reach_meters = CASE WHEN EXCLUDED.reach_meters > 0 THEN EXCLUDED.reach_meters ELSE transceivers.reach_meters END, + fiber_type = CASE WHEN EXCLUDED.fiber_type <> '' THEN EXCLUDED.fiber_type ELSE transceivers.fiber_type END, + wavelengths = COALESCE(EXCLUDED.wavelengths, transceivers.wavelengths), + updated_at = NOW() + RETURNING (xmax = 0) as was_inserted`, + [slug, p.pid, vendorId, p.formFactor, p.speed, p.speedGbps, + p.reachMeters, p.reachLabel, p.fiberType, p.connector, + p.wavelengths ?? null, p.standard ?? null, p.notes ?? null] + ); + if (res.rows[0]?.was_inserted) inserted++; else updated++; + } catch (err) { + console.warn(` Skip ${p.pid}: ${(err as Error).message.slice(0, 80)}`); + errors++; + } + } + + console.log(`\n=== Advantech OEM Seed Complete ===`); + console.log(` Inserted: ${inserted}`); + console.log(` Updated: ${updated}`); + console.log(` Errors: ${errors}`); + console.log(` Total PIDs: ${ADVANTECH_PIDS.length}\n`); +} + +if (require.main === module) { + scrapeAdvantechOem() + .then(() => pool.end()) + .catch((err) => { + console.error("Fatal:", err); + pool.end(); + process.exit(1); + }); +} diff --git a/packages/scraper/src/scrapers/ale-oem.ts b/packages/scraper/src/scrapers/ale-oem.ts new file mode 100644 index 0000000..b445f52 --- /dev/null +++ b/packages/scraper/src/scrapers/ale-oem.ts @@ -0,0 +1,123 @@ +/** + * Alcatel-Lucent Enterprise (ALE) OEM Transceiver Catalog Seed + * + * Seeds ALE-branded transceiver PIDs for OmniSwitch 6xxx/9xxx + * and OmniAccess Stellar platforms. + * Sources: ALE Transceiver Module Compatibility Guide (al-enterprise.com) + * Run: tsx packages/scraper/src/scrapers/ale-oem.ts + * Cron: daily at 10:00 + */ + +import { pool, ensureVendor } from "../utils/db"; + +interface AlePID { + pid: string; + formFactor: string; + speedGbps: number; + speed: string; + reachMeters: number; + reachLabel: string; + fiberType: string; + connector: string; + wavelengths?: string; + standard?: string; + notes?: string; +} + +const ALE_PIDS: AlePID[] = [ + // ── 1G SFP ────────────────────────────────────────────────────────────── + { pid: "iSFP-GIG-SX", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 550, reachLabel: "SX", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "1000BASE-SX" }, + { pid: "iSFP-GIG-LX", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 10000, reachLabel: "LX", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "1000BASE-LX" }, + { pid: "iSFP-GIG-ZX", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 80000, reachLabel: "ZX", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "1000BASE-ZX" }, + { pid: "iSFP-GIG-T", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 100, reachLabel: "T", fiberType: "DAC", connector: "RJ45", standard: "1000BASE-T" }, + { pid: "iSFP-GIG-LH40", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 40000, reachLabel: "LH40", fiberType: "SMF", connector: "LC", wavelengths: "1310nm" }, + { pid: "iSFP-GIG-BX-U", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 10000, reachLabel: "BiDi-U", fiberType: "SMF", connector: "LC", wavelengths: "1310/1490nm", notes: "BiDi TX1310/RX1490" }, + { pid: "iSFP-GIG-BX-D", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 10000, reachLabel: "BiDi-D", fiberType: "SMF", connector: "LC", wavelengths: "1490/1310nm", notes: "BiDi TX1490/RX1310" }, + + // ── 10G SFP+ ──────────────────────────────────────────────────────────── + { pid: "iSFP-10G-SR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 300, reachLabel: "SR", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "10GBASE-SR" }, + { pid: "iSFP-10G-LR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 10000, reachLabel: "LR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "10GBASE-LR" }, + { pid: "iSFP-10G-ER", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 40000, reachLabel: "ER", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "10GBASE-ER" }, + { pid: "iSFP-10G-ZR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 80000, reachLabel: "ZR", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "10GBASE-ZR" }, + { pid: "iSFP-10G-LRM", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 220, reachLabel: "LRM", fiberType: "MMF", connector: "LC", wavelengths: "1310nm", standard: "10GBASE-LRM" }, + { pid: "iSFP-10G-T", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 30, reachLabel: "T", fiberType: "DAC", connector: "RJ45", standard: "10GBASE-T" }, + + // ── 25G SFP28 ─────────────────────────────────────────────────────────── + { pid: "iSFP-25G-SR", formFactor: "SFP28", speedGbps: 25, speed: "25G", reachMeters: 100, reachLabel: "SR", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "25GBASE-SR" }, + { pid: "iSFP-25G-LR", formFactor: "SFP28", speedGbps: 25, speed: "25G", reachMeters: 10000, reachLabel: "LR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "25GBASE-LR" }, + { pid: "iSFP-25G-ER", formFactor: "SFP28", speedGbps: 25, speed: "25G", reachMeters: 30000, reachLabel: "ER", fiberType: "SMF", connector: "LC", wavelengths: "1310nm" }, + + // ── 40G QSFP+ ─────────────────────────────────────────────────────────── + { pid: "QSFP-40G-SR4", formFactor: "QSFP+", speedGbps: 40, speed: "40G", reachMeters: 150, reachLabel: "SR4", fiberType: "MMF", connector: "MPO", wavelengths: "850nm", standard: "40GBASE-SR4" }, + { pid: "QSFP-40G-LR4", formFactor: "QSFP+", speedGbps: 40, speed: "40G", reachMeters: 10000, reachLabel: "LR4", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "40GBASE-LR4" }, + + // ── 100G QSFP28 ───────────────────────────────────────────────────────── + { pid: "QSFP28-100G-SR4", formFactor: "QSFP28",speedGbps: 100, speed: "100G", reachMeters: 100, reachLabel: "SR4", fiberType: "MMF", connector: "MPO", wavelengths: "850nm", standard: "100GBASE-SR4" }, + { pid: "QSFP28-100G-LR4", formFactor: "QSFP28",speedGbps: 100, speed: "100G", reachMeters: 10000, reachLabel: "LR4", fiberType: "SMF", connector: "LC", wavelengths: "1295-1310nm", standard: "100GBASE-LR4" }, + { pid: "QSFP28-100G-CWDM4", formFactor: "QSFP28",speedGbps: 100, speed: "100G", reachMeters: 2000, reachLabel: "CWDM4", fiberType: "SMF", connector: "LC", wavelengths: "1271-1331nm", standard: "100GBASE-CWDM4" }, + { pid: "QSFP28-100G-DR", formFactor: "QSFP28",speedGbps: 100, speed: "100G", reachMeters: 500, reachLabel: "DR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "100GBASE-DR" }, + + // ── DAC ───────────────────────────────────────────────────────────────── + { pid: "iSFP-10G-DAC-1M", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 1, reachLabel: "DAC-1M", fiberType: "DAC", connector: "SFP+" }, + { pid: "iSFP-10G-DAC-3M", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 3, reachLabel: "DAC-3M", fiberType: "DAC", connector: "SFP+" }, + { pid: "QSFP-100G-DAC-1M", formFactor: "QSFP28",speedGbps: 100, speed: "100G", reachMeters: 1, reachLabel: "DAC-1M", fiberType: "DAC", connector: "QSFP28" }, + { pid: "QSFP-100G-DAC-3M", formFactor: "QSFP28",speedGbps: 100, speed: "100G", reachMeters: 3, reachLabel: "DAC-3M", fiberType: "DAC", connector: "QSFP28" }, +]; + +export async function scrapeAleOem(): Promise { + console.log("=== Alcatel-Lucent Enterprise (ALE) OEM Transceiver Seed ===\n"); + + const vendorId = await ensureVendor( + "Alcatel-Lucent Enterprise", + "oem", + "https://www.al-enterprise.com", + undefined + ); + + let inserted = 0; + let updated = 0; + let errors = 0; + + for (const p of ALE_PIDS) { + const slug = `ale-${p.pid.toLowerCase().replace(/[^a-z0-9]+/g, "-")}`; + try { + const res = await pool.query( + `INSERT INTO transceivers + (slug, part_number, vendor_id, form_factor, speed, speed_gbps, + reach_meters, reach_label, fiber_type, connector, wavelengths, + dom_support, ieee_reference, market_status, category, notes) + VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,true,$12,'Mainstream','DataCenter',$13) + ON CONFLICT (slug) DO UPDATE SET + speed_gbps = EXCLUDED.speed_gbps, + reach_meters = CASE WHEN EXCLUDED.reach_meters > 0 THEN EXCLUDED.reach_meters ELSE transceivers.reach_meters END, + fiber_type = CASE WHEN EXCLUDED.fiber_type <> '' THEN EXCLUDED.fiber_type ELSE transceivers.fiber_type END, + wavelengths = COALESCE(EXCLUDED.wavelengths, transceivers.wavelengths), + updated_at = NOW() + RETURNING (xmax = 0) as was_inserted`, + [slug, p.pid, vendorId, p.formFactor, p.speed, p.speedGbps, + p.reachMeters, p.reachLabel, p.fiberType, p.connector, + p.wavelengths ?? null, p.standard ?? null, p.notes ?? null] + ); + if (res.rows[0]?.was_inserted) inserted++; else updated++; + } catch (err) { + console.warn(` Skip ${p.pid}: ${(err as Error).message.slice(0, 80)}`); + errors++; + } + } + + console.log(`\n=== ALE OEM Seed Complete ===`); + console.log(` Inserted: ${inserted}`); + console.log(` Updated: ${updated}`); + console.log(` Errors: ${errors}`); + console.log(` Total PIDs: ${ALE_PIDS.length}\n`); +} + +if (require.main === module) { + scrapeAleOem() + .then(() => pool.end()) + .catch((err) => { + console.error("Fatal:", err); + pool.end(); + process.exit(1); + }); +} diff --git a/packages/scraper/src/scrapers/allied-telesis-oem.ts b/packages/scraper/src/scrapers/allied-telesis-oem.ts new file mode 100644 index 0000000..8fe0ba4 --- /dev/null +++ b/packages/scraper/src/scrapers/allied-telesis-oem.ts @@ -0,0 +1,127 @@ +/** + * Allied Telesis OEM Transceiver Catalog Seed + * + * Seeds Allied Telesis-branded SFP/SFP+/QSFP PIDs for AT-x530, AT-x550, + * AT-x950, and SwitchBlade series. + * + * Sources: Allied Telesis Transceiver Guide (alliedtelesis.com) + * + * Run: tsx packages/scraper/src/scrapers/allied-telesis-oem.ts + * Cron: daily at 09:15 + */ + +import { pool, ensureVendor } from "../utils/db"; + +interface AlliedPID { + pid: string; + formFactor: string; + speedGbps: number; + speed: string; + reachMeters: number; + reachLabel: string; + fiberType: string; + connector: string; + wavelengths?: string; + standard?: string; + notes?: string; +} + +const ALLIED_PIDS: AlliedPID[] = [ + // ── 1G SFP ────────────────────────────────────────────────────────────── + { pid: "AT-SPSX", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 550, reachLabel: "SX", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "1000BASE-SX" }, + { pid: "AT-SPLX10", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 10000, reachLabel: "LX", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "1000BASE-LX" }, + { pid: "AT-SPLX40", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 40000, reachLabel: "LH40", fiberType: "SMF", connector: "LC", wavelengths: "1310nm" }, + { pid: "AT-SPZX80", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 80000, reachLabel: "ZX", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "1000BASE-ZX" }, + { pid: "AT-SPTX", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 100, reachLabel: "T", fiberType: "DAC", connector: "RJ45", standard: "1000BASE-T" }, + { pid: "AT-SPBD10-13", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 10000, reachLabel: "BiDi-1310", fiberType: "SMF", connector: "LC", wavelengths: "1310/1550nm", notes: "BiDi TX1310/RX1550" }, + { pid: "AT-SPBD10-15", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 10000, reachLabel: "BiDi-1550", fiberType: "SMF", connector: "LC", wavelengths: "1550/1310nm", notes: "BiDi TX1550/RX1310" }, + + // ── 10G SFP+ ──────────────────────────────────────────────────────────── + { pid: "AT-SP10SR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 300, reachLabel: "SR", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "10GBASE-SR" }, + { pid: "AT-SP10LR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 10000, reachLabel: "LR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "10GBASE-LR" }, + { pid: "AT-SP10ER", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 40000, reachLabel: "ER", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "10GBASE-ER" }, + { pid: "AT-SP10ZR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 80000, reachLabel: "ZR", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "10GBASE-ZR" }, + { pid: "AT-SP10LRM", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 220, reachLabel: "LRM", fiberType: "MMF", connector: "LC", wavelengths: "1310nm", standard: "10GBASE-LRM" }, + { pid: "AT-SP10T", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 30, reachLabel: "T", fiberType: "DAC", connector: "RJ45", standard: "10GBASE-T" }, + { pid: "AT-SP10BD13", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 10000, reachLabel: "BiDi", fiberType: "SMF", connector: "LC", wavelengths: "1270/1330nm", notes: "10G BiDi single fiber" }, + + // ── 25G SFP28 ─────────────────────────────────────────────────────────── + { pid: "AT-SP25SR", formFactor: "SFP28", speedGbps: 25, speed: "25G", reachMeters: 100, reachLabel: "SR", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "25GBASE-SR" }, + { pid: "AT-SP25LR", formFactor: "SFP28", speedGbps: 25, speed: "25G", reachMeters: 10000, reachLabel: "LR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "25GBASE-LR" }, + { pid: "AT-SP25ER", formFactor: "SFP28", speedGbps: 25, speed: "25G", reachMeters: 30000, reachLabel: "ER", fiberType: "SMF", connector: "LC", wavelengths: "1310nm" }, + + // ── 40G QSFP+ ─────────────────────────────────────────────────────────── + { pid: "AT-QSFPSR4", formFactor: "QSFP+", speedGbps: 40, speed: "40G", reachMeters: 150, reachLabel: "SR4", fiberType: "MMF", connector: "MPO", wavelengths: "850nm", standard: "40GBASE-SR4" }, + { pid: "AT-QSFPLR4", formFactor: "QSFP+", speedGbps: 40, speed: "40G", reachMeters: 10000, reachLabel: "LR4", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "40GBASE-LR4" }, + + // ── 100G QSFP28 ───────────────────────────────────────────────────────── + { pid: "AT-QSFP28SR4", formFactor: "QSFP28",speedGbps: 100, speed: "100G", reachMeters: 100, reachLabel: "SR4", fiberType: "MMF", connector: "MPO", wavelengths: "850nm", standard: "100GBASE-SR4" }, + { pid: "AT-QSFP28LR4", formFactor: "QSFP28",speedGbps: 100, speed: "100G", reachMeters: 10000, reachLabel: "LR4", fiberType: "SMF", connector: "LC", wavelengths: "1295-1310nm", standard: "100GBASE-LR4" }, + { pid: "AT-QSFP28CWDM4",formFactor: "QSFP28",speedGbps: 100, speed: "100G", reachMeters: 2000, reachLabel: "CWDM4", fiberType: "SMF", connector: "LC", wavelengths: "1271-1331nm", standard: "100GBASE-CWDM4" }, + { pid: "AT-QSFP28DR", formFactor: "QSFP28",speedGbps: 100, speed: "100G", reachMeters: 500, reachLabel: "DR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "100GBASE-DR" }, + + // ── DAC ───────────────────────────────────────────────────────────────── + { pid: "AT-SP10TW1", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 1, reachLabel: "DAC-1M", fiberType: "DAC", connector: "SFP+" }, + { pid: "AT-SP10TW3", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 3, reachLabel: "DAC-3M", fiberType: "DAC", connector: "SFP+" }, + { pid: "AT-QSFPTW1", formFactor: "QSFP+", speedGbps: 40, speed: "40G", reachMeters: 1, reachLabel: "DAC-1M", fiberType: "DAC", connector: "QSFP+" }, + { pid: "AT-QSFP28TW1", formFactor: "QSFP28",speedGbps: 100, speed: "100G", reachMeters: 1, reachLabel: "DAC-1M", fiberType: "DAC", connector: "QSFP28" }, + { pid: "AT-QSFP28TW3", formFactor: "QSFP28",speedGbps: 100, speed: "100G", reachMeters: 3, reachLabel: "DAC-3M", fiberType: "DAC", connector: "QSFP28" }, +]; + +export async function scrapeAlliedTelesisOem(): Promise { + console.log("=== Allied Telesis OEM Transceiver Seed ===\n"); + + const vendorId = await ensureVendor( + "Allied Telesis", + "oem", + "https://www.alliedtelesis.com", + undefined + ); + + let inserted = 0; + let updated = 0; + let errors = 0; + + for (const p of ALLIED_PIDS) { + const slug = `allied-${p.pid.toLowerCase().replace(/[^a-z0-9]+/g, "-")}`; + try { + const res = await pool.query( + `INSERT INTO transceivers + (slug, part_number, vendor_id, form_factor, speed, speed_gbps, + reach_meters, reach_label, fiber_type, connector, wavelengths, + dom_support, ieee_reference, market_status, category, notes) + VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,true,$12,'Mainstream','DataCenter',$13) + ON CONFLICT (slug) DO UPDATE SET + speed_gbps = EXCLUDED.speed_gbps, + reach_meters = CASE WHEN EXCLUDED.reach_meters > 0 THEN EXCLUDED.reach_meters ELSE transceivers.reach_meters END, + fiber_type = CASE WHEN EXCLUDED.fiber_type <> '' THEN EXCLUDED.fiber_type ELSE transceivers.fiber_type END, + wavelengths = COALESCE(EXCLUDED.wavelengths, transceivers.wavelengths), + updated_at = NOW() + RETURNING (xmax = 0) as was_inserted`, + [slug, p.pid, vendorId, p.formFactor, p.speed, p.speedGbps, + p.reachMeters, p.reachLabel, p.fiberType, p.connector, + p.wavelengths ?? null, p.standard ?? null, p.notes ?? null] + ); + if (res.rows[0]?.was_inserted) inserted++; else updated++; + } catch (err) { + console.warn(` Skip ${p.pid}: ${(err as Error).message.slice(0, 80)}`); + errors++; + } + } + + console.log(`\n=== Allied Telesis OEM Seed Complete ===`); + console.log(` Inserted: ${inserted}`); + console.log(` Updated: ${updated}`); + console.log(` Errors: ${errors}`); + console.log(` Total PIDs: ${ALLIED_PIDS.length}\n`); +} + +if (require.main === module) { + scrapeAlliedTelesisOem() + .then(() => pool.end()) + .catch((err) => { + console.error("Fatal:", err); + pool.end(); + process.exit(1); + }); +} diff --git a/packages/scraper/src/scrapers/antaira-oem.ts b/packages/scraper/src/scrapers/antaira-oem.ts new file mode 100644 index 0000000..8d56c8d --- /dev/null +++ b/packages/scraper/src/scrapers/antaira-oem.ts @@ -0,0 +1,116 @@ +/** + * Antaira Technologies OEM Transceiver Catalog Seed + * + * Seeds transceiver PIDs for Antaira industrial-grade SFP modules used in + * harsh-environment industrial Ethernet managed switches. + * + * Sources: + * - Antaira SFP/SFP+ module datasheets (antaira.com) + * - Antaira industrial switch hardware installation guides + * + * Run: tsx packages/scraper/src/scrapers/antaira-oem.ts + * Cron: daily at 15:30 + */ + +import { pool, ensureVendor } from "../utils/db"; + +interface AntairaPID { + pid: string; + formFactor: string; + speedGbps: number; + speed: string; + reachMeters: number; + reachLabel: string; + fiberType: string; + connector: string; + wavelengths?: string; + standard?: string; + notes?: string; +} + +const ANTAIRA_PIDS: AntairaPID[] = [ + // ── 100M SFP ──────────────────────────────────────────────────────────── + { pid: "SFP-FE-S15-S", formFactor: "SFP", speedGbps: 0.1, speed: "100M", reachMeters: 15000, reachLabel: "LFX", fiberType: "SMF", connector: "SC", wavelengths: "1310nm", standard: "100BASE-FX", notes: "Antaira 100M SM SFP 15km SC" }, + { pid: "SFP-FE-M2-S", formFactor: "SFP", speedGbps: 0.1, speed: "100M", reachMeters: 2000, reachLabel: "FX", fiberType: "MMF", connector: "SC", wavelengths: "850nm", standard: "100BASE-FX", notes: "Antaira 100M MM SFP SC" }, + { pid: "SFP-FE-S40-S", formFactor: "SFP", speedGbps: 0.1, speed: "100M", reachMeters: 40000, reachLabel: "LFX", fiberType: "SMF", connector: "SC", wavelengths: "1310nm", notes: "Antaira 100M SM SFP 40km SC" }, + { pid: "SFP-FE-S80-S", formFactor: "SFP", speedGbps: 0.1, speed: "100M", reachMeters: 80000, reachLabel: "LFX", fiberType: "SMF", connector: "SC", wavelengths: "1550nm", notes: "Antaira 100M SM SFP 80km SC" }, + + // ── 1G SFP ────────────────────────────────────────────────────────────── + { pid: "SFP-GE-M550-S", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 550, reachLabel: "SX", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "1000BASE-SX" }, + { pid: "SFP-GE-S10-S", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 10000, reachLabel: "LX", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "1000BASE-LX" }, + { pid: "SFP-GE-S20-S", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 20000, reachLabel: "LH", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", notes: "Antaira 1G SM SFP 20km" }, + { pid: "SFP-GE-S40-S", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 40000, reachLabel: "LH", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", notes: "Antaira 1G SM SFP 40km" }, + { pid: "SFP-GE-S80-S", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 80000, reachLabel: "ZX", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "1000BASE-ZX" }, + { pid: "SFP-GE-T", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 100, reachLabel: "T", fiberType: "DAC", connector: "RJ45", standard: "1000BASE-T" }, + { pid: "SFP-GE-BX20U", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 20000, reachLabel: "BiDi", fiberType: "SMF", connector: "LC", wavelengths: "TX1310/RX1550", notes: "Antaira 1G BiDi SFP upstream" }, + { pid: "SFP-GE-BX20D", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 20000, reachLabel: "BiDi", fiberType: "SMF", connector: "LC", wavelengths: "TX1550/RX1310", notes: "Antaira 1G BiDi SFP downstream" }, + + // ── 10G SFP+ ──────────────────────────────────────────────────────────── + { pid: "SFP-10G-SR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 300, reachLabel: "SR", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "10GBASE-SR" }, + { pid: "SFP-10G-LR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 10000, reachLabel: "LR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "10GBASE-LR" }, + { pid: "SFP-10G-ER", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 40000, reachLabel: "ER", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "10GBASE-ER" }, + { pid: "SFP-10G-ZR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 80000, reachLabel: "ZR", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "10GBASE-ZR" }, + { pid: "SFP-10G-BXU", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 10000, reachLabel: "BiDi", fiberType: "SMF", connector: "LC", wavelengths: "TX1270/RX1330", notes: "Antaira 10G BiDi SFP+ upstream" }, + + // ── DAC ───────────────────────────────────────────────────────────────── + { pid: "DACP-10G-1M", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 1, reachLabel: "DAC", fiberType: "DAC", connector: "LC" }, + { pid: "DACP-10G-3M", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 3, reachLabel: "DAC", fiberType: "DAC", connector: "LC" }, +]; + +export async function scrapeAntairaOem(): Promise { + console.log("=== Antaira Technologies OEM Transceiver Seed ===\n"); + + const vendorId = await ensureVendor( + "Antaira Technologies", + "oem", + "https://www.antaira.com", + undefined + ); + + let inserted = 0; + let updated = 0; + let errors = 0; + + for (const p of ANTAIRA_PIDS) { + const slug = `antaira-${p.pid.toLowerCase().replace(/[^a-z0-9]+/g, "-")}`; + try { + const res = await pool.query( + `INSERT INTO transceivers + (slug, part_number, vendor_id, form_factor, speed, speed_gbps, + reach_meters, reach_label, fiber_type, connector, wavelengths, + dom_support, ieee_reference, market_status, category, notes) + VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,true,$12,'Mainstream','Industrial',$13) + ON CONFLICT (slug) DO UPDATE SET + speed_gbps = EXCLUDED.speed_gbps, + reach_meters = CASE WHEN EXCLUDED.reach_meters > 0 THEN EXCLUDED.reach_meters ELSE transceivers.reach_meters END, + fiber_type = CASE WHEN EXCLUDED.fiber_type <> '' THEN EXCLUDED.fiber_type ELSE transceivers.fiber_type END, + wavelengths = COALESCE(EXCLUDED.wavelengths, transceivers.wavelengths), + updated_at = NOW() + RETURNING (xmax = 0) as was_inserted`, + [slug, p.pid, vendorId, p.formFactor, p.speed, p.speedGbps, + p.reachMeters, p.reachLabel, p.fiberType, p.connector, + p.wavelengths ?? null, p.standard ?? null, p.notes ?? null] + ); + if (res.rows[0]?.was_inserted) inserted++; else updated++; + } catch (err) { + console.warn(` Skip ${p.pid}: ${(err as Error).message.slice(0, 80)}`); + errors++; + } + } + + console.log(`\n=== Antaira Technologies OEM Seed Complete ===`); + console.log(` Inserted: ${inserted}`); + console.log(` Updated: ${updated}`); + console.log(` Errors: ${errors}`); + console.log(` Total PIDs: ${ANTAIRA_PIDS.length}\n`); +} + +if (require.main === module) { + scrapeAntairaOem() + .then(() => pool.end()) + .catch((err) => { + console.error("Fatal:", err); + pool.end(); + process.exit(1); + }); +} diff --git a/packages/scraper/src/scrapers/aoi-oem.ts b/packages/scraper/src/scrapers/aoi-oem.ts new file mode 100644 index 0000000..f1115cf --- /dev/null +++ b/packages/scraper/src/scrapers/aoi-oem.ts @@ -0,0 +1,137 @@ +/** + * Applied Optoelectronics (AOI) OEM Transceiver Catalog Seed + * + * Seeds AOI-branded transceiver PIDs. Applied Optoelectronics, Inc. + * (Sugar Land, TX) is a US-listed manufacturer of fiber-optic networking + * products including transceivers for CATV, telecom, and data center markets. + * + * Sources: + * - AOI Product Portfolio (ao-inc.com) + * - AOI Data Center Transceiver Specifications + * - AOI CATV / FTTH Optical Transceiver Application Notes + * + * Run: tsx packages/scraper/src/scrapers/aoi-oem.ts + * Cron: daily at 21:30 + */ + +import { pool, ensureVendor } from "../utils/db"; + +interface AoiPID { + pid: string; + formFactor: string; + speedGbps: number; + speed: string; + reachMeters: number; + reachLabel: string; + fiberType: string; + connector: string; + wavelengths?: string; + standard?: string; + category?: string; + notes?: string; +} + +const TELECOM_PIDS = new Set([ + "AOI-SFP-10G-ZR", + "AOI-SFP-GPON-OLT", + "AOI-SFP-XGS-PON-OLT", + "AOI-DWDM-SFP10G-C", + "AOI-CFP2-DCO-100G", +]); + +const AOI_PIDS: AoiPID[] = [ + // ── 1G SFP ────────────────────────────────────────────────────────────── + { pid: "AOI-SFP-1G-SX", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 550, reachLabel: "SX", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "1000BASE-SX", notes: "AOI 1G SFP SX 550m MMF" }, + { pid: "AOI-SFP-1G-LX", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 10000, reachLabel: "LX", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "1000BASE-LX", notes: "AOI 1G SFP LX 10km SMF" }, + + // ── 10G SFP+ ──────────────────────────────────────────────────────────── + { pid: "AOI-SFP-10G-SR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 300, reachLabel: "SR", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "10GBASE-SR", notes: "AOI 10G SFP+ SR 300m MMF" }, + { pid: "AOI-SFP-10G-LR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 10000, reachLabel: "LR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "10GBASE-LR", notes: "AOI 10G SFP+ LR 10km SMF" }, + { pid: "AOI-SFP-10G-ER", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 40000, reachLabel: "ER", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "10GBASE-ER", notes: "AOI 10G SFP+ ER 40km SMF" }, + { pid: "AOI-SFP-10G-ZR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 80000, reachLabel: "ZR", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "10GBASE-ZR", notes: "AOI 10G SFP+ ZR 80km SMF" }, + + // ── 25G SFP28 ─────────────────────────────────────────────────────────── + { pid: "AOI-SFP28-25G-SR", formFactor: "SFP28", speedGbps: 25, speed: "25G", reachMeters: 100, reachLabel: "SR", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "25GBASE-SR", notes: "AOI 25G SFP28 SR 100m MMF" }, + { pid: "AOI-SFP28-25G-LR", formFactor: "SFP28", speedGbps: 25, speed: "25G", reachMeters: 10000, reachLabel: "LR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "25GBASE-LR", notes: "AOI 25G SFP28 LR 10km SMF" }, + + // ── 40G QSFP+ ─────────────────────────────────────────────────────────── + { pid: "AOI-QSFP-40G-SR4", formFactor: "QSFP+", speedGbps: 40, speed: "40G", reachMeters: 150, reachLabel: "SR4", fiberType: "MMF", connector: "MPO", wavelengths: "850nm", standard: "40GBASE-SR4", notes: "AOI 40G QSFP+ SR4 150m MMF" }, + { pid: "AOI-QSFP-40G-LR4", formFactor: "QSFP+", speedGbps: 40, speed: "40G", reachMeters: 10000, reachLabel: "LR4", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "40GBASE-LR4", notes: "AOI 40G QSFP+ LR4 10km SMF" }, + + // ── 100G QSFP28 ───────────────────────────────────────────────────────── + { pid: "AOI-QSFP28-100G-SR4", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 100, reachLabel: "SR4", fiberType: "MMF", connector: "MPO", wavelengths: "850nm", standard: "100GBASE-SR4", notes: "AOI 100G QSFP28 SR4 100m MMF" }, + { pid: "AOI-QSFP28-100G-LR4", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 10000, reachLabel: "LR4", fiberType: "SMF", connector: "LC", wavelengths: "1295-1310nm", standard: "100GBASE-LR4", notes: "AOI 100G QSFP28 LR4 10km SMF" }, + + // ── 400G QSFP-DD ──────────────────────────────────────────────────────── + { pid: "AOI-QSFP-DD-400G-DR4", formFactor: "QSFP-DD", speedGbps: 400, speed: "400G", reachMeters: 500, reachLabel: "DR4", fiberType: "SMF", connector: "MPO", wavelengths: "1310nm", standard: "400GBASE-DR4", notes: "AOI 400G QSFP-DD DR4 500m SMF" }, + { pid: "AOI-QSFP-DD-400G-FR4", formFactor: "QSFP-DD", speedGbps: 400, speed: "400G", reachMeters: 2000, reachLabel: "FR4", fiberType: "SMF", connector: "LC", wavelengths: "1271-1331nm", standard: "400GBASE-FR4", notes: "AOI 400G QSFP-DD FR4 2km SMF" }, + + // ── PON / Access (Telecom) ─────────────────────────────────────────────── + { pid: "AOI-SFP-GPON-OLT", formFactor: "SFP", speedGbps: 2.5, speed: "2.5G", reachMeters: 20000, reachLabel: "GPON", fiberType: "SMF", connector: "SC", wavelengths: "1490/1310nm", standard: "ITU-T G.984", notes: "AOI GPON OLT SFP TX1490/RX1310 20km" }, + { pid: "AOI-SFP-XGS-PON-OLT", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 20000, reachLabel: "XGS-PON",fiberType: "SMF", connector: "SC", wavelengths: "1577/1270nm", standard: "ITU-T G.9807", notes: "AOI XGS-PON OLT SFP+ TX1577/RX1270 20km" }, + + // ── DWDM (Telecom) ─────────────────────────────────────────────────────── + { pid: "AOI-DWDM-SFP10G-C", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 80000, reachLabel: "DWDM", fiberType: "SMF", connector: "LC", wavelengths: "C-band tunable", standard: "ITU-T G.694.1", notes: "AOI 10G DWDM SFP+ C-band tunable 80km" }, + + // ── CFP2-DCO (Telecom coherent) ────────────────────────────────────────── + { pid: "AOI-CFP2-DCO-100G", formFactor: "CFP2", speedGbps: 100, speed: "100G", reachMeters: 1000000, reachLabel: "DCO", fiberType: "SMF", connector: "LC", wavelengths: "C-band tunable", standard: "OIF CFP2-DCO", notes: "AOI 100G CFP2 DCO coherent C-band, 1000km" }, +]; + +export async function scrapeAoiOem(): Promise { + console.log("=== Applied Optoelectronics (AOI) OEM Transceiver Seed ===\n"); + + const vendorId = await ensureVendor( + "Applied Optoelectronics", + "oem", + "https://www.ao-inc.com", + undefined + ); + + let inserted = 0; + let updated = 0; + let errors = 0; + + for (const p of AOI_PIDS) { + const slug = `aoi-${p.pid.toLowerCase().replace(/[^a-z0-9]+/g, "-")}`; + const category = p.category ?? (TELECOM_PIDS.has(p.pid) ? "Telecom" : "DataCenter"); + try { + const res = await pool.query( + `INSERT INTO transceivers + (slug, part_number, vendor_id, form_factor, speed, speed_gbps, + reach_meters, reach_label, fiber_type, connector, wavelengths, + dom_support, ieee_reference, market_status, category, notes) + VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,true,$12,'Mainstream',$13,$14) + ON CONFLICT (slug) DO UPDATE SET + speed_gbps = EXCLUDED.speed_gbps, + reach_meters = CASE WHEN EXCLUDED.reach_meters > 0 THEN EXCLUDED.reach_meters ELSE transceivers.reach_meters END, + fiber_type = CASE WHEN EXCLUDED.fiber_type <> '' THEN EXCLUDED.fiber_type ELSE transceivers.fiber_type END, + wavelengths = COALESCE(EXCLUDED.wavelengths, transceivers.wavelengths), + updated_at = NOW() + RETURNING (xmax = 0) as was_inserted`, + [slug, p.pid, vendorId, p.formFactor, p.speed, p.speedGbps, + p.reachMeters, p.reachLabel, p.fiberType, p.connector, + p.wavelengths ?? null, p.standard ?? null, category, p.notes ?? null] + ); + if (res.rows[0]?.was_inserted) inserted++; else updated++; + } catch (err) { + console.warn(` Skip ${p.pid}: ${(err as Error).message.slice(0, 80)}`); + errors++; + } + } + + console.log(`\n=== AOI OEM Seed Complete ===`); + console.log(` Inserted: ${inserted}`); + console.log(` Updated: ${updated}`); + console.log(` Errors: ${errors}`); + console.log(` Total PIDs: ${AOI_PIDS.length}\n`); +} + +if (require.main === module) { + scrapeAoiOem() + .then(() => pool.end()) + .catch((err) => { + console.error("Fatal:", err); + pool.end(); + process.exit(1); + }); +} diff --git a/packages/scraper/src/scrapers/arista-7000-oem.ts b/packages/scraper/src/scrapers/arista-7000-oem.ts new file mode 100644 index 0000000..904fd3c --- /dev/null +++ b/packages/scraper/src/scrapers/arista-7000-oem.ts @@ -0,0 +1,126 @@ +/** + * Arista 7000 Series OEM Transceiver Catalog Seed + * + * Seeds Arista 7000 Series-branded transceiver PIDs for data center switching + * platforms (7010, 7020, 7050, 7060, 7080, 7170, 7260, 7280, 7300, 7500, 7800). + * + * Sources: + * - Arista 7000 Series Hardware Architecture Guide + * - Arista EOS Transceiver Compatibility Matrix (arista.com) + * - Arista 7800R3 / 7500R3 400G Platform Datasheet + * + * Run: tsx packages/scraper/src/scrapers/arista-7000-oem.ts + * Cron: daily at 14:15 + */ + +import { pool, ensureVendor } from "../utils/db"; + +interface Arista7kPID { + pid: string; + formFactor: string; + speedGbps: number; + speed: string; + reachMeters: number; + reachLabel: string; + fiberType: string; + connector: string; + wavelengths?: string; + standard?: string; + notes?: string; +} + +// ── Arista 7000 Series transceiver catalog ────────────────────────────────── +// Source: Arista 7000 Series HCL and EOS Transceiver Guide +const ARISTA_7K_PIDS: Arista7kPID[] = [ + // ── 1G SFP ────────────────────────────────────────────────────────────── + { pid: "SFP-1G-SX", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 550, reachLabel: "SX", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "1000BASE-SX", notes: "Arista 1G multimode SFP, 7010/7050/7060 management ports" }, + { pid: "SFP-1G-LX", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 10000, reachLabel: "LX", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "1000BASE-LX", notes: "Arista 1G single-mode SFP 10km for 7000 management/OOB" }, + { pid: "SFP-1G-T", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 100, reachLabel: "T", fiberType: "DAC", connector: "RJ45", standard: "1000BASE-T", notes: "Arista 1G copper SFP for 7000 Series out-of-band mgmt" }, + + // ── 10G SFP+ ──────────────────────────────────────────────────────────── + { pid: "SFP-10G-SR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 300, reachLabel: "SR", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "10GBASE-SR", notes: "Arista 10G SR SFP+ for 7050/7060 ToR server downlinks" }, + { pid: "SFP-10G-LR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 10000, reachLabel: "LR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "10GBASE-LR", notes: "Arista 10G LR SFP+ 10km for 7000 inter-DC links" }, + { pid: "SFP-10G-ER", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 40000, reachLabel: "ER", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "10GBASE-ER", notes: "Arista 10G ER 40km for 7000 campus/metro aggregation" }, + { pid: "SFP-10G-ZR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 80000, reachLabel: "ZR", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "10GBASE-ZR", notes: "Arista 10G ZR 80km dark-fiber WAN uplink for 7000" }, + { pid: "SFP-10G-LR-S", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 10000, reachLabel: "LR-S", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "10GBASE-LR", notes: "Arista 10G LR-S variant, reduced power for 7050TX" }, + + // ── 25G SFP28 ─────────────────────────────────────────────────────────── + { pid: "SFP-25G-SR", formFactor: "SFP28", speedGbps: 25, speed: "25G", reachMeters: 100, reachLabel: "SR", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "25GBASE-SR", notes: "Arista 25G SR SFP28 for 7060X/7260X server leaf ports" }, + { pid: "SFP-25G-LR", formFactor: "SFP28", speedGbps: 25, speed: "25G", reachMeters: 10000, reachLabel: "LR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "25GBASE-LR", notes: "Arista 25G LR SFP28 for 7060/7260 inter-rack spine uplinks" }, + + // ── 40G QSFP+ ─────────────────────────────────────────────────────────── + { pid: "QSFP-40G-SR4", formFactor: "QSFP+", speedGbps: 40, speed: "40G", reachMeters: 150, reachLabel: "SR4", fiberType: "MMF", connector: "MPO", wavelengths: "850nm", standard: "40GBASE-SR4", notes: "Arista 40G SR4 QSFP+ for 7050Q/7260Q fabric uplinks" }, + { pid: "QSFP-40G-LR4", formFactor: "QSFP+", speedGbps: 40, speed: "40G", reachMeters: 10000, reachLabel: "LR4", fiberType: "SMF", connector: "LC", wavelengths: "1295-1310nm", standard: "40GBASE-LR4", notes: "Arista 40G LR4 QSFP+ 10km for 7000 DCI spine uplinks" }, + { pid: "QSFP-40G-SRBD", formFactor: "QSFP+", speedGbps: 40, speed: "40G", reachMeters: 150, reachLabel: "SR-BiDi",fiberType: "MMF", connector: "LC", wavelengths: "TX832-860/RX882-910nm", standard: "40GBASE-BiDi", notes: "Arista 40G BiDi QSFP+ duplex LC OM3/OM4 for 7050/7060 rackscale" }, + + // ── 100G QSFP28 ───────────────────────────────────────────────────────── + { pid: "QSFP-100G-SR4", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 100, reachLabel: "SR4", fiberType: "MMF", connector: "MPO", wavelengths: "850nm", standard: "100GBASE-SR4", notes: "Arista 100G SR4 QSFP28 for 7260/7280/7300 100G fabric" }, + { pid: "QSFP-100G-LR4", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 10000, reachLabel: "LR4", fiberType: "SMF", connector: "LC", wavelengths: "1295-1310nm", standard: "100GBASE-LR4", notes: "Arista 100G LR4 QSFP28 10km for 7000 DCI and spine" }, + { pid: "QSFP-100G-CWDM4", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 2000, reachLabel: "CWDM4", fiberType: "SMF", connector: "LC", wavelengths: "1271-1331nm", standard: "100GBASE-CWDM4", notes: "Arista 100G CWDM4 QSFP28 2km SMF for 7000 metro DCI" }, + { pid: "QSFP-100G-PSM4", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 500, reachLabel: "PSM4", fiberType: "SMF", connector: "MPO", wavelengths: "1310nm", standard: "100GBASE-PSM4", notes: "Arista 100G PSM4 QSFP28 500m parallel SMF for 7000 hyper-scale" }, + + // ── 400G QSFP-DD ──────────────────────────────────────────────────────── + { pid: "QSFP-DD-400G-DR4", formFactor: "QSFP-DD", speedGbps: 400, speed: "400G", reachMeters: 500, reachLabel: "DR4", fiberType: "SMF", connector: "MPO", wavelengths: "1310nm", standard: "400GBASE-DR4", notes: "Arista 400G DR4 QSFP-DD for 7800R3/7500R3 leaf-spine fabric" }, + { pid: "QSFP-DD-400G-SR8", formFactor: "QSFP-DD", speedGbps: 400, speed: "400G", reachMeters: 100, reachLabel: "SR8", fiberType: "MMF", connector: "MPO", wavelengths: "850nm", standard: "400GBASE-SR8", notes: "Arista 400G SR8 QSFP-DD for 7800R3 OM4 within-DC fabric" }, + + // ── 800G QSFP-DD ──────────────────────────────────────────────────────── + { pid: "QSFP-DD-800G-DR8", formFactor: "QSFP-DD", speedGbps: 800, speed: "800G", reachMeters: 500, reachLabel: "DR8", fiberType: "SMF", connector: "MPO", wavelengths: "1310nm", standard: "800GBASE-DR8", notes: "Arista 800G DR8 QSFP-DD for next-gen 7800 AI/ML fabric spine" }, +]; + +export async function scrapeArista7000Oem(): Promise { + console.log("=== Arista 7000 Series OEM Transceiver Seed ===\n"); + + const vendorId = await ensureVendor( + "Arista 7000", + "oem", + "https://www.arista.com/en/products/7000-series", + undefined + ); + + let inserted = 0; + let updated = 0; + let errors = 0; + + for (const p of ARISTA_7K_PIDS) { + const slug = `arista-7k-${p.pid.toLowerCase().replace(/[^a-z0-9]+/g, "-")}`; + try { + const res = await pool.query( + `INSERT INTO transceivers + (slug, part_number, vendor_id, form_factor, speed, speed_gbps, + reach_meters, reach_label, fiber_type, connector, wavelengths, + dom_support, ieee_reference, market_status, category, notes) + VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,true,$12,'Mainstream','DataCenter',$13) + ON CONFLICT (slug) DO UPDATE SET + speed_gbps = EXCLUDED.speed_gbps, + reach_meters = CASE WHEN EXCLUDED.reach_meters > 0 THEN EXCLUDED.reach_meters ELSE transceivers.reach_meters END, + fiber_type = CASE WHEN EXCLUDED.fiber_type <> '' THEN EXCLUDED.fiber_type ELSE transceivers.fiber_type END, + wavelengths = COALESCE(EXCLUDED.wavelengths, transceivers.wavelengths), + updated_at = NOW() + RETURNING (xmax = 0) as was_inserted`, + [slug, p.pid, vendorId, p.formFactor, p.speed, p.speedGbps, + p.reachMeters, p.reachLabel, p.fiberType, p.connector, + p.wavelengths ?? null, p.standard ?? null, p.notes ?? null] + ); + if (res.rows[0]?.was_inserted) inserted++; else updated++; + } catch (err) { + console.warn(` Skip ${p.pid}: ${(err as Error).message.slice(0, 80)}`); + errors++; + } + } + + console.log(`\n=== Arista 7000 OEM Seed Complete ===`); + console.log(` Inserted: ${inserted}`); + console.log(` Updated: ${updated}`); + console.log(` Errors: ${errors}`); + console.log(` Total PIDs: ${ARISTA_7K_PIDS.length}\n`); +} + +if (require.main === module) { + scrapeArista7000Oem() + .then(() => pool.end()) + .catch((err) => { + console.error("Fatal:", err); + pool.end(); + process.exit(1); + }); +} diff --git a/packages/scraper/src/scrapers/arris-oem.ts b/packages/scraper/src/scrapers/arris-oem.ts new file mode 100644 index 0000000..79178ef --- /dev/null +++ b/packages/scraper/src/scrapers/arris-oem.ts @@ -0,0 +1,123 @@ +/** + * CommScope ARRIS OEM Transceiver Catalog Seed + * + * Seeds CommScope ARRIS-branded transceiver PIDs for CMTS, E6000, + * C3, and CAP-500 broadband platforms with SFP ports. + * + * Sources: + * - CommScope ARRIS CMTS E6000 Hardware Installation Guide + * - CommScope CAP-500 Platform Transceiver Compatibility Matrix + * - CommScope C3 CCAP Platform Hardware Reference + * + * Run: tsx packages/scraper/src/scrapers/arris-oem.ts + * Cron: daily at 19:00 + */ + +import { pool, ensureVendor } from "../utils/db"; + +interface ArrisPID { + pid: string; + formFactor: string; + speedGbps: number; + speed: string; + reachMeters: number; + reachLabel: string; + fiberType: string; + connector: string; + wavelengths?: string; + standard?: string; + notes?: string; +} + +const ARRIS_PIDS: ArrisPID[] = [ + // ── 1G SFP ────────────────────────────────────────────────────────────── + { pid: "COM-SFP-1GE-SX", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 550, reachLabel: "SX", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "1000BASE-SX" }, + { pid: "COM-SFP-1GE-LX", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 10000, reachLabel: "LX", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "1000BASE-LX" }, + { pid: "COM-SFP-1GE-ZX", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 80000, reachLabel: "ZX", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "1000BASE-ZX" }, + { pid: "COM-SFP-1GE-T", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 100, reachLabel: "T", fiberType: "DAC", connector: "RJ45", standard: "1000BASE-T" }, + { pid: "COM-SFP-1GE-BXU", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 20000, reachLabel: "BXU", fiberType: "SMF", connector: "LC", wavelengths: "TX1310/RX1550nm", standard: "1000BASE-BX", notes: "ARRIS 1G BiDi SFP upstream" }, + + // ── 10G SFP+ ──────────────────────────────────────────────────────────── + { pid: "COM-SFP-10GE-SR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 300, reachLabel: "SR", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "10GBASE-SR" }, + { pid: "COM-SFP-10GE-LR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 10000, reachLabel: "LR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "10GBASE-LR" }, + { pid: "COM-SFP-10GE-ER", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 40000, reachLabel: "ER", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "10GBASE-ER" }, + { pid: "COM-SFP-10GE-ZR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 80000, reachLabel: "ZR", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "10GBASE-ZR" }, + + // ── 25G SFP28 ─────────────────────────────────────────────────────────── + { pid: "COM-SFP28-25GE-SR", formFactor: "SFP28", speedGbps: 25, speed: "25G", reachMeters: 100, reachLabel: "SR", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "25GBASE-SR" }, + { pid: "COM-SFP28-25GE-LR", formFactor: "SFP28", speedGbps: 25, speed: "25G", reachMeters: 10000, reachLabel: "LR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "25GBASE-LR" }, + + // ── 40G QSFP+ ─────────────────────────────────────────────────────────── + { pid: "COM-QSFP-40GE-SR4", formFactor: "QSFP+", speedGbps: 40, speed: "40G", reachMeters: 150, reachLabel: "SR4", fiberType: "MMF", connector: "MPO", wavelengths: "850nm", standard: "40GBASE-SR4" }, + { pid: "COM-QSFP-40GE-LR4", formFactor: "QSFP+", speedGbps: 40, speed: "40G", reachMeters: 10000, reachLabel: "LR4", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "40GBASE-LR4" }, + + // ── 100G QSFP28 ───────────────────────────────────────────────────────── + { pid: "COM-QSFP28-100GE-SR4", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 100, reachLabel: "SR4", fiberType: "MMF", connector: "MPO", wavelengths: "850nm", standard: "100GBASE-SR4" }, + { pid: "COM-QSFP28-100GE-LR4", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 10000, reachLabel: "LR4", fiberType: "SMF", connector: "LC", wavelengths: "1295-1310nm", standard: "100GBASE-LR4" }, + { pid: "COM-QSFP28-100GE-CWDM4", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 2000, reachLabel: "CWDM4", fiberType: "SMF", connector: "LC", wavelengths: "1271-1331nm", standard: "100GBASE-CWDM4" }, + { pid: "COM-QSFP28-100GE-DR", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 500, reachLabel: "DR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "100GBASE-DR" }, + + // ── DAC ───────────────────────────────────────────────────────────────── + { pid: "COM-DAC-10GE-1M", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 1, reachLabel: "DAC-1M", fiberType: "DAC", connector: "SFP+" }, + { pid: "COM-DAC-10GE-3M", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 3, reachLabel: "DAC-3M", fiberType: "DAC", connector: "SFP+" }, + { pid: "COM-DAC-100GE-1M", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 1, reachLabel: "DAC-1M", fiberType: "DAC", connector: "QSFP28" }, + { pid: "COM-DAC-100GE-3M", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 3, reachLabel: "DAC-3M", fiberType: "DAC", connector: "QSFP28" }, +]; + +export async function scrapeArrisOem(): Promise { + console.log("=== CommScope ARRIS OEM Transceiver Seed ===\n"); + + const vendorId = await ensureVendor( + "CommScope ARRIS", + "oem", + "https://www.commscope.com", + undefined + ); + + let inserted = 0; + let updated = 0; + let errors = 0; + + for (const p of ARRIS_PIDS) { + const slug = `arris-${p.pid.toLowerCase().replace(/[^a-z0-9]+/g, "-")}`; + try { + const res = await pool.query( + `INSERT INTO transceivers + (slug, part_number, vendor_id, form_factor, speed, speed_gbps, + reach_meters, reach_label, fiber_type, connector, wavelengths, + dom_support, ieee_reference, market_status, category, notes) + VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,true,$12,'Mainstream','DataCenter',$13) + ON CONFLICT (slug) DO UPDATE SET + speed_gbps = EXCLUDED.speed_gbps, + reach_meters = CASE WHEN EXCLUDED.reach_meters > 0 THEN EXCLUDED.reach_meters ELSE transceivers.reach_meters END, + fiber_type = CASE WHEN EXCLUDED.fiber_type <> '' THEN EXCLUDED.fiber_type ELSE transceivers.fiber_type END, + wavelengths = COALESCE(EXCLUDED.wavelengths, transceivers.wavelengths), + updated_at = NOW() + RETURNING (xmax = 0) as was_inserted`, + [slug, p.pid, vendorId, p.formFactor, p.speed, p.speedGbps, + p.reachMeters, p.reachLabel, p.fiberType, p.connector, + p.wavelengths ?? null, p.standard ?? null, p.notes ?? null] + ); + if (res.rows[0]?.was_inserted) inserted++; else updated++; + } catch (err) { + console.warn(` Skip ${p.pid}: ${(err as Error).message.slice(0, 80)}`); + errors++; + } + } + + console.log(`\n=== CommScope ARRIS OEM Seed Complete ===`); + console.log(` Inserted: ${inserted}`); + console.log(` Updated: ${updated}`); + console.log(` Errors: ${errors}`); + console.log(` Total PIDs: ${ARRIS_PIDS.length}\n`); +} + +if (require.main === module) { + scrapeArrisOem() + .then(() => pool.end()) + .catch((err) => { + console.error("Fatal:", err); + pool.end(); + process.exit(1); + }); +} diff --git a/packages/scraper/src/scrapers/aruba-cx-oem.ts b/packages/scraper/src/scrapers/aruba-cx-oem.ts new file mode 100644 index 0000000..6636d1e --- /dev/null +++ b/packages/scraper/src/scrapers/aruba-cx-oem.ts @@ -0,0 +1,121 @@ +/** + * Aruba CX OEM Transceiver Catalog Seed + * + * Seeds HPE Aruba CX-branded transceiver PIDs for Aruba CX 6300, 6400, + * 8325, and 8400 series data center and campus switches. + * + * Sources: + * - HPE Aruba CX Switch Series Data Sheet + * - HPE Aruba Networking Transceiver Selection Guide (a00045495enw) + * - HPE Aruba CX Switches Hardware Compatibility Matrix + * - HPE Networking Transceiver Module QuickSpecs + * + * Run: tsx packages/scraper/src/scrapers/aruba-cx-oem.ts + * Cron: daily at 13:45 + */ + +import { pool, ensureVendor } from "../utils/db"; + +interface ArubaCxPID { + pid: string; + formFactor: string; + speedGbps: number; + speed: string; + reachMeters: number; + reachLabel: string; + fiberType: string; + connector: string; + wavelengths?: string; + standard?: string; + notes?: string; +} + +const ARUBA_CX_PIDS: ArubaCxPID[] = [ + // ── 1G SFP ────────────────────────────────────────────────────────────── + { pid: "J9142B", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 550, reachLabel: "SX", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "1000BASE-SX", notes: "HPE Aruba 1G SX SFP LC 550m MMF transceiver" }, + { pid: "J9143B", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 10000, reachLabel: "LX", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "1000BASE-LX", notes: "HPE Aruba 1G LX SFP LC 10km SMF transceiver" }, + { pid: "ARUBA-SFP-1G-T", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 100, reachLabel: "T", fiberType: "DAC", connector: "RJ45", standard: "1000BASE-T", notes: "HPE Aruba 1G T SFP RJ45 copper transceiver" }, + + // ── 10G SFP+ ──────────────────────────────────────────────────────────── + { pid: "J9150A", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 300, reachLabel: "SR", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "10GBASE-SR", notes: "HPE Aruba X2 10G SFP+ LC SR 300m MMF transceiver" }, + { pid: "J9151E", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 10000, reachLabel: "LR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "10GBASE-LR", notes: "HPE Aruba X2 10G SFP+ LC LR 10km SMF transceiver" }, + { pid: "J9152E", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 40000, reachLabel: "ER", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "10GBASE-ER", notes: "HPE Aruba X2 10G SFP+ LC ER 40km SMF transceiver" }, + { pid: "J9153E", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 80000, reachLabel: "ZR", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "10GBASE-ZR", notes: "HPE Aruba X2 10G SFP+ LC ZR 80km SMF transceiver" }, + { pid: "J9153A", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 220, reachLabel: "LRM", fiberType: "MMF", connector: "LC", wavelengths: "1310nm", standard: "10GBASE-LRM", notes: "HPE Aruba X2 10G SFP+ LC LRM 220m MMF transceiver" }, + { pid: "ARUBA-SFP-10G-T", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 30, reachLabel: "T", fiberType: "DAC", connector: "RJ45", standard: "10GBASE-T", notes: "HPE Aruba 10G T SFP+ RJ45 copper transceiver 30m Cat6A" }, + + // ── 25G SFP28 ─────────────────────────────────────────────────────────── + { pid: "JL308A", formFactor: "SFP28", speedGbps: 25, speed: "25G", reachMeters: 100, reachLabel: "SR", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "25GBASE-SR", notes: "HPE Aruba CX 25G SFP28 LC SR 100m MMF transceiver" }, + { pid: "JL309A", formFactor: "SFP28", speedGbps: 25, speed: "25G", reachMeters: 10000, reachLabel: "LR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "25GBASE-LR", notes: "HPE Aruba CX 25G SFP28 LC LR 10km SMF transceiver" }, + { pid: "JL546A", formFactor: "SFP28", speedGbps: 25, speed: "25G", reachMeters: 40000, reachLabel: "ER", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "25GBASE-ER", notes: "HPE Aruba CX 25G SFP28 LC ER 40km SMF transceiver" }, + + // ── 40G QSFP+ ─────────────────────────────────────────────────────────── + { pid: "J9285B", formFactor: "QSFP+", speedGbps: 40, speed: "40G", reachMeters: 150, reachLabel: "SR4", fiberType: "MMF", connector: "MPO", wavelengths: "850nm", standard: "40GBASE-SR4", notes: "HPE Aruba X142 40G QSFP+ MPO SR4 150m MMF transceiver" }, + { pid: "J9285D", formFactor: "QSFP+", speedGbps: 40, speed: "40G", reachMeters: 10000, reachLabel: "LR4", fiberType: "SMF", connector: "LC", wavelengths: "1295-1310nm", standard: "40GBASE-LR4", notes: "HPE Aruba X142 40G QSFP+ LC LR4 10km SMF transceiver" }, + + // ── 100G QSFP28 ───────────────────────────────────────────────────────── + { pid: "JL072A", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 100, reachLabel: "SR4", fiberType: "MMF", connector: "MPO", wavelengths: "850nm", standard: "100GBASE-SR4", notes: "HPE Aruba 100G QSFP28 MPO SR4 100m MMF transceiver" }, + { pid: "JL073A", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 10000, reachLabel: "LR4", fiberType: "SMF", connector: "LC", wavelengths: "1295-1310nm", standard: "100GBASE-LR4", notes: "HPE Aruba 100G QSFP28 LC LR4 10km SMF transceiver" }, + { pid: "ARUBA-QSFP28-100G-CWDM4", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 2000, reachLabel: "CWDM4", fiberType: "SMF", connector: "LC", wavelengths: "1271-1331nm", standard: "100GBASE-CWDM4", notes: "HPE Aruba CX 100G QSFP28 CWDM4 2km SMF transceiver" }, + + // ── 400G QSFP-DD ──────────────────────────────────────────────────────── + { pid: "R9B18A", formFactor: "QSFP-DD", speedGbps: 400, speed: "400G", reachMeters: 500, reachLabel: "DR4", fiberType: "SMF", connector: "MPO", wavelengths: "1310nm", standard: "400GBASE-DR4", notes: "HPE Aruba CX 8400 400G QSFP-DD MPO DR4 500m SMF transceiver" }, +]; + +export async function scrapeArubaCxOem(): Promise { + console.log("=== Aruba CX OEM Transceiver Seed ===\n"); + + const vendorId = await ensureVendor( + "Aruba CX", + "oem", + "https://www.arubanetworks.com/products/switches/", + undefined + ); + + let inserted = 0; + let updated = 0; + let errors = 0; + + for (const p of ARUBA_CX_PIDS) { + const slug = `aruba-cx-${p.pid.toLowerCase().replace(/[^a-z0-9]+/g, "-")}`; + try { + const res = await pool.query( + `INSERT INTO transceivers + (slug, part_number, vendor_id, form_factor, speed, speed_gbps, + reach_meters, reach_label, fiber_type, connector, wavelengths, + dom_support, ieee_reference, market_status, category, notes) + VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,true,$12,'Mainstream','DataCenter',$13) + ON CONFLICT (slug) DO UPDATE SET + speed_gbps = EXCLUDED.speed_gbps, + reach_meters = CASE WHEN EXCLUDED.reach_meters > 0 THEN EXCLUDED.reach_meters ELSE transceivers.reach_meters END, + fiber_type = CASE WHEN EXCLUDED.fiber_type <> '' THEN EXCLUDED.fiber_type ELSE transceivers.fiber_type END, + wavelengths = COALESCE(EXCLUDED.wavelengths, transceivers.wavelengths), + updated_at = NOW() + RETURNING (xmax = 0) as was_inserted`, + [slug, p.pid, vendorId, p.formFactor, p.speed, p.speedGbps, + p.reachMeters, p.reachLabel, p.fiberType, p.connector, + p.wavelengths ?? null, p.standard ?? null, p.notes ?? null] + ); + if (res.rows[0]?.was_inserted) inserted++; else updated++; + } catch (err) { + console.warn(` Skip ${p.pid}: ${(err as Error).message.slice(0, 80)}`); + errors++; + } + } + + console.log(`\n=== Aruba CX OEM Seed Complete ===`); + console.log(` Inserted: ${inserted}`); + console.log(` Updated: ${updated}`); + console.log(` Errors: ${errors}`); + console.log(` Total PIDs: ${ARUBA_CX_PIDS.length}\n`); +} + +if (require.main === module) { + scrapeArubaCxOem() + .then(() => pool.end()) + .catch((err) => { + console.error("Fatal:", err); + pool.end(); + process.exit(1); + }); +} diff --git a/packages/scraper/src/scrapers/aws-oem.ts b/packages/scraper/src/scrapers/aws-oem.ts new file mode 100644 index 0000000..8bdec7c --- /dev/null +++ b/packages/scraper/src/scrapers/aws-oem.ts @@ -0,0 +1,330 @@ +/** + * AWS OEM Transceiver Catalog Seed + * + * Seeds Amazon Web Services-branded transceiver PIDs used in Direct Connect + * dedicated connections and AWS Outposts rack/server hardware. AWS uses an + * AWS- prefix for SFP/QSFP optics validated on its custom network ASICs. + * + * Sources: + * - AWS Direct Connect hardware requirements (aws.amazon.com/directconnect/) + * - AWS Outposts rack network hardware guide + * - SFF-8024 / IEEE 802.3 speed codes + * + * Run: tsx packages/scraper/src/scrapers/aws-oem.ts + * Cron: daily at 07:15 + */ + +import { pool, ensureVendor } from "../utils/db"; + +interface AwsPID { + pid: string; + formFactor: string; + speedGbps: number; + speed: string; + reachMeters: number; + reachLabel: string; + fiberType: string; + connector: string; + wavelengths?: string; + standard?: string; + category?: string; + notes?: string; +} + +// PIDs that map to telecom / DWDM variants (ZR, ZR4) +const TELECOM_PIDS = new Set([ + "AWS-SFP-10G-ZR", + "AWS-QSFP28-100G-ZR4", +]); + +const AWS_PIDS: AwsPID[] = [ + // ── 1G SFP ─────────────────────────────────────────────────────────────── + { + pid: "AWS-SFP-1G-SX", + formFactor: "SFP", + speedGbps: 1, + speed: "1G", + reachMeters: 550, + reachLabel: "SX", + fiberType: "MMF", + connector: "LC", + wavelengths: "850nm", + standard: "1000BASE-SX", + category: "DataCenter", + notes: "1GbE SFP SX; AWS Outposts rack management port; OM2/OM3 MMF up to 550m", + }, + { + pid: "AWS-SFP-1G-LX", + formFactor: "SFP", + speedGbps: 1, + speed: "1G", + reachMeters: 10000, + reachLabel: "LX", + fiberType: "SMF", + connector: "LC", + wavelengths: "1310nm", + standard: "1000BASE-LX", + category: "DataCenter", + notes: "1GbE SFP LX; AWS Outposts rack management port; OS2 SMF up to 10km", + }, + // ── 1G Copper SFP ──────────────────────────────────────────────────────── + { + pid: "AWS-SFP-GE-T", + formFactor: "SFP", + speedGbps: 1, + speed: "1G", + reachMeters: 100, + reachLabel: "T", + fiberType: "DAC", + connector: "RJ45", + standard: "1000BASE-T", + category: "DataCenter", + notes: "1GbE copper SFP RJ45; AWS Outposts rack management copper option; Cat5e/6", + }, + // ── 10G SFP+ ───────────────────────────────────────────────────────────── + { + pid: "AWS-SFP-10G-SR", + formFactor: "SFP+", + speedGbps: 10, + speed: "10G", + reachMeters: 300, + reachLabel: "SR", + fiberType: "MMF", + connector: "LC", + wavelengths: "850nm", + standard: "10GBASE-SR", + category: "DataCenter", + notes: "10GbE SFP+ SR; AWS Outposts server uplink; OM3/OM4 MMF up to 300m", + }, + { + pid: "AWS-SFP-10G-LR", + formFactor: "SFP+", + speedGbps: 10, + speed: "10G", + reachMeters: 10000, + reachLabel: "LR", + fiberType: "SMF", + connector: "LC", + wavelengths: "1310nm", + standard: "10GBASE-LR", + category: "DataCenter", + notes: "10GbE SFP+ LR; AWS Direct Connect 10G port; OS2 SMF up to 10km", + }, + { + pid: "AWS-SFP-10G-ER", + formFactor: "SFP+", + speedGbps: 10, + speed: "10G", + reachMeters: 40000, + reachLabel: "ER", + fiberType: "SMF", + connector: "LC", + wavelengths: "1550nm", + standard: "10GBASE-ER", + category: "DataCenter", + notes: "10GbE SFP+ ER; AWS Direct Connect extended-reach; OS2 SMF up to 40km", + }, + { + pid: "AWS-SFP-10G-ZR", + formFactor: "SFP+", + speedGbps: 10, + speed: "10G", + reachMeters: 80000, + reachLabel: "ZR", + fiberType: "SMF", + connector: "LC", + wavelengths: "1550nm", + standard: "10GBASE-ZR", + category: "Telecom", + notes: "10GbE SFP+ ZR; AWS Direct Connect long-haul 80km DWDM link; OS2 SMF", + }, + // ── 25G SFP28 ──────────────────────────────────────────────────────────── + { + pid: "AWS-SFP28-25G-SR", + formFactor: "SFP28", + speedGbps: 25, + speed: "25G", + reachMeters: 100, + reachLabel: "SR", + fiberType: "MMF", + connector: "LC", + wavelengths: "850nm", + standard: "25GBASE-SR", + category: "DataCenter", + notes: "25GbE SFP28 SR; AWS Outposts server host port; OM4 MMF up to 100m", + }, + { + pid: "AWS-SFP28-25G-LR", + formFactor: "SFP28", + speedGbps: 25, + speed: "25G", + reachMeters: 10000, + reachLabel: "LR", + fiberType: "SMF", + connector: "LC", + wavelengths: "1310nm", + standard: "25GBASE-LR", + category: "DataCenter", + notes: "25GbE SFP28 LR; AWS Outposts server host port; OS2 SMF up to 10km", + }, + // ── 40G QSFP+ ──────────────────────────────────────────────────────────── + { + pid: "AWS-QSFP-40G-SR4", + formFactor: "QSFP+", + speedGbps: 40, + speed: "40G", + reachMeters: 150, + reachLabel: "SR4", + fiberType: "MMF", + connector: "MPO", + wavelengths: "850nm", + standard: "40GBASE-SR4", + category: "DataCenter", + notes: "40GbE QSFP+ SR4; AWS Outposts rack spine uplink; OM3/OM4 MPO-12 up to 150m", + }, + { + pid: "AWS-QSFP-40G-LR4", + formFactor: "QSFP+", + speedGbps: 40, + speed: "40G", + reachMeters: 10000, + reachLabel: "LR4", + fiberType: "SMF", + connector: "LC", + wavelengths: "1270-1330nm", + standard: "40GBASE-LR4", + category: "DataCenter", + notes: "40GbE QSFP+ LR4; AWS Direct Connect 40G port; OS2 SMF up to 10km", + }, + // ── 100G QSFP28 ────────────────────────────────────────────────────────── + { + pid: "AWS-QSFP28-100G-SR4", + formFactor: "QSFP28", + speedGbps: 100, + speed: "100G", + reachMeters: 100, + reachLabel: "SR4", + fiberType: "MMF", + connector: "MPO", + wavelengths: "850nm", + standard: "100GBASE-SR4", + category: "DataCenter", + notes: "100GbE QSFP28 SR4; AWS Direct Connect 100G / Outposts spine; OM4 MPO-12 up to 100m", + }, + { + pid: "AWS-QSFP28-100G-LR4", + formFactor: "QSFP28", + speedGbps: 100, + speed: "100G", + reachMeters: 10000, + reachLabel: "LR4", + fiberType: "SMF", + connector: "LC", + wavelengths: "1295-1310nm", + standard: "100GBASE-LR4", + category: "DataCenter", + notes: "100GbE QSFP28 LR4; AWS Direct Connect 100G dedicated connection; OS2 SMF up to 10km", + }, + { + pid: "AWS-QSFP28-100G-ZR4", + formFactor: "QSFP28", + speedGbps: 100, + speed: "100G", + reachMeters: 80000, + reachLabel: "ZR4", + fiberType: "SMF", + connector: "LC", + wavelengths: "1271-1331nm", + standard: "100G-ZR4", + category: "Telecom", + notes: "100G QSFP28 ZR4; AWS Direct Connect DWDM long-haul 80km; coherent-lite; OS2 SMF", + }, + // ── 400G QSFP-DD ───────────────────────────────────────────────────────── + { + pid: "AWS-QSFP-DD-400G-DR4", + formFactor: "QSFP-DD", + speedGbps: 400, + speed: "400G", + reachMeters: 500, + reachLabel: "DR4", + fiberType: "SMF", + connector: "MPO", + wavelengths: "1310nm", + standard: "400GBASE-DR4", + category: "DataCenter", + notes: "400GbE QSFP-DD DR4; AWS Outposts next-gen spine interconnect; OS2 SMF up to 500m", + }, + { + pid: "AWS-QSFP-DD-400G-SR8", + formFactor: "QSFP-DD", + speedGbps: 400, + speed: "400G", + reachMeters: 100, + reachLabel: "SR8", + fiberType: "MMF", + connector: "MPO", + wavelengths: "850nm", + standard: "400GBASE-SR8", + category: "DataCenter", + notes: "400GbE QSFP-DD SR8; AWS Outposts next-gen spine interconnect; OM4/OM5 MPO-16 up to 100m", + }, +]; + +export async function scrapeAwsOem(): Promise { + console.log("=== AWS OEM Transceiver Seed ===\n"); + + const vendorId = await ensureVendor( + "Amazon Web Services", + "oem", + "https://aws.amazon.com/directconnect/", + undefined + ); + + let inserted = 0; + let updated = 0; + let errors = 0; + + for (const p of AWS_PIDS) { + const slug = `aws-${p.pid.toLowerCase().replace(/[^a-z0-9]+/g, "-")}`; + const category = TELECOM_PIDS.has(p.pid) ? "Telecom" : (p.category ?? "DataCenter"); + try { + const res = await pool.query( + `INSERT INTO transceivers + (slug, part_number, vendor_id, form_factor, speed, speed_gbps, + reach_meters, reach_label, fiber_type, connector, wavelengths, + dom_support, ieee_reference, market_status, category, notes) + VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,true,$12,'Mainstream',$13,$14) + ON CONFLICT (slug) DO UPDATE SET + speed_gbps = EXCLUDED.speed_gbps, + reach_meters = CASE WHEN EXCLUDED.reach_meters > 0 THEN EXCLUDED.reach_meters ELSE transceivers.reach_meters END, + fiber_type = CASE WHEN EXCLUDED.fiber_type <> '' THEN EXCLUDED.fiber_type ELSE transceivers.fiber_type END, + wavelengths = COALESCE(EXCLUDED.wavelengths, transceivers.wavelengths), + updated_at = NOW() + RETURNING (xmax = 0) as was_inserted`, + [slug, p.pid, vendorId, p.formFactor, p.speed, p.speedGbps, + p.reachMeters, p.reachLabel, p.fiberType, p.connector, + p.wavelengths ?? null, p.standard ?? null, category, p.notes ?? null] + ); + if (res.rows[0]?.was_inserted) inserted++; else updated++; + } catch (err) { + console.warn(` Skip ${p.pid}: ${(err as Error).message.slice(0, 80)}`); + errors++; + } + } + + console.log(`\n=== AWS OEM Seed Complete ===`); + console.log(` Inserted: ${inserted}`); + console.log(` Updated: ${updated}`); + console.log(` Errors: ${errors}`); + console.log(` Total PIDs: ${AWS_PIDS.length}\n`); +} + +if (require.main === module) { + scrapeAwsOem() + .then(() => pool.end()) + .catch((err) => { + console.error("Fatal:", err); + pool.end(); + process.exit(1); + }); +} diff --git a/packages/scraper/src/scrapers/azure-oem.ts b/packages/scraper/src/scrapers/azure-oem.ts new file mode 100644 index 0000000..81f0c0b --- /dev/null +++ b/packages/scraper/src/scrapers/azure-oem.ts @@ -0,0 +1,331 @@ +/** + * Microsoft Azure OEM Transceiver Catalog Seed + * + * Seeds Microsoft Azure-branded transceiver PIDs used in ExpressRoute + * dedicated ports and Azure Stack Hub/HCI hardware. Azure uses an AZ- + * prefix for SFP/QSFP optics validated on its custom Azurite/SONiC-based + * network ASICs and Azure Stack hardware. + * + * Sources: + * - Azure ExpressRoute prerequisites (azure.microsoft.com/products/expressroute/) + * - Azure Stack Hub network hardware guide + * - SFF-8024 / IEEE 802.3 speed codes + * + * Run: tsx packages/scraper/src/scrapers/azure-oem.ts + * Cron: daily at 07:30 + */ + +import { pool, ensureVendor } from "../utils/db"; + +interface AzurePID { + pid: string; + formFactor: string; + speedGbps: number; + speed: string; + reachMeters: number; + reachLabel: string; + fiberType: string; + connector: string; + wavelengths?: string; + standard?: string; + category?: string; + notes?: string; +} + +// PIDs that map to telecom / DWDM variants (ZR, ER4) +const TELECOM_PIDS = new Set([ + "AZ-SFP-10G-ZR", + "AZ-QSFP28-100G-ER4", +]); + +const AZURE_PIDS: AzurePID[] = [ + // ── 1G SFP ─────────────────────────────────────────────────────────────── + { + pid: "AZ-SFP-1G-SX", + formFactor: "SFP", + speedGbps: 1, + speed: "1G", + reachMeters: 550, + reachLabel: "SX", + fiberType: "MMF", + connector: "LC", + wavelengths: "850nm", + standard: "1000BASE-SX", + category: "DataCenter", + notes: "1GbE SFP SX; Azure Stack Hub management port; OM2/OM3 MMF up to 550m", + }, + { + pid: "AZ-SFP-1G-LX", + formFactor: "SFP", + speedGbps: 1, + speed: "1G", + reachMeters: 10000, + reachLabel: "LX", + fiberType: "SMF", + connector: "LC", + wavelengths: "1310nm", + standard: "1000BASE-LX", + category: "DataCenter", + notes: "1GbE SFP LX; Azure Stack Hub management port; OS2 SMF up to 10km", + }, + // ── 1G Copper SFP ──────────────────────────────────────────────────────── + { + pid: "AZ-SFP-GE-T", + formFactor: "SFP", + speedGbps: 1, + speed: "1G", + reachMeters: 100, + reachLabel: "T", + fiberType: "DAC", + connector: "RJ45", + standard: "1000BASE-T", + category: "DataCenter", + notes: "1GbE copper SFP RJ45; Azure Stack Hub management copper option; Cat5e/6", + }, + // ── 10G SFP+ ───────────────────────────────────────────────────────────── + { + pid: "AZ-SFP-10G-SR", + formFactor: "SFP+", + speedGbps: 10, + speed: "10G", + reachMeters: 300, + reachLabel: "SR", + fiberType: "MMF", + connector: "LC", + wavelengths: "850nm", + standard: "10GBASE-SR", + category: "DataCenter", + notes: "10GbE SFP+ SR; Azure Stack Hub server uplink; OM3/OM4 MMF up to 300m", + }, + { + pid: "AZ-SFP-10G-LR", + formFactor: "SFP+", + speedGbps: 10, + speed: "10G", + reachMeters: 10000, + reachLabel: "LR", + fiberType: "SMF", + connector: "LC", + wavelengths: "1310nm", + standard: "10GBASE-LR", + category: "DataCenter", + notes: "10GbE SFP+ LR; Azure ExpressRoute 10G port; OS2 SMF up to 10km", + }, + { + pid: "AZ-SFP-10G-ER", + formFactor: "SFP+", + speedGbps: 10, + speed: "10G", + reachMeters: 40000, + reachLabel: "ER", + fiberType: "SMF", + connector: "LC", + wavelengths: "1550nm", + standard: "10GBASE-ER", + category: "DataCenter", + notes: "10GbE SFP+ ER; Azure ExpressRoute extended-reach; OS2 SMF up to 40km", + }, + { + pid: "AZ-SFP-10G-ZR", + formFactor: "SFP+", + speedGbps: 10, + speed: "10G", + reachMeters: 80000, + reachLabel: "ZR", + fiberType: "SMF", + connector: "LC", + wavelengths: "1550nm", + standard: "10GBASE-ZR", + category: "Telecom", + notes: "10GbE SFP+ ZR; Azure ExpressRoute long-haul DWDM 80km; OS2 SMF", + }, + // ── 25G SFP28 ──────────────────────────────────────────────────────────── + { + pid: "AZ-SFP28-25G-SR", + formFactor: "SFP28", + speedGbps: 25, + speed: "25G", + reachMeters: 100, + reachLabel: "SR", + fiberType: "MMF", + connector: "LC", + wavelengths: "850nm", + standard: "25GBASE-SR", + category: "DataCenter", + notes: "25GbE SFP28 SR; Azure Stack HCI server host port; OM4 MMF up to 100m", + }, + { + pid: "AZ-SFP28-25G-LR", + formFactor: "SFP28", + speedGbps: 25, + speed: "25G", + reachMeters: 10000, + reachLabel: "LR", + fiberType: "SMF", + connector: "LC", + wavelengths: "1310nm", + standard: "25GBASE-LR", + category: "DataCenter", + notes: "25GbE SFP28 LR; Azure Stack HCI server host port; OS2 SMF up to 10km", + }, + // ── 40G QSFP+ ──────────────────────────────────────────────────────────── + { + pid: "AZ-QSFP-40G-SR4", + formFactor: "QSFP+", + speedGbps: 40, + speed: "40G", + reachMeters: 150, + reachLabel: "SR4", + fiberType: "MMF", + connector: "MPO", + wavelengths: "850nm", + standard: "40GBASE-SR4", + category: "DataCenter", + notes: "40GbE QSFP+ SR4; Azure Stack Hub Top-of-Rack spine uplink; OM3/OM4 MPO-12 up to 150m", + }, + { + pid: "AZ-QSFP-40G-LR4", + formFactor: "QSFP+", + speedGbps: 40, + speed: "40G", + reachMeters: 10000, + reachLabel: "LR4", + fiberType: "SMF", + connector: "LC", + wavelengths: "1270-1330nm", + standard: "40GBASE-LR4", + category: "DataCenter", + notes: "40GbE QSFP+ LR4; Azure ExpressRoute 40G port; OS2 SMF up to 10km", + }, + // ── 100G QSFP28 ────────────────────────────────────────────────────────── + { + pid: "AZ-QSFP28-100G-SR4", + formFactor: "QSFP28", + speedGbps: 100, + speed: "100G", + reachMeters: 100, + reachLabel: "SR4", + fiberType: "MMF", + connector: "MPO", + wavelengths: "850nm", + standard: "100GBASE-SR4", + category: "DataCenter", + notes: "100GbE QSFP28 SR4; Azure ExpressRoute 100G / Stack HCI spine; OM4 MPO-12 up to 100m", + }, + { + pid: "AZ-QSFP28-100G-LR4", + formFactor: "QSFP28", + speedGbps: 100, + speed: "100G", + reachMeters: 10000, + reachLabel: "LR4", + fiberType: "SMF", + connector: "LC", + wavelengths: "1295-1310nm", + standard: "100GBASE-LR4", + category: "DataCenter", + notes: "100GbE QSFP28 LR4; Azure ExpressRoute 100G dedicated connection; OS2 SMF up to 10km", + }, + { + pid: "AZ-QSFP28-100G-ER4", + formFactor: "QSFP28", + speedGbps: 100, + speed: "100G", + reachMeters: 40000, + reachLabel: "ER4", + fiberType: "SMF", + connector: "LC", + wavelengths: "1295-1310nm", + standard: "100GBASE-ER4", + category: "Telecom", + notes: "100G QSFP28 ER4; Azure ExpressRoute long-reach 40km inter-datacenter replication; OS2 SMF", + }, + // ── 400G QSFP-DD ───────────────────────────────────────────────────────── + { + pid: "AZ-QSFP-DD-400G-DR4", + formFactor: "QSFP-DD", + speedGbps: 400, + speed: "400G", + reachMeters: 500, + reachLabel: "DR4", + fiberType: "SMF", + connector: "MPO", + wavelengths: "1310nm", + standard: "400GBASE-DR4", + category: "DataCenter", + notes: "400GbE QSFP-DD DR4; Azure next-gen datacenter spine interconnect; OS2 SMF up to 500m", + }, + { + pid: "AZ-QSFP-DD-400G-SR8", + formFactor: "QSFP-DD", + speedGbps: 400, + speed: "400G", + reachMeters: 100, + reachLabel: "SR8", + fiberType: "MMF", + connector: "MPO", + wavelengths: "850nm", + standard: "400GBASE-SR8", + category: "DataCenter", + notes: "400GbE QSFP-DD SR8; Azure next-gen datacenter spine interconnect; OM4/OM5 MPO-16 up to 100m", + }, +]; + +export async function scrapeAzureOem(): Promise { + console.log("=== Microsoft Azure OEM Transceiver Seed ===\n"); + + const vendorId = await ensureVendor( + "Microsoft Azure", + "oem", + "https://azure.microsoft.com/en-us/products/expressroute/", + undefined + ); + + let inserted = 0; + let updated = 0; + let errors = 0; + + for (const p of AZURE_PIDS) { + const slug = `azure-${p.pid.toLowerCase().replace(/[^a-z0-9]+/g, "-")}`; + const category = TELECOM_PIDS.has(p.pid) ? "Telecom" : (p.category ?? "DataCenter"); + try { + const res = await pool.query( + `INSERT INTO transceivers + (slug, part_number, vendor_id, form_factor, speed, speed_gbps, + reach_meters, reach_label, fiber_type, connector, wavelengths, + dom_support, ieee_reference, market_status, category, notes) + VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,true,$12,'Mainstream',$13,$14) + ON CONFLICT (slug) DO UPDATE SET + speed_gbps = EXCLUDED.speed_gbps, + reach_meters = CASE WHEN EXCLUDED.reach_meters > 0 THEN EXCLUDED.reach_meters ELSE transceivers.reach_meters END, + fiber_type = CASE WHEN EXCLUDED.fiber_type <> '' THEN EXCLUDED.fiber_type ELSE transceivers.fiber_type END, + wavelengths = COALESCE(EXCLUDED.wavelengths, transceivers.wavelengths), + updated_at = NOW() + RETURNING (xmax = 0) as was_inserted`, + [slug, p.pid, vendorId, p.formFactor, p.speed, p.speedGbps, + p.reachMeters, p.reachLabel, p.fiberType, p.connector, + p.wavelengths ?? null, p.standard ?? null, category, p.notes ?? null] + ); + if (res.rows[0]?.was_inserted) inserted++; else updated++; + } catch (err) { + console.warn(` Skip ${p.pid}: ${(err as Error).message.slice(0, 80)}`); + errors++; + } + } + + console.log(`\n=== Microsoft Azure OEM Seed Complete ===`); + console.log(` Inserted: ${inserted}`); + console.log(` Updated: ${updated}`); + console.log(` Errors: ${errors}`); + console.log(` Total PIDs: ${AZURE_PIDS.length}\n`); +} + +if (require.main === module) { + scrapeAzureOem() + .then(() => pool.end()) + .catch((err) => { + console.error("Fatal:", err); + pool.end(); + process.exit(1); + }); +} diff --git a/packages/scraper/src/scrapers/barracuda-oem.ts b/packages/scraper/src/scrapers/barracuda-oem.ts new file mode 100644 index 0000000..c15e515 --- /dev/null +++ b/packages/scraper/src/scrapers/barracuda-oem.ts @@ -0,0 +1,121 @@ +/** + * Barracuda Networks OEM Transceiver Catalog Seed + * + * Seeds Barracuda-branded transceiver PIDs for CloudGen Firewall + * F/S series and Email Security Gateway appliances. + * + * Sources: + * - Barracuda Networks Hardware Compatibility Guide (campus.barracuda.com) + * - CloudGen Firewall F-Series Hardware Reference + * - Barracuda CloudGen Firewall S-Series Datasheet + * + * Run: tsx packages/scraper/src/scrapers/barracuda-oem.ts + * Cron: daily at 16:15 + */ + +import { pool, ensureVendor } from "../utils/db"; + +interface BarracudaPID { + pid: string; + formFactor: string; + speedGbps: number; + speed: string; + reachMeters: number; + reachLabel: string; + fiberType: string; + connector: string; + wavelengths?: string; + standard?: string; + notes?: string; +} + +const BARRACUDA_PIDS: BarracudaPID[] = [ + // ── 1G SFP ────────────────────────────────────────────────────────────── + { pid: "BNSF-1G-SX", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 550, reachLabel: "SX", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "1000BASE-SX" }, + { pid: "BNSF-1G-LX", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 10000, reachLabel: "LX", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "1000BASE-LX" }, + { pid: "BNSF-1G-ZX", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 80000, reachLabel: "ZX", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "1000BASE-ZX" }, + { pid: "BNSF-1G-T", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 100, reachLabel: "T", fiberType: "DAC", connector: "RJ45", standard: "1000BASE-T" }, + + // ── 10G SFP+ ──────────────────────────────────────────────────────────── + { pid: "BNSF-10G-SR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 300, reachLabel: "SR", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "10GBASE-SR" }, + { pid: "BNSF-10G-LR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 10000, reachLabel: "LR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "10GBASE-LR" }, + { pid: "BNSF-10G-ER", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 40000, reachLabel: "ER", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "10GBASE-ER" }, + { pid: "BNSF-10G-ZR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 80000, reachLabel: "ZR", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "10GBASE-ZR" }, + { pid: "BNSF-10G-T", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 30, reachLabel: "T", fiberType: "DAC", connector: "RJ45", standard: "10GBASE-T" }, + + // ── 25G SFP28 ─────────────────────────────────────────────────────────── + { pid: "BNSF-25G-SR", formFactor: "SFP28", speedGbps: 25, speed: "25G", reachMeters: 100, reachLabel: "SR", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "25GBASE-SR" }, + { pid: "BNSF-25G-LR", formFactor: "SFP28", speedGbps: 25, speed: "25G", reachMeters: 10000, reachLabel: "LR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "25GBASE-LR" }, + + // ── 40G QSFP+ ─────────────────────────────────────────────────────────── + { pid: "BNSF-40G-SR4", formFactor: "QSFP+", speedGbps: 40, speed: "40G", reachMeters: 150, reachLabel: "SR4", fiberType: "MMF", connector: "MPO", wavelengths: "850nm", standard: "40GBASE-SR4" }, + { pid: "BNSF-40G-LR4", formFactor: "QSFP+", speedGbps: 40, speed: "40G", reachMeters: 10000, reachLabel: "LR4", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "40GBASE-LR4" }, + + // ── 100G QSFP28 ───────────────────────────────────────────────────────── + { pid: "BNSF-100G-SR4", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 100, reachLabel: "SR4", fiberType: "MMF", connector: "MPO", wavelengths: "850nm", standard: "100GBASE-SR4" }, + { pid: "BNSF-100G-LR4", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 10000, reachLabel: "LR4", fiberType: "SMF", connector: "LC", wavelengths: "1295-1310nm", standard: "100GBASE-LR4" }, + { pid: "BNSF-100G-CWDM4", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 2000, reachLabel: "CWDM4", fiberType: "SMF", connector: "LC", wavelengths: "1271-1331nm", standard: "100GBASE-CWDM4" }, + + // ── DAC ───────────────────────────────────────────────────────────────── + { pid: "BNSF-DAC-10G-1M", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 1, reachLabel: "DAC-1M", fiberType: "DAC", connector: "SFP+" }, + { pid: "BNSF-DAC-10G-3M", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 3, reachLabel: "DAC-3M", fiberType: "DAC", connector: "SFP+" }, + { pid: "BNSF-DAC-100G-1M", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 1, reachLabel: "DAC-1M", fiberType: "DAC", connector: "QSFP28" }, +]; + +export async function scrapeBarracudaOem(): Promise { + console.log("=== Barracuda Networks OEM Transceiver Seed ===\n"); + + const vendorId = await ensureVendor( + "Barracuda Networks", + "oem", + "https://www.barracuda.com", + undefined + ); + + let inserted = 0; + let updated = 0; + let errors = 0; + + for (const p of BARRACUDA_PIDS) { + const slug = `barracuda-${p.pid.toLowerCase().replace(/[^a-z0-9]+/g, "-")}`; + try { + const res = await pool.query( + `INSERT INTO transceivers + (slug, part_number, vendor_id, form_factor, speed, speed_gbps, + reach_meters, reach_label, fiber_type, connector, wavelengths, + dom_support, ieee_reference, market_status, category, notes) + VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,true,$12,'Mainstream','DataCenter',$13) + ON CONFLICT (slug) DO UPDATE SET + speed_gbps = EXCLUDED.speed_gbps, + reach_meters = CASE WHEN EXCLUDED.reach_meters > 0 THEN EXCLUDED.reach_meters ELSE transceivers.reach_meters END, + fiber_type = CASE WHEN EXCLUDED.fiber_type <> '' THEN EXCLUDED.fiber_type ELSE transceivers.fiber_type END, + wavelengths = COALESCE(EXCLUDED.wavelengths, transceivers.wavelengths), + updated_at = NOW() + RETURNING (xmax = 0) as was_inserted`, + [slug, p.pid, vendorId, p.formFactor, p.speed, p.speedGbps, + p.reachMeters, p.reachLabel, p.fiberType, p.connector, + p.wavelengths ?? null, p.standard ?? null, p.notes ?? null] + ); + if (res.rows[0]?.was_inserted) inserted++; else updated++; + } catch (err) { + console.warn(` Skip ${p.pid}: ${(err as Error).message.slice(0, 80)}`); + errors++; + } + } + + console.log(`\n=== Barracuda Networks OEM Seed Complete ===`); + console.log(` Inserted: ${inserted}`); + console.log(` Updated: ${updated}`); + console.log(` Errors: ${errors}`); + console.log(` Total PIDs: ${BARRACUDA_PIDS.length}\n`); +} + +if (require.main === module) { + scrapeBarracudaOem() + .then(() => pool.end()) + .catch((err) => { + console.error("Fatal:", err); + pool.end(); + process.exit(1); + }); +} diff --git a/packages/scraper/src/scrapers/beckhoff-oem.ts b/packages/scraper/src/scrapers/beckhoff-oem.ts new file mode 100644 index 0000000..db0f44f --- /dev/null +++ b/packages/scraper/src/scrapers/beckhoff-oem.ts @@ -0,0 +1,118 @@ +/** + * Beckhoff OEM Transceiver Catalog Seed + * + * Seeds transceiver PIDs for Beckhoff SFP/SFP+/QSFP+ industrial modules + * used in EtherCAT/TwinCAT industrial networking infrastructure and + * CX, EK, and EL series automation hardware. + * + * Sources: + * - Beckhoff SFP module datasheets (beckhoff.com) + * - Beckhoff Industrial Ethernet documentation + * + * Run: tsx packages/scraper/src/scrapers/beckhoff-oem.ts + * Cron: daily at 15:30 + */ + +import { pool, ensureVendor } from "../utils/db"; + +interface BeckhoffPID { + pid: string; + formFactor: string; + speedGbps: number; + speed: string; + reachMeters: number; + reachLabel: string; + fiberType: string; + connector: string; + wavelengths?: string; + standard?: string; + notes?: string; +} + +const BECKHOFF_PIDS: BeckhoffPID[] = [ + // ── 1G SFP ────────────────────────────────────────────────────────────── + { pid: "BHF-SFP-1G-SX", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 550, reachLabel: "SX", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "1000BASE-SX", notes: "Beckhoff industrial SFP 1G SX" }, + { pid: "BHF-SFP-1G-LX", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 10000, reachLabel: "LX", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "1000BASE-LX", notes: "Beckhoff industrial SFP 1G LX" }, + { pid: "BHF-SFP-1G-LH", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 80000, reachLabel: "LH", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "1000BASE-ZX", notes: "Beckhoff industrial SFP 1G LH 80km" }, + { pid: "BHF-SFP-1G-T", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 100, reachLabel: "T", fiberType: "DAC", connector: "RJ45", standard: "1000BASE-T", notes: "Beckhoff industrial SFP 1G copper RJ45" }, + + // ── 1G SFP BiDi ───────────────────────────────────────────────────────── + { pid: "BHF-SFP-GE-BIDI-1310", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 20000, reachLabel: "BiDi-TX1310", fiberType: "SMF", connector: "LC", wavelengths: "TX1310/RX1550nm", notes: "Beckhoff SFP 1G BiDi TX1310 single fiber" }, + { pid: "BHF-SFP-GE-BIDI-1550", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 20000, reachLabel: "BiDi-TX1550", fiberType: "SMF", connector: "LC", wavelengths: "TX1550/RX1310nm", notes: "Beckhoff SFP 1G BiDi TX1550 single fiber" }, + + // ── 10G SFP+ ──────────────────────────────────────────────────────────── + { pid: "BHF-SFP-10G-SR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 300, reachLabel: "SR", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "10GBASE-SR", notes: "Beckhoff industrial SFP+ 10G SR" }, + { pid: "BHF-SFP-10G-LR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 10000, reachLabel: "LR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "10GBASE-LR", notes: "Beckhoff industrial SFP+ 10G LR" }, + { pid: "BHF-SFP-10G-ER", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 40000, reachLabel: "ER", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "10GBASE-ER", notes: "Beckhoff industrial SFP+ 10G ER" }, + + // ── 1G CWDM SFP (factory/substation rings) ────────────────────────────── + { pid: "BHF-SFP-CWDM-1470", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 40000, reachLabel: "CWDM-1470", fiberType: "SMF", connector: "LC", wavelengths: "1470nm", notes: "Beckhoff SFP CWDM 1470nm 40km" }, + { pid: "BHF-SFP-CWDM-1530", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 40000, reachLabel: "CWDM-1530", fiberType: "SMF", connector: "LC", wavelengths: "1530nm", notes: "Beckhoff SFP CWDM 1530nm 40km" }, + { pid: "BHF-SFP-CWDM-1550", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 40000, reachLabel: "CWDM-1550", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", notes: "Beckhoff SFP CWDM 1550nm 40km" }, + { pid: "BHF-SFP-CWDM-1570", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 40000, reachLabel: "CWDM-1570", fiberType: "SMF", connector: "LC", wavelengths: "1570nm", notes: "Beckhoff SFP CWDM 1570nm 40km" }, + + // ── 40G QSFP+ ─────────────────────────────────────────────────────────── + { pid: "BHF-QSFP-40G-SR4", formFactor: "QSFP+", speedGbps: 40, speed: "40G", reachMeters: 150, reachLabel: "SR4", fiberType: "MMF", connector: "MPO", wavelengths: "850nm", standard: "40GBASE-SR4", notes: "Beckhoff QSFP+ 40G SR4 industrial" }, + { pid: "BHF-QSFP-40G-LR4", formFactor: "QSFP+", speedGbps: 40, speed: "40G", reachMeters: 10000, reachLabel: "LR4", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "40GBASE-LR4", notes: "Beckhoff QSFP+ 40G LR4 industrial" }, + + // ── 25G SFP28 ─────────────────────────────────────────────────────────── + { pid: "BHF-SFP28-25G-SR", formFactor: "SFP28", speedGbps: 25, speed: "25G", reachMeters: 100, reachLabel: "SR", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "25GBASE-SR", notes: "Beckhoff SFP28 25G SR industrial" }, +]; + +export async function scrapeBeckhoffOem(): Promise { + console.log("=== Beckhoff OEM Transceiver Seed ===\n"); + + const vendorId = await ensureVendor( + "Beckhoff", + "oem", + "https://www.beckhoff.com", + undefined + ); + + let inserted = 0; + let updated = 0; + let errors = 0; + + for (const p of BECKHOFF_PIDS) { + const slug = `beckhoff-${p.pid.toLowerCase().replace(/[^a-z0-9]+/g, "-")}`; + try { + const res = await pool.query( + `INSERT INTO transceivers + (slug, part_number, vendor_id, form_factor, speed, speed_gbps, + reach_meters, reach_label, fiber_type, connector, wavelengths, + dom_support, ieee_reference, market_status, category, notes) + VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,true,$12,'Mainstream','Industrial',$13) + ON CONFLICT (slug) DO UPDATE SET + speed_gbps = EXCLUDED.speed_gbps, + reach_meters = CASE WHEN EXCLUDED.reach_meters > 0 THEN EXCLUDED.reach_meters ELSE transceivers.reach_meters END, + fiber_type = CASE WHEN EXCLUDED.fiber_type <> '' THEN EXCLUDED.fiber_type ELSE transceivers.fiber_type END, + wavelengths = COALESCE(EXCLUDED.wavelengths, transceivers.wavelengths), + updated_at = NOW() + RETURNING (xmax = 0) as was_inserted`, + [slug, p.pid, vendorId, p.formFactor, p.speed, p.speedGbps, + p.reachMeters, p.reachLabel, p.fiberType, p.connector, + p.wavelengths ?? null, p.standard ?? null, p.notes ?? null] + ); + if (res.rows[0]?.was_inserted) inserted++; else updated++; + } catch (err) { + console.warn(` Skip ${p.pid}: ${(err as Error).message.slice(0, 80)}`); + errors++; + } + } + + console.log(`\n=== Beckhoff OEM Seed Complete ===`); + console.log(` Inserted: ${inserted}`); + console.log(` Updated: ${updated}`); + console.log(` Errors: ${errors}`); + console.log(` Total PIDs: ${BECKHOFF_PIDS.length}\n`); +} + +if (require.main === module) { + scrapeBeckhoffOem() + .then(() => pool.end()) + .catch((err) => { + console.error("Fatal:", err); + pool.end(); + process.exit(1); + }); +} diff --git a/packages/scraper/src/scrapers/belden-oem.ts b/packages/scraper/src/scrapers/belden-oem.ts new file mode 100644 index 0000000..a69bfb6 --- /dev/null +++ b/packages/scraper/src/scrapers/belden-oem.ts @@ -0,0 +1,121 @@ +/** + * Belden OEM Transceiver Catalog Seed + * + * Seeds transceiver PIDs for Belden-branded SFP/SFP+/SFP28/QSFP+ modules + * used in Belden's industrial networking portfolio for manufacturing, + * energy, and transportation infrastructure. + * + * Note: hirschmann-oem.ts covers the Hirschmann sub-brand separately. + * This file covers Belden-branded transceivers only. + * + * Sources: + * - Belden SFP Modules product family (belden.com/optical-fiber/sfp-modules) + * - Belden Industrial Networking Solutions catalog + * + * Run: tsx packages/scraper/src/scrapers/belden-oem.ts + * Cron: daily at 17:00 + */ + +import { pool, ensureVendor } from "../utils/db"; + +interface BeldenPID { + pid: string; + formFactor: string; + speedGbps: number; + speed: string; + reachMeters: number; + reachLabel: string; + fiberType: string; + connector: string; + wavelengths?: string; + standard?: string; + notes?: string; +} + +const BELDEN_PIDS: BeldenPID[] = [ + // ── 1G SFP ────────────────────────────────────────────────────────────── + { pid: "BLD-SFP-1G-SX", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 550, reachLabel: "SX", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "1000BASE-SX", notes: "Belden SFP 1G SX multimode industrial networking" }, + { pid: "BLD-SFP-1G-LX", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 10000, reachLabel: "LX", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "1000BASE-LX", notes: "Belden SFP 1G LX single-mode 10km industrial" }, + { pid: "BLD-SFP-1G-ZX", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 80000, reachLabel: "ZX", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "1000BASE-ZX", notes: "Belden SFP 1G ZX long-reach 80km" }, + { pid: "BLD-SFP-1G-T", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 100, reachLabel: "T", fiberType: "DAC", connector: "RJ45", standard: "1000BASE-T", notes: "Belden SFP 1G copper RJ45 industrial" }, + + // ── 1G SFP BiDi ───────────────────────────────────────────────────────── + { pid: "BLD-SFP-1G-BIDI-1310", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 20000, reachLabel: "BiDi-TX1310", fiberType: "SMF", connector: "LC", wavelengths: "TX1310/RX1550nm", notes: "Belden SFP 1G BiDi TX1310 single fiber 20km" }, + { pid: "BLD-SFP-1G-BIDI-1550", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 20000, reachLabel: "BiDi-TX1550", fiberType: "SMF", connector: "LC", wavelengths: "TX1550/RX1310nm", notes: "Belden SFP 1G BiDi TX1550 single fiber 20km" }, + + // ── 10G SFP+ ──────────────────────────────────────────────────────────── + { pid: "BLD-SFP-10G-SR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 300, reachLabel: "SR", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "10GBASE-SR", notes: "Belden SFP+ 10G SR multimode industrial" }, + { pid: "BLD-SFP-10G-LR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 10000, reachLabel: "LR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "10GBASE-LR", notes: "Belden SFP+ 10G LR single-mode 10km" }, + { pid: "BLD-SFP-10G-ER", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 40000, reachLabel: "ER", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "10GBASE-ER", notes: "Belden SFP+ 10G ER extended-reach 40km" }, + { pid: "BLD-SFP-10G-ZR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 80000, reachLabel: "ZR", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "10GBASE-ZR", notes: "Belden SFP+ 10G ZR long-haul 80km" }, + + // ── 1G CWDM SFP (energy/transport rings) ──────────────────────────────── + { pid: "BLD-SFP-CWDM-1470", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 40000, reachLabel: "CWDM-1470", fiberType: "SMF", connector: "LC", wavelengths: "1470nm", notes: "Belden SFP CWDM 1470nm 40km energy/transport ring" }, + { pid: "BLD-SFP-CWDM-1530", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 40000, reachLabel: "CWDM-1530", fiberType: "SMF", connector: "LC", wavelengths: "1530nm", notes: "Belden SFP CWDM 1530nm 40km energy/transport ring" }, + { pid: "BLD-SFP-CWDM-1550", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 40000, reachLabel: "CWDM-1550", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", notes: "Belden SFP CWDM 1550nm 40km energy/transport ring" }, + { pid: "BLD-SFP-CWDM-1610", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 40000, reachLabel: "CWDM-1610", fiberType: "SMF", connector: "LC", wavelengths: "1610nm", notes: "Belden SFP CWDM 1610nm 40km energy/transport ring" }, + + // ── 40G QSFP+ ─────────────────────────────────────────────────────────── + { pid: "BLD-QSFP-40G-LR4", formFactor: "QSFP+", speedGbps: 40, speed: "40G", reachMeters: 10000, reachLabel: "LR4", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "40GBASE-LR4", notes: "Belden QSFP+ 40G LR4 industrial backbone" }, + + // ── 25G SFP28 ─────────────────────────────────────────────────────────── + { pid: "BLD-SFP28-25G-LR", formFactor: "SFP28", speedGbps: 25, speed: "25G", reachMeters: 10000, reachLabel: "LR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "25GBASE-LR", notes: "Belden SFP28 25G LR industrial single-mode" }, +]; + +export async function scrapeBeldenOem(): Promise { + console.log("=== Belden OEM Transceiver Seed ===\n"); + + const vendorId = await ensureVendor( + "Belden", + "oem", + "https://www.belden.com/products/infrastructure/optical-fiber/sfp-modules", + undefined + ); + + let inserted = 0; + let updated = 0; + let errors = 0; + + for (const p of BELDEN_PIDS) { + const slug = `belden-${p.pid.toLowerCase().replace(/[^a-z0-9]+/g, "-")}`; + try { + const res = await pool.query( + `INSERT INTO transceivers + (slug, part_number, vendor_id, form_factor, speed, speed_gbps, + reach_meters, reach_label, fiber_type, connector, wavelengths, + dom_support, ieee_reference, market_status, category, notes) + VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,true,$12,'Mainstream','Industrial',$13) + ON CONFLICT (slug) DO UPDATE SET + speed_gbps = EXCLUDED.speed_gbps, + reach_meters = CASE WHEN EXCLUDED.reach_meters > 0 THEN EXCLUDED.reach_meters ELSE transceivers.reach_meters END, + fiber_type = CASE WHEN EXCLUDED.fiber_type <> '' THEN EXCLUDED.fiber_type ELSE transceivers.fiber_type END, + wavelengths = COALESCE(EXCLUDED.wavelengths, transceivers.wavelengths), + updated_at = NOW() + RETURNING (xmax = 0) as was_inserted`, + [slug, p.pid, vendorId, p.formFactor, p.speed, p.speedGbps, + p.reachMeters, p.reachLabel, p.fiberType, p.connector, + p.wavelengths ?? null, p.standard ?? null, p.notes ?? null] + ); + if (res.rows[0]?.was_inserted) inserted++; else updated++; + } catch (err) { + console.warn(` Skip ${p.pid}: ${(err as Error).message.slice(0, 80)}`); + errors++; + } + } + + console.log(`\n=== Belden OEM Seed Complete ===`); + console.log(` Inserted: ${inserted}`); + console.log(` Updated: ${updated}`); + console.log(` Errors: ${errors}`); + console.log(` Total PIDs: ${BELDEN_PIDS.length}\n`); +} + +if (require.main === module) { + scrapeBeldenOem() + .then(() => pool.end()) + .catch((err) => { + console.error("Fatal:", err); + pool.end(); + process.exit(1); + }); +} diff --git a/packages/scraper/src/scrapers/blackbox-oem.ts b/packages/scraper/src/scrapers/blackbox-oem.ts new file mode 100644 index 0000000..9ef2eba --- /dev/null +++ b/packages/scraper/src/scrapers/blackbox-oem.ts @@ -0,0 +1,127 @@ +/** + * Black Box Network Services OEM Transceiver Catalog Seed + * + * Seeds Black Box-branded SFP/SFP+/SFP28/QSFP+/QSFP28/DAC transceiver PIDs + * for media converters, managed switches, and fiber infrastructure solutions. + * + * Sources: + * - Black Box Fiber Optic Transceivers product catalog (blackbox.com) + * - LFP/LSP/LEM/LQP/LPD series datasheets + * + * Run: tsx packages/scraper/src/scrapers/blackbox-oem.ts + * Cron: daily at 16:45 + */ + +import { pool, ensureVendor } from "../utils/db"; + +interface BlackboxPID { + pid: string; + formFactor: string; + speedGbps: number; + speed: string; + reachMeters: number; + reachLabel: string; + fiberType: string; + connector: string; + wavelengths?: string; + standard?: string; + notes?: string; +} + +const BLACKBOX_PIDS: BlackboxPID[] = [ + // ── 1G SFP ────────────────────────────────────────────────────────────── + { pid: "LFP402", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 550, reachLabel: "SX", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "1000BASE-SX", notes: "Black Box 1G MM SFP 550m" }, + { pid: "LFP411", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 10000, reachLabel: "LX", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "1000BASE-LX" }, + { pid: "LFP421", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 40000, reachLabel: "LH", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", notes: "Black Box 1G SM SFP 40km" }, + { pid: "LFP431", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 80000, reachLabel: "ZX", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "1000BASE-ZX" }, + { pid: "LFP451", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 100, reachLabel: "T", fiberType: "DAC", connector: "RJ45", standard: "1000BASE-T" }, + { pid: "LFP461", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 20000, reachLabel: "BiDi", fiberType: "SMF", connector: "LC", wavelengths: "TX1310/RX1550", notes: "Black Box 1G BiDi SFP upstream" }, + { pid: "LFP462", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 20000, reachLabel: "BiDi", fiberType: "SMF", connector: "LC", wavelengths: "TX1550/RX1310", notes: "Black Box 1G BiDi SFP downstream" }, + + // ── 10G SFP+ ──────────────────────────────────────────────────────────── + { pid: "LSP401", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 300, reachLabel: "SR", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "10GBASE-SR" }, + { pid: "LSP411", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 10000, reachLabel: "LR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "10GBASE-LR" }, + { pid: "LSP421", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 40000, reachLabel: "ER", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "10GBASE-ER" }, + { pid: "LSP431", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 80000, reachLabel: "ZR", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "10GBASE-ZR" }, + { pid: "LSP441", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 30, reachLabel: "T", fiberType: "DAC", connector: "RJ45", standard: "10GBASE-T" }, + { pid: "LSP451", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 10000, reachLabel: "BiDi", fiberType: "SMF", connector: "LC", wavelengths: "TX1270/RX1330", notes: "Black Box 10G BiDi SFP+ upstream" }, + + // ── 25G SFP28 ─────────────────────────────────────────────────────────── + { pid: "LEM401", formFactor: "SFP28", speedGbps: 25, speed: "25G", reachMeters: 100, reachLabel: "SR", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "25GBASE-SR" }, + { pid: "LEM411", formFactor: "SFP28", speedGbps: 25, speed: "25G", reachMeters: 10000, reachLabel: "LR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "25GBASE-LR" }, + { pid: "LEM421", formFactor: "SFP28", speedGbps: 25, speed: "25G", reachMeters: 30000, reachLabel: "ER", fiberType: "SMF", connector: "LC", wavelengths: "1310nm" }, + + // ── 40G QSFP+ ─────────────────────────────────────────────────────────── + { pid: "LQP401", formFactor: "QSFP+", speedGbps: 40, speed: "40G", reachMeters: 150, reachLabel: "SR4", fiberType: "MMF", connector: "MPO", wavelengths: "850nm", standard: "40GBASE-SR4" }, + { pid: "LQP411", formFactor: "QSFP+", speedGbps: 40, speed: "40G", reachMeters: 10000, reachLabel: "LR4", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "40GBASE-LR4" }, + + // ── 100G QSFP28 ───────────────────────────────────────────────────────── + { pid: "LQP501", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 100, reachLabel: "SR4", fiberType: "MMF", connector: "MPO", wavelengths: "850nm", standard: "100GBASE-SR4" }, + { pid: "LQP511", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 10000, reachLabel: "LR4", fiberType: "SMF", connector: "LC", wavelengths: "1295-1310nm", standard: "100GBASE-LR4" }, + { pid: "LQP521", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 2000, reachLabel: "CWDM4", fiberType: "SMF", connector: "LC", wavelengths: "1271-1331nm", standard: "100GBASE-CWDM4" }, + { pid: "LQP531", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 500, reachLabel: "DR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "100GBASE-DR" }, + + // ── DAC ───────────────────────────────────────────────────────────────── + { pid: "LPD401", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 1, reachLabel: "DAC-1M", fiberType: "DAC", connector: "SFP+" }, + { pid: "LPD403", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 3, reachLabel: "DAC-3M", fiberType: "DAC", connector: "SFP+" }, + { pid: "LPD501", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 1, reachLabel: "DAC-1M", fiberType: "DAC", connector: "QSFP28" }, + { pid: "LPD503", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 3, reachLabel: "DAC-3M", fiberType: "DAC", connector: "QSFP28" }, +]; + +export async function scrapeBlackboxOem(): Promise { + console.log("=== Black Box Network Services OEM Transceiver Seed ===\n"); + + const vendorId = await ensureVendor( + "Black Box", + "oem", + "https://www.blackbox.com", + undefined + ); + + let inserted = 0; + let updated = 0; + let errors = 0; + + for (const p of BLACKBOX_PIDS) { + const slug = `blackbox-${p.pid.toLowerCase().replace(/[^a-z0-9]+/g, "-")}`; + try { + const res = await pool.query( + `INSERT INTO transceivers + (slug, part_number, vendor_id, form_factor, speed, speed_gbps, + reach_meters, reach_label, fiber_type, connector, wavelengths, + dom_support, ieee_reference, market_status, category, notes) + VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,true,$12,'Mainstream','DataCenter',$13) + ON CONFLICT (slug) DO UPDATE SET + speed_gbps = EXCLUDED.speed_gbps, + reach_meters = CASE WHEN EXCLUDED.reach_meters > 0 THEN EXCLUDED.reach_meters ELSE transceivers.reach_meters END, + fiber_type = CASE WHEN EXCLUDED.fiber_type <> '' THEN EXCLUDED.fiber_type ELSE transceivers.fiber_type END, + wavelengths = COALESCE(EXCLUDED.wavelengths, transceivers.wavelengths), + updated_at = NOW() + RETURNING (xmax = 0) as was_inserted`, + [slug, p.pid, vendorId, p.formFactor, p.speed, p.speedGbps, + p.reachMeters, p.reachLabel, p.fiberType, p.connector, + p.wavelengths ?? null, p.standard ?? null, p.notes ?? null] + ); + if (res.rows[0]?.was_inserted) inserted++; else updated++; + } catch (err) { + console.warn(` Skip ${p.pid}: ${(err as Error).message.slice(0, 80)}`); + errors++; + } + } + + console.log(`\n=== Black Box OEM Seed Complete ===`); + console.log(` Inserted: ${inserted}`); + console.log(` Updated: ${updated}`); + console.log(` Errors: ${errors}`); + console.log(` Total PIDs: ${BLACKBOX_PIDS.length}\n`); +} + +if (require.main === module) { + scrapeBlackboxOem() + .then(() => pool.end()) + .catch((err) => { + console.error("Fatal:", err); + pool.end(); + process.exit(1); + }); +} diff --git a/packages/scraper/src/scrapers/broadcom-oem.ts b/packages/scraper/src/scrapers/broadcom-oem.ts new file mode 100644 index 0000000..7567ec0 --- /dev/null +++ b/packages/scraper/src/scrapers/broadcom-oem.ts @@ -0,0 +1,129 @@ +/** + * Broadcom OEM Transceiver Catalog Seed + * + * Seeds Broadcom-branded transceiver PIDs for Emulex HBAs (LPe-series), + * Brocade FC switches, and Ethernet adapters (NetXtreme / Liqid lineage). + * + * Sources: + * - Broadcom Emulex Gen 6/7 HBA Transceiver Guide (broadcom.com) + * - Brocade SAN Switch Optics Compatibility Matrix + * - Broadcom NetXtreme-E NIC Optics Reference + * + * Run: tsx packages/scraper/src/scrapers/broadcom-oem.ts + * Cron: daily at 22:15 + */ + +import { pool, ensureVendor } from "../utils/db"; + +interface BroadcomPID { + pid: string; + formFactor: string; + speedGbps: number; + speed: string; + reachMeters: number; + reachLabel: string; + fiberType: string; + connector: string; + wavelengths?: string; + standard?: string; + notes?: string; +} + +const BROADCOM_PIDS: BroadcomPID[] = [ + // ── FC HBA modules (Emulex LPe-series) ───────────────────────────────── + { pid: "LPe16002-M6", formFactor: "SFP+", speedGbps: 16, speed: "16G", reachMeters: 100, reachLabel: "FC-SW", fiberType: "MMF", connector: "LC", wavelengths: "850nm", notes: "Emulex 16G FC dual-port HBA SFP+ module" }, + { pid: "LPe32002-M2", formFactor: "SFP28", speedGbps: 32, speed: "32G", reachMeters: 100, reachLabel: "FC-SW", fiberType: "MMF", connector: "LC", wavelengths: "850nm", notes: "Emulex 32G FC Gen 6 dual-port HBA SFP28 module" }, + { pid: "LPe35002-M2", formFactor: "SFP28", speedGbps: 32, speed: "32G", reachMeters: 100, reachLabel: "FC-SW", fiberType: "MMF", connector: "LC", wavelengths: "850nm", notes: "Emulex 32G FC Gen 7 dual-port HBA SFP28 module" }, + + // ── Fibre Channel SFP (Brocade / Broadcom SAN) ───────────────────────── + { pid: "SFP-8G-FC-SW", formFactor: "SFP+", speedGbps: 8, speed: "8G", reachMeters: 150, reachLabel: "FC-SW", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "FC-PI-4", notes: "8G FC SW short-wave SFP" }, + { pid: "SFP-16G-FC-SW", formFactor: "SFP+", speedGbps: 16, speed: "16G", reachMeters: 100, reachLabel: "FC-SW", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "FC-PI-5", notes: "16G FC SW short-wave SFP" }, + { pid: "SFP-32G-FC-SW", formFactor: "SFP28", speedGbps: 32, speed: "32G", reachMeters: 100, reachLabel: "FC-SW", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "FC-PI-6", notes: "32G FC SW short-wave SFP28" }, + { pid: "SFP-64G-FC-SW", formFactor: "SFP56", speedGbps: 64, speed: "64G", reachMeters: 100, reachLabel: "FC-SW", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "FC-PI-7", notes: "64G FC SW short-wave SFP56" }, + { pid: "SFP-16G-FC-LW", formFactor: "SFP+", speedGbps: 16, speed: "16G", reachMeters: 10000, reachLabel: "FC-LW", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "FC-PI-5", notes: "16G FC LW long-wave SFP for inter-building SAN" }, + { pid: "SFP-32G-FC-LW", formFactor: "SFP28", speedGbps: 32, speed: "32G", reachMeters: 10000, reachLabel: "FC-LW", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "FC-PI-6", notes: "32G FC LW long-wave SFP28 for SAN extension" }, + + // ── 1G SFP (NetXtreme / Brocade access) ──────────────────────────────── + { pid: "SFP-1G-SX", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 550, reachLabel: "SX", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "1000BASE-SX" }, + { pid: "SFP-1G-LX", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 10000, reachLabel: "LX", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "1000BASE-LX" }, + + // ── 10G SFP+ ──────────────────────────────────────────────────────────── + { pid: "SFP+-10G-SR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 300, reachLabel: "SR", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "10GBASE-SR" }, + { pid: "SFP+-10G-LR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 10000, reachLabel: "LR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "10GBASE-LR" }, + { pid: "SFP-10G-ZR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 80000, reachLabel: "ZR", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "10GBASE-ZR", notes: "10G ZR 80km for long-haul SAN extension" }, + + // ── 25G SFP28 ─────────────────────────────────────────────────────────── + { pid: "SFP28-25G-SR", formFactor: "SFP28", speedGbps: 25, speed: "25G", reachMeters: 100, reachLabel: "SR", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "25GBASE-SR" }, + { pid: "SFP28-25G-LR", formFactor: "SFP28", speedGbps: 25, speed: "25G", reachMeters: 10000, reachLabel: "LR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "25GBASE-LR" }, + + // ── 40G QSFP+ ─────────────────────────────────────────────────────────── + { pid: "QSFP-40G-SR4", formFactor: "QSFP+", speedGbps: 40, speed: "40G", reachMeters: 150, reachLabel: "SR4", fiberType: "MMF", connector: "MPO", wavelengths: "850nm", standard: "40GBASE-SR4" }, + { pid: "QSFP-40G-LR4", formFactor: "QSFP+", speedGbps: 40, speed: "40G", reachMeters: 10000, reachLabel: "LR4", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "40GBASE-LR4" }, + + // ── 100G QSFP28 ───────────────────────────────────────────────────────── + { pid: "QSFP28-100G-SR4", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 100, reachLabel: "SR4", fiberType: "MMF", connector: "MPO", wavelengths: "850nm", standard: "100GBASE-SR4" }, + { pid: "QSFP28-100G-LR4", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 10000, reachLabel: "LR4", fiberType: "SMF", connector: "LC", wavelengths: "1295-1310nm", standard: "100GBASE-LR4" }, + + // ── 400G QSFP-DD (NetXtreme-E P225P / BCM57508) ───────────────────────── + { pid: "QSFP-DD-400G-DR4", formFactor: "QSFP-DD", speedGbps: 400, speed: "400G", reachMeters: 500, reachLabel: "DR4", fiberType: "SMF", connector: "MPO", wavelengths: "1310nm", standard: "400GBASE-DR4" }, + { pid: "QSFP-DD-400G-SR8", formFactor: "QSFP-DD", speedGbps: 400, speed: "400G", reachMeters: 100, reachLabel: "SR8", fiberType: "MMF", connector: "MPO", wavelengths: "850nm", standard: "400GBASE-SR8" }, +]; + +export async function scrapeBroadcomOem(): Promise { + console.log("=== Broadcom OEM Transceiver Seed ===\n"); + + const vendorId = await ensureVendor( + "Broadcom", + "oem", + "https://www.broadcom.com", + undefined + ); + + let inserted = 0; + let updated = 0; + let errors = 0; + + for (const p of BROADCOM_PIDS) { + const slug = `broadcom-${p.pid.toLowerCase().replace(/[^a-z0-9]+/g, "-")}`; + try { + const res = await pool.query( + `INSERT INTO transceivers + (slug, part_number, vendor_id, form_factor, speed, speed_gbps, + reach_meters, reach_label, fiber_type, connector, wavelengths, + dom_support, ieee_reference, market_status, category, notes) + VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,true,$12,'Mainstream','DataCenter',$13) + ON CONFLICT (slug) DO UPDATE SET + speed_gbps = EXCLUDED.speed_gbps, + reach_meters = CASE WHEN EXCLUDED.reach_meters > 0 THEN EXCLUDED.reach_meters ELSE transceivers.reach_meters END, + fiber_type = CASE WHEN EXCLUDED.fiber_type <> '' THEN EXCLUDED.fiber_type ELSE transceivers.fiber_type END, + wavelengths = COALESCE(EXCLUDED.wavelengths, transceivers.wavelengths), + is_oem_seed = true, + updated_at = NOW() + RETURNING (xmax = 0) as was_inserted`, + [slug, p.pid, vendorId, p.formFactor, p.speed, p.speedGbps, + p.reachMeters, p.reachLabel, p.fiberType, p.connector, + p.wavelengths ?? null, p.standard ?? null, p.notes ?? null] + ); + if (res.rows[0]?.was_inserted) inserted++; else updated++; + } catch (err) { + console.warn(` Skip ${p.pid}: ${(err as Error).message.slice(0, 80)}`); + errors++; + } + } + + console.log(`\n=== Broadcom OEM Seed Complete ===`); + console.log(` Inserted: ${inserted}`); + console.log(` Updated: ${updated}`); + console.log(` Errors: ${errors}`); + console.log(` Total PIDs: ${BROADCOM_PIDS.length}\n`); +} + +if (require.main === module) { + scrapeBroadcomOem() + .then(() => pool.end()) + .catch((err) => { + console.error("Fatal:", err); + pool.end(); + process.exit(1); + }); +} diff --git a/packages/scraper/src/scrapers/brocade-oem.ts b/packages/scraper/src/scrapers/brocade-oem.ts new file mode 100644 index 0000000..2e857fe --- /dev/null +++ b/packages/scraper/src/scrapers/brocade-oem.ts @@ -0,0 +1,138 @@ +/** + * Brocade OEM Transceiver Catalog Seed + * + * Seeds Brocade-branded transceiver PIDs for Fibre Channel and IP networking. + * Brocade's networking division is now part of Broadcom/Avago, but transceivers + * are still sold under the Brocade brand (XBR- prefix) for FC SANs and Ethernet. + * + * Sources: + * - Broadcom Fibre Channel Networking product pages (broadcom.com/products/fibre-channel-networking) + * - Brocade SFP/QSFP Transceiver Hardware Reference + * - Brocade Switch Compatibility Guide + * + * Run: tsx packages/scraper/src/scrapers/brocade-oem.ts + * Cron: daily at 12:00 + */ + +import { pool, ensureVendor } from "../utils/db"; + +interface BrocadePID { + pid: string; + formFactor: string; + speedGbps: number; + speed: string; + reachMeters: number; + reachLabel: string; + fiberType: string; + connector: string; + wavelengths?: string; + standard?: string; + notes?: string; +} + +const BROCADE_PIDS: BrocadePID[] = [ + // ── 1G SFP (Ethernet) ─────────────────────────────────────────────────── + { pid: "XBR-000099", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 550, reachLabel: "SX", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "1000BASE-SX" }, + { pid: "XBR-000100", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 10000, reachLabel: "LX", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "1000BASE-LX" }, + { pid: "XBR-000102", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 80000, reachLabel: "ZX", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "1000BASE-ZX" }, + { pid: "XBR-000143", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 100, reachLabel: "T", fiberType: "DAC", connector: "RJ45", standard: "1000BASE-T" }, + + // ── 8G FC SFP+ ────────────────────────────────────────────────────────── + { pid: "XBR-SFP8G0LR", formFactor: "SFP+", speedGbps: 8, speed: "8GFC", reachMeters: 10000, reachLabel: "LW", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "8GFC-LW" }, + { pid: "XBR-SFP8G0SR", formFactor: "SFP+", speedGbps: 8, speed: "8GFC", reachMeters: 500, reachLabel: "SW", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "8GFC-SW" }, + + // ── 16G FC SFP+ ───────────────────────────────────────────────────────── + { pid: "XBR-SFP16GW", formFactor: "SFP+", speedGbps: 16, speed: "16GFC", reachMeters: 300, reachLabel: "SW", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "16GFC-SW" }, + { pid: "XBR-SFP16GLR", formFactor: "SFP+", speedGbps: 16, speed: "16GFC", reachMeters: 10000, reachLabel: "LW", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "16GFC-LW" }, + { pid: "XBR-SFP16GER", formFactor: "SFP+", speedGbps: 16, speed: "16GFC", reachMeters: 40000, reachLabel: "EW", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "16GFC-EW" }, + + // ── 32G FC SFP+ ───────────────────────────────────────────────────────── + { pid: "XBR-SFP32GW", formFactor: "SFP+", speedGbps: 32, speed: "32GFC", reachMeters: 100, reachLabel: "SW", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "32GFC-SW" }, + { pid: "XBR-SFP32GLR", formFactor: "SFP+", speedGbps: 32, speed: "32GFC", reachMeters: 10000, reachLabel: "LW", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "32GFC-LW" }, + { pid: "XBR-SFP32GER", formFactor: "SFP+", speedGbps: 32, speed: "32GFC", reachMeters: 40000, reachLabel: "EW", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "32GFC-EW" }, + + // ── 10G Ethernet SFP+ ─────────────────────────────────────────────────── + { pid: "XBR-10G0SR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 300, reachLabel: "SR", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "10GBASE-SR" }, + { pid: "XBR-10G0LR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 10000, reachLabel: "LR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "10GBASE-LR" }, + { pid: "XBR-10G0ER", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 40000, reachLabel: "ER", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "10GBASE-ER" }, + + // ── 25G SFP28 ─────────────────────────────────────────────────────────── + { pid: "XBR-25G0SR", formFactor: "SFP28", speedGbps: 25, speed: "25G", reachMeters: 100, reachLabel: "SR", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "25GBASE-SR" }, + { pid: "XBR-25G0LR", formFactor: "SFP28", speedGbps: 25, speed: "25G", reachMeters: 10000, reachLabel: "LR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "25GBASE-LR" }, + + // ── 40G QSFP+ ─────────────────────────────────────────────────────────── + { pid: "XBR-40G0SR4", formFactor: "QSFP+", speedGbps: 40, speed: "40G", reachMeters: 150, reachLabel: "SR4", fiberType: "MMF", connector: "MPO", wavelengths: "850nm", standard: "40GBASE-SR4" }, + { pid: "XBR-40G0LR4", formFactor: "QSFP+", speedGbps: 40, speed: "40G", reachMeters: 10000, reachLabel: "LR4", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "40GBASE-LR4" }, + + // ── 100G QSFP28 ───────────────────────────────────────────────────────── + { pid: "XBR-100G0SR4", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 100, reachLabel: "SR4", fiberType: "MMF", connector: "MPO", wavelengths: "850nm", standard: "100GBASE-SR4" }, + { pid: "XBR-100G0LR4", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 10000, reachLabel: "LR4", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "100GBASE-LR4" }, + { pid: "XBR-100G0CWDM4", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 2000, reachLabel: "CWDM4", fiberType: "SMF", connector: "LC", wavelengths: "1271-1331nm", standard: "100GBASE-CWDM4" }, + + // ── 128G FC QSFP28 ────────────────────────────────────────────────────── + { pid: "XBR-QSFP28-128GW", formFactor: "QSFP28", speedGbps: 128, speed: "128GFC", reachMeters: 100, reachLabel: "SW", fiberType: "MMF", connector: "MPO", wavelengths: "850nm", standard: "128GFC-SW" }, + { pid: "XBR-QSFP28-128GLR", formFactor: "QSFP28", speedGbps: 128, speed: "128GFC", reachMeters: 2000, reachLabel: "LW", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "128GFC-LW" }, + + // ── DAC ───────────────────────────────────────────────────────────────── + { pid: "XBR-TWX-0101", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 1, reachLabel: "DAC-1M", fiberType: "DAC", connector: "SFP+" }, + { pid: "XBR-TWX-0301", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 3, reachLabel: "DAC-3M", fiberType: "DAC", connector: "SFP+" }, + { pid: "XBR-TWX-0107", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 1, reachLabel: "DAC-1M", fiberType: "DAC", connector: "QSFP28" }, +]; + +export async function scrapeBrocadeOem(): Promise { + console.log("=== Brocade OEM Transceiver Seed ===\n"); + + const vendorId = await ensureVendor( + "Brocade", + "oem", + "https://www.broadcom.com/products/fibre-channel-networking", + undefined + ); + + let inserted = 0; + let updated = 0; + let errors = 0; + + for (const p of BROCADE_PIDS) { + const slug = `brocade-${p.pid.toLowerCase().replace(/[^a-z0-9]+/g, "-")}`; + try { + const res = await pool.query( + `INSERT INTO transceivers + (slug, part_number, vendor_id, form_factor, speed, speed_gbps, + reach_meters, reach_label, fiber_type, connector, wavelengths, + dom_support, ieee_reference, market_status, category, notes) + VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,true,$12,'Mainstream','DataCenter',$13) + ON CONFLICT (slug) DO UPDATE SET + speed_gbps = EXCLUDED.speed_gbps, + reach_meters = CASE WHEN EXCLUDED.reach_meters > 0 THEN EXCLUDED.reach_meters ELSE transceivers.reach_meters END, + fiber_type = CASE WHEN EXCLUDED.fiber_type <> '' THEN EXCLUDED.fiber_type ELSE transceivers.fiber_type END, + wavelengths = COALESCE(EXCLUDED.wavelengths, transceivers.wavelengths), + updated_at = NOW() + RETURNING (xmax = 0) as was_inserted`, + [slug, p.pid, vendorId, p.formFactor, p.speed, p.speedGbps, + p.reachMeters, p.reachLabel, p.fiberType, p.connector, + p.wavelengths ?? null, p.standard ?? null, p.notes ?? null] + ); + if (res.rows[0]?.was_inserted) inserted++; else updated++; + } catch (err) { + console.warn(` Skip ${p.pid}: ${(err as Error).message.slice(0, 80)}`); + errors++; + } + } + + console.log(`\n=== Brocade OEM Seed Complete ===`); + console.log(` Inserted: ${inserted}`); + console.log(` Updated: ${updated}`); + console.log(` Errors: ${errors}`); + console.log(` Total PIDs: ${BROCADE_PIDS.length}\n`); +} + +if (require.main === module) { + scrapeBrocadeOem() + .then(() => pool.end()) + .catch((err) => { + console.error("Fatal:", err); + pool.end(); + process.exit(1); + }); +} diff --git a/packages/scraper/src/scrapers/calix-access-oem.ts b/packages/scraper/src/scrapers/calix-access-oem.ts new file mode 100644 index 0000000..4d63947 --- /dev/null +++ b/packages/scraper/src/scrapers/calix-access-oem.ts @@ -0,0 +1,127 @@ +/** + * Calix Access OEM Transceiver Catalog Seed + * + * Seeds Calix-branded transceiver PIDs for AXOS, GigaSPEED, and + * Intelligent Access EDGE platforms with a focus on PON/access optics + * (GPON, XGS-PON, EPON, BiDi) not covered in the base calix-oem.ts seed. + * + * Sources: + * - Calix Support Cloud Optics Compatibility Guide (calix.com) + * - Calix AXOS E9-2 / E7-2 / GigaSPEED Hardware Reference + * - ITU-T G.984/G.9807/G.987 PON specifications + * + * Run: tsx packages/scraper/src/scrapers/calix-access-oem.ts + * Cron: daily at 22:30 + */ + +import { pool, ensureVendor } from "../utils/db"; + +interface CalixAccessPID { + pid: string; + formFactor: string; + speedGbps: number; + speed: string; + reachMeters: number; + reachLabel: string; + fiberType: string; + connector: string; + wavelengths?: string; + standard?: string; + notes?: string; + isTelecom?: boolean; +} + +// ── Calix Access OEM transceiver catalog ──────────────────────────────────── +// Focus: PON OLT/ONU optics + access-edge SFP variants for AXOS platforms +const CALIX_ACCESS_PIDS: CalixAccessPID[] = [ + // ── 1G SFP (access uplinks) ────────────────────────────────────────────── + { pid: "SFP-GE-SX", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 550, reachLabel: "SX", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "1000BASE-SX" }, + { pid: "SFP-GE-LX", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 10000, reachLabel: "LX", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "1000BASE-LX" }, + { pid: "SFP-GE-T", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 100, reachLabel: "T", fiberType: "DAC", connector: "RJ45", standard: "1000BASE-T" }, + { pid: "SFP-BIDI-1310-1490", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 20000, reachLabel: "BiDi", fiberType: "SMF", connector: "LC", wavelengths: "1310/1490nm", notes: "1G BiDi single-fiber upstream 1310nm / downstream 1490nm for AXOS access" }, + + // ── 10G SFP+ (access uplinks) ──────────────────────────────────────────── + { pid: "SFP-10G-SR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 300, reachLabel: "SR", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "10GBASE-SR" }, + { pid: "SFP-10G-LR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 10000, reachLabel: "LR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "10GBASE-LR" }, + { pid: "SFP-10G-ER", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 40000, reachLabel: "ER", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "10GBASE-ER" }, + { pid: "SFP-10G-LR-S", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 10000, reachLabel: "LR-S", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", notes: "10G LR industrial temp -40 to +85°C for outdoor AXOS pods" }, + { pid: "SFP-10G-T", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 30, reachLabel: "T", fiberType: "DAC", connector: "RJ45", standard: "10GBASE-T" }, + + // ── 25G SFP28 ──────────────────────────────────────────────────────────── + { pid: "SFP-25G-SR", formFactor: "SFP28", speedGbps: 25, speed: "25G", reachMeters: 100, reachLabel: "SR", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "25GBASE-SR" }, + { pid: "SFP-25G-LR", formFactor: "SFP28", speedGbps: 25, speed: "25G", reachMeters: 10000, reachLabel: "LR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "25GBASE-LR" }, + + // ── 40G QSFP+ ──────────────────────────────────────────────────────────── + { pid: "QSFP-40G-SR4", formFactor: "QSFP+", speedGbps: 40, speed: "40G", reachMeters: 150, reachLabel: "SR4", fiberType: "MMF", connector: "MPO", wavelengths: "850nm", standard: "40GBASE-SR4" }, + { pid: "QSFP-40G-LR4", formFactor: "QSFP+", speedGbps: 40, speed: "40G", reachMeters: 10000, reachLabel: "LR4", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "40GBASE-LR4" }, + + // ── 100G QSFP28 ────────────────────────────────────────────────────────── + { pid: "QSFP-100G-SR4", formFactor: "QSFP28",speedGbps: 100, speed: "100G", reachMeters: 100, reachLabel: "SR4", fiberType: "MMF", connector: "MPO", wavelengths: "850nm", standard: "100GBASE-SR4" }, + { pid: "QSFP-100G-LR4", formFactor: "QSFP28",speedGbps: 100, speed: "100G", reachMeters: 10000, reachLabel: "LR4", fiberType: "SMF", connector: "LC", wavelengths: "1295-1310nm", standard: "100GBASE-LR4" }, + + // ── PON OLT optics (Telecom) ───────────────────────────────────────────── + { pid: "SFP-GPON-OLT", formFactor: "SFP", speedGbps: 2.5, speed: "2.5G", reachMeters: 20000, reachLabel: "GPON-OLT", fiberType: "SMF", connector: "SC", wavelengths: "1490/1310nm", standard: "ITU-T G.984", notes: "GPON OLT SFP Class B+; DS 1490nm 2.488Gbps / US 1310nm 1.244Gbps", isTelecom: true }, + { pid: "SFP-XGSPON-OLT", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 20000, reachLabel: "XGSPON-OLT", fiberType: "SMF", connector: "SC", wavelengths: "1577/1270nm", standard: "ITU-T G.9807", notes: "XGS-PON OLT SFP+ Class N1+; DS 1577nm 9.953Gbps / US 1270nm 9.953Gbps", isTelecom: true }, + { pid: "SFP-EPON-OLT", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 20000, reachLabel: "EPON-OLT", fiberType: "SMF", connector: "SC", wavelengths: "1490/1310nm", standard: "IEEE 802.3ah", notes: "EPON OLT SFP PX20+; DS 1490nm 1Gbps / US 1310nm 1Gbps", isTelecom: true }, + { pid: "SFP-GPON-ONU", formFactor: "SFP", speedGbps: 2.5, speed: "2.5G", reachMeters: 20000, reachLabel: "GPON-ONU", fiberType: "SMF", connector: "SC", wavelengths: "1310/1490nm", standard: "ITU-T G.984", notes: "GPON ONU SFP Class B+; US 1310nm 1.244Gbps / DS 1490nm 2.488Gbps", isTelecom: true }, +]; + +export async function scrapeCalixAccessOem(): Promise { + console.log("=== Calix Access OEM Transceiver Seed ===\n"); + + const vendorId = await ensureVendor( + "Calix", + "oem", + "https://www.calix.com", + undefined + ); + + let inserted = 0; + let updated = 0; + let errors = 0; + + for (const p of CALIX_ACCESS_PIDS) { + const slug = `calix-access-${p.pid.toLowerCase().replace(/[^a-z0-9]+/g, "-")}`; + const category = p.isTelecom ? "Telecom" : "DataCenter"; + try { + const res = await pool.query( + `INSERT INTO transceivers + (slug, part_number, vendor_id, form_factor, speed, speed_gbps, + reach_meters, reach_label, fiber_type, connector, wavelengths, + dom_support, ieee_reference, market_status, category, notes) + VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,true,$12,'Mainstream',$13,$14) + ON CONFLICT (slug) DO UPDATE SET + speed_gbps = EXCLUDED.speed_gbps, + reach_meters = CASE WHEN EXCLUDED.reach_meters > 0 THEN EXCLUDED.reach_meters ELSE transceivers.reach_meters END, + fiber_type = CASE WHEN EXCLUDED.fiber_type <> '' THEN EXCLUDED.fiber_type ELSE transceivers.fiber_type END, + wavelengths = COALESCE(EXCLUDED.wavelengths, transceivers.wavelengths), + is_oem_seed = true, + updated_at = NOW() + RETURNING (xmax = 0) as was_inserted`, + [slug, p.pid, vendorId, p.formFactor, p.speed, p.speedGbps, + p.reachMeters, p.reachLabel, p.fiberType, p.connector, + p.wavelengths ?? null, p.standard ?? null, category, p.notes ?? null] + ); + if (res.rows[0]?.was_inserted) inserted++; else updated++; + } catch (err) { + console.warn(` Skip ${p.pid}: ${(err as Error).message.slice(0, 80)}`); + errors++; + } + } + + console.log(`\n=== Calix Access OEM Seed Complete ===`); + console.log(` Inserted: ${inserted}`); + console.log(` Updated: ${updated}`); + console.log(` Errors: ${errors}`); + console.log(` Total PIDs: ${CALIX_ACCESS_PIDS.length}\n`); +} + +if (require.main === module) { + scrapeCalixAccessOem() + .then(() => pool.end()) + .catch((err) => { + console.error("Fatal:", err); + pool.end(); + process.exit(1); + }); +} diff --git a/packages/scraper/src/scrapers/calix-gigapoint-oem.ts b/packages/scraper/src/scrapers/calix-gigapoint-oem.ts new file mode 100644 index 0000000..7de6d37 --- /dev/null +++ b/packages/scraper/src/scrapers/calix-gigapoint-oem.ts @@ -0,0 +1,140 @@ +/** + * Calix GigaPoint OEM Transceiver Catalog Seed + * + * Seeds Calix GigaPoint / Revenue EDGE-branded transceiver PIDs for + * Calix E-Series and AXOS OLT platforms supporting GPON, XGS-PON, + * and 10G-EPON broadband access deployments. + * + * Sources: + * - Calix Broadband Cloud Access Systems (calix.com) + * - Calix E7-2 / AXOS E9-2 Hardware Reference Guides + * - Calix GigaPoint Optical Module Data Sheets + * + * Run: tsx packages/scraper/src/scrapers/calix-gigapoint-oem.ts + * Cron: daily at 09:00 + */ + +import { pool, ensureVendor } from "../utils/db"; + +interface CalixGigapointPID { + pid: string; + formFactor: string; + speedGbps: number; + speed: string; + reachMeters: number; + reachLabel: string; + fiberType: string; + connector: string; + wavelengths?: string; + standard?: string; + notes?: string; + isTelecom?: boolean; +} + +const TELECOM_PIDS: Set = new Set([ + "CGP-GPON-OLT-B", + "CGP-GPON-OLT-C", + "CGP-XGS-PON-OLT", + "CGP-XGS-PON-ONU", + "CGP-EPON-OLT", + "CGP-10G-EPON-OLT", + "CGP-SFP-CWDM-1490", + "CGP-SFP-CWDM-1550", + "CGP-SFP-BIDI-1310", + "CGP-SFP-BIDI-1490", +]); + +const CALIX_GIGAPOINT_PIDS: CalixGigapointPID[] = [ + // ── GPON OLT SFP ───────────────────────────────────────────────────────── + { pid: "CGP-GPON-OLT-B", formFactor: "SFP", speedGbps: 2.488, speed: "GPON", reachMeters: 20000, reachLabel: "GPON-20K", fiberType: "SMF", connector: "SC", wavelengths: "1490/1310nm", standard: "G.984", notes: "Calix GigaPoint GPON OLT SFP Class B+, E7-2/AXOS platform", isTelecom: true }, + { pid: "CGP-GPON-OLT-C", formFactor: "SFP", speedGbps: 2.488, speed: "GPON", reachMeters: 20000, reachLabel: "GPON-C+", fiberType: "SMF", connector: "SC", wavelengths: "1490/1310nm", standard: "G.984", notes: "Calix GigaPoint GPON OLT SFP Class C+, extended reach", isTelecom: true }, + + // ── XGS-PON OLT / ONU SFP+ ─────────────────────────────────────────────── + { pid: "CGP-XGS-PON-OLT", formFactor: "SFP+", speedGbps: 10, speed: "XGS-PON", reachMeters: 20000, reachLabel: "XGS-PON-20K", fiberType: "SMF", connector: "SC", wavelengths: "1577/1270nm", standard: "G.9807.1", notes: "Calix GigaPoint XGS-PON OLT SFP+ for E9-2", isTelecom: true }, + { pid: "CGP-XGS-PON-ONU", formFactor: "SFP+", speedGbps: 10, speed: "XGS-PON", reachMeters: 20000, reachLabel: "XGS-ONU-20K", fiberType: "SMF", connector: "SC", wavelengths: "1270/1577nm", standard: "G.9807.1", notes: "Calix GigaPoint XGS-PON ONU SFP+ 1270nm TX", isTelecom: true }, + + // ── EPON OLT SFP ───────────────────────────────────────────────────────── + { pid: "CGP-EPON-OLT", formFactor: "SFP", speedGbps: 1, speed: "EPON", reachMeters: 20000, reachLabel: "EPON-20K", fiberType: "SMF", connector: "SC", wavelengths: "1490/1310nm", standard: "802.3ah", notes: "Calix GigaPoint EPON OLT SFP 1G/1G", isTelecom: true }, + { pid: "CGP-10G-EPON-OLT", formFactor: "SFP+", speedGbps: 10, speed: "10G-EPON", reachMeters: 20000, reachLabel: "10G-EPON-20K",fiberType: "SMF", connector: "SC", wavelengths: "1577/1270nm", standard: "802.3av", notes: "Calix GigaPoint 10G-EPON OLT SFP+", isTelecom: true }, + + // ── Standard 1G SFP ────────────────────────────────────────────────────── + { pid: "CGP-SFP-1G-SX", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 550, reachLabel: "SX", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "1000BASE-SX" }, + { pid: "CGP-SFP-1G-LX", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 10000, reachLabel: "LX", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "1000BASE-LX" }, + + // ── Standard 10G SFP+ ──────────────────────────────────────────────────── + { pid: "CGP-SFP-10G-SR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 300, reachLabel: "SR", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "10GBASE-SR" }, + { pid: "CGP-SFP-10G-LR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 10000, reachLabel: "LR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "10GBASE-LR" }, + + // ── CWDM SFP ───────────────────────────────────────────────────────────── + { pid: "CGP-SFP-CWDM-1490", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 40000, reachLabel: "CWDM-1490", fiberType: "SMF", connector: "LC", wavelengths: "1490nm", standard: "CWDM", notes: "Calix GigaPoint CWDM SFP 1490nm", isTelecom: true }, + { pid: "CGP-SFP-CWDM-1550", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 40000, reachLabel: "CWDM-1550", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "CWDM", notes: "Calix GigaPoint CWDM SFP 1550nm", isTelecom: true }, + + // ── BiDi SFP ───────────────────────────────────────────────────────────── + { pid: "CGP-SFP-BIDI-1310", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 20000, reachLabel: "BiDi-1310", fiberType: "SMF", connector: "SC", wavelengths: "1310/1490nm", notes: "Calix GigaPoint 1G BiDi SFP 1310nm TX / 1490nm RX", isTelecom: true }, + { pid: "CGP-SFP-BIDI-1490", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 20000, reachLabel: "BiDi-1490", fiberType: "SMF", connector: "SC", wavelengths: "1490/1310nm", notes: "Calix GigaPoint 1G BiDi SFP 1490nm TX / 1310nm RX", isTelecom: true }, + + // ── 25G SFP28 ──────────────────────────────────────────────────────────── + { pid: "CGP-SFP-25G-LR", formFactor: "SFP28", speedGbps: 25, speed: "25G", reachMeters: 10000, reachLabel: "LR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "25GBASE-LR" }, + + // ── 100G QSFP28 ────────────────────────────────────────────────────────── + { pid: "CGP-QSFP-100G-LR4", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 10000, reachLabel: "LR4", fiberType: "SMF", connector: "LC", wavelengths: "1295-1310nm", standard: "100GBASE-LR4" }, +]; + +export async function scrapeCalixGigapointOem(): Promise { + console.log("=== Calix GigaPoint OEM Transceiver Seed ===\n"); + + const vendorId = await ensureVendor( + "Calix GigaPoint", + "oem", + "https://www.calix.com/calix-platforms/calix-broadband-cloud-access-systems.html", + undefined + ); + + let inserted = 0; + let updated = 0; + let errors = 0; + + for (const p of CALIX_GIGAPOINT_PIDS) { + const slug = `calix-gp-${p.pid.toLowerCase().replace(/[^a-z0-9]+/g, "-")}`; + const category = TELECOM_PIDS.has(p.pid) ? "Telecom" : "DataCenter"; + try { + const res = await pool.query( + `INSERT INTO transceivers + (slug, part_number, vendor_id, form_factor, speed, speed_gbps, + reach_meters, reach_label, fiber_type, connector, wavelengths, + dom_support, ieee_reference, market_status, category, notes) + VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,true,$12,'Mainstream',$13,$14) + ON CONFLICT (slug) DO UPDATE SET + speed_gbps = EXCLUDED.speed_gbps, + reach_meters = CASE WHEN EXCLUDED.reach_meters > 0 THEN EXCLUDED.reach_meters ELSE transceivers.reach_meters END, + fiber_type = CASE WHEN EXCLUDED.fiber_type <> '' THEN EXCLUDED.fiber_type ELSE transceivers.fiber_type END, + wavelengths = COALESCE(EXCLUDED.wavelengths, transceivers.wavelengths), + updated_at = NOW() + RETURNING (xmax = 0) as was_inserted`, + [slug, p.pid, vendorId, p.formFactor, p.speed, p.speedGbps, + p.reachMeters, p.reachLabel, p.fiberType, p.connector, + p.wavelengths ?? null, p.standard ?? null, category, p.notes ?? null] + ); + if (res.rows[0]?.was_inserted) inserted++; else updated++; + } catch (err) { + console.warn(` Skip ${p.pid}: ${(err as Error).message.slice(0, 80)}`); + errors++; + } + } + + console.log(`\n=== Calix GigaPoint OEM Seed Complete ===`); + console.log(` Inserted: ${inserted}`); + console.log(` Updated: ${updated}`); + console.log(` Errors: ${errors}`); + console.log(` Total PIDs: ${CALIX_GIGAPOINT_PIDS.length}\n`); +} + +if (require.main === module) { + scrapeCalixGigapointOem() + .then(() => pool.end()) + .catch((err) => { + console.error("Fatal:", err); + pool.end(); + process.exit(1); + }); +} diff --git a/packages/scraper/src/scrapers/calix-oem.ts b/packages/scraper/src/scrapers/calix-oem.ts new file mode 100644 index 0000000..6980dde --- /dev/null +++ b/packages/scraper/src/scrapers/calix-oem.ts @@ -0,0 +1,119 @@ +/** + * Calix OEM Transceiver Catalog Seed + * Seeds Calix-branded transceiver PIDs for E-Series, GigaSPEED, + * AXOS, and Intelligent Access EDGE platforms. + * Sources: Calix Support Cloud / Hardware Compatibility Guide (calix.com) + * Run: tsx packages/scraper/src/scrapers/calix-oem.ts + * Cron: daily at 08:45 + */ + +import { pool, ensureVendor } from "../utils/db"; + +interface CalixPID { + pid: string; + formFactor: string; + speedGbps: number; + speed: string; + reachMeters: number; + reachLabel: string; + fiberType: string; + connector: string; + wavelengths?: string; + standard?: string; + notes?: string; +} + +// ── Calix OEM transceiver catalog ─────────────────────────────────────────── +// Source: Calix Support Cloud / Hardware Compatibility Guide (calix.com) +const CALIX_PIDS: CalixPID[] = [ + // ── 1G SFP ────────────────────────────────────────────────────────────── + { pid: "100-02013", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 550, reachLabel: "SX", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "1000BASE-SX" }, + { pid: "100-02014", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 10000, reachLabel: "LX", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "1000BASE-LX" }, + { pid: "100-02015", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 80000, reachLabel: "ZX", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "1000BASE-ZX" }, + { pid: "100-02016", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 100, reachLabel: "T", fiberType: "DAC", connector: "RJ45", standard: "1000BASE-T" }, + { pid: "100-02017", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 40000, reachLabel: "LH40", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", notes: "Calix 1G SM 40km" }, + { pid: "100-02018", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 10000, reachLabel: "BiDi", fiberType: "SMF", connector: "LC", wavelengths: "1310/1550nm", notes: "Calix 1G BiDi single fiber" }, + // ── 10G SFP+ ──────────────────────────────────────────────────────────── + { pid: "100-04025", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 300, reachLabel: "SR", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "10GBASE-SR" }, + { pid: "100-04026", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 10000, reachLabel: "LR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "10GBASE-LR" }, + { pid: "100-04027", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 40000, reachLabel: "ER", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "10GBASE-ER" }, + { pid: "100-04028", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 80000, reachLabel: "ZR", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "10GBASE-ZR" }, + { pid: "100-04029", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 30, reachLabel: "T", fiberType: "DAC", connector: "RJ45", standard: "10GBASE-T" }, + { pid: "100-04030", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 10000, reachLabel: "BiDi", fiberType: "SMF", connector: "LC", wavelengths: "1270/1330nm", notes: "Calix 10G BiDi SFP+" }, + // ── 25G SFP28 ─────────────────────────────────────────────────────────── + { pid: "100-04050", formFactor: "SFP28", speedGbps: 25, speed: "25G", reachMeters: 100, reachLabel: "SR", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "25GBASE-SR" }, + { pid: "100-04051", formFactor: "SFP28", speedGbps: 25, speed: "25G", reachMeters: 10000, reachLabel: "LR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "25GBASE-LR" }, + { pid: "100-04052", formFactor: "SFP28", speedGbps: 25, speed: "25G", reachMeters: 30000, reachLabel: "ER", fiberType: "SMF", connector: "LC", wavelengths: "1310nm" }, + // ── 40G QSFP+ ─────────────────────────────────────────────────────────── + { pid: "100-04060", formFactor: "QSFP+", speedGbps: 40, speed: "40G", reachMeters: 150, reachLabel: "SR4", fiberType: "MMF", connector: "MPO", wavelengths: "850nm", standard: "40GBASE-SR4" }, + { pid: "100-04061", formFactor: "QSFP+", speedGbps: 40, speed: "40G", reachMeters: 10000, reachLabel: "LR4", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "40GBASE-LR4" }, + // ── 100G QSFP28 ───────────────────────────────────────────────────────── + { pid: "100-04070", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 100, reachLabel: "SR4", fiberType: "MMF", connector: "MPO", wavelengths: "850nm", standard: "100GBASE-SR4" }, + { pid: "100-04071", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 10000, reachLabel: "LR4", fiberType: "SMF", connector: "LC", wavelengths: "1295-1310nm", standard: "100GBASE-LR4" }, + { pid: "100-04072", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 2000, reachLabel: "CWDM4", fiberType: "SMF", connector: "LC", wavelengths: "1271-1331nm", standard: "100GBASE-CWDM4" }, + { pid: "100-04073", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 500, reachLabel: "DR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "100GBASE-DR" }, + { pid: "100-04074", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 2000, reachLabel: "FR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "100GBASE-FR" }, + // ── DAC cables ────────────────────────────────────────────────────────── + { pid: "100-03901", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 1, reachLabel: "DAC-1M", fiberType: "DAC", connector: "SFP+" }, + { pid: "100-03903", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 3, reachLabel: "DAC-3M", fiberType: "DAC", connector: "SFP+" }, + { pid: "100-03911", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 1, reachLabel: "DAC-1M", fiberType: "DAC", connector: "QSFP28" }, + { pid: "100-03913", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 3, reachLabel: "DAC-3M", fiberType: "DAC", connector: "QSFP28" }, +]; + +export async function scrapeCalixOem(): Promise { + console.log("=== Calix OEM Transceiver Seed ===\n"); + + const calixVendorId = await ensureVendor( + "Calix", + "oem", + "https://www.calix.com", + undefined + ); + + let inserted = 0; + let updated = 0; + let errors = 0; + + for (const p of CALIX_PIDS) { + const slug = `calix-${p.pid.toLowerCase().replace(/[^a-z0-9]+/g, "-")}`; + try { + const res = await pool.query( + `INSERT INTO transceivers + (slug, part_number, vendor_id, form_factor, speed, speed_gbps, + reach_meters, reach_label, fiber_type, connector, wavelengths, + dom_support, ieee_reference, market_status, category, notes) + VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,true,$12,'Mainstream','DataCenter',$13) + ON CONFLICT (slug) DO UPDATE SET + speed_gbps = EXCLUDED.speed_gbps, + reach_meters = CASE WHEN EXCLUDED.reach_meters > 0 THEN EXCLUDED.reach_meters ELSE transceivers.reach_meters END, + fiber_type = CASE WHEN EXCLUDED.fiber_type <> '' THEN EXCLUDED.fiber_type ELSE transceivers.fiber_type END, + wavelengths = COALESCE(EXCLUDED.wavelengths, transceivers.wavelengths), + updated_at = NOW() + RETURNING (xmax = 0) as was_inserted`, + [slug, p.pid, calixVendorId, p.formFactor, p.speed, p.speedGbps, + p.reachMeters, p.reachLabel, p.fiberType, p.connector, + p.wavelengths ?? null, p.standard ?? null, p.notes ?? null] + ); + if (res.rows[0]?.was_inserted) inserted++; else updated++; + } catch (err) { + console.warn(` Skip ${p.pid}: ${(err as Error).message.slice(0, 80)}`); + errors++; + } + } + + console.log(`\n=== Calix OEM Seed Complete ===`); + console.log(` Inserted: ${inserted}`); + console.log(` Updated: ${updated}`); + console.log(` Errors: ${errors}`); + console.log(` Total PIDs: ${CALIX_PIDS.length}\n`); +} + +if (require.main === module) { + scrapeCalixOem() + .then(() => pool.end()) + .catch((err) => { + console.error("Fatal:", err); + pool.end(); + process.exit(1); + }); +} diff --git a/packages/scraper/src/scrapers/cambium-oem.ts b/packages/scraper/src/scrapers/cambium-oem.ts new file mode 100644 index 0000000..b612c15 --- /dev/null +++ b/packages/scraper/src/scrapers/cambium-oem.ts @@ -0,0 +1,121 @@ +/** + * Cambium Networks OEM Transceiver Catalog Seed + * + * Seeds transceiver PIDs for Cambium Networks branded optics used in + * cnMatrix EX series enterprise switches and PTP 820 platforms. + * + * Sources: + * - Cambium Networks cnMatrix transceiver compatibility guide (cambiumnetworks.com) + * - Cambium EX2052R/EX2082R hardware installation guides + * + * Run: tsx packages/scraper/src/scrapers/cambium-oem.ts + * Cron: daily at 11:00 + */ + +import { pool, ensureVendor } from "../utils/db"; + +interface CambiumPID { + pid: string; + formFactor: string; + speedGbps: number; + speed: string; + reachMeters: number; + reachLabel: string; + fiberType: string; + connector: string; + wavelengths?: string; + standard?: string; + notes?: string; +} + +const CAMBIUM_PIDS: CambiumPID[] = [ + // ── 1G SFP ────────────────────────────────────────────────────────────── + { pid: "C000065L001A", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 550, reachLabel: "SX", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "1000BASE-SX" }, + { pid: "C000065L002A", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 10000, reachLabel: "LX", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "1000BASE-LX" }, + { pid: "C000065L003A", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 80000, reachLabel: "ZX", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "1000BASE-ZX" }, + { pid: "C000065L004A", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 100, reachLabel: "T", fiberType: "DAC", connector: "RJ45", standard: "1000BASE-T" }, + { pid: "C000065L005A", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 20000, reachLabel: "BiDi", fiberType: "SMF", connector: "LC", wavelengths: "1310/1550nm", notes: "cnMatrix 1G BiDi SFP" }, + + // ── 10G SFP+ ──────────────────────────────────────────────────────────── + { pid: "C000065L010A", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 300, reachLabel: "SR", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "10GBASE-SR" }, + { pid: "C000065L011A", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 10000, reachLabel: "LR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "10GBASE-LR" }, + { pid: "C000065L012A", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 40000, reachLabel: "ER", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "10GBASE-ER" }, + { pid: "C000065L013A", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 30, reachLabel: "T", fiberType: "DAC", connector: "RJ45", standard: "10GBASE-T" }, + { pid: "C000065L014A", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 10000, reachLabel: "BiDi", fiberType: "SMF", connector: "LC", wavelengths: "1270/1330nm" }, + + // ── 25G SFP28 ─────────────────────────────────────────────────────────── + { pid: "C000065L020A", formFactor: "SFP28", speedGbps: 25, speed: "25G", reachMeters: 100, reachLabel: "SR", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "25GBASE-SR" }, + { pid: "C000065L021A", formFactor: "SFP28", speedGbps: 25, speed: "25G", reachMeters: 10000, reachLabel: "LR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "25GBASE-LR" }, + + // ── 40G QSFP+ ─────────────────────────────────────────────────────────── + { pid: "C000065L030A", formFactor: "QSFP+", speedGbps: 40, speed: "40G", reachMeters: 150, reachLabel: "SR4", fiberType: "MMF", connector: "MPO", wavelengths: "850nm", standard: "40GBASE-SR4" }, + { pid: "C000065L031A", formFactor: "QSFP+", speedGbps: 40, speed: "40G", reachMeters: 10000, reachLabel: "LR4", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "40GBASE-LR4" }, + + // ── 100G QSFP28 ───────────────────────────────────────────────────────── + { pid: "C000065L040A", formFactor: "QSFP28",speedGbps: 100, speed: "100G", reachMeters: 100, reachLabel: "SR4", fiberType: "MMF", connector: "MPO", wavelengths: "850nm", standard: "100GBASE-SR4" }, + { pid: "C000065L041A", formFactor: "QSFP28",speedGbps: 100, speed: "100G", reachMeters: 10000, reachLabel: "LR4", fiberType: "SMF", connector: "LC", wavelengths: "1295-1310nm", standard: "100GBASE-LR4" }, + { pid: "C000065L042A", formFactor: "QSFP28",speedGbps: 100, speed: "100G", reachMeters: 2000, reachLabel: "CWDM4", fiberType: "SMF", connector: "LC", wavelengths: "1271-1331nm", standard: "100GBASE-CWDM4" }, + + // ── DAC ───────────────────────────────────────────────────────────────── + { pid: "C000065L050A", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 1, reachLabel: "DAC-1M", fiberType: "DAC", connector: "SFP+" }, + { pid: "C000065L051A", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 3, reachLabel: "DAC-3M", fiberType: "DAC", connector: "SFP+" }, + { pid: "C000065L060A", formFactor: "QSFP28",speedGbps: 100, speed: "100G", reachMeters: 1, reachLabel: "DAC-1M", fiberType: "DAC", connector: "QSFP28" }, +]; + +export async function scrapeCambiumOem(): Promise { + console.log("=== Cambium Networks OEM Transceiver Seed ===\n"); + + const vendorId = await ensureVendor( + "Cambium Networks", + "oem", + "https://www.cambiumnetworks.com", + undefined + ); + + let inserted = 0; + let updated = 0; + let errors = 0; + + for (const p of CAMBIUM_PIDS) { + const slug = `cambium-${p.pid.toLowerCase().replace(/[^a-z0-9]+/g, "-")}`; + try { + const res = await pool.query( + `INSERT INTO transceivers + (slug, part_number, vendor_id, form_factor, speed, speed_gbps, + reach_meters, reach_label, fiber_type, connector, wavelengths, + dom_support, ieee_reference, market_status, category, notes) + VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,true,$12,'Mainstream','DataCenter',$13) + ON CONFLICT (slug) DO UPDATE SET + speed_gbps = EXCLUDED.speed_gbps, + reach_meters = CASE WHEN EXCLUDED.reach_meters > 0 THEN EXCLUDED.reach_meters ELSE transceivers.reach_meters END, + fiber_type = CASE WHEN EXCLUDED.fiber_type <> '' THEN EXCLUDED.fiber_type ELSE transceivers.fiber_type END, + wavelengths = COALESCE(EXCLUDED.wavelengths, transceivers.wavelengths), + updated_at = NOW() + RETURNING (xmax = 0) as was_inserted`, + [slug, p.pid, vendorId, p.formFactor, p.speed, p.speedGbps, + p.reachMeters, p.reachLabel, p.fiberType, p.connector, + p.wavelengths ?? null, p.standard ?? null, p.notes ?? null] + ); + if (res.rows[0]?.was_inserted) inserted++; else updated++; + } catch (err) { + console.warn(` Skip ${p.pid}: ${(err as Error).message.slice(0, 80)}`); + errors++; + } + } + + console.log(`\n=== Cambium Networks OEM Seed Complete ===`); + console.log(` Inserted: ${inserted}`); + console.log(` Updated: ${updated}`); + console.log(` Errors: ${errors}`); + console.log(` Total PIDs: ${CAMBIUM_PIDS.length}\n`); +} + +if (require.main === module) { + scrapeCambiumOem() + .then(() => pool.end()) + .catch((err) => { + console.error("Fatal:", err); + pool.end(); + process.exit(1); + }); +} diff --git a/packages/scraper/src/scrapers/casa-systems-oem.ts b/packages/scraper/src/scrapers/casa-systems-oem.ts new file mode 100644 index 0000000..29dadd5 --- /dev/null +++ b/packages/scraper/src/scrapers/casa-systems-oem.ts @@ -0,0 +1,126 @@ +/** + * Casa Systems OEM Transceiver Catalog Seed + * + * Seeds Casa Systems-branded transceiver PIDs for CMTS/CCAP platforms + * (APEX HFC, C100G, C40G) used in cable access and broadband networks. + * + * Sources: + * - Casa Systems Product Portfolio (casa-systems.com) + * - C100G CCAP Platform Hardware Guide + * - APEX HFC Platform Line Card Compatibility Matrix + * + * Run: tsx packages/scraper/src/scrapers/casa-systems-oem.ts + * Cron: daily at 21:15 + */ + +import { pool, ensureVendor } from "../utils/db"; + +interface CasaPID { + pid: string; + formFactor: string; + speedGbps: number; + speed: string; + reachMeters: number; + reachLabel: string; + fiberType: string; + connector: string; + wavelengths?: string; + standard?: string; + notes?: string; +} + +const CASA_PIDS: CasaPID[] = [ + // ── 1G SFP ────────────────────────────────────────────────────────────── + { pid: "CASA-SFP-1G-SX", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 550, reachLabel: "SX", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "1000BASE-SX" }, + { pid: "CASA-SFP-1G-LX", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 10000, reachLabel: "LX", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "1000BASE-LX" }, + { pid: "CASA-SFP-1G-T", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 100, reachLabel: "T", fiberType: "DAC", connector: "RJ45", standard: "1000BASE-T", notes: "Casa Systems 1G copper SFP" }, + + // ── 10G SFP+ ──────────────────────────────────────────────────────────── + { pid: "CASA-SFP-10G-SR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 300, reachLabel: "SR", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "10GBASE-SR" }, + { pid: "CASA-SFP-10G-LR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 10000, reachLabel: "LR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "10GBASE-LR" }, + { pid: "CASA-SFP-10G-ER", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 40000, reachLabel: "ER", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "10GBASE-ER" }, + { pid: "CASA-SFP-10G-ZR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 80000, reachLabel: "ZR", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "10GBASE-ZR", notes: "Casa Systems 10G ZR for CCAP uplink" }, + { pid: "CASA-SFP-10G-T", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 30, reachLabel: "T", fiberType: "DAC", connector: "RJ45", standard: "10GBASE-T", notes: "Casa Systems 10GBASE-T copper SFP+" }, + + // ── 25G SFP28 ─────────────────────────────────────────────────────────── + { pid: "CASA-SFP-25G-SR", formFactor: "SFP28", speedGbps: 25, speed: "25G", reachMeters: 100, reachLabel: "SR", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "25GBASE-SR" }, + { pid: "CASA-SFP-25G-LR", formFactor: "SFP28", speedGbps: 25, speed: "25G", reachMeters: 10000, reachLabel: "LR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "25GBASE-LR" }, + + // ── 40G QSFP+ ─────────────────────────────────────────────────────────── + { pid: "CASA-QSFP-40G-SR4", formFactor: "QSFP+", speedGbps: 40, speed: "40G", reachMeters: 150, reachLabel: "SR4", fiberType: "MMF", connector: "MPO", wavelengths: "850nm", standard: "40GBASE-SR4" }, + { pid: "CASA-QSFP-40G-LR4", formFactor: "QSFP+", speedGbps: 40, speed: "40G", reachMeters: 10000, reachLabel: "LR4", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "40GBASE-LR4" }, + + // ── 100G QSFP28 ───────────────────────────────────────────────────────── + { pid: "CASA-QSFP-100G-SR4", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 100, reachLabel: "SR4", fiberType: "MMF", connector: "MPO", wavelengths: "850nm", standard: "100GBASE-SR4" }, + { pid: "CASA-QSFP-100G-LR4", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 10000, reachLabel: "LR4", fiberType: "SMF", connector: "LC", wavelengths: "1295-1310nm", standard: "100GBASE-LR4" }, + { pid: "CASA-QSFP-100G-ER4", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 40000, reachLabel: "ER4", fiberType: "SMF", connector: "LC", wavelengths: "1295-1310nm", standard: "100GBASE-ER4", notes: "Casa Systems 100G ER4 for CCAP long-reach uplink" }, + { pid: "CASA-QSFP-100G-CWDM4", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 2000, reachLabel: "CWDM4", fiberType: "SMF", connector: "LC", wavelengths: "1271-1331nm", standard: "100GBASE-CWDM4" }, + + // ── 400G QSFP-DD ──────────────────────────────────────────────────────── + { pid: "CASA-QSFPDD-400G-DR4", formFactor: "QSFP-DD",speedGbps: 400, speed: "400G", reachMeters: 500, reachLabel: "DR4", fiberType: "SMF", connector: "MPO", wavelengths: "1310nm", standard: "400GBASE-DR4", notes: "Casa Systems 400G DR4 next-gen CCAP uplink" }, + { pid: "CASA-QSFPDD-400G-FR4", formFactor: "QSFP-DD",speedGbps: 400, speed: "400G", reachMeters: 2000, reachLabel: "FR4", fiberType: "SMF", connector: "LC", wavelengths: "1271-1331nm", standard: "400GBASE-FR4" }, + + // ── DAC ───────────────────────────────────────────────────────────────── + { pid: "CASA-DAC-10G-1M", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 1, reachLabel: "DAC-1M", fiberType: "DAC", connector: "SFP+", notes: "Casa Systems 10G DAC 1m" }, + { pid: "CASA-DAC-10G-3M", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 3, reachLabel: "DAC-3M", fiberType: "DAC", connector: "SFP+", notes: "Casa Systems 10G DAC 3m" }, + { pid: "CASA-DAC-100G-1M", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 1, reachLabel: "DAC-1M", fiberType: "DAC", connector: "QSFP28", notes: "Casa Systems 100G DAC 1m" }, + { pid: "CASA-DAC-100G-3M", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 3, reachLabel: "DAC-3M", fiberType: "DAC", connector: "QSFP28", notes: "Casa Systems 100G DAC 3m" }, +]; + +export async function scrapeCasaSystemsOem(): Promise { + console.log("=== Casa Systems OEM Transceiver Seed ===\n"); + + const vendorId = await ensureVendor( + "Casa Systems", + "oem", + "https://www.casa-systems.com", + undefined + ); + + let inserted = 0; + let updated = 0; + let errors = 0; + + for (const p of CASA_PIDS) { + const slug = `casa-systems-${p.pid.toLowerCase().replace(/[^a-z0-9]+/g, "-")}`; + try { + const res = await pool.query( + `INSERT INTO transceivers + (slug, part_number, vendor_id, form_factor, speed, speed_gbps, + reach_meters, reach_label, fiber_type, connector, wavelengths, + dom_support, ieee_reference, market_status, category, notes) + VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,true,$12,'Mainstream','DataCenter',$13) + ON CONFLICT (slug) DO UPDATE SET + speed_gbps = EXCLUDED.speed_gbps, + reach_meters = CASE WHEN EXCLUDED.reach_meters > 0 THEN EXCLUDED.reach_meters ELSE transceivers.reach_meters END, + fiber_type = CASE WHEN EXCLUDED.fiber_type <> '' THEN EXCLUDED.fiber_type ELSE transceivers.fiber_type END, + wavelengths = COALESCE(EXCLUDED.wavelengths, transceivers.wavelengths), + updated_at = NOW() + RETURNING (xmax = 0) as was_inserted`, + [slug, p.pid, vendorId, p.formFactor, p.speed, p.speedGbps, + p.reachMeters, p.reachLabel, p.fiberType, p.connector, + p.wavelengths ?? null, p.standard ?? null, p.notes ?? null] + ); + if (res.rows[0]?.was_inserted) inserted++; else updated++; + } catch (err) { + console.warn(` Skip ${p.pid}: ${(err as Error).message.slice(0, 80)}`); + errors++; + } + } + + console.log(`\n=== Casa Systems OEM Seed Complete ===`); + console.log(` Inserted: ${inserted}`); + console.log(` Updated: ${updated}`); + console.log(` Errors: ${errors}`); + console.log(` Total PIDs: ${CASA_PIDS.length}\n`); +} + +if (require.main === module) { + scrapeCasaSystemsOem() + .then(() => pool.end()) + .catch((err) => { + console.error("Fatal:", err); + pool.end(); + process.exit(1); + }); +} diff --git a/packages/scraper/src/scrapers/centec-oem.ts b/packages/scraper/src/scrapers/centec-oem.ts new file mode 100644 index 0000000..9c1e103 --- /dev/null +++ b/packages/scraper/src/scrapers/centec-oem.ts @@ -0,0 +1,118 @@ +/** + * Centec Networks OEM Transceiver Catalog Seed + * + * Seeds Centec-branded transceiver PIDs for V580/V350/V330-series + * white-box Ethernet switches built on Centec Ethernet switching ASICs. + * + * Sources: + * - Centec Networks Optical Transceiver Data Sheet (centecnetworks.com) + * - Centec V580/V350 Hardware Compatibility Guide + * - Centec Open Networking Transceiver Module Specifications + * + * Run: tsx packages/scraper/src/scrapers/centec-oem.ts + * Cron: daily at 11:45 + */ + +import { pool, ensureVendor } from "../utils/db"; + +interface CentecPID { + pid: string; + formFactor: string; + speedGbps: number; + speed: string; + reachMeters: number; + reachLabel: string; + fiberType: string; + connector: string; + wavelengths?: string; + standard?: string; + notes?: string; +} + +const CENTEC_PIDS: CentecPID[] = [ + // ── 1G SFP ────────────────────────────────────────────────────────────── + { pid: "CT-SFP-1G-SX", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 550, reachLabel: "SX", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "1000BASE-SX", notes: "Centec 1G SFP SX 550m MMF" }, + { pid: "CT-SFP-1G-LX", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 10000, reachLabel: "LX", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "1000BASE-LX", notes: "Centec 1G SFP LX 10km SMF" }, + { pid: "CT-SFP-1G-ZX", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 80000, reachLabel: "ZX", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "1000BASE-ZX", notes: "Centec 1G SFP ZX 80km SMF" }, + { pid: "CT-SFP-GE-T", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 100, reachLabel: "T", fiberType: "DAC", connector: "RJ45", standard: "1000BASE-T", notes: "Centec 1G SFP copper RJ45" }, + + // ── 10G SFP+ ──────────────────────────────────────────────────────────── + { pid: "CT-SFP-10G-SR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 300, reachLabel: "SR", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "10GBASE-SR", notes: "Centec 10G SFP+ SR 300m MMF" }, + { pid: "CT-SFP-10G-LR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 10000, reachLabel: "LR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "10GBASE-LR", notes: "Centec 10G SFP+ LR 10km SMF" }, + { pid: "CT-SFP-10G-ER", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 40000, reachLabel: "ER", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "10GBASE-ER", notes: "Centec 10G SFP+ ER 40km SMF" }, + { pid: "CT-SFP-10G-ZR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 80000, reachLabel: "ZR", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "10GBASE-ZR", notes: "Centec 10G SFP+ ZR 80km SMF" }, + + // ── 25G SFP28 ─────────────────────────────────────────────────────────── + { pid: "CT-SFP28-25G-SR", formFactor: "SFP28", speedGbps: 25, speed: "25G", reachMeters: 100, reachLabel: "SR", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "25GBASE-SR", notes: "Centec 25G SFP28 SR 100m MMF" }, + { pid: "CT-SFP28-25G-LR", formFactor: "SFP28", speedGbps: 25, speed: "25G", reachMeters: 10000, reachLabel: "LR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "25GBASE-LR", notes: "Centec 25G SFP28 LR 10km SMF" }, + + // ── 40G QSFP+ ─────────────────────────────────────────────────────────── + { pid: "CT-QSFP-40G-SR4", formFactor: "QSFP+", speedGbps: 40, speed: "40G", reachMeters: 150, reachLabel: "SR4", fiberType: "MMF", connector: "MPO", wavelengths: "850nm", standard: "40GBASE-SR4", notes: "Centec 40G QSFP+ SR4 150m MMF" }, + { pid: "CT-QSFP-40G-LR4", formFactor: "QSFP+", speedGbps: 40, speed: "40G", reachMeters: 10000, reachLabel: "LR4", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "40GBASE-LR4", notes: "Centec 40G QSFP+ LR4 10km SMF" }, + + // ── 100G QSFP28 ───────────────────────────────────────────────────────── + { pid: "CT-QSFP28-100G-SR4", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 100, reachLabel: "SR4", fiberType: "MMF", connector: "MPO", wavelengths: "850nm", standard: "100GBASE-SR4", notes: "Centec 100G QSFP28 SR4 100m MMF" }, + { pid: "CT-QSFP28-100G-LR4", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 10000, reachLabel: "LR4", fiberType: "SMF", connector: "LC", wavelengths: "1295-1310nm", standard: "100GBASE-LR4", notes: "Centec 100G QSFP28 LR4 10km SMF" }, + + // ── 400G QSFP-DD ──────────────────────────────────────────────────────── + { pid: "CT-QSFP-DD-400G-DR4",formFactor: "QSFP-DD",speedGbps: 400, speed: "400G", reachMeters: 500, reachLabel: "DR4", fiberType: "SMF", connector: "MPO", wavelengths: "1310nm", standard: "400GBASE-DR4", notes: "Centec 400G QSFP-DD DR4 500m SMF" }, + { pid: "CT-QSFP-DD-400G-SR8",formFactor: "QSFP-DD",speedGbps: 400, speed: "400G", reachMeters: 100, reachLabel: "SR8", fiberType: "MMF", connector: "MPO", wavelengths: "850nm", standard: "400GBASE-SR8", notes: "Centec 400G QSFP-DD SR8 100m MMF" }, +]; + +export async function scrapeCentecOem(): Promise { + console.log("=== Centec Networks OEM Transceiver Seed ===\n"); + + const vendorId = await ensureVendor( + "Centec Networks", + "oem", + "https://www.centecnetworks.com", + undefined + ); + + let inserted = 0; + let updated = 0; + let errors = 0; + + for (const p of CENTEC_PIDS) { + const slug = `centec-${p.pid.toLowerCase().replace(/[^a-z0-9]+/g, "-")}`; + try { + const res = await pool.query( + `INSERT INTO transceivers + (slug, part_number, vendor_id, form_factor, speed, speed_gbps, + reach_meters, reach_label, fiber_type, connector, wavelengths, + dom_support, ieee_reference, market_status, category, notes) + VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,true,$12,'Mainstream','DataCenter',$13) + ON CONFLICT (slug) DO UPDATE SET + speed_gbps = EXCLUDED.speed_gbps, + reach_meters = CASE WHEN EXCLUDED.reach_meters > 0 THEN EXCLUDED.reach_meters ELSE transceivers.reach_meters END, + fiber_type = CASE WHEN EXCLUDED.fiber_type <> '' THEN EXCLUDED.fiber_type ELSE transceivers.fiber_type END, + wavelengths = COALESCE(EXCLUDED.wavelengths, transceivers.wavelengths), + updated_at = NOW() + RETURNING (xmax = 0) as was_inserted`, + [slug, p.pid, vendorId, p.formFactor, p.speed, p.speedGbps, + p.reachMeters, p.reachLabel, p.fiberType, p.connector, + p.wavelengths ?? null, p.standard ?? null, p.notes ?? null] + ); + if (res.rows[0]?.was_inserted) inserted++; else updated++; + } catch (err) { + console.warn(` Skip ${p.pid}: ${(err as Error).message.slice(0, 80)}`); + errors++; + } + } + + console.log(`\n=== Centec Networks OEM Seed Complete ===`); + console.log(` Inserted: ${inserted}`); + console.log(` Updated: ${updated}`); + console.log(` Errors: ${errors}`); + console.log(` Total PIDs: ${CENTEC_PIDS.length}\n`); +} + +if (require.main === module) { + scrapeCentecOem() + .then(() => pool.end()) + .catch((err) => { + console.error("Fatal:", err); + pool.end(); + process.exit(1); + }); +} diff --git a/packages/scraper/src/scrapers/ceragon-oem.ts b/packages/scraper/src/scrapers/ceragon-oem.ts new file mode 100644 index 0000000..323ac58 --- /dev/null +++ b/packages/scraper/src/scrapers/ceragon-oem.ts @@ -0,0 +1,123 @@ +/** + * Ceragon Networks OEM Transceiver Catalog Seed + * + * Seeds Ceragon-branded transceiver PIDs used in microwave and millimeter-wave + * wireless backhaul platforms (FibeAir IP-20, IP-50, IP-10). Ceragon is a + * Nasdaq-listed vendor (CRNT) and parent of Siklu. + * + * Sources: + * - Ceragon Networks Product Catalog (ceragon.com) + * - FibeAir IP-20/IP-50 hardware and interface guides + * - Ceragon SFP/QSFP optical compatibility matrices + * + * Run: tsx packages/scraper/src/scrapers/ceragon-oem.ts + * Cron: daily at 03:45 + */ + +import { pool, ensureVendor } from "../utils/db"; + +interface CeragonPID { + pid: string; + formFactor: string; + speedGbps: number; + speed: string; + reachMeters: number; + reachLabel: string; + fiberType: string; + connector: string; + wavelengths?: string; + standard?: string; + notes?: string; +} + +const CERAGON_PIDS: CeragonPID[] = [ + // ── 1G SFP ────────────────────────────────────────────────────────────── + { pid: "SFP-1G-SX", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 550, reachLabel: "SX", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "1000BASE-SX", notes: "Ceragon 1G SFP SX for FibeAir IP-20 access nodes" }, + { pid: "SFP-1G-LX", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 10000, reachLabel: "LX", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "1000BASE-LX" }, + { pid: "SFP-1G-T", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 100, reachLabel: "T", fiberType: "DAC", connector: "RJ45", standard: "1000BASE-T" }, + + // ── 10G SFP+ ──────────────────────────────────────────────────────────── + { pid: "SFP-10G-SR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 300, reachLabel: "SR", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "10GBASE-SR", notes: "Ceragon 10G SFP+ SR; FibeAir IP-50 Ethernet uplink" }, + { pid: "SFP-10G-LR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 10000, reachLabel: "LR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "10GBASE-LR" }, + { pid: "SFP-10G-ER", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 40000, reachLabel: "ER", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "10GBASE-ER" }, + { pid: "SFP-10G-ZR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 80000, reachLabel: "ZR", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "10GBASE-ZR", notes: "Ceragon 10G ZR for long-haul microwave site uplinks" }, + + // ── BiDi SFP ──────────────────────────────────────────────────────────── + { pid: "SFP-GE-BIDI-1310", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 20000, reachLabel: "BIDI", fiberType: "SMF", connector: "LC", wavelengths: "1310/1550nm", standard: "1000BASE-BX", notes: "BiDi SFP for single-fiber backhaul; Tx1310/Rx1550" }, + + // ── 25G SFP28 ─────────────────────────────────────────────────────────── + { pid: "SFP28-25G-SR", formFactor: "SFP28", speedGbps: 25, speed: "25G", reachMeters: 100, reachLabel: "SR", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "25GBASE-SR" }, + { pid: "SFP28-25G-LR", formFactor: "SFP28", speedGbps: 25, speed: "25G", reachMeters: 10000, reachLabel: "LR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "25GBASE-LR", notes: "Ceragon 25G SFP28 for 5G fronthaul and aggregation" }, + + // ── 40G QSFP+ ─────────────────────────────────────────────────────────── + { pid: "QSFP-40G-SR4", formFactor: "QSFP+", speedGbps: 40, speed: "40G", reachMeters: 150, reachLabel: "SR4", fiberType: "MMF", connector: "MPO", wavelengths: "850nm", standard: "40GBASE-SR4" }, + { pid: "QSFP-40G-LR4", formFactor: "QSFP+", speedGbps: 40, speed: "40G", reachMeters: 10000, reachLabel: "LR4", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "40GBASE-LR4", notes: "Ceragon 40G QSFP+ LR4 for FibeAir IP-50 hub uplink" }, + + // ── 100G QSFP28 ───────────────────────────────────────────────────────── + { pid: "QSFP28-100G-SR4", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 100, reachLabel: "SR4", fiberType: "MMF", connector: "MPO", wavelengths: "850nm", standard: "100GBASE-SR4" }, + { pid: "QSFP28-100G-LR4", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 10000, reachLabel: "LR4", fiberType: "SMF", connector: "LC", wavelengths: "1295-1310nm", standard: "100GBASE-LR4", notes: "Ceragon 100G QSFP28 LR4 for high-capacity backhaul rings" }, + + // ── 1G Copper ─────────────────────────────────────────────────────────── + { pid: "SFP-GE-T", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 100, reachLabel: "T", fiberType: "DAC", connector: "RJ45", standard: "1000BASE-T", notes: "Copper GE SFP for management interface" }, + + // ── 400G QSFP-DD ──────────────────────────────────────────────────────── + { pid: "QSFP-DD-400G-DR4", formFactor: "QSFP-DD", speedGbps: 400, speed: "400G", reachMeters: 500, reachLabel: "DR4", fiberType: "SMF", connector: "MPO", wavelengths: "1310nm", standard: "400GBASE-DR4", notes: "Ceragon 400G QSFP-DD for next-gen microwave core aggregation" }, +]; + +export async function scrapeCeragonOem(): Promise { + console.log("=== Ceragon Networks OEM Transceiver Seed ===\n"); + + const vendorId = await ensureVendor( + "Ceragon Networks", + "oem", + "https://www.ceragon.com", + undefined + ); + + let inserted = 0; + let updated = 0; + let errors = 0; + + for (const p of CERAGON_PIDS) { + const slug = `ceragon-${p.pid.toLowerCase().replace(/[^a-z0-9]+/g, "-")}`; + try { + const res = await pool.query( + `INSERT INTO transceivers + (slug, part_number, vendor_id, form_factor, speed, speed_gbps, + reach_meters, reach_label, fiber_type, connector, wavelengths, + dom_support, ieee_reference, market_status, category, notes) + VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,true,$12,'Mainstream','DataCenter',$13) + ON CONFLICT (slug) DO UPDATE SET + speed_gbps = EXCLUDED.speed_gbps, + reach_meters = CASE WHEN EXCLUDED.reach_meters > 0 THEN EXCLUDED.reach_meters ELSE transceivers.reach_meters END, + fiber_type = CASE WHEN EXCLUDED.fiber_type <> '' THEN EXCLUDED.fiber_type ELSE transceivers.fiber_type END, + wavelengths = COALESCE(EXCLUDED.wavelengths, transceivers.wavelengths), + updated_at = NOW() + RETURNING (xmax = 0) as was_inserted`, + [slug, p.pid, vendorId, p.formFactor, p.speed, p.speedGbps, + p.reachMeters, p.reachLabel, p.fiberType, p.connector, + p.wavelengths ?? null, p.standard ?? null, p.notes ?? null] + ); + if (res.rows[0]?.was_inserted) inserted++; else updated++; + } catch (err) { + console.warn(` Skip ${p.pid}: ${(err as Error).message.slice(0, 80)}`); + errors++; + } + } + + console.log(`\n=== Ceragon OEM Seed Complete ===`); + console.log(` Inserted: ${inserted}`); + console.log(` Updated: ${updated}`); + console.log(` Errors: ${errors}`); + console.log(` Total PIDs: ${CERAGON_PIDS.length}\n`); +} + +if (require.main === module) { + scrapeCeragonOem() + .then(() => pool.end()) + .catch((err) => { + console.error("Fatal:", err); + pool.end(); + process.exit(1); + }); +} diff --git a/packages/scraper/src/scrapers/checkpoint-oem.ts b/packages/scraper/src/scrapers/checkpoint-oem.ts new file mode 100644 index 0000000..46e03d0 --- /dev/null +++ b/packages/scraper/src/scrapers/checkpoint-oem.ts @@ -0,0 +1,133 @@ +/** + * Check Point OEM Transceiver Catalog Seed + * + * Seeds Check Point-branded transceiver PIDs for Quantum Maestro, + * Quantum Spark, and 6000/7000/16000/26000 series security gateways. + * + * Sources: + * - Check Point Hardware Compatibility Guide (support.checkpoint.com) + * - Quantum Maestro Hyperscale Hardware Reference + * - Check Point 16000/26000 Appliance Hardware Guide + * + * Run: tsx packages/scraper/src/scrapers/checkpoint-oem.ts + * Cron: daily at 09:00 + */ + +import { pool, ensureVendor } from "../utils/db"; + +interface CheckpointPID { + pid: string; + formFactor: string; + speedGbps: number; + speed: string; + reachMeters: number; + reachLabel: string; + fiberType: string; + connector: string; + wavelengths?: string; + standard?: string; + notes?: string; +} + +const CHECKPOINT_PIDS: CheckpointPID[] = [ + // ── 1G SFP ────────────────────────────────────────────────────────────── + { pid: "CPAC-SFP-1G-SX", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 550, reachLabel: "SX", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "1000BASE-SX" }, + { pid: "CPAC-SFP-1G-LX", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 10000, reachLabel: "LX", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "1000BASE-LX" }, + { pid: "CPAC-SFP-1G-ZX", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 80000, reachLabel: "ZX", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "1000BASE-ZX" }, + { pid: "CPAC-SFP-1G-T", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 100, reachLabel: "T", fiberType: "DAC", connector: "RJ45", standard: "1000BASE-T" }, + + // ── 10G SFP+ ──────────────────────────────────────────────────────────── + { pid: "CPAC-SFP+-10G-SR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 300, reachLabel: "SR", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "10GBASE-SR" }, + { pid: "CPAC-SFP+-10G-LR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 10000, reachLabel: "LR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "10GBASE-LR" }, + { pid: "CPAC-SFP+-10G-ER", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 40000, reachLabel: "ER", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "10GBASE-ER" }, + { pid: "CPAC-SFP+-10G-ZR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 80000, reachLabel: "ZR", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "10GBASE-ZR" }, + { pid: "CPAC-SFP+-10G-LRM", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 220, reachLabel: "LRM", fiberType: "MMF", connector: "LC", wavelengths: "1310nm", standard: "10GBASE-LRM" }, + { pid: "CPAC-SFP+-10G-T", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 30, reachLabel: "T", fiberType: "DAC", connector: "RJ45", standard: "10GBASE-T" }, + + // ── 25G SFP28 ─────────────────────────────────────────────────────────── + { pid: "CPAC-SFP28-25G-SR", formFactor: "SFP28", speedGbps: 25, speed: "25G", reachMeters: 100, reachLabel: "SR", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "25GBASE-SR" }, + { pid: "CPAC-SFP28-25G-LR", formFactor: "SFP28", speedGbps: 25, speed: "25G", reachMeters: 10000, reachLabel: "LR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "25GBASE-LR" }, + { pid: "CPAC-SFP28-25G-ER", formFactor: "SFP28", speedGbps: 25, speed: "25G", reachMeters: 30000, reachLabel: "ER", fiberType: "SMF", connector: "LC", wavelengths: "1310nm" }, + + // ── 40G QSFP+ ─────────────────────────────────────────────────────────── + { pid: "CPAC-QSFP+-40G-SR4", formFactor: "QSFP+", speedGbps: 40, speed: "40G", reachMeters: 150, reachLabel: "SR4", fiberType: "MMF", connector: "MPO", wavelengths: "850nm", standard: "40GBASE-SR4" }, + { pid: "CPAC-QSFP+-40G-LR4", formFactor: "QSFP+", speedGbps: 40, speed: "40G", reachMeters: 10000, reachLabel: "LR4", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "40GBASE-LR4" }, + + // ── 100G QSFP28 ───────────────────────────────────────────────────────── + { pid: "CPAC-QSFP28-100G-SR4", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 100, reachLabel: "SR4", fiberType: "MMF", connector: "MPO", wavelengths: "850nm", standard: "100GBASE-SR4" }, + { pid: "CPAC-QSFP28-100G-LR4", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 10000, reachLabel: "LR4", fiberType: "SMF", connector: "LC", wavelengths: "1295-1310nm", standard: "100GBASE-LR4" }, + { pid: "CPAC-QSFP28-100G-CWDM4", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 2000, reachLabel: "CWDM4", fiberType: "SMF", connector: "LC", wavelengths: "1271-1331nm", standard: "100GBASE-CWDM4" }, + { pid: "CPAC-QSFP28-100G-DR", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 500, reachLabel: "DR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "100GBASE-DR" }, + { pid: "CPAC-QSFP28-100G-FR", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 2000, reachLabel: "FR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "100GBASE-FR" }, + + // ── 400G QSFP-DD (Quantum Maestro) ────────────────────────────────────── + { pid: "CPAC-QSFPDD-400G-SR8", formFactor: "QSFP-DD",speedGbps: 400, speed: "400G", reachMeters: 100, reachLabel: "SR8", fiberType: "MMF", connector: "MPO", wavelengths: "850nm", standard: "400GBASE-SR8" }, + { pid: "CPAC-QSFPDD-400G-DR4", formFactor: "QSFP-DD",speedGbps: 400, speed: "400G", reachMeters: 500, reachLabel: "DR4", fiberType: "SMF", connector: "MPO", wavelengths: "1310nm", standard: "400GBASE-DR4" }, + { pid: "CPAC-QSFPDD-400G-FR4", formFactor: "QSFP-DD",speedGbps: 400, speed: "400G", reachMeters: 2000, reachLabel: "FR4", fiberType: "SMF", connector: "LC", wavelengths: "1271-1331nm", standard: "400GBASE-FR4" }, + { pid: "CPAC-QSFPDD-400G-LR4", formFactor: "QSFP-DD",speedGbps: 400, speed: "400G", reachMeters: 10000, reachLabel: "LR4", fiberType: "SMF", connector: "LC", wavelengths: "1295-1310nm", standard: "400GBASE-LR4" }, + + // ── DAC ───────────────────────────────────────────────────────────────── + { pid: "CPAC-CABLE-DAC-10G-1M", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 1, reachLabel: "DAC-1M", fiberType: "DAC", connector: "SFP+" }, + { pid: "CPAC-CABLE-DAC-10G-3M", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 3, reachLabel: "DAC-3M", fiberType: "DAC", connector: "SFP+" }, + { pid: "CPAC-CABLE-DAC-100G-1M", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 1, reachLabel: "DAC-1M", fiberType: "DAC", connector: "QSFP28" }, + { pid: "CPAC-CABLE-DAC-100G-3M", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 3, reachLabel: "DAC-3M", fiberType: "DAC", connector: "QSFP28" }, + { pid: "CPAC-CABLE-DAC-400G-1M", formFactor: "QSFP-DD",speedGbps: 400, speed: "400G", reachMeters: 1, reachLabel: "DAC-1M", fiberType: "DAC", connector: "QSFP-DD" }, +]; + +export async function scrapeCheckpointOem(): Promise { + console.log("=== Check Point OEM Transceiver Seed ===\n"); + + const vendorId = await ensureVendor( + "Check Point", + "oem", + "https://www.checkpoint.com", + undefined + ); + + let inserted = 0; + let updated = 0; + let errors = 0; + + for (const p of CHECKPOINT_PIDS) { + const slug = `checkpoint-${p.pid.toLowerCase().replace(/[^a-z0-9]+/g, "-")}`; + try { + const res = await pool.query( + `INSERT INTO transceivers + (slug, part_number, vendor_id, form_factor, speed, speed_gbps, + reach_meters, reach_label, fiber_type, connector, wavelengths, + dom_support, ieee_reference, market_status, category, notes) + VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,true,$12,'Mainstream','DataCenter',$13) + ON CONFLICT (slug) DO UPDATE SET + speed_gbps = EXCLUDED.speed_gbps, + reach_meters = CASE WHEN EXCLUDED.reach_meters > 0 THEN EXCLUDED.reach_meters ELSE transceivers.reach_meters END, + fiber_type = CASE WHEN EXCLUDED.fiber_type <> '' THEN EXCLUDED.fiber_type ELSE transceivers.fiber_type END, + wavelengths = COALESCE(EXCLUDED.wavelengths, transceivers.wavelengths), + updated_at = NOW() + RETURNING (xmax = 0) as was_inserted`, + [slug, p.pid, vendorId, p.formFactor, p.speed, p.speedGbps, + p.reachMeters, p.reachLabel, p.fiberType, p.connector, + p.wavelengths ?? null, p.standard ?? null, p.notes ?? null] + ); + if (res.rows[0]?.was_inserted) inserted++; else updated++; + } catch (err) { + console.warn(` Skip ${p.pid}: ${(err as Error).message.slice(0, 80)}`); + errors++; + } + } + + console.log(`\n=== Check Point OEM Seed Complete ===`); + console.log(` Inserted: ${inserted}`); + console.log(` Updated: ${updated}`); + console.log(` Errors: ${errors}`); + console.log(` Total PIDs: ${CHECKPOINT_PIDS.length}\n`); +} + +if (require.main === module) { + scrapeCheckpointOem() + .then(() => pool.end()) + .catch((err) => { + console.error("Fatal:", err); + pool.end(); + process.exit(1); + }); +} diff --git a/packages/scraper/src/scrapers/ciena-oem.ts b/packages/scraper/src/scrapers/ciena-oem.ts new file mode 100644 index 0000000..c486b56 --- /dev/null +++ b/packages/scraper/src/scrapers/ciena-oem.ts @@ -0,0 +1,141 @@ +/** + * Ciena OEM Transceiver Catalog Seed + * + * Seeds Ciena-branded transceiver PIDs for Waveserver, 6500/6550 + * packet-optical platforms, and 3000/5000-series switches. + * + * Sources: + * - Ciena Optics Guide (ciena.com) + * - Ciena 6500 Packet-Optical Platform Hardware Guide + * - Ciena Waveserver AI hardware reference + * + * Run: tsx packages/scraper/src/scrapers/ciena-oem.ts + * Cron: daily at 06:30 + */ + +import { pool, ensureVendor } from "../utils/db"; + +interface CienaPID { + pid: string; + formFactor: string; + speedGbps: number; + speed: string; + reachMeters: number; + reachLabel: string; + fiberType: string; + connector: string; + wavelengths?: string; + standard?: string; + notes?: string; +} + +const CIENA_PIDS: CienaPID[] = [ + // ── 1G SFP ────────────────────────────────────────────────────────────── + { pid: "XCVR-A00G85", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 550, reachLabel: "SX", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "1000BASE-SX" }, + { pid: "XCVR-A00G31", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 10000, reachLabel: "LX", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "1000BASE-LX" }, + { pid: "XCVR-A00G55", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 80000, reachLabel: "ZX", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "1000BASE-ZX" }, + { pid: "XCVR-A00T", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 100, reachLabel: "T", fiberType: "DAC", connector: "RJ45", standard: "1000BASE-T" }, + + // ── 10G SFP+ ──────────────────────────────────────────────────────────── + { pid: "XCVR-B10G85", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 300, reachLabel: "SR", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "10GBASE-SR" }, + { pid: "XCVR-B10G31", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 10000, reachLabel: "LR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "10GBASE-LR" }, + { pid: "XCVR-B10G55", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 40000, reachLabel: "ER", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "10GBASE-ER" }, + { pid: "XCVR-B10G55Z", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 80000, reachLabel: "ZR", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "10GBASE-ZR" }, + + // ── DWDM SFP+ (Waveserver / 6500 platform) ────────────────────────────── + { pid: "XCVR-B10U3131", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 80000, reachLabel: "DWDM", fiberType: "SMF", connector: "LC", wavelengths: "C-band", notes: "10G DWDM tunable SFP+" }, + { pid: "XCVR-B10U31DT", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 80000, reachLabel: "DWDM-T",fiberType: "SMF", connector: "LC", wavelengths: "C-band", notes: "10G DWDM tunable extended temp" }, + + // ── 25G SFP28 ─────────────────────────────────────────────────────────── + { pid: "XCVR-C25G85", formFactor: "SFP28", speedGbps: 25, speed: "25G", reachMeters: 100, reachLabel: "SR", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "25GBASE-SR" }, + { pid: "XCVR-C25G31", formFactor: "SFP28", speedGbps: 25, speed: "25G", reachMeters: 10000, reachLabel: "LR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "25GBASE-LR" }, + { pid: "XCVR-C25G31E", formFactor: "SFP28", speedGbps: 25, speed: "25G", reachMeters: 30000, reachLabel: "ER", fiberType: "SMF", connector: "LC", wavelengths: "1310nm" }, + + // ── 40G QSFP+ ─────────────────────────────────────────────────────────── + { pid: "XCVR-D40G85M4", formFactor: "QSFP+", speedGbps: 40, speed: "40G", reachMeters: 150, reachLabel: "SR4", fiberType: "MMF", connector: "MPO", wavelengths: "850nm", standard: "40GBASE-SR4" }, + { pid: "XCVR-D40G31L4", formFactor: "QSFP+", speedGbps: 40, speed: "40G", reachMeters: 10000, reachLabel: "LR4", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "40GBASE-LR4" }, + { pid: "XCVR-D40G55E4", formFactor: "QSFP+", speedGbps: 40, speed: "40G", reachMeters: 40000, reachLabel: "ER4", fiberType: "SMF", connector: "LC", wavelengths: "1310nm" }, + + // ── 100G QSFP28 ───────────────────────────────────────────────────────── + { pid: "XCVR-E100G85M4", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 100, reachLabel: "SR4", fiberType: "MMF", connector: "MPO", wavelengths: "850nm", standard: "100GBASE-SR4" }, + { pid: "XCVR-E100G31L4", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 10000, reachLabel: "LR4", fiberType: "SMF", connector: "LC", wavelengths: "1295-1310nm", standard: "100GBASE-LR4" }, + { pid: "XCVR-E100G31CW4", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 2000, reachLabel: "CWDM4", fiberType: "SMF", connector: "LC", wavelengths: "1271-1331nm", standard: "100GBASE-CWDM4" }, + { pid: "XCVR-E100G31DR", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 500, reachLabel: "DR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "100GBASE-DR" }, + { pid: "XCVR-E100G31FR", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 2000, reachLabel: "FR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "100GBASE-FR" }, + + // ── 100G Coherent CFP2 (Waveserver 5 / 6500) ──────────────────────────── + { pid: "XCVR-E100GCFP2", formFactor: "CFP2", speedGbps: 100, speed: "100G", reachMeters: 2000000,reachLabel: "ZR+", fiberType: "SMF", connector: "LC", wavelengths: "C-band", notes: "100G coherent CFP2 long-haul" }, + { pid: "XCVR-E100GCFP2DT", formFactor: "CFP2", speedGbps: 100, speed: "100G", reachMeters: 2000000,reachLabel: "DWDM", fiberType: "SMF", connector: "LC", wavelengths: "C-band", notes: "100G coherent CFP2 DWDM tunable" }, + + // ── 400G coherent QSFP-DD / OSFP (Waveserver Ai) ──────────────────────── + { pid: "XCVR-F400GQD-ZR", formFactor: "QSFP-DD",speedGbps: 400, speed: "400G", reachMeters: 120000, reachLabel: "ZR", fiberType: "SMF", connector: "LC", wavelengths: "C-band", standard: "400ZR", notes: "400G coherent QSFP-DD" }, + { pid: "XCVR-F400GQD-SR8", formFactor: "QSFP-DD",speedGbps: 400, speed: "400G", reachMeters: 100, reachLabel: "SR8", fiberType: "MMF", connector: "MPO", wavelengths: "850nm", standard: "400GBASE-SR8" }, + { pid: "XCVR-F400GQD-DR4", formFactor: "QSFP-DD",speedGbps: 400, speed: "400G", reachMeters: 500, reachLabel: "DR4", fiberType: "SMF", connector: "MPO", wavelengths: "1310nm", standard: "400GBASE-DR4" }, + { pid: "XCVR-F400GQD-FR4", formFactor: "QSFP-DD",speedGbps: 400, speed: "400G", reachMeters: 2000, reachLabel: "FR4", fiberType: "SMF", connector: "LC", wavelengths: "1271-1331nm", standard: "400GBASE-FR4" }, + { pid: "XCVR-F400GQD-LR4", formFactor: "QSFP-DD",speedGbps: 400, speed: "400G", reachMeters: 10000, reachLabel: "LR4", fiberType: "SMF", connector: "LC", wavelengths: "1295-1310nm", standard: "400GBASE-LR4" }, + + // ── DAC ───────────────────────────────────────────────────────────────── + { pid: "XCVR-DAC-10G-1M", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 1, reachLabel: "DAC-1M",fiberType: "DAC", connector: "SFP+", notes: "10G DAC 1m" }, + { pid: "XCVR-DAC-10G-3M", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 3, reachLabel: "DAC-3M",fiberType: "DAC", connector: "SFP+", notes: "10G DAC 3m" }, + { pid: "XCVR-DAC-100G-1M", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 1, reachLabel: "DAC-1M",fiberType: "DAC", connector: "QSFP28", notes: "100G DAC 1m" }, + { pid: "XCVR-DAC-100G-3M", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 3, reachLabel: "DAC-3M",fiberType: "DAC", connector: "QSFP28", notes: "100G DAC 3m" }, + { pid: "XCVR-DAC-400G-1M", formFactor: "QSFP-DD",speedGbps: 400, speed: "400G", reachMeters: 1, reachLabel: "DAC-1M",fiberType: "DAC", connector: "QSFP-DD",notes: "400G DAC 1m" }, +]; + +export async function scrapeCienaOem(): Promise { + console.log("=== Ciena OEM Transceiver Seed ===\n"); + + const vendorId = await ensureVendor( + "Ciena", + "oem", + "https://www.ciena.com", + undefined + ); + + let inserted = 0; + let updated = 0; + let errors = 0; + + for (const p of CIENA_PIDS) { + const slug = `ciena-${p.pid.toLowerCase().replace(/[^a-z0-9]+/g, "-")}`; + try { + const res = await pool.query( + `INSERT INTO transceivers + (slug, part_number, vendor_id, form_factor, speed, speed_gbps, + reach_meters, reach_label, fiber_type, connector, wavelengths, + dom_support, ieee_reference, market_status, category, notes) + VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,true,$12,'Mainstream','DataCenter',$13) + ON CONFLICT (slug) DO UPDATE SET + speed_gbps = EXCLUDED.speed_gbps, + reach_meters = CASE WHEN EXCLUDED.reach_meters > 0 THEN EXCLUDED.reach_meters ELSE transceivers.reach_meters END, + fiber_type = CASE WHEN EXCLUDED.fiber_type <> '' THEN EXCLUDED.fiber_type ELSE transceivers.fiber_type END, + wavelengths = COALESCE(EXCLUDED.wavelengths, transceivers.wavelengths), + updated_at = NOW() + RETURNING (xmax = 0) as was_inserted`, + [slug, p.pid, vendorId, p.formFactor, p.speed, p.speedGbps, + p.reachMeters, p.reachLabel, p.fiberType, p.connector, + p.wavelengths ?? null, p.standard ?? null, p.notes ?? null] + ); + if (res.rows[0]?.was_inserted) inserted++; else updated++; + } catch (err) { + console.warn(` Skip ${p.pid}: ${(err as Error).message.slice(0, 80)}`); + errors++; + } + } + + console.log(`\n=== Ciena OEM Seed Complete ===`); + console.log(` Inserted: ${inserted}`); + console.log(` Updated: ${updated}`); + console.log(` Errors: ${errors}`); + console.log(` Total PIDs: ${CIENA_PIDS.length}\n`); +} + +if (require.main === module) { + scrapeCienaOem() + .then(() => pool.end()) + .catch((err) => { + console.error("Fatal:", err); + pool.end(); + process.exit(1); + }); +} diff --git a/packages/scraper/src/scrapers/ciena-waveserver-oem.ts b/packages/scraper/src/scrapers/ciena-waveserver-oem.ts new file mode 100644 index 0000000..11a2aaa --- /dev/null +++ b/packages/scraper/src/scrapers/ciena-waveserver-oem.ts @@ -0,0 +1,150 @@ +/** + * Ciena WaveServer / WaveLogic OEM Transceiver Catalog Seed + * + * Seeds Ciena-branded transceiver and coherent module PIDs for WaveServer, + * WaveLogic 5e/5n open line system platforms and packet-optical equipment. + * + * Sources: + * - Ciena WaveServer 5 Product Overview (ciena.com) + * - Ciena WaveLogic 5e/5n Module Datasheet + * - Ciena Client Optics Portfolio Guide + * + * Run: tsx packages/scraper/src/scrapers/ciena-waveserver-oem.ts + * Cron: daily at 23:15 + */ + +import { pool, ensureVendor } from "../utils/db"; + +interface CienaWaveserverPID { + pid: string; + formFactor: string; + speedGbps: number; + speed: string; + reachMeters: number; + reachLabel: string; + fiberType: string; + connector: string; + wavelengths?: string; + standard?: string; + category?: string; + notes?: string; +} + +const CIENA_WAVESERVER_PIDS: CienaWaveserverPID[] = [ + // ── 1G SFP Client ─────────────────────────────────────────────────────── + { pid: "SFP-10G-SR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 300, reachLabel: "SR", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "10GBASE-SR" }, + { pid: "SFP-10G-LR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 10000, reachLabel: "LR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "10GBASE-LR" }, + { pid: "SFP-10G-ER", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 40000, reachLabel: "ER", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "10GBASE-ER" }, + { pid: "SFP-10G-ZR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 80000, reachLabel: "ZR", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "10GBASE-ZR" }, + + // ── 10G SONET/SDH ──────────────────────────────────────────────────────── + { pid: "OC48-SFP", formFactor: "SFP", speedGbps: 2.5, speed: "OC48", reachMeters: 40000, reachLabel: "LR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", category: "Telecom", notes: "Ciena OC-48/STM-16 2.488G SFP" }, + { pid: "OC192-SFP", formFactor: "SFP+", speedGbps: 10, speed: "OC192",reachMeters: 40000, reachLabel: "LR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", category: "Telecom", notes: "Ciena OC-192/STM-64 9.953G SFP+" }, + + // ── 10G OTN ───────────────────────────────────────────────────────────── + { pid: "SFP-OTU2-10G", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 40000, reachLabel: "LR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", category: "Telecom", notes: "Ciena OTU2 10.709G SFP+" }, + + // ── 10G DWDM SFP+ ──────────────────────────────────────────────────────── + { pid: "DWDM-SFP10G-C-xx.x", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 80000, reachLabel: "DWDM", fiberType: "SMF", connector: "LC", wavelengths: "C-band ITU DWDM", category: "Telecom", notes: "Ciena DWDM C-band 10G SFP+ (wavelength per order)" }, + + // ── 25G SFP28 ──────────────────────────────────────────────────────────── + { pid: "XCVR-S10V", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 10000, reachLabel: "LR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "10GBASE-LR", notes: "Ciena WaveServer client SFP+ 10G" }, + { pid: "XCVR-S28V", formFactor: "SFP28", speedGbps: 25, speed: "25G", reachMeters: 10000, reachLabel: "LR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "25GBASE-LR", notes: "Ciena WaveServer client SFP28 25G" }, + + // ── 40G QSFP+ ──────────────────────────────────────────────────────────── + { pid: "QSFP-40G-SR4", formFactor: "QSFP+", speedGbps: 40, speed: "40G", reachMeters: 150, reachLabel: "SR4", fiberType: "MMF", connector: "MPO", wavelengths: "850nm", standard: "40GBASE-SR4" }, + { pid: "QSFP-40G-LR4", formFactor: "QSFP+", speedGbps: 40, speed: "40G", reachMeters: 10000, reachLabel: "LR4", fiberType: "SMF", connector: "LC", wavelengths: "1295-1310nm", standard: "40GBASE-LR4" }, + + // ── 100G QSFP28 ────────────────────────────────────────────────────────── + { pid: "XCVR-A00AQ4", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 100, reachLabel: "SR4", fiberType: "MMF", connector: "MPO", wavelengths: "850nm", standard: "100GBASE-SR4", notes: "Ciena WaveServer QSFP28 100G SR4" }, + { pid: "XCVR-A00BQ4", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 10000, reachLabel: "LR4", fiberType: "SMF", connector: "LC", wavelengths: "1295-1310nm", standard: "100GBASE-LR4", notes: "Ciena WaveServer QSFP28 100G LR4" }, + { pid: "QSFP28-100G-ER4", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 40000, reachLabel: "ER4", fiberType: "SMF", connector: "LC", wavelengths: "1295-1310nm", standard: "100GBASE-ER4" }, + + // ── 100G CFP2 Coherent ─────────────────────────────────────────────────── + { pid: "CFP2-ACO-100G", formFactor: "CFP2", speedGbps: 100, speed: "100G", reachMeters: 1000000, reachLabel: "ACO", fiberType: "SMF", connector: "LC", wavelengths: "C-band", category: "Telecom", notes: "Ciena 100G CFP2 Analogue Coherent Optics" }, + { pid: "CFP2-DCO-200G", formFactor: "CFP2", speedGbps: 200, speed: "200G", reachMeters: 1500000, reachLabel: "DCO", fiberType: "SMF", connector: "LC", wavelengths: "C-band", category: "Telecom", notes: "Ciena 200G CFP2 Digital Coherent Optics" }, + + // ── 100G CFP OTN ───────────────────────────────────────────────────────── + { pid: "CFP-OTU4-100G", formFactor: "CFP", speedGbps: 100, speed: "100G", reachMeters: 40000, reachLabel: "LR4", fiberType: "SMF", connector: "LC", wavelengths: "1295-1310nm", category: "Telecom", notes: "Ciena OTU4 100G CFP LR4" }, + + // ── WaveLogic 5 Coherent Line Modules ──────────────────────────────────── + { pid: "WL5e-SEQ", formFactor: "QSFP-DD", speedGbps: 400, speed: "400G", reachMeters: 3000000, reachLabel: "WL5e", fiberType: "SMF", connector: "LC", wavelengths: "C-band", category: "Telecom", notes: "Ciena WaveLogic 5e coherent 400G-800G QSFP-DD" }, + { pid: "WL5n-SEQ", formFactor: "QSFP-DD", speedGbps: 200, speed: "200G", reachMeters: 3000000, reachLabel: "WL5n", fiberType: "SMF", connector: "LC", wavelengths: "C-band", category: "Telecom", notes: "Ciena WaveLogic 5 nano coherent QSFP-DD" }, + + // ── 400G QSFP-DD Client ────────────────────────────────────────────────── + { pid: "XCVR-B00DPP", formFactor: "QSFP-DD", speedGbps: 400, speed: "400G", reachMeters: 2000, reachLabel: "DR4", fiberType: "SMF", connector: "MPO", wavelengths: "1310nm", standard: "400GBASE-DR4", notes: "Ciena WaveServer QSFP-DD 400G DR4" }, + { pid: "QSFP-DD-ZR-400G", formFactor: "QSFP-DD", speedGbps: 400, speed: "400G", reachMeters: 120000, reachLabel: "ZR", fiberType: "SMF", connector: "LC", wavelengths: "C-band", category: "Telecom", standard: "400ZR", notes: "Ciena 400G ZR coherent QSFP-DD" }, +]; + +// PIDs that use 'Telecom' category (coherent/OTN/SONET/DWDM) +const TELECOM_PIDS = new Set([ + "OC48-SFP", + "OC192-SFP", + "SFP-OTU2-10G", + "DWDM-SFP10G-C-xx.x", + "CFP2-ACO-100G", + "CFP2-DCO-200G", + "CFP-OTU4-100G", + "WL5e-SEQ", + "WL5n-SEQ", + "QSFP-DD-ZR-400G", +]); + +export async function scrapeCienaWaveserverOem(): Promise { + console.log("=== Ciena WaveServer/WaveLogic OEM Transceiver Seed ===\n"); + + const vendorId = await ensureVendor( + "Ciena", + "oem", + "https://www.ciena.com", + undefined + ); + + let inserted = 0; + let updated = 0; + let errors = 0; + + for (const p of CIENA_WAVESERVER_PIDS) { + const slug = `ciena-ws-${p.pid.toLowerCase().replace(/[^a-z0-9]+/g, "-")}`; + const category = p.category ?? (TELECOM_PIDS.has(p.pid) ? "Telecom" : "DataCenter"); + try { + const res = await pool.query( + `INSERT INTO transceivers + (slug, part_number, vendor_id, form_factor, speed, speed_gbps, + reach_meters, reach_label, fiber_type, connector, wavelengths, + dom_support, ieee_reference, market_status, category, notes) + VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,true,$12,'Mainstream',$13,$14) + ON CONFLICT (slug) DO UPDATE SET + speed_gbps = EXCLUDED.speed_gbps, + reach_meters = CASE WHEN EXCLUDED.reach_meters > 0 THEN EXCLUDED.reach_meters ELSE transceivers.reach_meters END, + fiber_type = CASE WHEN EXCLUDED.fiber_type <> '' THEN EXCLUDED.fiber_type ELSE transceivers.fiber_type END, + wavelengths = COALESCE(EXCLUDED.wavelengths, transceivers.wavelengths), + updated_at = NOW() + RETURNING (xmax = 0) as was_inserted`, + [slug, p.pid, vendorId, p.formFactor, p.speed, p.speedGbps, + p.reachMeters, p.reachLabel, p.fiberType, p.connector, + p.wavelengths ?? null, p.standard ?? null, category, p.notes ?? null] + ); + if (res.rows[0]?.was_inserted) inserted++; else updated++; + } catch (err) { + console.warn(` Skip ${p.pid}: ${(err as Error).message.slice(0, 80)}`); + errors++; + } + } + + console.log(`\n=== Ciena WaveServer/WaveLogic OEM Seed Complete ===`); + console.log(` Inserted: ${inserted}`); + console.log(` Updated: ${updated}`); + console.log(` Errors: ${errors}`); + console.log(` Total PIDs: ${CIENA_WAVESERVER_PIDS.length}\n`); +} + +if (require.main === module) { + scrapeCienaWaveserverOem() + .then(() => pool.end()) + .catch((err) => { + console.error("Fatal:", err); + pool.end(); + process.exit(1); + }); +} diff --git a/packages/scraper/src/scrapers/cimc-oem.ts b/packages/scraper/src/scrapers/cimc-oem.ts new file mode 100644 index 0000000..179101f --- /dev/null +++ b/packages/scraper/src/scrapers/cimc-oem.ts @@ -0,0 +1,138 @@ +/** + * CIMC Semiconductors (legacy II-VI / Finisar integration-era, now Coherent Corp) OEM Seed + * + * Seeds CIMC-branded transceiver PIDs covering the legacy II-VI/Finisar product + * lines that Coherent Corp continues to manufacture and sell under the CIMC + * Semiconductors brand. Includes datacenter optics, telecom/OTN, CFP2-DCO, + * DWDM tunable, and CWDM variants from the II-VI/Finisar integration era. + * + * Sources: + * - Coherent Corp (formerly II-VI) product catalog (coherent.com) + * - CIMC Semiconductors transceiver datasheets + * - Legacy II-VI/Finisar product numbering conventions + * + * Run: tsx packages/scraper/src/scrapers/cimc-oem.ts + * Cron: daily at 05:00 + */ + +import { pool, ensureVendor } from "../utils/db"; + +interface CimcPID { + pid: string; + formFactor: string; + speedGbps: number; + speed: string; + reachMeters: number; + reachLabel: string; + fiberType: string; + connector: string; + wavelengths?: string; + standard?: string; + category?: string; + notes?: string; +} + +// PIDs that fall into Telecom/carrier category rather than DataCenter +const TELECOM_PIDS = new Set([ + "CIMC-CFP2-DCO-200G", + "CIMC-QSFP-DD-ZR-400G", + "CIMC-SFP-OTN-10G", + "CIMC-SFP-CWDM-1550", + "CIMC-DWDM-SFP-C", +]); + +const CIMC_PIDS: CimcPID[] = [ + // ── 1G SFP ────────────────────────────────────────────────────────────── + { pid: "CIMC-SFP-1G-SX", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 550, reachLabel: "SX", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "1000BASE-SX", notes: "CIMC 1G MM SFP — legacy Finisar FTLF8524P3BNV lineage" }, + { pid: "CIMC-SFP-1G-LX", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 10000, reachLabel: "LX", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "1000BASE-LX", notes: "CIMC 1G SM SFP — legacy Finisar FTLF1324P2BTL lineage" }, + + // ── 10G SFP+ ──────────────────────────────────────────────────────────── + { pid: "CIMC-SFP-10G-SR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 300, reachLabel: "SR", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "10GBASE-SR", notes: "CIMC 10G SR SFP+ — legacy Finisar FTLX8571D3BCL lineage" }, + { pid: "CIMC-SFP-10G-LR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 10000, reachLabel: "LR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "10GBASE-LR", notes: "CIMC 10G LR SFP+ — legacy Finisar FTLX1475D3BCL lineage" }, + { pid: "CIMC-SFP-10G-ER", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 40000, reachLabel: "ER", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "10GBASE-ER" }, + { pid: "CIMC-SFP-10G-ZR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 80000, reachLabel: "ZR", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "10GBASE-ZR", notes: "CIMC 10G ZR 80km — ex-II-VI long-haul series" }, + + // ── 10G OTN / CWDM / DWDM (Telecom) ──────────────────────────────────── + { pid: "CIMC-SFP-OTN-10G", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 80000, reachLabel: "OTN", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "OTU2", category: "Telecom", notes: "CIMC 10G OTN SFP+ for OTU2 transport — ex-II-VI Finisar OTN lineage" }, + { pid: "CIMC-SFP-CWDM-1550", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 40000, reachLabel: "CWDM", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "CWDM", category: "Telecom", notes: "CIMC 10G CWDM SFP+ 1550nm — legacy Finisar CWDM channel optic" }, + { pid: "CIMC-DWDM-SFP-C", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 80000, reachLabel: "DWDM", fiberType: "SMF", connector: "LC", wavelengths: "C-band ITU", standard: "DWDM ITU-T G.694.1",category: "Telecom", notes: "CIMC 10G DWDM tunable SFP+ C-band — ex-II-VI Finisar DWDM series" }, + + // ── 25G SFP28 ─────────────────────────────────────────────────────────── + { pid: "CIMC-SFP28-25G-SR", formFactor: "SFP28", speedGbps: 25, speed: "25G", reachMeters: 100, reachLabel: "SR", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "25GBASE-SR", notes: "CIMC 25G SR SFP28 — ex-II-VI high-volume hyperscale series" }, + { pid: "CIMC-SFP28-25G-LR", formFactor: "SFP28", speedGbps: 25, speed: "25G", reachMeters: 10000, reachLabel: "LR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "25GBASE-LR" }, + + // ── 100G QSFP28 ───────────────────────────────────────────────────────── + { pid: "CIMC-QSFP28-100G-SR4", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 100, reachLabel: "SR4", fiberType: "MMF", connector: "MPO", wavelengths: "850nm", standard: "100GBASE-SR4", notes: "CIMC 100G SR4 QSFP28 — ex-II-VI Finisar FTLC9551REPM lineage" }, + { pid: "CIMC-QSFP28-100G-LR4", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 10000, reachLabel: "LR4", fiberType: "SMF", connector: "LC", wavelengths: "1295-1310nm", standard: "100GBASE-LR4" }, + { pid: "CIMC-QSFP28-100G-ER4", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 40000, reachLabel: "ER4", fiberType: "SMF", connector: "LC", wavelengths: "1295-1310nm", standard: "100GBASE-ER4", notes: "CIMC 100G ER4 40km QSFP28 — ex-II-VI extended-reach datacenter" }, + + // ── 200G CFP2-DCO (Telecom) ───────────────────────────────────────────── + { pid: "CIMC-CFP2-DCO-200G", formFactor: "CFP2", speedGbps: 200, speed: "200G", reachMeters: 1000000, reachLabel: "DCO", fiberType: "SMF", connector: "LC", wavelengths: "C-band tunable", standard: "OIF CFP2-DCO", category: "Telecom", notes: "CIMC CFP2-DCO 200G coherent — ex-II-VI Finisar DCO lineage, 1000km EDFA reach" }, + + // ── 400G QSFP-DD ──────────────────────────────────────────────────────── + { pid: "CIMC-QSFP-DD-400G-DR4", formFactor: "QSFP-DD", speedGbps: 400, speed: "400G", reachMeters: 500, reachLabel: "DR4", fiberType: "SMF", connector: "MPO", wavelengths: "1310nm", standard: "400GBASE-DR4", notes: "CIMC 400G DR4 QSFP-DD — Coherent Corp next-gen datacenter optic" }, + { pid: "CIMC-QSFP-DD-400G-SR8", formFactor: "QSFP-DD", speedGbps: 400, speed: "400G", reachMeters: 100, reachLabel: "SR8", fiberType: "MMF", connector: "MPO", wavelengths: "850nm", standard: "400GBASE-SR8", notes: "CIMC 400G SR8 QSFP-DD MPO for short-reach hyperscale fabric" }, + + // ── 400G ZR Coherent (Telecom) ────────────────────────────────────────── + { pid: "CIMC-QSFP-DD-ZR-400G", formFactor: "QSFP-DD", speedGbps: 400, speed: "400G", reachMeters: 120000, reachLabel: "ZR", fiberType: "SMF", connector: "LC", wavelengths: "C-band tunable", standard: "OpenZR+ / OIF 400ZR", category: "Telecom", notes: "CIMC 400G ZR QSFP-DD coherent — ex-II-VI Finisar 400ZR, 120km unamplified" }, +]; + +export async function scrapeCimcOem(): Promise { + console.log("=== CIMC Semiconductors (Coherent Corp / ex-II-VI Finisar) OEM Transceiver Seed ===\n"); + + const vendorId = await ensureVendor( + "CIMC Semiconductors", + "oem", + "https://www.coherent.com", + undefined + ); + + let inserted = 0; + let updated = 0; + let errors = 0; + + for (const p of CIMC_PIDS) { + const slug = `cimc-${p.pid.toLowerCase().replace(/[^a-z0-9]+/g, "-")}`; + const category = p.category ?? (TELECOM_PIDS.has(p.pid) ? "Telecom" : "DataCenter"); + try { + const res = await pool.query( + `INSERT INTO transceivers + (slug, part_number, vendor_id, form_factor, speed, speed_gbps, + reach_meters, reach_label, fiber_type, connector, wavelengths, + dom_support, ieee_reference, market_status, category, notes) + VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,true,$12,'Mainstream',$13,$14) + ON CONFLICT (slug) DO UPDATE SET + speed_gbps = EXCLUDED.speed_gbps, + reach_meters = CASE WHEN EXCLUDED.reach_meters > 0 THEN EXCLUDED.reach_meters ELSE transceivers.reach_meters END, + fiber_type = CASE WHEN EXCLUDED.fiber_type <> '' THEN EXCLUDED.fiber_type ELSE transceivers.fiber_type END, + wavelengths = COALESCE(EXCLUDED.wavelengths, transceivers.wavelengths), + updated_at = NOW() + RETURNING (xmax = 0) as was_inserted`, + [slug, p.pid, vendorId, p.formFactor, p.speed, p.speedGbps, + p.reachMeters, p.reachLabel, p.fiberType, p.connector, + p.wavelengths ?? null, p.standard ?? null, category, p.notes ?? null] + ); + if (res.rows[0]?.was_inserted) inserted++; else updated++; + } catch (err) { + console.warn(` Skip ${p.pid}: ${(err as Error).message.slice(0, 80)}`); + errors++; + } + } + + console.log(`\n=== CIMC Semiconductors OEM Seed Complete ===`); + console.log(` Inserted: ${inserted}`); + console.log(` Updated: ${updated}`); + console.log(` Errors: ${errors}`); + console.log(` Total PIDs: ${CIMC_PIDS.length}`); + console.log(` Telecom PIDs: ${[...TELECOM_PIDS].length} (CFP2-DCO, ZR, OTN, CWDM, DWDM)\n`); +} + +if (require.main === module) { + scrapeCimcOem() + .then(() => pool.end()) + .catch((err) => { + console.error("Fatal:", err); + pool.end(); + process.exit(1); + }); +} diff --git a/packages/scraper/src/scrapers/cisco-asr-oem.ts b/packages/scraper/src/scrapers/cisco-asr-oem.ts new file mode 100644 index 0000000..81a5f40 --- /dev/null +++ b/packages/scraper/src/scrapers/cisco-asr-oem.ts @@ -0,0 +1,130 @@ +/** + * Cisco ASR OEM Transceiver Catalog Seed + * + * Seeds Cisco ASR-branded transceiver PIDs for ASR 1000, 9000, and 9900 + * series service provider edge and core routers, including OC-n SONET, + * CFP/CFP2 coherent, and DWDM modules. + * + * Sources: + * - Cisco ASR 9000 Series Router Data Sheet + * - Cisco ASR 1000 Series Transceiver Module Selection Guide + * - Cisco 400G Coherent Pluggable Optics for ASR 9000 Data Sheet + * - Cisco DWDM SFP10G Transceiver Module (OID EDCS-959978) + * + * Run: tsx packages/scraper/src/scrapers/cisco-asr-oem.ts + * Cron: daily at 13:00 + */ + +import { pool, ensureVendor } from "../utils/db"; + +interface AsrPID { + pid: string; + formFactor: string; + speedGbps: number; + speed: string; + reachMeters: number; + reachLabel: string; + fiberType: string; + connector: string; + wavelengths?: string; + standard?: string; + category: "DataCenter" | "Telecom"; + notes?: string; +} + +// Telecom PIDs: OC-n SONET, CFP, CFP2-DCO coherent, DWDM, ZR variants. +const ASR_PIDS: AsrPID[] = [ + // ── GE SFP ────────────────────────────────────────────────────────────── + { pid: "SFP-GE-S", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 550, reachLabel: "SX", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "1000BASE-SX", category: "DataCenter", notes: "Cisco ASR GE multimode SFP" }, + + // ── 10G SFP+ ──────────────────────────────────────────────────────────── + { pid: "SFP-10G-SR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 300, reachLabel: "SR", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "10GBASE-SR", category: "DataCenter", notes: "Cisco ASR 10G multimode SFP+" }, + { pid: "SFP-10G-LR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 10000, reachLabel: "LR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "10GBASE-LR", category: "DataCenter", notes: "Cisco ASR 10G single-mode SFP+ 10km" }, + { pid: "SFP-10G-LR-S", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 10000, reachLabel: "LR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "10GBASE-LR", category: "DataCenter", notes: "Cisco ASR 10G single-mode SFP+ S-variant" }, + { pid: "SFP-10G-ER", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 40000, reachLabel: "ER", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "10GBASE-ER", category: "DataCenter", notes: "Cisco ASR 10G extended-reach SFP+ 40km" }, + { pid: "SFP-10G-ZR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 80000, reachLabel: "ZR", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "10GBASE-ZR", category: "Telecom", notes: "Cisco ASR 10G ZR SFP+ 80km metro/SP" }, + + // ── SONET/SDH OC-n SFP ────────────────────────────────────────────────── + { pid: "SFP-OC3-SR", formFactor: "SFP", speedGbps: 0.155, speed: "OC3", reachMeters: 2000, reachLabel: "SR", fiberType: "MMF", connector: "LC", wavelengths: "1310nm", standard: "OC-3/STM-1", category: "Telecom", notes: "Cisco ASR OC-3 short-reach SONET SFP" }, + { pid: "SFP-OC3-LR", formFactor: "SFP", speedGbps: 0.155, speed: "OC3", reachMeters: 40000, reachLabel: "LR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "OC-3/STM-1", category: "Telecom", notes: "Cisco ASR OC-3 long-reach SONET SFP" }, + { pid: "SFP-OC12-SR", formFactor: "SFP", speedGbps: 0.622, speed: "OC12", reachMeters: 2000, reachLabel: "SR", fiberType: "MMF", connector: "LC", wavelengths: "1310nm", standard: "OC-12/STM-4", category: "Telecom", notes: "Cisco ASR OC-12 short-reach SONET SFP" }, + { pid: "SFP-OC12-LR", formFactor: "SFP", speedGbps: 0.622, speed: "OC12", reachMeters: 40000, reachLabel: "LR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "OC-12/STM-4", category: "Telecom", notes: "Cisco ASR OC-12 long-reach SONET SFP" }, + { pid: "SFP-OC48-SR", formFactor: "SFP", speedGbps: 2.488, speed: "OC48", reachMeters: 2000, reachLabel: "SR", fiberType: "MMF", connector: "LC", wavelengths: "1310nm", standard: "OC-48/STM-16", category: "Telecom", notes: "Cisco ASR OC-48 short-reach SONET SFP" }, + { pid: "SFP-OC48-LR", formFactor: "SFP", speedGbps: 2.488, speed: "OC48", reachMeters: 40000, reachLabel: "LR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "OC-48/STM-16", category: "Telecom", notes: "Cisco ASR OC-48 long-reach SONET SFP" }, + + // ── 40G QSFP+ ─────────────────────────────────────────────────────────── + { pid: "QSFP-40G-LR4-S", formFactor: "QSFP+", speedGbps: 40, speed: "40G", reachMeters: 10000, reachLabel: "LR4", fiberType: "SMF", connector: "LC", wavelengths: "1295-1310nm", standard: "40GBASE-LR4", category: "DataCenter", notes: "Cisco ASR 40G QSFP+ LR4 10km" }, + + // ── 100G QSFP28 / CFP ─────────────────────────────────────────────────── + { pid: "QSFP-100G-LR4-S", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 10000, reachLabel: "LR4", fiberType: "SMF", connector: "LC", wavelengths: "1295-1310nm", standard: "100GBASE-LR4", category: "DataCenter", notes: "Cisco ASR 100G QSFP28 LR4 10km" }, + { pid: "QSFP-100G-ZR-S", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 80000, reachLabel: "ZR", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "100GBASE-ZR", category: "Telecom", notes: "Cisco ASR 100G coherent ZR QSFP28 80km metro" }, + { pid: "CFP-100G-LR4", formFactor: "CFP", speedGbps: 100, speed: "100G", reachMeters: 10000, reachLabel: "LR4", fiberType: "SMF", connector: "LC", wavelengths: "1295-1310nm", standard: "100GBASE-LR4", category: "Telecom", notes: "Cisco ASR 100G CFP LR4 10km SP router line card" }, + { pid: "CFP2-100G-LR4", formFactor: "CFP2", speedGbps: 100, speed: "100G", reachMeters: 10000, reachLabel: "LR4", fiberType: "SMF", connector: "LC", wavelengths: "1295-1310nm", standard: "100GBASE-LR4", category: "Telecom", notes: "Cisco ASR 100G CFP2 LR4 10km compact form factor" }, + { pid: "CFP2-DCO-200G", formFactor: "CFP2", speedGbps: 200, speed: "200G", reachMeters: 1000000, reachLabel: "DCO-longhaul", fiberType: "SMF", connector: "LC", wavelengths: "C-band DWDM", standard: "OTN/FlexE", category: "Telecom", notes: "Cisco ASR 200G CFP2 digital coherent optics long-haul DWDM" }, + + // ── DWDM SFP10G / 400G ZR ─────────────────────────────────────────────── + { pid: "DWDM-SFP10G-C", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 80000, reachLabel: "DWDM-C", fiberType: "SMF", connector: "LC", wavelengths: "C-band ITU 100GHz", standard: "10GBASE-ZR", category: "Telecom", notes: "Cisco ASR 9000 DWDM SFP10G C-band ITU tunable 80km" }, + { pid: "QSFP-DD-400G-ZR-S", formFactor: "QSFP-DD", speedGbps: 400, speed: "400G", reachMeters: 120000, reachLabel: "ZR-120km", fiberType: "SMF", connector: "LC", wavelengths: "C-band DWDM", standard: "400ZR OpenROADM", category: "Telecom", notes: "Cisco ASR 400G QSFP-DD coherent ZR 120km metro DWDM" }, +]; + +export async function scrapeCiscoAsrOem(): Promise { + console.log("=== Cisco ASR OEM Transceiver Seed ===\n"); + + const vendorId = await ensureVendor( + "Cisco ASR", + "oem", + "https://www.cisco.com/c/en/us/products/routers/asr-series/index.html", + undefined + ); + + let inserted = 0; + let updated = 0; + let errors = 0; + + for (const p of ASR_PIDS) { + const slug = `cisco-asr-${p.pid.toLowerCase().replace(/[^a-z0-9]+/g, "-")}`; + try { + const res = await pool.query( + `INSERT INTO transceivers + (slug, part_number, vendor_id, form_factor, speed, speed_gbps, + reach_meters, reach_label, fiber_type, connector, wavelengths, + dom_support, ieee_reference, market_status, category, notes) + VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,true,$12,'Mainstream',$13,$14) + ON CONFLICT (slug) DO UPDATE SET + speed_gbps = EXCLUDED.speed_gbps, + reach_meters = CASE WHEN EXCLUDED.reach_meters > 0 THEN EXCLUDED.reach_meters ELSE transceivers.reach_meters END, + fiber_type = CASE WHEN EXCLUDED.fiber_type <> '' THEN EXCLUDED.fiber_type ELSE transceivers.fiber_type END, + wavelengths = COALESCE(EXCLUDED.wavelengths, transceivers.wavelengths), + category = EXCLUDED.category, + updated_at = NOW() + RETURNING (xmax = 0) as was_inserted`, + [slug, p.pid, vendorId, p.formFactor, p.speed, p.speedGbps, + p.reachMeters, p.reachLabel, p.fiberType, p.connector, + p.wavelengths ?? null, p.standard ?? null, p.category, p.notes ?? null] + ); + if (res.rows[0]?.was_inserted) inserted++; else updated++; + } catch (err) { + console.warn(` Skip ${p.pid}: ${(err as Error).message.slice(0, 80)}`); + errors++; + } + } + + const telecomCount = ASR_PIDS.filter(p => p.category === "Telecom").length; + const dcCount = ASR_PIDS.filter(p => p.category === "DataCenter").length; + + console.log(`\n=== Cisco ASR OEM Seed Complete ===`); + console.log(` Inserted: ${inserted}`); + console.log(` Updated: ${updated}`); + console.log(` Errors: ${errors}`); + console.log(` Total PIDs: ${ASR_PIDS.length} (Telecom: ${telecomCount}, DataCenter: ${dcCount})\n`); +} + +if (require.main === module) { + scrapeCiscoAsrOem() + .then(() => pool.end()) + .catch((err) => { + console.error("Fatal:", err); + pool.end(); + process.exit(1); + }); +} diff --git a/packages/scraper/src/scrapers/cisco-catalyst-oem.ts b/packages/scraper/src/scrapers/cisco-catalyst-oem.ts new file mode 100644 index 0000000..4f0257a --- /dev/null +++ b/packages/scraper/src/scrapers/cisco-catalyst-oem.ts @@ -0,0 +1,122 @@ +/** + * Cisco Catalyst OEM Transceiver Catalog Seed + * + * Seeds Cisco Catalyst-branded transceiver PIDs (SFP= prefix) used in + * Catalyst 9000, 3000, 4000, and 6000 series access/distribution switches. + * + * Sources: + * - Cisco Catalyst Transceiver Module Selection Guide + * - Cisco SFP and SFP+ Transceiver Modules Data Sheet (EDCS-806701) + * - Cisco Catalyst 9000 Hardware Compatibility Matrix + * + * Run: tsx packages/scraper/src/scrapers/cisco-catalyst-oem.ts + * Cron: daily at 12:30 + */ + +import { pool, ensureVendor } from "../utils/db"; + +interface CatalystPID { + pid: string; + formFactor: string; + speedGbps: number; + speed: string; + reachMeters: number; + reachLabel: string; + fiberType: string; + connector: string; + wavelengths?: string; + standard?: string; + notes?: string; +} + +const CATALYST_PIDS: CatalystPID[] = [ + // ── 1G GLC SFP ────────────────────────────────────────────────────────── + { pid: "GLC-SX-MMD", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 550, reachLabel: "SX", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "1000BASE-SX", notes: "Cisco GLC 1G multimode SFP w/ DOM" }, + { pid: "GLC-LH-SMD", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 10000, reachLabel: "LH", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "1000BASE-LX", notes: "Cisco GLC 1G single-mode 10km w/ DOM" }, + { pid: "GLC-T", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 100, reachLabel: "T", fiberType: "DAC", connector: "RJ45", standard: "1000BASE-T", notes: "Cisco GLC 1G copper SFP" }, + { pid: "GLC-BX-U", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 10000, reachLabel: "BX-U", fiberType: "SMF", connector: "LC", wavelengths: "TX1310/RX1490nm", standard: "1000BASE-BX", notes: "Cisco 1G BiDi SFP upstream (1310nm TX)" }, + { pid: "GLC-BX-D", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 10000, reachLabel: "BX-D", fiberType: "SMF", connector: "LC", wavelengths: "TX1490/RX1310nm", standard: "1000BASE-BX", notes: "Cisco 1G BiDi SFP downstream (1490nm TX)" }, + { pid: "GLC-ZX-SMD", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 80000, reachLabel: "ZX", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "1000BASE-ZX", notes: "Cisco GLC 1G extended-reach 80km w/ DOM" }, + + // ── 10G SFP+ ──────────────────────────────────────────────────────────── + { pid: "SFP-10G-SR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 300, reachLabel: "SR", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "10GBASE-SR", notes: "Cisco 10G multimode SFP+" }, + { pid: "SFP-10G-SR-S", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 300, reachLabel: "SR", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "10GBASE-SR", notes: "Cisco 10G multimode SFP+ S-variant (Catalyst)" }, + { pid: "SFP-10G-LR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 10000, reachLabel: "LR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "10GBASE-LR", notes: "Cisco 10G single-mode SFP+ 10km" }, + { pid: "SFP-10G-LR-S", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 10000, reachLabel: "LR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "10GBASE-LR", notes: "Cisco 10G single-mode SFP+ 10km S-variant" }, + { pid: "SFP-10G-ER", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 40000, reachLabel: "ER", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "10GBASE-ER", notes: "Cisco 10G extended-reach SFP+ 40km" }, + { pid: "SFP-10G-ZR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 80000, reachLabel: "ZR", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "10GBASE-ZR", notes: "Cisco 10G ZR SFP+ 80km" }, + + // ── 25G SFP28 ─────────────────────────────────────────────────────────── + { pid: "SFP-25G-SR-S", formFactor: "SFP28", speedGbps: 25, speed: "25G", reachMeters: 100, reachLabel: "SR", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "25GBASE-SR", notes: "Cisco 25G multimode SFP28 Catalyst" }, + { pid: "SFP-25G-LR-S", formFactor: "SFP28", speedGbps: 25, speed: "25G", reachMeters: 10000, reachLabel: "LR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "25GBASE-LR", notes: "Cisco 25G single-mode SFP28 Catalyst 10km" }, + + // ── 40G QSFP+ ─────────────────────────────────────────────────────────── + { pid: "QSFP-40G-SR4", formFactor: "QSFP+", speedGbps: 40, speed: "40G", reachMeters: 150, reachLabel: "SR4", fiberType: "MMF", connector: "MPO", wavelengths: "850nm", standard: "40GBASE-SR4", notes: "Cisco 40G multimode QSFP+" }, + { pid: "QSFP-40G-LR4-S", formFactor: "QSFP+", speedGbps: 40, speed: "40G", reachMeters: 10000, reachLabel: "LR4", fiberType: "SMF", connector: "LC", wavelengths: "1295-1310nm", standard: "40GBASE-LR4", notes: "Cisco 40G single-mode QSFP+ Catalyst S-variant" }, + + // ── 100G QSFP28 ───────────────────────────────────────────────────────── + { pid: "QSFP-100G-SR4-S", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 100, reachLabel: "SR4", fiberType: "MMF", connector: "MPO", wavelengths: "850nm", standard: "100GBASE-SR4", notes: "Cisco 100G multimode QSFP28 Catalyst" }, + { pid: "QSFP-100G-LR4-S", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 10000, reachLabel: "LR4", fiberType: "SMF", connector: "LC", wavelengths: "1295-1310nm", standard: "100GBASE-LR4", notes: "Cisco 100G single-mode QSFP28 Catalyst 10km" }, + { pid: "QSFP-100G-CWDM4-S", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 2000, reachLabel: "CWDM4", fiberType: "SMF", connector: "LC", wavelengths: "1271-1331nm", standard: "100GBASE-CWDM4", notes: "Cisco 100G CWDM4 QSFP28 Catalyst 2km SMF" }, + + // ── 400G QSFP-DD ──────────────────────────────────────────────────────── + { pid: "QSFP-DD-400G-DR4-S", formFactor: "QSFP-DD", speedGbps: 400, speed: "400G", reachMeters: 500, reachLabel: "DR4", fiberType: "SMF", connector: "MPO", wavelengths: "1310nm", standard: "400GBASE-DR4", notes: "Cisco 400G QSFP-DD DR4 Catalyst 500m SMF" }, +]; + +export async function scrapeCiscoCatalystOem(): Promise { + console.log("=== Cisco Catalyst OEM Transceiver Seed ===\n"); + + const vendorId = await ensureVendor( + "Cisco Catalyst", + "oem", + "https://www.cisco.com/c/en/us/products/switches/catalyst-series-switches.html", + undefined + ); + + let inserted = 0; + let updated = 0; + let errors = 0; + + for (const p of CATALYST_PIDS) { + const slug = `cisco-cat-${p.pid.toLowerCase().replace(/[^a-z0-9]+/g, "-")}`; + try { + const res = await pool.query( + `INSERT INTO transceivers + (slug, part_number, vendor_id, form_factor, speed, speed_gbps, + reach_meters, reach_label, fiber_type, connector, wavelengths, + dom_support, ieee_reference, market_status, category, notes) + VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,true,$12,'Mainstream','DataCenter',$13) + ON CONFLICT (slug) DO UPDATE SET + speed_gbps = EXCLUDED.speed_gbps, + reach_meters = CASE WHEN EXCLUDED.reach_meters > 0 THEN EXCLUDED.reach_meters ELSE transceivers.reach_meters END, + fiber_type = CASE WHEN EXCLUDED.fiber_type <> '' THEN EXCLUDED.fiber_type ELSE transceivers.fiber_type END, + wavelengths = COALESCE(EXCLUDED.wavelengths, transceivers.wavelengths), + updated_at = NOW() + RETURNING (xmax = 0) as was_inserted`, + [slug, p.pid, vendorId, p.formFactor, p.speed, p.speedGbps, + p.reachMeters, p.reachLabel, p.fiberType, p.connector, + p.wavelengths ?? null, p.standard ?? null, p.notes ?? null] + ); + if (res.rows[0]?.was_inserted) inserted++; else updated++; + } catch (err) { + console.warn(` Skip ${p.pid}: ${(err as Error).message.slice(0, 80)}`); + errors++; + } + } + + console.log(`\n=== Cisco Catalyst OEM Seed Complete ===`); + console.log(` Inserted: ${inserted}`); + console.log(` Updated: ${updated}`); + console.log(` Errors: ${errors}`); + console.log(` Total PIDs: ${CATALYST_PIDS.length}\n`); +} + +if (require.main === module) { + scrapeCiscoCatalystOem() + .then(() => pool.end()) + .catch((err) => { + console.error("Fatal:", err); + pool.end(); + process.exit(1); + }); +} diff --git a/packages/scraper/src/scrapers/cisco-ie-oem.ts b/packages/scraper/src/scrapers/cisco-ie-oem.ts new file mode 100644 index 0000000..d4e0a34 --- /dev/null +++ b/packages/scraper/src/scrapers/cisco-ie-oem.ts @@ -0,0 +1,119 @@ +/** + * Cisco Industrial Ethernet (IE) OEM Transceiver Catalog Seed + * + * Seeds transceiver PIDs for Cisco Industrial Ethernet SFP/SFP+/SFP28/QSFP+ + * modules qualified for the IE 2000, IE 3000, IE 4000, and IE 5000 switch + * families used in industrial automation, utility, and ruggedized deployments. + * + * Sources: + * - Cisco Industrial Ethernet product catalog + * (cisco.com/c/en/us/products/switches/industrial-ethernet-switches) + * - Cisco IE-series compatibility matrices and SFP datasheets + * + * Run: tsx packages/scraper/src/scrapers/cisco-ie-oem.ts + * Cron: daily at 18:00 + */ + +import { pool, ensureVendor } from "../utils/db"; + +interface CiscoIePID { + pid: string; + formFactor: string; + speedGbps: number; + speed: string; + reachMeters: number; + reachLabel: string; + fiberType: string; + connector: string; + wavelengths?: string; + standard?: string; + notes?: string; +} + +const CISCO_IE_PIDS: CiscoIePID[] = [ + // ── 1G SFP ────────────────────────────────────────────────────────────── + { pid: "IE-SFP-1G-SX", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 550, reachLabel: "SX", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "1000BASE-SX", notes: "Cisco IE SFP 1G SX IE2000/3000/4000/5000 series" }, + { pid: "IE-SFP-1G-LX", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 10000, reachLabel: "LX", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "1000BASE-LX", notes: "Cisco IE SFP 1G LX IE2000/3000/4000/5000 series" }, + { pid: "IE-SFP-1G-T", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 100, reachLabel: "T", fiberType: "DAC", connector: "RJ45", standard: "1000BASE-T", notes: "Cisco IE SFP 1G copper RJ45 industrial" }, + { pid: "IE-SFP-GE-ZX", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 80000, reachLabel: "ZX", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "1000BASE-ZX", notes: "Cisco IE SFP GE ZX 80km long-haul industrial" }, + + // ── 1G SFP BiDi ───────────────────────────────────────────────────────── + { pid: "IE-SFP-GE-BIDI-1310", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 20000, reachLabel: "BiDi-TX1310", fiberType: "SMF", connector: "LC", wavelengths: "TX1310/RX1490nm", notes: "Cisco IE SFP GE BiDi TX1310 single fiber industrial" }, + { pid: "IE-SFP-GE-BIDI-1490", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 20000, reachLabel: "BiDi-TX1490", fiberType: "SMF", connector: "LC", wavelengths: "TX1490/RX1310nm", notes: "Cisco IE SFP GE BiDi TX1490 single fiber industrial" }, + + // ── 10G SFP+ ──────────────────────────────────────────────────────────── + { pid: "IE-SFP-10G-SR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 300, reachLabel: "SR", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "10GBASE-SR", notes: "Cisco IE SFP+ 10G SR IE4000/IE5000 series" }, + { pid: "IE-SFP-10G-LR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 10000, reachLabel: "LR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "10GBASE-LR", notes: "Cisco IE SFP+ 10G LR IE4000/IE5000 series" }, + { pid: "IE-SFP-10G-ER", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 40000, reachLabel: "ER", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "10GBASE-ER", notes: "Cisco IE SFP+ 10G ER IE4000/IE5000 series" }, + + // ── 1G CWDM SFP (industrial/utility rings) ────────────────────────────── + { pid: "IE-SFP-CWDM-1470", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 40000, reachLabel: "CWDM-1470", fiberType: "SMF", connector: "LC", wavelengths: "1470nm", notes: "Cisco IE SFP CWDM 1470nm 40km industrial ring" }, + { pid: "IE-SFP-CWDM-1490", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 40000, reachLabel: "CWDM-1490", fiberType: "SMF", connector: "LC", wavelengths: "1490nm", notes: "Cisco IE SFP CWDM 1490nm 40km industrial ring" }, + { pid: "IE-SFP-CWDM-1510", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 40000, reachLabel: "CWDM-1510", fiberType: "SMF", connector: "LC", wavelengths: "1510nm", notes: "Cisco IE SFP CWDM 1510nm 40km industrial ring" }, + { pid: "IE-SFP-CWDM-1530", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 40000, reachLabel: "CWDM-1530", fiberType: "SMF", connector: "LC", wavelengths: "1530nm", notes: "Cisco IE SFP CWDM 1530nm 40km industrial ring" }, + { pid: "IE-SFP-CWDM-1550", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 40000, reachLabel: "CWDM-1550", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", notes: "Cisco IE SFP CWDM 1550nm 40km industrial ring" }, + + // ── 40G QSFP+ ─────────────────────────────────────────────────────────── + { pid: "IE-QSFP-40G-LR4", formFactor: "QSFP+", speedGbps: 40, speed: "40G", reachMeters: 10000, reachLabel: "LR4", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "40GBASE-LR4", notes: "Cisco IE QSFP+ 40G LR4 IE5000 core uplink" }, + + // ── 25G SFP28 ─────────────────────────────────────────────────────────── + { pid: "IE-SFP28-25G-LR", formFactor: "SFP28", speedGbps: 25, speed: "25G", reachMeters: 10000, reachLabel: "LR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "25GBASE-LR", notes: "Cisco IE SFP28 25G LR IE5000 next-gen uplink" }, +]; + +export async function scrapeCiscoIeOem(): Promise { + console.log("=== Cisco Industrial Ethernet (IE) OEM Transceiver Seed ===\n"); + + const vendorId = await ensureVendor( + "Cisco Industrial", + "oem", + "https://www.cisco.com/c/en/us/products/switches/industrial-ethernet-switches/index.html", + undefined + ); + + let inserted = 0; + let updated = 0; + let errors = 0; + + for (const p of CISCO_IE_PIDS) { + const slug = `cisco-ie-${p.pid.toLowerCase().replace(/[^a-z0-9]+/g, "-")}`; + try { + const res = await pool.query( + `INSERT INTO transceivers + (slug, part_number, vendor_id, form_factor, speed, speed_gbps, + reach_meters, reach_label, fiber_type, connector, wavelengths, + dom_support, ieee_reference, market_status, category, notes) + VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,true,$12,'Mainstream','Industrial',$13) + ON CONFLICT (slug) DO UPDATE SET + speed_gbps = EXCLUDED.speed_gbps, + reach_meters = CASE WHEN EXCLUDED.reach_meters > 0 THEN EXCLUDED.reach_meters ELSE transceivers.reach_meters END, + fiber_type = CASE WHEN EXCLUDED.fiber_type <> '' THEN EXCLUDED.fiber_type ELSE transceivers.fiber_type END, + wavelengths = COALESCE(EXCLUDED.wavelengths, transceivers.wavelengths), + updated_at = NOW() + RETURNING (xmax = 0) as was_inserted`, + [slug, p.pid, vendorId, p.formFactor, p.speed, p.speedGbps, + p.reachMeters, p.reachLabel, p.fiberType, p.connector, + p.wavelengths ?? null, p.standard ?? null, p.notes ?? null] + ); + if (res.rows[0]?.was_inserted) inserted++; else updated++; + } catch (err) { + console.warn(` Skip ${p.pid}: ${(err as Error).message.slice(0, 80)}`); + errors++; + } + } + + console.log(`\n=== Cisco Industrial Ethernet (IE) OEM Seed Complete ===`); + console.log(` Inserted: ${inserted}`); + console.log(` Updated: ${updated}`); + console.log(` Errors: ${errors}`); + console.log(` Total PIDs: ${CISCO_IE_PIDS.length}\n`); +} + +if (require.main === module) { + scrapeCiscoIeOem() + .then(() => pool.end()) + .catch((err) => { + console.error("Fatal:", err); + pool.end(); + process.exit(1); + }); +} diff --git a/packages/scraper/src/scrapers/cisco-meraki-oem.ts b/packages/scraper/src/scrapers/cisco-meraki-oem.ts new file mode 100644 index 0000000..1f6e84b --- /dev/null +++ b/packages/scraper/src/scrapers/cisco-meraki-oem.ts @@ -0,0 +1,120 @@ +/** + * Cisco Meraki OEM Transceiver Catalog Seed + * + * Seeds Cisco Meraki-branded transceiver PIDs for MX security appliances, + * MS switches, and MR wireless platforms (cloud-managed networking). + * + * Sources: + * - Cisco Meraki Hardware Compatibility List (meraki.cisco.com) + * - Meraki MX/MS/MR Datasheet Transceiver Appendices + * - Cisco Meraki Transceiver Module Selection Guide + * + * Run: tsx packages/scraper/src/scrapers/cisco-meraki-oem.ts + * Cron: daily at 12:15 + */ + +import { pool, ensureVendor } from "../utils/db"; + +interface MerakiPID { + pid: string; + formFactor: string; + speedGbps: number; + speed: string; + reachMeters: number; + reachLabel: string; + fiberType: string; + connector: string; + wavelengths?: string; + standard?: string; + notes?: string; +} + +const MERAKI_PIDS: MerakiPID[] = [ + // ── 1G SFP ────────────────────────────────────────────────────────────── + { pid: "MA-SFP-1GB-SX", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 550, reachLabel: "SX", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "1000BASE-SX", notes: "Meraki 1G multimode SFP, MX/MS" }, + { pid: "MA-SFP-1GB-LX10", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 10000, reachLabel: "LX10", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "1000BASE-LX", notes: "Meraki 1G single-mode SFP 10km" }, + { pid: "MA-SFP-1GB-TX", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 100, reachLabel: "TX", fiberType: "DAC", connector: "RJ45", standard: "1000BASE-T", notes: "Meraki 1G copper SFP" }, + { pid: "MA-SFP-GE-T", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 100, reachLabel: "GE-T", fiberType: "DAC", connector: "RJ45", standard: "1000BASE-T", notes: "Meraki GE copper SFP alternate SKU" }, + { pid: "MA-SFP-1GB-SX-MR", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 550, reachLabel: "SX-MR", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "1000BASE-SX", notes: "Meraki MR-series 1G multimode SFP" }, + { pid: "MA-SFP-1GB-TELEWORKER", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 20000, reachLabel: "BiDi-20km", fiberType: "SMF", connector: "LC", wavelengths: "TX1310/RX1550nm", standard: "1000BASE-BX", notes: "Meraki teleworker BiDi SFP 1310/1550nm" }, + + // ── 10G SFP+ ──────────────────────────────────────────────────────────── + { pid: "MA-SFP-10GB-SR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 300, reachLabel: "SR", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "10GBASE-SR", notes: "Meraki 10G multimode SFP+" }, + { pid: "MA-SFP-10GB-LR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 10000, reachLabel: "LR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "10GBASE-LR", notes: "Meraki 10G single-mode SFP+ 10km" }, + { pid: "MA-SFP-10GB-LRM", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 220, reachLabel: "LRM", fiberType: "MMF", connector: "LC", wavelengths: "1310nm", standard: "10GBASE-LRM", notes: "Meraki 10G long-reach multimode SFP+" }, + { pid: "MA-SFP-10GB-ER", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 40000, reachLabel: "ER", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "10GBASE-ER", notes: "Meraki 10G extended-reach SFP+ 40km" }, + { pid: "MA-SFP-10GB-BIDI", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 10000, reachLabel: "BiDi-10km", fiberType: "SMF", connector: "LC", wavelengths: "TX1270/RX1330nm", standard: "10GBASE-BX", notes: "Meraki 10G BiDi SFP+ single fiber" }, + + // ── 25G SFP28 ─────────────────────────────────────────────────────────── + { pid: "MA-SFP28-25G-SR", formFactor: "SFP28", speedGbps: 25, speed: "25G", reachMeters: 100, reachLabel: "SR", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "25GBASE-SR", notes: "Meraki 25G multimode SFP28" }, + { pid: "MA-SFP28-25G-LR", formFactor: "SFP28", speedGbps: 25, speed: "25G", reachMeters: 10000, reachLabel: "LR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "25GBASE-LR", notes: "Meraki 25G single-mode SFP28 10km" }, + + // ── 40G QSFP+ ─────────────────────────────────────────────────────────── + { pid: "MA-QSFP-40G-SR4", formFactor: "QSFP+", speedGbps: 40, speed: "40G", reachMeters: 150, reachLabel: "SR4", fiberType: "MMF", connector: "MPO", wavelengths: "850nm", standard: "40GBASE-SR4", notes: "Meraki 40G multimode QSFP+" }, + { pid: "MA-QSFP-40G-LR4", formFactor: "QSFP+", speedGbps: 40, speed: "40G", reachMeters: 10000, reachLabel: "LR4", fiberType: "SMF", connector: "LC", wavelengths: "1295-1310nm", standard: "40GBASE-LR4", notes: "Meraki 40G single-mode QSFP+ 10km" }, + + // ── 100G QSFP28 ───────────────────────────────────────────────────────── + { pid: "MA-QSFP28-100G-SR4", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 100, reachLabel: "SR4", fiberType: "MMF", connector: "MPO", wavelengths: "850nm", standard: "100GBASE-SR4", notes: "Meraki 100G multimode QSFP28" }, + { pid: "MA-QSFP28-100G-LR4", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 10000, reachLabel: "LR4", fiberType: "SMF", connector: "LC", wavelengths: "1295-1310nm", standard: "100GBASE-LR4", notes: "Meraki 100G single-mode QSFP28 10km" }, + + // ── 400G QSFP-DD ──────────────────────────────────────────────────────── + { pid: "MA-QSFP-DD-400G-DR4", formFactor: "QSFP-DD", speedGbps: 400, speed: "400G", reachMeters: 500, reachLabel: "DR4", fiberType: "SMF", connector: "MPO", wavelengths: "1310nm", standard: "400GBASE-DR4", notes: "Meraki 400G QSFP-DD DR4 500m SMF" }, +]; + +export async function scrapeCiscoMerakiOem(): Promise { + console.log("=== Cisco Meraki OEM Transceiver Seed ===\n"); + + const vendorId = await ensureVendor( + "Cisco Meraki", + "oem", + "https://meraki.cisco.com", + undefined + ); + + let inserted = 0; + let updated = 0; + let errors = 0; + + for (const p of MERAKI_PIDS) { + const slug = `meraki-${p.pid.toLowerCase().replace(/[^a-z0-9]+/g, "-")}`; + try { + const res = await pool.query( + `INSERT INTO transceivers + (slug, part_number, vendor_id, form_factor, speed, speed_gbps, + reach_meters, reach_label, fiber_type, connector, wavelengths, + dom_support, ieee_reference, market_status, category, notes) + VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,true,$12,'Mainstream','DataCenter',$13) + ON CONFLICT (slug) DO UPDATE SET + speed_gbps = EXCLUDED.speed_gbps, + reach_meters = CASE WHEN EXCLUDED.reach_meters > 0 THEN EXCLUDED.reach_meters ELSE transceivers.reach_meters END, + fiber_type = CASE WHEN EXCLUDED.fiber_type <> '' THEN EXCLUDED.fiber_type ELSE transceivers.fiber_type END, + wavelengths = COALESCE(EXCLUDED.wavelengths, transceivers.wavelengths), + updated_at = NOW() + RETURNING (xmax = 0) as was_inserted`, + [slug, p.pid, vendorId, p.formFactor, p.speed, p.speedGbps, + p.reachMeters, p.reachLabel, p.fiberType, p.connector, + p.wavelengths ?? null, p.standard ?? null, p.notes ?? null] + ); + if (res.rows[0]?.was_inserted) inserted++; else updated++; + } catch (err) { + console.warn(` Skip ${p.pid}: ${(err as Error).message.slice(0, 80)}`); + errors++; + } + } + + console.log(`\n=== Cisco Meraki OEM Seed Complete ===`); + console.log(` Inserted: ${inserted}`); + console.log(` Updated: ${updated}`); + console.log(` Errors: ${errors}`); + console.log(` Total PIDs: ${MERAKI_PIDS.length}\n`); +} + +if (require.main === module) { + scrapeCiscoMerakiOem() + .then(() => pool.end()) + .catch((err) => { + console.error("Fatal:", err); + pool.end(); + process.exit(1); + }); +} diff --git a/packages/scraper/src/scrapers/cisco-nexus-oem.ts b/packages/scraper/src/scrapers/cisco-nexus-oem.ts new file mode 100644 index 0000000..3d8ee15 --- /dev/null +++ b/packages/scraper/src/scrapers/cisco-nexus-oem.ts @@ -0,0 +1,125 @@ +/** + * Cisco Nexus OEM Transceiver Catalog Seed + * + * Seeds Cisco Nexus-branded transceiver PIDs for Nexus 2000, 3000, 5000, + * 7000, and 9000 series data center switches (N-prefix PIDs). + * + * Sources: + * - Cisco Nexus Transceiver Module Selection Guide + * - Nexus 9000 Series Hardware Reference (N9K-C9336C-FX2, N9K-C93180YC-FX) + * - Cisco 400G Transceiver Modules for Nexus 9000 Data Sheet + * + * Run: tsx packages/scraper/src/scrapers/cisco-nexus-oem.ts + * Cron: daily at 12:45 + */ + +import { pool, ensureVendor } from "../utils/db"; + +interface NexusPID { + pid: string; + formFactor: string; + speedGbps: number; + speed: string; + reachMeters: number; + reachLabel: string; + fiberType: string; + connector: string; + wavelengths?: string; + standard?: string; + notes?: string; +} + +// All Nexus transceivers are DataCenter; no telecom OC-n PIDs in this portfolio. +const NEXUS_PIDS: NexusPID[] = [ + // ── 1G GLC SFP ────────────────────────────────────────────────────────── + { pid: "GLC-SX-MMD", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 550, reachLabel: "SX", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "1000BASE-SX", notes: "Cisco 1G multimode SFP w/ DOM, Nexus compatible" }, + { pid: "GLC-LH-SMD", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 10000, reachLabel: "LH", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "1000BASE-LX", notes: "Cisco 1G single-mode SFP 10km w/ DOM, Nexus" }, + + // ── 10G SFP+ ──────────────────────────────────────────────────────────── + { pid: "SFP-10G-SR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 300, reachLabel: "SR", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "10GBASE-SR", notes: "Cisco 10G multimode SFP+ Nexus" }, + { pid: "SFP-10G-LR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 10000, reachLabel: "LR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "10GBASE-LR", notes: "Cisco 10G single-mode SFP+ Nexus 10km" }, + { pid: "SFP-10G-ER", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 40000, reachLabel: "ER", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "10GBASE-ER", notes: "Cisco 10G extended-reach SFP+ Nexus 40km" }, + + // ── 25G SFP28 ─────────────────────────────────────────────────────────── + { pid: "SFP-25G-SR-S", formFactor: "SFP28", speedGbps: 25, speed: "25G", reachMeters: 100, reachLabel: "SR", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "25GBASE-SR", notes: "Cisco 25G multimode SFP28 Nexus" }, + { pid: "SFP-25G-LR-S", formFactor: "SFP28", speedGbps: 25, speed: "25G", reachMeters: 10000, reachLabel: "LR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "25GBASE-LR", notes: "Cisco 25G single-mode SFP28 Nexus 10km" }, + + // ── 40G QSFP+ ─────────────────────────────────────────────────────────── + { pid: "QSFP-40G-SR4", formFactor: "QSFP+", speedGbps: 40, speed: "40G", reachMeters: 150, reachLabel: "SR4", fiberType: "MMF", connector: "MPO", wavelengths: "850nm", standard: "40GBASE-SR4", notes: "Cisco 40G multimode QSFP+ Nexus" }, + { pid: "QSFP-40G-LR4", formFactor: "QSFP+", speedGbps: 40, speed: "40G", reachMeters: 10000, reachLabel: "LR4", fiberType: "SMF", connector: "LC", wavelengths: "1295-1310nm", standard: "40GBASE-LR4", notes: "Cisco 40G single-mode QSFP+ Nexus 10km" }, + { pid: "QSFP-40G-SR-BD", formFactor: "QSFP+", speedGbps: 40, speed: "40G", reachMeters: 150, reachLabel: "SR-BiDi", fiberType: "MMF", connector: "LC", wavelengths: "TX832-860/RX882-910nm", standard: "40GBASE-BiDi", notes: "Cisco 40G BiDi QSFP+ duplex LC on OM3/OM4 MMF" }, + { pid: "QSFP-40G-CSR4-S", formFactor: "QSFP+", speedGbps: 40, speed: "40G", reachMeters: 400, reachLabel: "CSR4-400m", fiberType: "MMF", connector: "MPO", wavelengths: "850nm", standard: "40GBASE-CSR4", notes: "Cisco 40G extended-reach AOC/CSR4 QSFP+ 400m MMF" }, + + // ── 100G QSFP28 ───────────────────────────────────────────────────────── + { pid: "QSFP-100G-SR4-S", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 100, reachLabel: "SR4", fiberType: "MMF", connector: "MPO", wavelengths: "850nm", standard: "100GBASE-SR4", notes: "Cisco 100G multimode QSFP28 Nexus" }, + { pid: "QSFP-100G-LR4-S", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 10000, reachLabel: "LR4", fiberType: "SMF", connector: "LC", wavelengths: "1295-1310nm", standard: "100GBASE-LR4", notes: "Cisco 100G single-mode QSFP28 Nexus 10km" }, + { pid: "QSFP-100G-CWDM4-S", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 2000, reachLabel: "CWDM4", fiberType: "SMF", connector: "LC", wavelengths: "1271-1331nm", standard: "100GBASE-CWDM4", notes: "Cisco 100G CWDM4 QSFP28 Nexus 2km SMF" }, + { pid: "QSFP-100G-PSM4-S", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 500, reachLabel: "PSM4-500m", fiberType: "SMF", connector: "MPO", wavelengths: "1310nm", standard: "100GBASE-PSM4", notes: "Cisco 100G PSM4 QSFP28 Nexus 500m parallel SMF" }, + { pid: "QSFP-100G-SM4-S", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 2000, reachLabel: "SM4-BiDi", fiberType: "SMF", connector: "LC", wavelengths: "TX1270/RX1330nm", standard: "100GBASE-BiDi", notes: "Cisco 100G BiDi SM4 QSFP28 Nexus duplex SMF 2km" }, + { pid: "QSFP-100G-AOC1M-S", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 1, reachLabel: "AOC-1m", fiberType: "MMF", connector: "MPO", wavelengths: "850nm", standard: "100GBASE-SR4", notes: "Cisco 100G active optical cable 1m Nexus" }, + + // ── 400G QSFP-DD ──────────────────────────────────────────────────────── + { pid: "QSFP-DD-400G-DR4-S", formFactor: "QSFP-DD", speedGbps: 400, speed: "400G", reachMeters: 500, reachLabel: "DR4", fiberType: "SMF", connector: "MPO", wavelengths: "1310nm", standard: "400GBASE-DR4", notes: "Cisco 400G QSFP-DD DR4 Nexus 9000 500m SMF" }, + { pid: "QSFP-DD-400G-SR8-S", formFactor: "QSFP-DD", speedGbps: 400, speed: "400G", reachMeters: 100, reachLabel: "SR8", fiberType: "MMF", connector: "MPO", wavelengths: "850nm", standard: "400GBASE-SR8", notes: "Cisco 400G QSFP-DD SR8 Nexus 9000 100m MMF" }, + + // ── 800G QSFP-DD ──────────────────────────────────────────────────────── + { pid: "QSFP-DD-800G-DR8", formFactor: "QSFP-DD", speedGbps: 800, speed: "800G", reachMeters: 500, reachLabel: "DR8", fiberType: "SMF", connector: "MPO", wavelengths: "1310nm", standard: "800GBASE-DR8", notes: "Cisco 800G QSFP-DD DR8 Nexus 9000 next-gen DC" }, +]; + +export async function scrapeCiscoNexusOem(): Promise { + console.log("=== Cisco Nexus OEM Transceiver Seed ===\n"); + + const vendorId = await ensureVendor( + "Cisco Nexus", + "oem", + "https://www.cisco.com/c/en/us/products/switches/nexus-series/index.html", + undefined + ); + + let inserted = 0; + let updated = 0; + let errors = 0; + + for (const p of NEXUS_PIDS) { + const slug = `cisco-nx-${p.pid.toLowerCase().replace(/[^a-z0-9]+/g, "-")}`; + try { + const res = await pool.query( + `INSERT INTO transceivers + (slug, part_number, vendor_id, form_factor, speed, speed_gbps, + reach_meters, reach_label, fiber_type, connector, wavelengths, + dom_support, ieee_reference, market_status, category, notes) + VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,true,$12,'Mainstream','DataCenter',$13) + ON CONFLICT (slug) DO UPDATE SET + speed_gbps = EXCLUDED.speed_gbps, + reach_meters = CASE WHEN EXCLUDED.reach_meters > 0 THEN EXCLUDED.reach_meters ELSE transceivers.reach_meters END, + fiber_type = CASE WHEN EXCLUDED.fiber_type <> '' THEN EXCLUDED.fiber_type ELSE transceivers.fiber_type END, + wavelengths = COALESCE(EXCLUDED.wavelengths, transceivers.wavelengths), + updated_at = NOW() + RETURNING (xmax = 0) as was_inserted`, + [slug, p.pid, vendorId, p.formFactor, p.speed, p.speedGbps, + p.reachMeters, p.reachLabel, p.fiberType, p.connector, + p.wavelengths ?? null, p.standard ?? null, p.notes ?? null] + ); + if (res.rows[0]?.was_inserted) inserted++; else updated++; + } catch (err) { + console.warn(` Skip ${p.pid}: ${(err as Error).message.slice(0, 80)}`); + errors++; + } + } + + console.log(`\n=== Cisco Nexus OEM Seed Complete ===`); + console.log(` Inserted: ${inserted}`); + console.log(` Updated: ${updated}`); + console.log(` Errors: ${errors}`); + console.log(` Total PIDs: ${NEXUS_PIDS.length}\n`); +} + +if (require.main === module) { + scrapeCiscoNexusOem() + .then(() => pool.end()) + .catch((err) => { + console.error("Fatal:", err); + pool.end(); + process.exit(1); + }); +} diff --git a/packages/scraper/src/scrapers/coherent-oem.ts b/packages/scraper/src/scrapers/coherent-oem.ts new file mode 100644 index 0000000..ad98771 --- /dev/null +++ b/packages/scraper/src/scrapers/coherent-oem.ts @@ -0,0 +1,153 @@ +/** + * Coherent Corp (formerly II-VI / Finisar) OEM Transceiver Catalog Seed + * + * Seeds Coherent Corp transceiver PIDs sold under OEM branding. + * Covers 1G–800G optical transceivers, coherent DWDM/ZR modules, and DAC cables + * across SFP, SFP+, SFP28, QSFP+, QSFP28, CFP2, QSFP-DD, and OSFP form factors. + * + * Sources: + * - Coherent Corp Product Selector (coherent.com/networking) + * - II-VI Incorporated Optical Transceivers Datasheet Archive + * - Finisar / II-VI FTLX / FTCD / FCBN series datasheets + * + * Run: tsx packages/scraper/src/scrapers/coherent-oem.ts + * Cron: daily at 11:45 + */ + +import { pool, ensureVendor } from "../utils/db"; + +interface CoherentPID { + pid: string; + formFactor: string; + speedGbps: number; + speed: string; + reachMeters: number; + reachLabel: string; + fiberType: string; + connector: string; + wavelengths?: string; + standard?: string; + notes?: string; +} + +const COHERENT_PIDS: CoherentPID[] = [ + // ── 1G SFP ────────────────────────────────────────────────────────────── + { pid: "FTLF8521P2BNL", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 550, reachLabel: "SX", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "1000BASE-SX" }, + { pid: "FTLF1318P3BTL", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 10000, reachLabel: "LX", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "1000BASE-LX" }, + { pid: "FTLF1324P3BTL", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 80000, reachLabel: "ZX", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "1000BASE-ZX" }, + { pid: "FTLF1318P3BCL", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 10000, reachLabel: "LX-10", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "1000BASE-LX" }, + + // ── 10G SFP+ ──────────────────────────────────────────────────────────── + { pid: "FTLX8571D3BCL", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 300, reachLabel: "SR", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "10GBASE-SR" }, + { pid: "FTLX1475D3BCL", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 10000, reachLabel: "LR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "10GBASE-LR" }, + { pid: "FTLX1471D3BCL", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 40000, reachLabel: "ER", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "10GBASE-ER" }, + { pid: "FTLX1871D3BCL", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 80000, reachLabel: "ZR", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "10GBASE-ZR" }, + { pid: "FTLX1471D3BNL", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 220, reachLabel: "LRM", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "10GBASE-LRM" }, + + // ── 10G DWDM SFP+ ─────────────────────────────────────────────────────── + { pid: "FTLX3811M327-xx", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 80000, reachLabel: "DWDM", fiberType: "SMF", connector: "LC", wavelengths: "C-band", standard: undefined, notes: "II-VI 10G DWDM SFP+ tunable" }, + + // ── 25G SFP28 ─────────────────────────────────────────────────────────── + { pid: "FTCD1312E1PCM", formFactor: "SFP28", speedGbps: 25, speed: "25G", reachMeters: 100, reachLabel: "SR", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "25GBASE-SR" }, + { pid: "FTCD1321E1PCM", formFactor: "SFP28", speedGbps: 25, speed: "25G", reachMeters: 10000, reachLabel: "LR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "25GBASE-LR" }, + { pid: "FTCD1321E3PCM", formFactor: "SFP28", speedGbps: 25, speed: "25G", reachMeters: 30000, reachLabel: "ER", fiberType: "SMF", connector: "LC", wavelengths: "1310nm" }, + + // ── 40G QSFP+ ─────────────────────────────────────────────────────────── + { pid: "FTL410QE2C", formFactor: "QSFP+", speedGbps: 40, speed: "40G", reachMeters: 150, reachLabel: "SR4", fiberType: "MMF", connector: "MPO", wavelengths: "850nm", standard: "40GBASE-SR4" }, + { pid: "FTL4C1QE1C", formFactor: "QSFP+", speedGbps: 40, speed: "40G", reachMeters: 10000, reachLabel: "LR4", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "40GBASE-LR4" }, + + // ── 100G QSFP28 ───────────────────────────────────────────────────────── + { pid: "FTCD2600P1BCM", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 100, reachLabel: "SR4", fiberType: "MMF", connector: "MPO", wavelengths: "850nm", standard: "100GBASE-SR4" }, + { pid: "FTCD4601P1BCM", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 10000, reachLabel: "LR4", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "100GBASE-LR4" }, + { pid: "FTCD4601PBCM", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 2000, reachLabel: "CWDM4", fiberType: "SMF", connector: "LC", wavelengths: "1271-1331nm", standard: "100GBASE-CWDM4" }, + { pid: "FTCD2601P2BCM", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 500, reachLabel: "DR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "100GBASE-DR" }, + { pid: "FTCD2621P2BCM", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 2000, reachLabel: "FR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "100GBASE-FR" }, + + // ── 100G CFP2 coherent DWDM ───────────────────────────────────────────── + { pid: "CFP2-DCO-100G", formFactor: "CFP2", speedGbps: 100, speed: "100G", reachMeters: 1500000, reachLabel: "DCO", fiberType: "SMF", connector: "LC", wavelengths: "C-band", notes: "II-VI 100G CFP2 DCO coherent" }, + + // ── 400G QSFP-DD ──────────────────────────────────────────────────────── + { pid: "FTCD8601P1BCM", formFactor: "QSFP-DD", speedGbps: 400, speed: "400G", reachMeters: 100, reachLabel: "SR8", fiberType: "MMF", connector: "MPO", wavelengths: "850nm", standard: "400GBASE-SR8" }, + { pid: "FTCD2628P2BCM", formFactor: "QSFP-DD", speedGbps: 400, speed: "400G", reachMeters: 500, reachLabel: "DR4", fiberType: "SMF", connector: "MPO", wavelengths: "1310nm", standard: "400GBASE-DR4" }, + { pid: "FTCD4628P2BCM", formFactor: "QSFP-DD", speedGbps: 400, speed: "400G", reachMeters: 2000, reachLabel: "FR4", fiberType: "SMF", connector: "LC", wavelengths: "1271-1331nm", standard: "400GBASE-FR4" }, + { pid: "FTCD4629P2BCM", formFactor: "QSFP-DD", speedGbps: 400, speed: "400G", reachMeters: 10000, reachLabel: "LR4", fiberType: "SMF", connector: "LC", wavelengths: "1295-1310nm", standard: "400GBASE-LR4" }, + + // ── 400G ZR coherent QSFP-DD ──────────────────────────────────────────── + { pid: "ZR400-QSFPDD", formFactor: "QSFP-DD", speedGbps: 400, speed: "400G", reachMeters: 120000, reachLabel: "ZR", fiberType: "SMF", connector: "LC", wavelengths: "C-band", standard: "400ZR", notes: "II-VI 400G ZR coherent QSFP-DD" }, + + // ── 800G OSFP ─────────────────────────────────────────────────────────── + { pid: "800G-OSFP-DR8", formFactor: "OSFP", speedGbps: 800, speed: "800G", reachMeters: 500, reachLabel: "DR8", fiberType: "SMF", connector: "MPO", wavelengths: "1310nm", standard: "800GBASE-DR8" }, + { pid: "800G-OSFP-FR8", formFactor: "OSFP", speedGbps: 800, speed: "800G", reachMeters: 2000, reachLabel: "FR8", fiberType: "SMF", connector: "LC", wavelengths: "1271-1331nm" }, + + // ── DAC ───────────────────────────────────────────────────────────────── + { pid: "FCBN210QB1Cxx", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 1, reachLabel: "DAC-1M", fiberType: "DAC", connector: "SFP+" }, + { pid: "FCBN225QB1Cxx", formFactor: "SFP28", speedGbps: 25, speed: "25G", reachMeters: 1, reachLabel: "DAC-1M", fiberType: "DAC", connector: "SFP28" }, + { pid: "FCBN410QB1Cxx", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 1, reachLabel: "DAC-1M", fiberType: "DAC", connector: "QSFP28" }, +]; + +/** PIDs that belong to the Telecom category instead of DataCenter */ +const TELECOM_PIDS = new Set([ + "FTLX3811M327-xx", + "CFP2-DCO-100G", + "ZR400-QSFPDD", +]); + +export async function scrapeCoherentOem(): Promise { + console.log("=== Coherent Corp OEM Transceiver Seed ===\n"); + + const vendorId = await ensureVendor( + "Coherent Corp", + "oem", + "https://www.coherent.com", + undefined + ); + + let inserted = 0; + let updated = 0; + let errors = 0; + + for (const p of COHERENT_PIDS) { + const slug = `coherent-${p.pid.toLowerCase().replace(/[^a-z0-9]+/g, "-")}`; + const category = TELECOM_PIDS.has(p.pid) ? "Telecom" : "DataCenter"; + + try { + const res = await pool.query( + `INSERT INTO transceivers + (slug, part_number, vendor_id, form_factor, speed, speed_gbps, + reach_meters, reach_label, fiber_type, connector, wavelengths, + dom_support, ieee_reference, market_status, category, notes) + VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,true,$12,'Mainstream',$13,$14) + ON CONFLICT (slug) DO UPDATE SET + speed_gbps = EXCLUDED.speed_gbps, + reach_meters = CASE WHEN EXCLUDED.reach_meters > 0 THEN EXCLUDED.reach_meters ELSE transceivers.reach_meters END, + fiber_type = CASE WHEN EXCLUDED.fiber_type <> '' THEN EXCLUDED.fiber_type ELSE transceivers.fiber_type END, + wavelengths = COALESCE(EXCLUDED.wavelengths, transceivers.wavelengths), + updated_at = NOW() + RETURNING (xmax = 0) as was_inserted`, + [slug, p.pid, vendorId, p.formFactor, p.speed, p.speedGbps, + p.reachMeters, p.reachLabel, p.fiberType, p.connector, + p.wavelengths ?? null, p.standard ?? null, category, p.notes ?? null] + ); + if (res.rows[0]?.was_inserted) inserted++; else updated++; + } catch (err) { + console.warn(` Skip ${p.pid}: ${(err as Error).message.slice(0, 80)}`); + errors++; + } + } + + console.log(`\n=== Coherent Corp OEM Seed Complete ===`); + console.log(` Inserted: ${inserted}`); + console.log(` Updated: ${updated}`); + console.log(` Errors: ${errors}`); + console.log(` Total PIDs: ${COHERENT_PIDS.length}\n`); +} + +if (require.main === module) { + scrapeCoherentOem() + .then(() => pool.end()) + .catch((err) => { + console.error("Fatal:", err); + pool.end(); + process.exit(1); + }); +} diff --git a/packages/scraper/src/scrapers/commscope-oem.ts b/packages/scraper/src/scrapers/commscope-oem.ts new file mode 100644 index 0000000..1a6e0e1 --- /dev/null +++ b/packages/scraper/src/scrapers/commscope-oem.ts @@ -0,0 +1,133 @@ +/** + * CommScope OEM Transceiver Catalog Seed + * + * Seeds CommScope-branded transceiver PIDs for RUCKUS ICX switching, + * former ARRIS broadband, and CommScope network infrastructure platforms. + * + * Sources: + * - CommScope RUCKUS ICX Optics Compatibility Matrix (commscope.com) + * - CommScope Access Network Optics Portfolio + * - RUCKUS Networks SFP/QSFP Product Guide + * + * Run: tsx packages/scraper/src/scrapers/commscope-oem.ts + * Cron: daily at 23:30 + */ + +import { pool, ensureVendor } from "../utils/db"; + +interface CommScopePID { + pid: string; + formFactor: string; + speedGbps: number; + speed: string; + reachMeters: number; + reachLabel: string; + fiberType: string; + connector: string; + wavelengths?: string; + standard?: string; + category?: string; + notes?: string; +} + +const COMMSCOPE_PIDS: CommScopePID[] = [ + // ── 1G SFP ─────────────────────────────────────────────────────────────── + { pid: "SFP-1G-SX", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 550, reachLabel: "SX", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "1000BASE-SX" }, + { pid: "SFP-1G-LX", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 10000, reachLabel: "LX", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "1000BASE-LX" }, + { pid: "SFP-1G-T", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 100, reachLabel: "RJ45", fiberType: "Cu", connector: "RJ45" }, + { pid: "SFP-GE-BIDI", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 10000, reachLabel: "BIDI", fiberType: "SMF", connector: "LC", wavelengths: "1310/1490nm", notes: "CommScope 1G BiDi SFP 1310Tx/1490Rx" }, + + // ── 10G SFP+ ───────────────────────────────────────────────────────────── + { pid: "SFP-10G-SR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 300, reachLabel: "SR", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "10GBASE-SR" }, + { pid: "SFP-10G-LR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 10000, reachLabel: "LR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "10GBASE-LR" }, + { pid: "SFP-10G-ER", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 40000, reachLabel: "ER", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "10GBASE-ER" }, + { pid: "SFP-10G-ZR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 80000, reachLabel: "ZR", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "10GBASE-ZR" }, + { pid: "SFP-10G-T", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 30, reachLabel: "RJ45", fiberType: "Cu", connector: "RJ45", standard: "10GBASE-T" }, + + // ── 25G SFP28 ───────────────────────────────────────────────────────────── + { pid: "SFP-25G-SR", formFactor: "SFP28", speedGbps: 25, speed: "25G", reachMeters: 100, reachLabel: "SR", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "25GBASE-SR" }, + { pid: "SFP-25G-LR", formFactor: "SFP28", speedGbps: 25, speed: "25G", reachMeters: 10000, reachLabel: "LR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "25GBASE-LR" }, + { pid: "SFP28-25G-ER", formFactor: "SFP28", speedGbps: 25, speed: "25G", reachMeters: 40000, reachLabel: "ER", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "25GBASE-ER" }, + + // ── 40G QSFP+ ───────────────────────────────────────────────────────────── + { pid: "QSFP-40G-SR4", formFactor: "QSFP+", speedGbps: 40, speed: "40G", reachMeters: 150, reachLabel: "SR4", fiberType: "MMF", connector: "MPO", wavelengths: "850nm", standard: "40GBASE-SR4" }, + { pid: "QSFP-40G-LR4", formFactor: "QSFP+", speedGbps: 40, speed: "40G", reachMeters: 10000, reachLabel: "LR4", fiberType: "SMF", connector: "LC", wavelengths: "1295-1310nm", standard: "40GBASE-LR4" }, + + // ── 100G QSFP28 ─────────────────────────────────────────────────────────── + { pid: "QSFP-100G-SR4", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 100, reachLabel: "SR4", fiberType: "MMF", connector: "MPO", wavelengths: "850nm", standard: "100GBASE-SR4" }, + { pid: "QSFP-100G-LR4", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 10000, reachLabel: "LR4", fiberType: "SMF", connector: "LC", wavelengths: "1295-1310nm", standard: "100GBASE-LR4" }, + + // ── 400G QSFP-DD ────────────────────────────────────────────────────────── + { pid: "QSFP-DD-400G-DR4", formFactor: "QSFP-DD", speedGbps: 400, speed: "400G", reachMeters: 500, reachLabel: "DR4", fiberType: "SMF", connector: "MPO", wavelengths: "1310nm", standard: "400GBASE-DR4" }, + + // ── PON / Access (Telecom) ──────────────────────────────────────────────── + { pid: "SFP-GPON-OLT", formFactor: "SFP", speedGbps: 2.5, speed: "GPON", reachMeters: 20000, reachLabel: "OLT", fiberType: "SMF", connector: "SC", wavelengths: "1490/1310nm", category: "Telecom", notes: "CommScope GPON OLT SFP 2.488G Tx / 1.244G Rx" }, + { pid: "SFP-EPON-OLT", formFactor: "SFP", speedGbps: 1, speed: "EPON", reachMeters: 20000, reachLabel: "OLT", fiberType: "SMF", connector: "SC", wavelengths: "1490/1310nm", category: "Telecom", notes: "CommScope EPON OLT SFP 1G" }, + { pid: "SFP-XGS-PON-OLT", formFactor: "SFP+", speedGbps: 10, speed: "XGS-PON", reachMeters: 20000, reachLabel: "OLT", fiberType: "SMF", connector: "SC", wavelengths: "1577/1270nm", category: "Telecom", notes: "CommScope XGS-PON OLT SFP+ 10G symmetric" }, +]; + +// PIDs that use 'Telecom' category (PON/access OLT modules) +const TELECOM_PIDS = new Set([ + "SFP-GPON-OLT", + "SFP-EPON-OLT", + "SFP-XGS-PON-OLT", +]); + +export async function scrapeCommScopeOem(): Promise { + console.log("=== CommScope OEM Transceiver Seed ===\n"); + + const vendorId = await ensureVendor( + "CommScope", + "oem", + "https://www.commscope.com", + undefined + ); + + let inserted = 0; + let updated = 0; + let errors = 0; + + for (const p of COMMSCOPE_PIDS) { + const slug = `commscope-${p.pid.toLowerCase().replace(/[^a-z0-9]+/g, "-")}`; + const category = p.category ?? (TELECOM_PIDS.has(p.pid) ? "Telecom" : "DataCenter"); + try { + const res = await pool.query( + `INSERT INTO transceivers + (slug, part_number, vendor_id, form_factor, speed, speed_gbps, + reach_meters, reach_label, fiber_type, connector, wavelengths, + dom_support, ieee_reference, market_status, category, notes) + VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,true,$12,'Mainstream',$13,$14) + ON CONFLICT (slug) DO UPDATE SET + speed_gbps = EXCLUDED.speed_gbps, + reach_meters = CASE WHEN EXCLUDED.reach_meters > 0 THEN EXCLUDED.reach_meters ELSE transceivers.reach_meters END, + fiber_type = CASE WHEN EXCLUDED.fiber_type <> '' THEN EXCLUDED.fiber_type ELSE transceivers.fiber_type END, + wavelengths = COALESCE(EXCLUDED.wavelengths, transceivers.wavelengths), + updated_at = NOW() + RETURNING (xmax = 0) as was_inserted`, + [slug, p.pid, vendorId, p.formFactor, p.speed, p.speedGbps, + p.reachMeters, p.reachLabel, p.fiberType, p.connector, + p.wavelengths ?? null, p.standard ?? null, category, p.notes ?? null] + ); + if (res.rows[0]?.was_inserted) inserted++; else updated++; + } catch (err) { + console.warn(` Skip ${p.pid}: ${(err as Error).message.slice(0, 80)}`); + errors++; + } + } + + console.log(`\n=== CommScope OEM Seed Complete ===`); + console.log(` Inserted: ${inserted}`); + console.log(` Updated: ${updated}`); + console.log(` Errors: ${errors}`); + console.log(` Total PIDs: ${COMMSCOPE_PIDS.length}\n`); +} + +if (require.main === module) { + scrapeCommScopeOem() + .then(() => pool.end()) + .catch((err) => { + console.error("Fatal:", err); + pool.end(); + process.exit(1); + }); +} diff --git a/packages/scraper/src/scrapers/comnet-oem.ts b/packages/scraper/src/scrapers/comnet-oem.ts new file mode 100644 index 0000000..184af38 --- /dev/null +++ b/packages/scraper/src/scrapers/comnet-oem.ts @@ -0,0 +1,116 @@ +/** + * Comnet OEM Transceiver Catalog Seed + * + * Seeds transceiver PIDs for Comnet industrial-grade SFP modules used in + * media converters, managed switches, and NMS platforms for utilities + * and transportation infrastructure. + * + * Sources: + * - Comnet SFP module product catalog (comnet.net) + * - Comnet industrial switch hardware installation guides + * + * Run: tsx packages/scraper/src/scrapers/comnet-oem.ts + * Cron: daily at 17:30 + */ + +import { pool, ensureVendor } from "../utils/db"; + +interface ComnetPID { + pid: string; + formFactor: string; + speedGbps: number; + speed: string; + reachMeters: number; + reachLabel: string; + fiberType: string; + connector: string; + wavelengths?: string; + standard?: string; + notes?: string; +} + +const COMNET_PIDS: ComnetPID[] = [ + // ── 100M SFP ──────────────────────────────────────────────────────────── + { pid: "SFP-1FESX-M", formFactor: "SFP", speedGbps: 0.1, speed: "100M", reachMeters: 2000, reachLabel: "FX", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "100BASE-FX" }, + { pid: "SFP-1FELX-S", formFactor: "SFP", speedGbps: 0.1, speed: "100M", reachMeters: 40000, reachLabel: "LFX", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "100BASE-LFX" }, + { pid: "SFP-1FEW1BXU", formFactor: "SFP", speedGbps: 0.1, speed: "100M", reachMeters: 20000, reachLabel: "BiDi-20K", fiberType: "SMF", connector: "LC", wavelengths: "TX1310/RX1550nm", notes: "Comnet 100M BiDi SFP upstream" }, + + // ── 1G SFP ────────────────────────────────────────────────────────────── + { pid: "SFP-1GESX-M", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 550, reachLabel: "SX", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "1000BASE-SX" }, + { pid: "SFP-1GELX-S10", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 10000, reachLabel: "LX", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "1000BASE-LX" }, + { pid: "SFP-1GELX-S20", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 20000, reachLabel: "LH", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", notes: "Comnet 1G SM SFP 20km" }, + { pid: "SFP-1GELX-S40", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 40000, reachLabel: "LH", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", notes: "Comnet 1G SM SFP 40km" }, + { pid: "SFP-1GEZX-S80", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 80000, reachLabel: "ZX", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "1000BASE-ZX" }, + { pid: "SFP-1GETP-M", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 100, reachLabel: "T", fiberType: "DAC", connector: "RJ45", standard: "1000BASE-T" }, + { pid: "SFP-1GEW1BXU", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 20000, reachLabel: "BiDi-20K", fiberType: "SMF", connector: "LC", wavelengths: "TX1310/RX1550nm", notes: "Comnet 1G BiDi SFP upstream" }, + { pid: "SFP-1GEW1BXD", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 20000, reachLabel: "BiDi-20K", fiberType: "SMF", connector: "LC", wavelengths: "TX1550/RX1310nm", notes: "Comnet 1G BiDi SFP downstream" }, + + // ── 10G SFP+ ──────────────────────────────────────────────────────────── + { pid: "SFP-10GESR-M", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 300, reachLabel: "SR", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "10GBASE-SR" }, + { pid: "SFP-10GELR-S", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 10000, reachLabel: "LR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "10GBASE-LR" }, + { pid: "SFP-10GEER-S", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 40000, reachLabel: "ER", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "10GBASE-ER" }, + { pid: "SFP-10GEZR-S", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 80000, reachLabel: "ZR", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "10GBASE-ZR" }, + { pid: "SFP-10GETP-M", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 30, reachLabel: "T", fiberType: "DAC", connector: "RJ45", standard: "10GBASE-T" }, + + // ── DAC ───────────────────────────────────────────────────────────────── + { pid: "SFP-10GDAC1M", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 1, reachLabel: "DAC-1m", fiberType: "DAC", connector: "SFP+", notes: "Comnet SFP+ 10G DAC 1m" }, + { pid: "SFP-10GDAC3M", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 3, reachLabel: "DAC-3m", fiberType: "DAC", connector: "SFP+", notes: "Comnet SFP+ 10G DAC 3m" }, +]; + +export async function scrapeComnetOem(): Promise { + console.log("=== Comnet OEM Transceiver Seed ===\n"); + + const vendorId = await ensureVendor( + "Comnet", + "oem", + "https://www.comnet.net", + undefined + ); + + let inserted = 0; + let updated = 0; + let errors = 0; + + for (const p of COMNET_PIDS) { + const slug = `comnet-${p.pid.toLowerCase().replace(/[^a-z0-9]+/g, "-")}`; + try { + const res = await pool.query( + `INSERT INTO transceivers + (slug, part_number, vendor_id, form_factor, speed, speed_gbps, + reach_meters, reach_label, fiber_type, connector, wavelengths, + dom_support, ieee_reference, market_status, category, notes) + VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,true,$12,'Mainstream','Industrial',$13) + ON CONFLICT (slug) DO UPDATE SET + speed_gbps = EXCLUDED.speed_gbps, + reach_meters = CASE WHEN EXCLUDED.reach_meters > 0 THEN EXCLUDED.reach_meters ELSE transceivers.reach_meters END, + fiber_type = CASE WHEN EXCLUDED.fiber_type <> '' THEN EXCLUDED.fiber_type ELSE transceivers.fiber_type END, + wavelengths = COALESCE(EXCLUDED.wavelengths, transceivers.wavelengths), + updated_at = NOW() + RETURNING (xmax = 0) as was_inserted`, + [slug, p.pid, vendorId, p.formFactor, p.speed, p.speedGbps, + p.reachMeters, p.reachLabel, p.fiberType, p.connector, + p.wavelengths ?? null, p.standard ?? null, p.notes ?? null] + ); + if (res.rows[0]?.was_inserted) inserted++; else updated++; + } catch (err) { + console.warn(` Skip ${p.pid}: ${(err as Error).message.slice(0, 80)}`); + errors++; + } + } + + console.log(`\n=== Comnet OEM Seed Complete ===`); + console.log(` Inserted: ${inserted}`); + console.log(` Updated: ${updated}`); + console.log(` Errors: ${errors}`); + console.log(` Total PIDs: ${COMNET_PIDS.length}\n`); +} + +if (require.main === module) { + scrapeComnetOem() + .then(() => pool.end()) + .catch((err) => { + console.error("Fatal:", err); + pool.end(); + process.exit(1); + }); +} diff --git a/packages/scraper/src/scrapers/comtrend-oem.ts b/packages/scraper/src/scrapers/comtrend-oem.ts new file mode 100644 index 0000000..82c6c5e --- /dev/null +++ b/packages/scraper/src/scrapers/comtrend-oem.ts @@ -0,0 +1,147 @@ +/** + * Comtrend OEM Transceiver Catalog Seed + * + * Seeds Comtrend-branded transceiver PIDs for DSL/GPON/XGS-PON/EPON + * CPE and OLT access platforms. + * Comtrend is a DSL and fibre access networking vendor supplying SFP + * modules for GPON, XGS-PON, EPON, and GE/10GE CPE and OLT equipment. + * + * Sources: + * - Comtrend GPON OLT/ONU SFP Module Data Sheets + * - Comtrend XGS-PON Pluggable Optics Guide + * - Comtrend EPON SFP Specification Documents + * - comtrend.com product catalogue + * + * Run: tsx packages/scraper/src/scrapers/comtrend-oem.ts + * Cron: daily at 01:30 + */ + +import { pool, ensureVendor } from "../utils/db"; + +interface ComtrendPID { + pid: string; + formFactor: string; + speedGbps: number; + speed: string; + reachMeters: number; + reachLabel: string; + fiberType: string; + connector: string; + wavelengths?: string; + standard?: string; + category?: string; + notes?: string; +} + +const COMTREND_PIDS: ComtrendPID[] = [ + // ── Standard 1G SFP ────────────────────────────────────────────────────── + { pid: "SFP-1G-SX", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 550, reachLabel: "SX", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "1000BASE-SX" }, + { pid: "SFP-1G-LX", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 10000, reachLabel: "LX", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "1000BASE-LX" }, + { pid: "SFP-1G-T", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 100, reachLabel: "T", fiberType: "Cu", connector: "RJ45", standard: "1000BASE-T" }, + + // ── 10G SFP+ ──────────────────────────────────────────────────────────── + { pid: "SFP-10G-SR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 300, reachLabel: "SR", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "10GBASE-SR" }, + { pid: "SFP-10G-LR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 10000, reachLabel: "LR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "10GBASE-LR" }, + { pid: "SFP-10G-ER", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 40000, reachLabel: "ER", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "10GBASE-ER" }, + { pid: "SFP-10G-ZR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 80000, reachLabel: "ZR", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "10GBASE-ZR", category: "Telecom", notes: "Comtrend 10G ZR for extended backhaul" }, + + // ── GPON SFP (OLT-side, 1490nm TX / 1310nm RX) ─────────────────────────── + { pid: "SFP-GPON-OLT", formFactor: "SFP", speedGbps: 1.244, speed: "GPON", reachMeters: 20000, reachLabel: "OLT", fiberType: "SMF", connector: "SC", wavelengths: "1490/1310nm", standard: "ITU-T G.984", category: "Telecom", notes: "Comtrend GPON OLT SFP — 1490nm TX, 1310nm RX, class B+" }, + // ── GPON SFP (ONU-side, 1310nm TX / 1490nm RX) ─────────────────────────── + { pid: "SFP-GPON-ONU", formFactor: "SFP", speedGbps: 1.244, speed: "GPON", reachMeters: 20000, reachLabel: "ONU", fiberType: "SMF", connector: "SC", wavelengths: "1310/1490nm", standard: "ITU-T G.984", category: "Telecom", notes: "Comtrend GPON ONU SFP — 1310nm TX, 1490nm RX" }, + + // ── XGS-PON SFP+ (OLT-side) ────────────────────────────────────────────── + { pid: "SFP-XGS-PON-OLT", formFactor: "SFP+", speedGbps: 10, speed: "XGS-PON", reachMeters: 20000, reachLabel: "OLT", fiberType: "SMF", connector: "SC", wavelengths: "1577/1270nm", standard: "ITU-T G.9807.1", category: "Telecom", notes: "Comtrend XGS-PON OLT SFP+ — 1577nm TX, 1270nm RX" }, + // ── XGS-PON SFP+ (ONU-side) ────────────────────────────────────────────── + { pid: "SFP-XGS-PON-ONU", formFactor: "SFP+", speedGbps: 10, speed: "XGS-PON", reachMeters: 20000, reachLabel: "ONU", fiberType: "SMF", connector: "SC", wavelengths: "1270/1577nm", standard: "ITU-T G.9807.1", category: "Telecom", notes: "Comtrend XGS-PON ONU SFP+ — 1270nm TX, 1577nm RX" }, + + // ── EPON SFP (OLT-side) ────────────────────────────────────────────────── + { pid: "SFP-EPON-OLT", formFactor: "SFP", speedGbps: 1.25, speed: "EPON", reachMeters: 20000, reachLabel: "OLT", fiberType: "SMF", connector: "SC", wavelengths: "1490/1310nm", standard: "IEEE 802.3ah", category: "Telecom", notes: "Comtrend EPON OLT SFP — 1490nm TX, 1310nm RX" }, + // ── EPON SFP (ONU-side) ────────────────────────────────────────────────── + { pid: "SFP-EPON-ONU", formFactor: "SFP", speedGbps: 1.25, speed: "EPON", reachMeters: 20000, reachLabel: "ONU", fiberType: "SMF", connector: "SC", wavelengths: "1310/1490nm", standard: "IEEE 802.3ah", category: "Telecom", notes: "Comtrend EPON ONU SFP — 1310nm TX, 1490nm RX" }, + + // ── BiDi SFP ───────────────────────────────────────────────────────────── + { pid: "SFP-BIDI-1310-1490", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 20000, reachLabel: "BiDi", fiberType: "SMF", connector: "LC", wavelengths: "1310/1490nm", category: "Telecom", notes: "Comtrend BiDi SFP 1310nm TX / 1490nm RX" }, + { pid: "SFP-BIDI-1310-1550", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 40000, reachLabel: "BiDi", fiberType: "SMF", connector: "LC", wavelengths: "1310/1550nm", category: "Telecom", notes: "Comtrend BiDi SFP 1310nm TX / 1550nm RX" }, + { pid: "SFP-GE-BIDI-1550", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 40000, reachLabel: "BiDi-1550", fiberType: "SMF", connector: "LC", wavelengths: "1550/1310nm", category: "Telecom", notes: "Comtrend BiDi SFP 1550nm TX / 1310nm RX" }, + + // ── 10G BiDi SFP+ ──────────────────────────────────────────────────────── + { pid: "SFP-10G-BIDI-1270", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 10000, reachLabel: "BiDi", fiberType: "SMF", connector: "LC", wavelengths: "1270/1330nm", category: "Telecom", notes: "Comtrend 10G BiDi SFP+ 1270nm TX / 1330nm RX" }, + + // ── 25G SFP28 ──────────────────────────────────────────────────────────── + { pid: "SFP-25G-SR", formFactor: "SFP28", speedGbps: 25, speed: "25G", reachMeters: 100, reachLabel: "SR", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "25GBASE-SR" }, +]; + +// PIDs that use 'Telecom' category (PON, BiDi, ZR) +const TELECOM_PIDS = new Set([ + "SFP-10G-ZR", + "SFP-GPON-OLT", + "SFP-GPON-ONU", + "SFP-XGS-PON-OLT", + "SFP-XGS-PON-ONU", + "SFP-EPON-OLT", + "SFP-EPON-ONU", + "SFP-BIDI-1310-1490", + "SFP-BIDI-1310-1550", + "SFP-GE-BIDI-1550", + "SFP-10G-BIDI-1270", +]); + +export async function scrapeComtrendOem(): Promise { + console.log("=== Comtrend OEM Transceiver Seed ===\n"); + + const vendorId = await ensureVendor( + "Comtrend", + "oem", + "https://www.comtrend.com", + undefined + ); + + let inserted = 0; + let updated = 0; + let errors = 0; + + for (const p of COMTREND_PIDS) { + const slug = `comtrend-${p.pid.toLowerCase().replace(/[^a-z0-9]+/g, "-")}`; + const category = p.category ?? (TELECOM_PIDS.has(p.pid) ? "Telecom" : "DataCenter"); + try { + const res = await pool.query( + `INSERT INTO transceivers + (slug, part_number, vendor_id, form_factor, speed, speed_gbps, + reach_meters, reach_label, fiber_type, connector, wavelengths, + dom_support, ieee_reference, market_status, category, notes) + VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,true,$12,'Mainstream',$13,$14) + ON CONFLICT (slug) DO UPDATE SET + speed_gbps = EXCLUDED.speed_gbps, + reach_meters = CASE WHEN EXCLUDED.reach_meters > 0 THEN EXCLUDED.reach_meters ELSE transceivers.reach_meters END, + fiber_type = CASE WHEN EXCLUDED.fiber_type <> '' THEN EXCLUDED.fiber_type ELSE transceivers.fiber_type END, + wavelengths = COALESCE(EXCLUDED.wavelengths, transceivers.wavelengths), + updated_at = NOW() + RETURNING (xmax = 0) as was_inserted`, + [slug, p.pid, vendorId, p.formFactor, p.speed, p.speedGbps, + p.reachMeters, p.reachLabel, p.fiberType, p.connector, + p.wavelengths ?? null, p.standard ?? null, category, p.notes ?? null] + ); + if (res.rows[0]?.was_inserted) inserted++; else updated++; + } catch (err) { + console.warn(` Skip ${p.pid}: ${(err as Error).message.slice(0, 80)}`); + errors++; + } + } + + console.log(`\n=== Comtrend OEM Seed Complete ===`); + console.log(` Inserted: ${inserted}`); + console.log(` Updated: ${updated}`); + console.log(` Errors: ${errors}`); + console.log(` Total PIDs: ${COMTREND_PIDS.length}\n`); +} + +if (require.main === module) { + scrapeComtrendOem() + .then(() => pool.end()) + .catch((err) => { + console.error("Fatal:", err); + pool.end(); + process.exit(1); + }); +} diff --git a/packages/scraper/src/scrapers/coriant-oem.ts b/packages/scraper/src/scrapers/coriant-oem.ts new file mode 100644 index 0000000..d0fa2c8 --- /dev/null +++ b/packages/scraper/src/scrapers/coriant-oem.ts @@ -0,0 +1,139 @@ +/** + * Coriant OEM Transceiver Catalog Seed + * + * Seeds Coriant-branded transceiver PIDs for WDM platforms: + * hiT 7300, hiT 7100 series, and Groove G30. + * + * Note: Coriant was previously Tellabs/Siemens/Nokia Siemens Networks. + * Coriant was acquired by Infinera in 2018. These PIDs cover legacy + * Coriant WDM platform optics and are distinct from infinera-oem.ts + * which covers modern Infinera HIL PIDs. + * + * Sources: + * - Coriant hiT 7300 Product Documentation + * - Coriant hiT 7100 System Description + * - Coriant Groove G30 Platform Guide + * - Infinera (Coriant) Legacy Product Portfolio (infinera.com/products/coriant/) + * + * Run: tsx packages/scraper/src/scrapers/coriant-oem.ts + * Cron: daily at 21:00 + */ + +import { pool, ensureVendor } from "../utils/db"; + +interface CoriantPID { + pid: string; + formFactor: string; + speedGbps: number; + speed: string; + reachMeters: number; + reachLabel: string; + fiberType: string; + connector: string; + wavelengths?: string; + standard?: string; + category?: string; + notes?: string; +} + +const CORIANT_PIDS: CoriantPID[] = [ + // ── 1G SFP ────────────────────────────────────────────────────────────── + { pid: "COR-SFP-1G-SX", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 550, reachLabel: "SX", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "1000BASE-SX" }, + { pid: "COR-SFP-1G-LX", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 10000, reachLabel: "LX", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "1000BASE-LX" }, + { pid: "COR-SFP-1G-ZX", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 80000, reachLabel: "ZX", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "1000BASE-ZX" }, + + // ── 10G SFP+ ──────────────────────────────────────────────────────────── + { pid: "COR-SFP-10G-SR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 300, reachLabel: "SR", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "10GBASE-SR" }, + { pid: "COR-SFP-10G-LR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 10000, reachLabel: "LR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "10GBASE-LR" }, + { pid: "COR-SFP-10G-ER", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 40000, reachLabel: "ER", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "10GBASE-ER" }, + { pid: "COR-SFP-10G-ZR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 80000, reachLabel: "ZR", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "10GBASE-ZR" }, + + // ── 10G DWDM SFP+ (hiT WDM) ───────────────────────────────────────────── + { pid: "COR-SFP-10G-DW-TUNE", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 80000, reachLabel: "DWDM", fiberType: "SMF", connector: "LC", wavelengths: "C-band DWDM", category: "Telecom", notes: "Coriant hiT 10G DWDM tunable SFP+" }, + + // ── 100G CFP Coherent (hiT 7300) ──────────────────────────────────────── + { pid: "COR-CFP-100G-OTU4", formFactor: "CFP", speedGbps: 100, speed: "100G", reachMeters: 1500000, reachLabel: "OTU4", fiberType: "SMF", connector: "LC", wavelengths: "C-band", standard: "OTU4", category: "Telecom", notes: "Coriant hiT 7300 100G CFP OTU4 coherent" }, + + // ── 100G CFP2 Coherent (Groove G30) ───────────────────────────────────── + { pid: "COR-CFP2-100G-DCO", formFactor: "CFP2", speedGbps: 100, speed: "100G", reachMeters: 1500000, reachLabel: "DCO", fiberType: "SMF", connector: "LC", wavelengths: "C-band", category: "Telecom", notes: "Coriant Groove G30 100G CFP2 DCO coherent" }, + + // ── 100G QSFP28 ───────────────────────────────────────────────────────── + { pid: "COR-QSFP28-100G-SR4", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 100, reachLabel: "SR4", fiberType: "MMF", connector: "MPO", wavelengths: "850nm", standard: "100GBASE-SR4" }, + { pid: "COR-QSFP28-100G-LR4", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 10000, reachLabel: "LR4", fiberType: "SMF", connector: "LC", wavelengths: "1295-1310nm", standard: "100GBASE-LR4" }, + { pid: "COR-QSFP28-100G-CWDM4", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 2000, reachLabel: "CWDM4", fiberType: "SMF", connector: "LC", wavelengths: "1271-1331nm", standard: "100GBASE-CWDM4" }, + + // ── 400G QSFP-DD ──────────────────────────────────────────────────────── + { pid: "COR-QSFPDD-400G-FR4", formFactor: "QSFP-DD", speedGbps: 400, speed: "400G", reachMeters: 2000, reachLabel: "FR4", fiberType: "SMF", connector: "LC", wavelengths: "1271-1331nm", standard: "400GBASE-FR4" }, + { pid: "COR-QSFPDD-400G-ZR", formFactor: "QSFP-DD", speedGbps: 400, speed: "400G", reachMeters: 120000, reachLabel: "ZR", fiberType: "SMF", connector: "LC", wavelengths: "C-band", standard: "400ZR", category: "Telecom", notes: "Coriant/Infinera Groove 400G ZR coherent QSFP-DD" }, + + // ── DAC ───────────────────────────────────────────────────────────────── + { pid: "COR-DAC-10G-1M", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 1, reachLabel: "DAC-1M", fiberType: "DAC", connector: "SFP+" }, + { pid: "COR-DAC-100G-1M", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 1, reachLabel: "DAC-1M", fiberType: "DAC", connector: "QSFP28" }, +]; + +// PIDs that use 'Telecom' category (coherent/DWDM) +const TELECOM_PIDS = new Set([ + "COR-SFP-10G-DW-TUNE", + "COR-CFP-100G-OTU4", + "COR-CFP2-100G-DCO", + "COR-QSFPDD-400G-ZR", +]); + +export async function scrapeCoriantOem(): Promise { + console.log("=== Coriant OEM Transceiver Seed ===\n"); + + const vendorId = await ensureVendor( + "Coriant", + "oem", + "https://www.infinera.com/products/coriant/", + undefined + ); + + let inserted = 0; + let updated = 0; + let errors = 0; + + for (const p of CORIANT_PIDS) { + const slug = `coriant-${p.pid.toLowerCase().replace(/[^a-z0-9]+/g, "-")}`; + const category = p.category ?? (TELECOM_PIDS.has(p.pid) ? "Telecom" : "DataCenter"); + try { + const res = await pool.query( + `INSERT INTO transceivers + (slug, part_number, vendor_id, form_factor, speed, speed_gbps, + reach_meters, reach_label, fiber_type, connector, wavelengths, + dom_support, ieee_reference, market_status, category, notes) + VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,true,$12,'Mainstream',$13,$14) + ON CONFLICT (slug) DO UPDATE SET + speed_gbps = EXCLUDED.speed_gbps, + reach_meters = CASE WHEN EXCLUDED.reach_meters > 0 THEN EXCLUDED.reach_meters ELSE transceivers.reach_meters END, + fiber_type = CASE WHEN EXCLUDED.fiber_type <> '' THEN EXCLUDED.fiber_type ELSE transceivers.fiber_type END, + wavelengths = COALESCE(EXCLUDED.wavelengths, transceivers.wavelengths), + updated_at = NOW() + RETURNING (xmax = 0) as was_inserted`, + [slug, p.pid, vendorId, p.formFactor, p.speed, p.speedGbps, + p.reachMeters, p.reachLabel, p.fiberType, p.connector, + p.wavelengths ?? null, p.standard ?? null, category, p.notes ?? null] + ); + if (res.rows[0]?.was_inserted) inserted++; else updated++; + } catch (err) { + console.warn(` Skip ${p.pid}: ${(err as Error).message.slice(0, 80)}`); + errors++; + } + } + + console.log(`\n=== Coriant OEM Seed Complete ===`); + console.log(` Inserted: ${inserted}`); + console.log(` Updated: ${updated}`); + console.log(` Errors: ${errors}`); + console.log(` Total PIDs: ${CORIANT_PIDS.length}\n`); +} + +if (require.main === module) { + scrapeCoriantOem() + .then(() => pool.end()) + .catch((err) => { + console.error("Fatal:", err); + pool.end(); + process.exit(1); + }); +} diff --git a/packages/scraper/src/scrapers/corning-oem.ts b/packages/scraper/src/scrapers/corning-oem.ts new file mode 100644 index 0000000..8ff738d --- /dev/null +++ b/packages/scraper/src/scrapers/corning-oem.ts @@ -0,0 +1,123 @@ +/** + * Corning OEM Transceiver Catalog Seed + * + * Seeds Corning-branded SFP/QSFP modules sold with Pretium EDGE infrastructure. + * + * Sources: + * - Corning Optical Communications Pretium EDGE Solutions (corning.com/optical-communications) + * - Corning Pretium EDGE Hardware & Transceiver Compatibility Guide + * + * Run: tsx packages/scraper/src/scrapers/corning-oem.ts + * Cron: daily at 02:15 + */ + +import { pool, ensureVendor } from "../utils/db"; + +interface CorningPID { + pid: string; + formFactor: string; + speedGbps: number; + speed: string; + reachMeters: number; + reachLabel: string; + fiberType: string; + connector: string; + wavelengths?: string; + standard?: string; + category?: string; + notes?: string; +} + +const CORNING_PIDS: CorningPID[] = [ + // ── 1G SFP ────────────────────────────────────────────────────────────── + { pid: "COR-SFP-1G-SX", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 550, reachLabel: "SX", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "1000BASE-SX" }, + { pid: "COR-SFP-1G-LX", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 10000, reachLabel: "LX", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "1000BASE-LX" }, + { pid: "COR-SFP-1G-LX10", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 10000, reachLabel: "LX10", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "1000BASE-LX10" }, + { pid: "COR-SFP-GE-T", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 100, reachLabel: "T", fiberType: "Cu", connector: "RJ45", wavelengths: "N/A", standard: "1000BASE-T" }, + + // ── 10G SFP+ ──────────────────────────────────────────────────────────── + { pid: "COR-SFP-10G-SR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 300, reachLabel: "SR", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "10GBASE-SR" }, + { pid: "COR-SFP-10G-LR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 10000, reachLabel: "LR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "10GBASE-LR" }, + { pid: "COR-SFP-10G-ER", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 40000, reachLabel: "ER", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "10GBASE-ER" }, + { pid: "COR-SFP-10G-ZR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 80000, reachLabel: "ZR", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "10GBASE-ZR" }, + + // ── 40G QSFP+ ─────────────────────────────────────────────────────────── + { pid: "COR-QSFP-40G-SR4", formFactor: "QSFP+", speedGbps: 40, speed: "40G", reachMeters: 150, reachLabel: "SR4", fiberType: "MMF", connector: "MPO", wavelengths: "850nm", standard: "40GBASE-SR4" }, + { pid: "COR-QSFP-40G-LR4", formFactor: "QSFP+", speedGbps: 40, speed: "40G", reachMeters: 10000, reachLabel: "LR4", fiberType: "SMF", connector: "LC", wavelengths: "1295-1310nm", standard: "40GBASE-LR4" }, + { pid: "COR-QSFP-40G-ESR4", formFactor: "QSFP+", speedGbps: 40, speed: "40G", reachMeters: 300, reachLabel: "ESR4", fiberType: "MMF", connector: "MPO", wavelengths: "850nm", standard: "40GBASE-ESR4", notes: "Extended reach MMF 300m" }, + + // ── 25G SFP28 ─────────────────────────────────────────────────────────── + { pid: "COR-SFP28-25G-SR", formFactor: "SFP28", speedGbps: 25, speed: "25G", reachMeters: 300, reachLabel: "SR", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "25GBASE-SR" }, + { pid: "COR-SFP28-25G-LR", formFactor: "SFP28", speedGbps: 25, speed: "25G", reachMeters: 10000, reachLabel: "LR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "25GBASE-LR" }, + + // ── 100G QSFP28 ───────────────────────────────────────────────────────── + { pid: "COR-QSFP28-100G-SR4", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 100, reachLabel: "SR4", fiberType: "MMF", connector: "MPO", wavelengths: "850nm", standard: "100GBASE-SR4" }, + { pid: "COR-QSFP28-100G-LR4", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 10000, reachLabel: "LR4", fiberType: "SMF", connector: "LC", wavelengths: "1295-1310nm", standard: "100GBASE-LR4" }, + { pid: "COR-QSFP28-100G-CWDM4", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 2000, reachLabel: "CWDM4", fiberType: "SMF", connector: "LC", wavelengths: "1271-1331nm", standard: "100GBASE-CWDM4" }, + + // ── 400G QSFP-DD ──────────────────────────────────────────────────────── + { pid: "COR-QSFP-DD-400G-DR4", formFactor: "QSFP-DD", speedGbps: 400, speed: "400G", reachMeters: 500, reachLabel: "DR4", fiberType: "SMF", connector: "MPO", wavelengths: "1310nm", standard: "400GBASE-DR4" }, + { pid: "COR-QSFP-DD-400G-SR8", formFactor: "QSFP-DD", speedGbps: 400, speed: "400G", reachMeters: 100, reachLabel: "SR8", fiberType: "MMF", connector: "MPO", wavelengths: "850nm", standard: "400GBASE-SR8" }, +]; + +// PIDs that use 'Telecom' category +const TELECOM_PIDS = new Set([]); + +export async function scrapeCorningOem(): Promise { + console.log("=== Corning OEM Transceiver Seed ===\n"); + + const vendorId = await ensureVendor( + "Corning", + "oem", + "https://www.corning.com/optical-communications", + undefined + ); + + let inserted = 0; + let updated = 0; + let errors = 0; + + for (const p of CORNING_PIDS) { + const slug = `corning-${p.pid.toLowerCase().replace(/[^a-z0-9]+/g, "-")}`; + const category = p.category ?? (TELECOM_PIDS.has(p.pid) ? "Telecom" : "DataCenter"); + try { + const res = await pool.query( + `INSERT INTO transceivers + (slug, part_number, vendor_id, form_factor, speed, speed_gbps, + reach_meters, reach_label, fiber_type, connector, wavelengths, + dom_support, ieee_reference, market_status, category, notes) + VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,true,$12,'Mainstream',$13,$14) + ON CONFLICT (slug) DO UPDATE SET + speed_gbps = EXCLUDED.speed_gbps, + reach_meters = CASE WHEN EXCLUDED.reach_meters > 0 THEN EXCLUDED.reach_meters ELSE transceivers.reach_meters END, + fiber_type = CASE WHEN EXCLUDED.fiber_type <> '' THEN EXCLUDED.fiber_type ELSE transceivers.fiber_type END, + wavelengths = COALESCE(EXCLUDED.wavelengths, transceivers.wavelengths), + updated_at = NOW() + RETURNING (xmax = 0) as was_inserted`, + [slug, p.pid, vendorId, p.formFactor, p.speed, p.speedGbps, + p.reachMeters, p.reachLabel, p.fiberType, p.connector, + p.wavelengths ?? null, p.standard ?? null, category, p.notes ?? null] + ); + if (res.rows[0]?.was_inserted) inserted++; else updated++; + } catch (err) { + console.warn(` Skip ${p.pid}: ${(err as Error).message.slice(0, 80)}`); + errors++; + } + } + + console.log(`\n=== Corning OEM Seed Complete ===`); + console.log(` Inserted: ${inserted}`); + console.log(` Updated: ${updated}`); + console.log(` Errors: ${errors}`); + console.log(` Total PIDs: ${CORNING_PIDS.length}\n`); +} + +if (require.main === module) { + scrapeCorningOem() + .then(() => pool.end()) + .catch((err) => { + console.error("Fatal:", err); + pool.end(); + process.exit(1); + }); +} diff --git a/packages/scraper/src/scrapers/cradlepoint-oem.ts b/packages/scraper/src/scrapers/cradlepoint-oem.ts new file mode 100644 index 0000000..b0f1776 --- /dev/null +++ b/packages/scraper/src/scrapers/cradlepoint-oem.ts @@ -0,0 +1,117 @@ +/** + * Cradlepoint OEM Transceiver Catalog Seed + * + * Seeds Cradlepoint-branded transceiver PIDs for R1900, E3000, S700 series + * enterprise 5G/LTE branch routers with SFP ports. + * + * Sources: + * - Cradlepoint Hardware Compatibility Guide (cradlepoint.com) + * - R-series / E-series Router Hardware Reference + * - Cradlepoint S700 Series Datasheet + * + * Run: tsx packages/scraper/src/scrapers/cradlepoint-oem.ts + * Cron: daily at 18:15 + */ + +import { pool, ensureVendor } from "../utils/db"; + +interface CradlepointPID { + pid: string; + formFactor: string; + speedGbps: number; + speed: string; + reachMeters: number; + reachLabel: string; + fiberType: string; + connector: string; + wavelengths?: string; + standard?: string; + notes?: string; +} + +const CRADLEPOINT_PIDS: CradlepointPID[] = [ + // ── 1G SFP ────────────────────────────────────────────────────────────── + { pid: "CP-SFP-1G-SX", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 550, reachLabel: "SX", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "1000BASE-SX" }, + { pid: "CP-SFP-1G-LX", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 10000, reachLabel: "LX", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "1000BASE-LX" }, + { pid: "CP-SFP-1G-ZX", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 80000, reachLabel: "ZX", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "1000BASE-ZX" }, + { pid: "CP-SFP-1G-T", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 100, reachLabel: "T", fiberType: "DAC", connector: "RJ45", standard: "1000BASE-T" }, + { pid: "CP-SFP-1G-BXU", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 20000, reachLabel: "BXU", fiberType: "SMF", connector: "LC", wavelengths: "TX1310/RX1550nm", standard: "1000BASE-BX", notes: "Cradlepoint 1G BiDi SFP upstream" }, + { pid: "CP-SFP-1G-BXD", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 20000, reachLabel: "BXD", fiberType: "SMF", connector: "LC", wavelengths: "TX1550/RX1310nm", standard: "1000BASE-BX", notes: "Cradlepoint 1G BiDi SFP downstream" }, + + // ── 10G SFP+ ──────────────────────────────────────────────────────────── + { pid: "CP-SFP-10G-SR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 300, reachLabel: "SR", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "10GBASE-SR" }, + { pid: "CP-SFP-10G-LR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 10000, reachLabel: "LR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "10GBASE-LR" }, + { pid: "CP-SFP-10G-ER", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 40000, reachLabel: "ER", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "10GBASE-ER" }, + { pid: "CP-SFP-10G-T", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 30, reachLabel: "T", fiberType: "DAC", connector: "RJ45", standard: "10GBASE-T" }, + + // ── 25G SFP28 ─────────────────────────────────────────────────────────── + { pid: "CP-SFP28-25G-SR", formFactor: "SFP28", speedGbps: 25, speed: "25G", reachMeters: 100, reachLabel: "SR", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "25GBASE-SR" }, + { pid: "CP-SFP28-25G-LR", formFactor: "SFP28", speedGbps: 25, speed: "25G", reachMeters: 10000, reachLabel: "LR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "25GBASE-LR" }, + + // ── 100G QSFP28 ───────────────────────────────────────────────────────── + { pid: "CP-QSFP28-100G-SR4", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 100, reachLabel: "SR4", fiberType: "MMF", connector: "MPO", wavelengths: "850nm", standard: "100GBASE-SR4" }, + { pid: "CP-QSFP28-100G-LR4", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 10000, reachLabel: "LR4", fiberType: "SMF", connector: "LC", wavelengths: "1295-1310nm", standard: "100GBASE-LR4" }, + + // ── DAC ───────────────────────────────────────────────────────────────── + { pid: "CP-DAC-10G-1M", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 1, reachLabel: "DAC-1M", fiberType: "DAC", connector: "SFP+" }, + { pid: "CP-DAC-10G-3M", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 3, reachLabel: "DAC-3M", fiberType: "DAC", connector: "SFP+" }, + { pid: "CP-DAC-100G-1M", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 1, reachLabel: "DAC-1M", fiberType: "DAC", connector: "QSFP28" }, +]; + +export async function scrapeCradlepointOem(): Promise { + console.log("=== Cradlepoint OEM Transceiver Seed ===\n"); + + const vendorId = await ensureVendor( + "Cradlepoint", + "oem", + "https://www.cradlepoint.com", + undefined + ); + + let inserted = 0; + let updated = 0; + let errors = 0; + + for (const p of CRADLEPOINT_PIDS) { + const slug = `cradlepoint-${p.pid.toLowerCase().replace(/[^a-z0-9]+/g, "-")}`; + try { + const res = await pool.query( + `INSERT INTO transceivers + (slug, part_number, vendor_id, form_factor, speed, speed_gbps, + reach_meters, reach_label, fiber_type, connector, wavelengths, + dom_support, ieee_reference, market_status, category, notes) + VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,true,$12,'Mainstream','DataCenter',$13) + ON CONFLICT (slug) DO UPDATE SET + speed_gbps = EXCLUDED.speed_gbps, + reach_meters = CASE WHEN EXCLUDED.reach_meters > 0 THEN EXCLUDED.reach_meters ELSE transceivers.reach_meters END, + fiber_type = CASE WHEN EXCLUDED.fiber_type <> '' THEN EXCLUDED.fiber_type ELSE transceivers.fiber_type END, + wavelengths = COALESCE(EXCLUDED.wavelengths, transceivers.wavelengths), + updated_at = NOW() + RETURNING (xmax = 0) as was_inserted`, + [slug, p.pid, vendorId, p.formFactor, p.speed, p.speedGbps, + p.reachMeters, p.reachLabel, p.fiberType, p.connector, + p.wavelengths ?? null, p.standard ?? null, p.notes ?? null] + ); + if (res.rows[0]?.was_inserted) inserted++; else updated++; + } catch (err) { + console.warn(` Skip ${p.pid}: ${(err as Error).message.slice(0, 80)}`); + errors++; + } + } + + console.log(`\n=== Cradlepoint OEM Seed Complete ===`); + console.log(` Inserted: ${inserted}`); + console.log(` Updated: ${updated}`); + console.log(` Errors: ${errors}`); + console.log(` Total PIDs: ${CRADLEPOINT_PIDS.length}\n`); +} + +if (require.main === module) { + scrapeCradlepointOem() + .then(() => pool.end()) + .catch((err) => { + console.error("Fatal:", err); + pool.end(); + process.exit(1); + }); +} diff --git a/packages/scraper/src/scrapers/cumulus-networks-oem.ts b/packages/scraper/src/scrapers/cumulus-networks-oem.ts new file mode 100644 index 0000000..7075934 --- /dev/null +++ b/packages/scraper/src/scrapers/cumulus-networks-oem.ts @@ -0,0 +1,120 @@ +/** + * Cumulus Networks / NVIDIA OEM Transceiver Catalog Seed + * + * Seeds Cumulus-branded transceiver PIDs for Cumulus Linux NOS running + * on white-box and bare-metal switches (Open Compute, AS series, etc.). + * + * Sources: + * - Cumulus Networks Air Platform (air.cumulusnetworks.com) + * - Cumulus Linux Hardware Compatibility List (HCL) + * - NVIDIA Cumulus Linux Data Sheets and Platform Guides + * + * Run: tsx packages/scraper/src/scrapers/cumulus-networks-oem.ts + * Cron: daily at 10:45 + */ + +import { pool, ensureVendor } from "../utils/db"; + +interface CumulusPID { + pid: string; + formFactor: string; + speedGbps: number; + speed: string; + reachMeters: number; + reachLabel: string; + fiberType: string; + connector: string; + wavelengths?: string; + standard?: string; + notes?: string; +} + +const CUMULUS_PIDS: CumulusPID[] = [ + // ── 1G SFP ────────────────────────────────────────────────────────────── + { pid: "CN-SFP-1G-SX", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 550, reachLabel: "SX", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "1000BASE-SX" }, + { pid: "CN-SFP-1G-LX", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 10000, reachLabel: "LX", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "1000BASE-LX" }, + { pid: "CN-SFP-1G-T", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 100, reachLabel: "T", fiberType: "DAC", connector: "RJ45", standard: "1000BASE-T" }, + + // ── 10G SFP+ ──────────────────────────────────────────────────────────── + { pid: "CN-SFP-10G-SR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 300, reachLabel: "SR", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "10GBASE-SR" }, + { pid: "CN-SFP-10G-LR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 10000, reachLabel: "LR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "10GBASE-LR" }, + { pid: "CN-SFP-10G-ER", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 40000, reachLabel: "ER", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "10GBASE-ER" }, + + // ── 25G SFP28 ─────────────────────────────────────────────────────────── + { pid: "CN-SFP28-25G-SR", formFactor: "SFP28", speedGbps: 25, speed: "25G", reachMeters: 100, reachLabel: "SR", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "25GBASE-SR" }, + { pid: "CN-SFP28-25G-LR", formFactor: "SFP28", speedGbps: 25, speed: "25G", reachMeters: 10000, reachLabel: "LR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "25GBASE-LR" }, + + // ── 40G QSFP+ ─────────────────────────────────────────────────────────── + { pid: "CN-QSFP-40G-SR4", formFactor: "QSFP+", speedGbps: 40, speed: "40G", reachMeters: 150, reachLabel: "SR4", fiberType: "MMF", connector: "MPO", wavelengths: "850nm", standard: "40GBASE-SR4" }, + { pid: "CN-QSFP-40G-LR4", formFactor: "QSFP+", speedGbps: 40, speed: "40G", reachMeters: 10000, reachLabel: "LR4", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "40GBASE-LR4" }, + + // ── 100G QSFP28 ───────────────────────────────────────────────────────── + { pid: "CN-QSFP28-100G-SR4", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 100, reachLabel: "SR4", fiberType: "MMF", connector: "MPO", wavelengths: "850nm", standard: "100GBASE-SR4" }, + { pid: "CN-QSFP28-100G-LR4", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 10000, reachLabel: "LR4", fiberType: "SMF", connector: "LC", wavelengths: "1295-1310nm", standard: "100GBASE-LR4" }, + { pid: "CN-SFP28-100G-ER4", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 40000, reachLabel: "ER4", fiberType: "SMF", connector: "LC", wavelengths: "1295-1310nm", standard: "100GBASE-ER4", notes: "Extended reach for spine-to-spine links" }, + + // ── 400G QSFP-DD ──────────────────────────────────────────────────────── + { pid: "CN-QSFP-DD-400G-DR4", formFactor: "QSFP-DD", speedGbps: 400, speed: "400G", reachMeters: 500, reachLabel: "DR4", fiberType: "SMF", connector: "MPO", wavelengths: "1310nm", standard: "400GBASE-DR4" }, + { pid: "CN-QSFP-DD-400G-SR8", formFactor: "QSFP-DD", speedGbps: 400, speed: "400G", reachMeters: 100, reachLabel: "SR8", fiberType: "MMF", connector: "MPO", wavelengths: "850nm", standard: "400GBASE-SR8" }, + + // ── Copper SFP ────────────────────────────────────────────────────────── + { pid: "CN-SFP-GE-T", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 100, reachLabel: "T", fiberType: "DAC", connector: "RJ45", standard: "1000BASE-T", notes: "GE copper for OOB management ports" }, +]; + +export async function scrapeCumulusNetworksOem(): Promise { + console.log("=== Cumulus Networks / NVIDIA OEM Transceiver Seed ===\n"); + + const vendorId = await ensureVendor( + "Cumulus Networks", + "oem", + "https://air.cumulusnetworks.com", + undefined + ); + + let inserted = 0; + let updated = 0; + let errors = 0; + + for (const p of CUMULUS_PIDS) { + const slug = `cumulus-${p.pid.toLowerCase().replace(/[^a-z0-9]+/g, "-")}`; + try { + const res = await pool.query( + `INSERT INTO transceivers + (slug, part_number, vendor_id, form_factor, speed, speed_gbps, + reach_meters, reach_label, fiber_type, connector, wavelengths, + dom_support, ieee_reference, market_status, category, notes) + VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,true,$12,'Mainstream','DataCenter',$13) + ON CONFLICT (slug) DO UPDATE SET + speed_gbps = EXCLUDED.speed_gbps, + reach_meters = CASE WHEN EXCLUDED.reach_meters > 0 THEN EXCLUDED.reach_meters ELSE transceivers.reach_meters END, + fiber_type = CASE WHEN EXCLUDED.fiber_type <> '' THEN EXCLUDED.fiber_type ELSE transceivers.fiber_type END, + wavelengths = COALESCE(EXCLUDED.wavelengths, transceivers.wavelengths), + updated_at = NOW() + RETURNING (xmax = 0) as was_inserted`, + [slug, p.pid, vendorId, p.formFactor, p.speed, p.speedGbps, + p.reachMeters, p.reachLabel, p.fiberType, p.connector, + p.wavelengths ?? null, p.standard ?? null, p.notes ?? null] + ); + if (res.rows[0]?.was_inserted) inserted++; else updated++; + } catch (err) { + console.warn(` Skip ${p.pid}: ${(err as Error).message.slice(0, 80)}`); + errors++; + } + } + + console.log(`\n=== Cumulus Networks OEM Seed Complete ===`); + console.log(` Inserted: ${inserted}`); + console.log(` Updated: ${updated}`); + console.log(` Errors: ${errors}`); + console.log(` Total PIDs: ${CUMULUS_PIDS.length}\n`); +} + +if (require.main === module) { + scrapeCumulusNetworksOem() + .then(() => pool.end()) + .catch((err) => { + console.error("Fatal:", err); + pool.end(); + process.exit(1); + }); +} diff --git a/packages/scraper/src/scrapers/datang-oem.ts b/packages/scraper/src/scrapers/datang-oem.ts new file mode 100644 index 0000000..aa08cba --- /dev/null +++ b/packages/scraper/src/scrapers/datang-oem.ts @@ -0,0 +1,148 @@ +/** + * Datang Telecom / CICT OEM Transceiver Catalog Seed + * + * Seeds Datang-branded transceiver PIDs used in TD-LTE and 5G NR base stations, + * OTN/DWDM transport systems, and carrier Ethernet platforms from Datang Telecom + * Technology (大唐电信) and its subsidiary CICT Mobile Communication Technology. + * Includes telecom-grade OTN, CWDM, DWDM, and CFP form factors in addition to + * standard DataCenter SFP/QSFP variants. + * + * Sources: + * - CICT Mobile Product Catalog (cictmobile.com) + * - Datang Telecom TD-LTE/NR hardware guides + * - OTN/DWDM transceiver specification sheets + * - SFF-8024 and ITU-T G.698.2 DWDM channel plans + * + * Run: tsx packages/scraper/src/scrapers/datang-oem.ts + * Cron: daily at 04:00 + */ + +import { pool, ensureVendor } from "../utils/db"; + +interface DatangPID { + pid: string; + formFactor: string; + speedGbps: number; + speed: string; + reachMeters: number; + reachLabel: string; + fiberType: string; + connector: string; + wavelengths?: string; + standard?: string; + category?: string; + notes?: string; +} + +const DATANG_PIDS: DatangPID[] = [ + // ── 1G SFP (DataCenter) ───────────────────────────────────────────────── + { pid: "SFP-1G-SX", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 550, reachLabel: "SX", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "1000BASE-SX", notes: "Datang 1G SFP SX for TD-LTE eNodeB uplink" }, + { pid: "SFP-1G-LX", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 10000, reachLabel: "LX", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "1000BASE-LX" }, + { pid: "SFP-GE-T", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 100, reachLabel: "T", fiberType: "DAC", connector: "RJ45", standard: "1000BASE-T", notes: "Copper GE SFP for management/S1 interface" }, + + // ── 10G SFP+ (DataCenter) ─────────────────────────────────────────────── + { pid: "SFP-10G-SR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 300, reachLabel: "SR", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "10GBASE-SR", notes: "Datang 10G SFP+ SR for 5G NR gNB fronthaul" }, + { pid: "SFP-10G-LR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 10000, reachLabel: "LR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "10GBASE-LR" }, + { pid: "SFP-10G-ER", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 40000, reachLabel: "ER", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "10GBASE-ER" }, + + // ── 10G ZR SFP+ (Telecom — long-haul OTN backhaul) ───────────────────── + { pid: "SFP-10G-ZR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 80000, reachLabel: "ZR", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "10GBASE-ZR", category: "Telecom", notes: "Datang 10G ZR for OTN ring backhaul; carrier transport" }, + + // ── SDH / SONET OC-3 / OC-12 SFP (Telecom) ───────────────────────────── + { pid: "SFP-OC3-SR", formFactor: "SFP", speedGbps: 0.155, speed: "155M", reachMeters: 2000, reachLabel: "SR", fiberType: "MMF", connector: "LC", wavelengths: "1310nm", standard: "OC-3/STM-1", category: "Telecom", notes: "Datang OC-3/STM-1 SFP for SDH legacy circuit interconnect" }, + { pid: "SFP-OC12-SR", formFactor: "SFP", speedGbps: 0.622, speed: "622M", reachMeters: 2000, reachLabel: "SR", fiberType: "MMF", connector: "LC", wavelengths: "1310nm", standard: "OC-12/STM-4", category: "Telecom", notes: "Datang OC-12/STM-4 SFP; TD-LTE legacy SDH transport" }, + + // ── OTU2 10G SFP+ (Telecom) ───────────────────────────────────────────── + { pid: "SFP-OTU2-10G", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 40000, reachLabel: "ER", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "G.709 OTU2", category: "Telecom", notes: "Datang OTU2 10G SFP+ for OTN framing on backhaul links" }, + + // ── 25G SFP28 (DataCenter) ────────────────────────────────────────────── + { pid: "SFP28-25G-LR", formFactor: "SFP28", speedGbps: 25, speed: "25G", reachMeters: 10000, reachLabel: "LR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "25GBASE-LR", notes: "Datang 25G SFP28 for 5G NR C-RAN fronthaul (eCPRI)" }, + + // ── 40G QSFP+ (DataCenter) ────────────────────────────────────────────── + { pid: "QSFP-40G-LR4", formFactor: "QSFP+", speedGbps: 40, speed: "40G", reachMeters: 10000, reachLabel: "LR4", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "40GBASE-LR4" }, + + // ── 100G QSFP28 (DataCenter) ──────────────────────────────────────────── + { pid: "QSFP28-100G-LR4", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 10000, reachLabel: "LR4", fiberType: "SMF", connector: "LC", wavelengths: "1295-1310nm", standard: "100GBASE-LR4", notes: "Datang 100G QSFP28 LR4 for 5G midhaul aggregation" }, + + // ── CWDM SFP (Telecom) ────────────────────────────────────────────────── + { pid: "SFP-CWDM-1550", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 80000, reachLabel: "CWDM", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "G.694.2 CWDM", category: "Telecom", notes: "Datang CWDM SFP 1550nm for metro WDM rings; TD-LTE backhaul" }, + + // ── DWDM SFP (Telecom) ────────────────────────────────────────────────── + { pid: "DWDM-SFP-C", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 80000, reachLabel: "DWDM", fiberType: "SMF", connector: "LC", wavelengths: "C-band ITU", standard: "G.694.1 DWDM", category: "Telecom", notes: "Datang DWDM SFP C-band (ITU grid) for dense WDM transport" }, + + // ── CFP 100G (Telecom — OTN/coherent line-side) ───────────────────────── + { pid: "CFP-100G-LR4", formFactor: "CFP", speedGbps: 100, speed: "100G", reachMeters: 10000, reachLabel: "LR4", fiberType: "SMF", connector: "LC", wavelengths: "1295-1310nm", standard: "OIF CFP", category: "Telecom", notes: "Datang 100G CFP LR4 for OTN/SDN line card; carrier transport" }, + + // ── 400G QSFP-DD (DataCenter) ─────────────────────────────────────────── + { pid: "QSFP-DD-400G-DR4", formFactor: "QSFP-DD",speedGbps: 400, speed: "400G", reachMeters: 500, reachLabel: "DR4", fiberType: "SMF", connector: "MPO", wavelengths: "1310nm", standard: "400GBASE-DR4", notes: "Datang 400G QSFP-DD for 5G core DC interconnect" }, +]; + +// PIDs classified as Telecom (OTN, SONET/SDH, CWDM, DWDM, coherent CFP, ZR) +const TELECOM_PIDS = new Set([ + "SFP-10G-ZR", + "SFP-OC3-SR", + "SFP-OC12-SR", + "SFP-OTU2-10G", + "SFP-CWDM-1550", + "DWDM-SFP-C", + "CFP-100G-LR4", +]); + +export async function scrapeDatangOem(): Promise { + console.log("=== Datang Telecom / CICT OEM Transceiver Seed ===\n"); + + const vendorId = await ensureVendor( + "Datang Telecom", + "oem", + "https://www.cictmobile.com", + undefined + ); + + let inserted = 0; + let updated = 0; + let errors = 0; + + for (const p of DATANG_PIDS) { + const slug = `datang-${p.pid.toLowerCase().replace(/[^a-z0-9]+/g, "-")}`; + const category = p.category ?? (TELECOM_PIDS.has(p.pid) ? "Telecom" : "DataCenter"); + try { + const res = await pool.query( + `INSERT INTO transceivers + (slug, part_number, vendor_id, form_factor, speed, speed_gbps, + reach_meters, reach_label, fiber_type, connector, wavelengths, + dom_support, ieee_reference, market_status, category, notes) + VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,true,$12,'Mainstream',$13,$14) + ON CONFLICT (slug) DO UPDATE SET + speed_gbps = EXCLUDED.speed_gbps, + reach_meters = CASE WHEN EXCLUDED.reach_meters > 0 THEN EXCLUDED.reach_meters ELSE transceivers.reach_meters END, + fiber_type = CASE WHEN EXCLUDED.fiber_type <> '' THEN EXCLUDED.fiber_type ELSE transceivers.fiber_type END, + wavelengths = COALESCE(EXCLUDED.wavelengths, transceivers.wavelengths), + updated_at = NOW() + RETURNING (xmax = 0) as was_inserted`, + [slug, p.pid, vendorId, p.formFactor, p.speed, p.speedGbps, + p.reachMeters, p.reachLabel, p.fiberType, p.connector, + p.wavelengths ?? null, p.standard ?? null, category, p.notes ?? null] + ); + if (res.rows[0]?.was_inserted) inserted++; else updated++; + } catch (err) { + console.warn(` Skip ${p.pid}: ${(err as Error).message.slice(0, 80)}`); + errors++; + } + } + + console.log(`\n=== Datang OEM Seed Complete ===`); + console.log(` Inserted: ${inserted}`); + console.log(` Updated: ${updated}`); + console.log(` Errors: ${errors}`); + console.log(` Total PIDs: ${DATANG_PIDS.length}\n`); +} + +if (require.main === module) { + scrapeDatangOem() + .then(() => pool.end()) + .catch((err) => { + console.error("Fatal:", err); + pool.end(); + process.exit(1); + }); +} diff --git a/packages/scraper/src/scrapers/dell-storage-oem.ts b/packages/scraper/src/scrapers/dell-storage-oem.ts new file mode 100644 index 0000000..8c79340 --- /dev/null +++ b/packages/scraper/src/scrapers/dell-storage-oem.ts @@ -0,0 +1,341 @@ +/** + * Dell Storage OEM Transceiver Catalog Seed + * + * Seeds Dell Storage-branded transceiver PIDs for PowerStore, PowerMax, + * Unity XT, and SC Series (Compellent) SAN storage systems. Covers FC, + * iSCSI, and NVMe-oF host/target optical modules specific to Dell SAN storage. + * + * Sources: + * - Dell Technologies Compatibility Matrix (dell.com/support) + * - Dell PowerStore/PowerMax Hardware Installation Guides + * - Dell Unity XT Expansion Module optical compatibility tables + * + * Run: tsx packages/scraper/src/scrapers/dell-storage-oem.ts + * Cron: daily at 06:45 + */ + +import { pool, ensureVendor } from "../utils/db"; + +interface DellStoragePID { + pid: string; + formFactor: string; + speedGbps: number; + speed: string; + reachMeters: number; + reachLabel: string; + fiberType: string; + connector: string; + wavelengths?: string; + standard?: string; + notes?: string; +} + +// Fibre Channel line-rate speeds (Gbps): +// 8G = 8.5 Gbps (8GFC) +// 16G = 14.025 Gbps (16GFC) +// 32G = 28.05 Gbps (32GFC) +// 64G = 56.1 Gbps (64GFC) +const DELL_STORAGE_PIDS: DellStoragePID[] = [ + // ── 8G FC SFP+ ─────────────────────────────────────────────────────────── + { + pid: "DELL-SFP-8G-FC-SW", + formFactor: "SFP+", + speedGbps: 8.5, + speed: "8G FC", + reachMeters: 150, + reachLabel: "SW", + fiberType: "MMF", + connector: "LC", + wavelengths: "850nm", + standard: "8GFC", + notes: "8G FC SFP+ SW; Dell PowerStore/Unity XT FC host port; OM3/OM4 MMF up to 150m", + }, + { + pid: "DELL-SFP-8G-FC-LW", + formFactor: "SFP+", + speedGbps: 8.5, + speed: "8G FC", + reachMeters: 10000, + reachLabel: "LW", + fiberType: "SMF", + connector: "LC", + wavelengths: "1310nm", + standard: "8GFC", + notes: "8G FC SFP+ LW; Dell PowerStore/Unity XT FC host port long-reach; OS2 SMF up to 10km", + }, + // ── 16G FC SFP+ ────────────────────────────────────────────────────────── + { + pid: "DELL-SFP-16G-FC-SW", + formFactor: "SFP+", + speedGbps: 14.025, + speed: "16G FC", + reachMeters: 125, + reachLabel: "SW", + fiberType: "MMF", + connector: "LC", + wavelengths: "850nm", + standard: "16GFC", + notes: "16G FC SFP+ SW; Dell PowerStore 500T/1000T/3000T FC target port; OM4 MMF up to 125m", + }, + { + pid: "DELL-SFP-16G-FC-LW", + formFactor: "SFP+", + speedGbps: 14.025, + speed: "16G FC", + reachMeters: 10000, + reachLabel: "LW", + fiberType: "SMF", + connector: "LC", + wavelengths: "1310nm", + standard: "16GFC", + notes: "16G FC SFP+ LW; Dell PowerStore 500T/1000T/3000T FC target port long-reach; OS2 SMF", + }, + // ── 32G FC SFP28 ───────────────────────────────────────────────────────── + { + pid: "DELL-SFP-32G-FC-SW", + formFactor: "SFP28", + speedGbps: 28.05, + speed: "32G FC", + reachMeters: 100, + reachLabel: "SW", + fiberType: "MMF", + connector: "LC", + wavelengths: "850nm", + standard: "32GFC", + notes: "32G FC SFP28 SW; Dell PowerStore 5000T/9000T NVMe/FC port; OM4/OM5 MMF", + }, + // ── 64G FC SFP28 ───────────────────────────────────────────────────────── + { + pid: "DELL-SFP28-64G-FC-SW", + formFactor: "SFP28", + speedGbps: 56.1, + speed: "64G FC", + reachMeters: 70, + reachLabel: "SW", + fiberType: "MMF", + connector: "LC", + wavelengths: "850nm", + standard: "64GFC", + notes: "64G FC SFP28 SW; Dell PowerMax 2500/8500 next-gen NVMe/FC; OM5 WBMMF up to 70m", + }, + // ── 10GbE SFP+ ─────────────────────────────────────────────────────────── + { + pid: "DELL-SFP-10G-SR", + formFactor: "SFP+", + speedGbps: 10, + speed: "10G", + reachMeters: 300, + reachLabel: "SR", + fiberType: "MMF", + connector: "LC", + wavelengths: "850nm", + standard: "10GBASE-SR", + notes: "10GbE SFP+ SR; Dell Unity XT/SC Series iSCSI and FCoE host port; OM3/OM4 MMF", + }, + { + pid: "DELL-SFP-10G-LR", + formFactor: "SFP+", + speedGbps: 10, + speed: "10G", + reachMeters: 10000, + reachLabel: "LR", + fiberType: "SMF", + connector: "LC", + wavelengths: "1310nm", + standard: "10GBASE-LR", + notes: "10GbE SFP+ LR; Dell Unity XT/SC Series iSCSI long-reach; OS2 SMF up to 10km", + }, + // ── 25GbE SFP28 ────────────────────────────────────────────────────────── + { + pid: "DELL-SFP28-25G-SR", + formFactor: "SFP28", + speedGbps: 25, + speed: "25G", + reachMeters: 100, + reachLabel: "SR", + fiberType: "MMF", + connector: "LC", + wavelengths: "850nm", + standard: "25GBASE-SR", + notes: "25GbE SFP28 SR; Dell PowerStore NVMe-oF iSCSI host port; OM4 MMF", + }, + { + pid: "DELL-SFP28-25G-LR", + formFactor: "SFP28", + speedGbps: 25, + speed: "25G", + reachMeters: 10000, + reachLabel: "LR", + fiberType: "SMF", + connector: "LC", + wavelengths: "1310nm", + standard: "25GBASE-LR", + notes: "25GbE SFP28 LR; Dell PowerStore NVMe-oF iSCSI host port long-reach; OS2 SMF", + }, + // ── 100GbE QSFP28 ──────────────────────────────────────────────────────── + { + pid: "DELL-QSFP28-100G-SR4", + formFactor: "QSFP28", + speedGbps: 100, + speed: "100G", + reachMeters: 100, + reachLabel: "SR4", + fiberType: "MMF", + connector: "MPO", + wavelengths: "850nm", + standard: "100GBASE-SR4", + notes: "100GbE QSFP28 SR4; Dell PowerStore/PowerMax backend replication interconnect; OM4 MPO-12", + }, + { + pid: "DELL-QSFP28-100G-LR4", + formFactor: "QSFP28", + speedGbps: 100, + speed: "100G", + reachMeters: 10000, + reachLabel: "LR4", + fiberType: "SMF", + connector: "LC", + wavelengths: "1295-1310nm", + standard: "100GBASE-LR4", + notes: "100GbE QSFP28 LR4; Dell PowerStore/PowerMax replication long-reach; OS2 SMF", + }, + // ── 400GbE QSFP-DD ─────────────────────────────────────────────────────── + { + pid: "DELL-QSFP-DD-400G-DR4", + formFactor: "QSFP-DD", + speedGbps: 400, + speed: "400G", + reachMeters: 500, + reachLabel: "DR4", + fiberType: "SMF", + connector: "MPO", + wavelengths: "1310nm", + standard: "400GBASE-DR4", + notes: "400GbE QSFP-DD DR4; Dell PowerMax next-gen NVMe-oF fabric; OS2 SMF up to 500m", + }, + // ── 1GbE SFP ───────────────────────────────────────────────────────────── + { + pid: "DELL-SFP-1G-SX", + formFactor: "SFP", + speedGbps: 1, + speed: "1G", + reachMeters: 550, + reachLabel: "SX", + fiberType: "MMF", + connector: "LC", + wavelengths: "850nm", + standard: "1000BASE-SX", + notes: "1GbE SFP SX; Dell storage management and iSCSI port; OM2/OM3 MMF", + }, + { + pid: "DELL-SFP-1G-LX", + formFactor: "SFP", + speedGbps: 1, + speed: "1G", + reachMeters: 10000, + reachLabel: "LX", + fiberType: "SMF", + connector: "LC", + wavelengths: "1310nm", + standard: "1000BASE-LX", + notes: "1GbE SFP LX; Dell storage management and iSCSI port long-reach; OS2 SMF", + }, + // ── Copper SFP ─────────────────────────────────────────────────────────── + { + pid: "DELL-SFP-1G-T", + formFactor: "SFP", + speedGbps: 1, + speed: "1G", + reachMeters: 100, + reachLabel: "T", + fiberType: "DAC", + connector: "RJ45", + standard: "1000BASE-T", + notes: "1GbE copper SFP RJ45; Dell storage management copper option; Cat5e/6", + }, + // ── 40GbE QSFP+ ────────────────────────────────────────────────────────── + { + pid: "DELL-QSFP-40G-SR4", + formFactor: "QSFP+", + speedGbps: 40, + speed: "40G", + reachMeters: 150, + reachLabel: "SR4", + fiberType: "MMF", + connector: "MPO", + wavelengths: "850nm", + standard: "40GBASE-SR4", + notes: "40GbE QSFP+ SR4; Dell storage fabric switch uplink; OM3/OM4 MPO-12", + }, + { + pid: "DELL-QSFP-40G-LR4", + formFactor: "QSFP+", + speedGbps: 40, + speed: "40G", + reachMeters: 10000, + reachLabel: "LR4", + fiberType: "SMF", + connector: "LC", + wavelengths: "1310nm", + standard: "40GBASE-LR4", + notes: "40GbE QSFP+ LR4; Dell storage fabric switch uplink long-reach; OS2 SMF", + }, +]; + +export async function scrapeDellStorageOem(): Promise { + console.log("=== Dell Storage OEM Transceiver Seed ===\n"); + + const vendorId = await ensureVendor( + "Dell Storage", + "oem", + "https://www.dell.com/en-us/dt/storage/", + undefined + ); + + let inserted = 0; + let updated = 0; + let errors = 0; + + for (const p of DELL_STORAGE_PIDS) { + const slug = `dell-storage-${p.pid.toLowerCase().replace(/[^a-z0-9]+/g, "-")}`; + try { + const res = await pool.query( + `INSERT INTO transceivers + (slug, part_number, vendor_id, form_factor, speed, speed_gbps, + reach_meters, reach_label, fiber_type, connector, wavelengths, + dom_support, ieee_reference, market_status, category, notes) + VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,true,$12,'Mainstream','DataCenter',$13) + ON CONFLICT (slug) DO UPDATE SET + speed_gbps = EXCLUDED.speed_gbps, + reach_meters = CASE WHEN EXCLUDED.reach_meters > 0 THEN EXCLUDED.reach_meters ELSE transceivers.reach_meters END, + fiber_type = CASE WHEN EXCLUDED.fiber_type <> '' THEN EXCLUDED.fiber_type ELSE transceivers.fiber_type END, + wavelengths = COALESCE(EXCLUDED.wavelengths, transceivers.wavelengths), + updated_at = NOW() + RETURNING (xmax = 0) as was_inserted`, + [slug, p.pid, vendorId, p.formFactor, p.speed, p.speedGbps, + p.reachMeters, p.reachLabel, p.fiberType, p.connector, + p.wavelengths ?? null, p.standard ?? null, p.notes ?? null] + ); + if (res.rows[0]?.was_inserted) inserted++; else updated++; + } catch (err) { + console.warn(` Skip ${p.pid}: ${(err as Error).message.slice(0, 80)}`); + errors++; + } + } + + console.log(`\n=== Dell Storage OEM Seed Complete ===`); + console.log(` Inserted: ${inserted}`); + console.log(` Updated: ${updated}`); + console.log(` Errors: ${errors}`); + console.log(` Total PIDs: ${DELL_STORAGE_PIDS.length}\n`); +} + +if (require.main === module) { + scrapeDellStorageOem() + .then(() => pool.end()) + .catch((err) => { + console.error("Fatal:", err); + pool.end(); + process.exit(1); + }); +} diff --git a/packages/scraper/src/scrapers/dlink-oem.ts b/packages/scraper/src/scrapers/dlink-oem.ts new file mode 100644 index 0000000..ef303bd --- /dev/null +++ b/packages/scraper/src/scrapers/dlink-oem.ts @@ -0,0 +1,125 @@ +/** + * D-Link OEM Transceiver Catalog Seed + * + * Seeds D-Link-branded transceiver PIDs for DGS, DXS, and DBS + * series managed switches. + * Sources: D-Link Transceiver Module Datasheet (dlink.com) + * Run: tsx packages/scraper/src/scrapers/dlink-oem.ts + * Cron: daily at 09:45 + */ + +import { pool, ensureVendor } from "../utils/db"; + +interface DlinkPID { + pid: string; + formFactor: string; + speedGbps: number; + speed: string; + reachMeters: number; + reachLabel: string; + fiberType: string; + connector: string; + wavelengths?: string; + standard?: string; + notes?: string; +} + +const DLINK_PIDS: DlinkPID[] = [ + // ── 1G SFP ────────────────────────────────────────────────────────────── + { pid: "DEM-310GT", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 550, reachLabel: "SX", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "1000BASE-SX" }, + { pid: "DEM-311GT", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 10000, reachLabel: "LX", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "1000BASE-LX" }, + { pid: "DEM-314GT", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 80000, reachLabel: "ZX", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "1000BASE-ZX" }, + { pid: "DEM-315GT", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 40000, reachLabel: "LH40", fiberType: "SMF", connector: "LC", wavelengths: "1310nm" }, + { pid: "DEM-302S-LX", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 10000, reachLabel: "LX", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "1000BASE-LX", notes: "Simplex" }, + { pid: "DEM-330T", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 10000, reachLabel: "BiDi-1310", fiberType: "SMF", connector: "LC", wavelengths: "1310/1550nm", notes: "WDM TX1310/RX1550" }, + { pid: "DEM-330R", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 10000, reachLabel: "BiDi-1550", fiberType: "SMF", connector: "LC", wavelengths: "1550/1310nm", notes: "WDM TX1550/RX1310" }, + { pid: "DEM-301T", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 100, reachLabel: "T", fiberType: "DAC", connector: "RJ45", standard: "1000BASE-T" }, + + // ── 10G SFP+ ──────────────────────────────────────────────────────────── + { pid: "DEM-431XT", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 300, reachLabel: "SR", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "10GBASE-SR" }, + { pid: "DEM-432XT", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 10000, reachLabel: "LR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "10GBASE-LR" }, + { pid: "DEM-433XT", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 40000, reachLabel: "ER", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "10GBASE-ER" }, + { pid: "DEM-434XT", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 80000, reachLabel: "ZR", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "10GBASE-ZR" }, + { pid: "DEM-435XT", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 220, reachLabel: "LRM", fiberType: "MMF", connector: "LC", wavelengths: "1310nm", standard: "10GBASE-LRM" }, + { pid: "DEM-CB100S-T", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 30, reachLabel: "T", fiberType: "DAC", connector: "RJ45", standard: "10GBASE-T", notes: "Copper RJ45" }, + { pid: "DEM-436XT-BXU", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 10000, reachLabel: "BiDi-1270", fiberType: "SMF", connector: "LC", wavelengths: "1270/1330nm", notes: "BiDi TX1270" }, + { pid: "DEM-436XT-BXD", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 10000, reachLabel: "BiDi-1330", fiberType: "SMF", connector: "LC", wavelengths: "1330/1270nm", notes: "BiDi TX1330" }, + + // ── 25G SFP28 ─────────────────────────────────────────────────────────── + { pid: "DEM-25GSR", formFactor: "SFP28", speedGbps: 25, speed: "25G", reachMeters: 100, reachLabel: "SR", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "25GBASE-SR" }, + { pid: "DEM-25GLR", formFactor: "SFP28", speedGbps: 25, speed: "25G", reachMeters: 10000, reachLabel: "LR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "25GBASE-LR" }, + + // ── 40G QSFP+ ─────────────────────────────────────────────────────────── + { pid: "DEM-Q40GSR", formFactor: "QSFP+", speedGbps: 40, speed: "40G", reachMeters: 150, reachLabel: "SR4", fiberType: "MMF", connector: "MPO", wavelengths: "850nm", standard: "40GBASE-SR4" }, + { pid: "DEM-Q40MLR4", formFactor: "QSFP+", speedGbps: 40, speed: "40G", reachMeters: 10000, reachLabel: "LR4", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "40GBASE-LR4" }, + + // ── 100G QSFP28 ───────────────────────────────────────────────────────── + { pid: "DEM-Q28SR4", formFactor: "QSFP28",speedGbps: 100, speed: "100G", reachMeters: 100, reachLabel: "SR4", fiberType: "MMF", connector: "MPO", wavelengths: "850nm", standard: "100GBASE-SR4" }, + { pid: "DEM-Q28LR4", formFactor: "QSFP28",speedGbps: 100, speed: "100G", reachMeters: 10000, reachLabel: "LR4", fiberType: "SMF", connector: "LC", wavelengths: "1295-1310nm", standard: "100GBASE-LR4" }, + { pid: "DEM-Q28CWDM4", formFactor: "QSFP28",speedGbps: 100, speed: "100G", reachMeters: 2000, reachLabel: "CWDM4", fiberType: "SMF", connector: "LC", wavelengths: "1271-1331nm", standard: "100GBASE-CWDM4" }, + + // ── DAC ───────────────────────────────────────────────────────────────── + { pid: "DEM-CB100S", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 1, reachLabel: "DAC-1M", fiberType: "DAC", connector: "SFP+", notes: "10G DAC 1m" }, + { pid: "DEM-CB300S", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 3, reachLabel: "DAC-3M", fiberType: "DAC", connector: "SFP+" }, + { pid: "DEM-CB100Q", formFactor: "QSFP+", speedGbps: 40, speed: "40G", reachMeters: 1, reachLabel: "DAC-1M", fiberType: "DAC", connector: "QSFP+" }, + { pid: "DEM-CB100C", formFactor: "QSFP28",speedGbps: 100, speed: "100G", reachMeters: 1, reachLabel: "DAC-1M", fiberType: "DAC", connector: "QSFP28", notes: "100G DAC 1m" }, + { pid: "DEM-CB300C", formFactor: "QSFP28",speedGbps: 100, speed: "100G", reachMeters: 3, reachLabel: "DAC-3M", fiberType: "DAC", connector: "QSFP28" }, +]; + +export async function scrapeDlinkOem(): Promise { + console.log("=== D-Link OEM Transceiver Seed ===\n"); + + const vendorId = await ensureVendor( + "D-Link", + "oem", + "https://www.dlink.com", + undefined + ); + + let inserted = 0; + let updated = 0; + let errors = 0; + + for (const p of DLINK_PIDS) { + const slug = `dlink-${p.pid.toLowerCase().replace(/[^a-z0-9]+/g, "-")}`; + try { + const res = await pool.query( + `INSERT INTO transceivers + (slug, part_number, vendor_id, form_factor, speed, speed_gbps, + reach_meters, reach_label, fiber_type, connector, wavelengths, + dom_support, ieee_reference, market_status, category, notes) + VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,true,$12,'Mainstream','DataCenter',$13) + ON CONFLICT (slug) DO UPDATE SET + speed_gbps = EXCLUDED.speed_gbps, + reach_meters = CASE WHEN EXCLUDED.reach_meters > 0 THEN EXCLUDED.reach_meters ELSE transceivers.reach_meters END, + fiber_type = CASE WHEN EXCLUDED.fiber_type <> '' THEN EXCLUDED.fiber_type ELSE transceivers.fiber_type END, + wavelengths = COALESCE(EXCLUDED.wavelengths, transceivers.wavelengths), + updated_at = NOW() + RETURNING (xmax = 0) as was_inserted`, + [slug, p.pid, vendorId, p.formFactor, p.speed, p.speedGbps, + p.reachMeters, p.reachLabel, p.fiberType, p.connector, + p.wavelengths ?? null, p.standard ?? null, p.notes ?? null] + ); + if (res.rows[0]?.was_inserted) inserted++; else updated++; + } catch (err) { + console.warn(` Skip ${p.pid}: ${(err as Error).message.slice(0, 80)}`); + errors++; + } + } + + console.log(`\n=== D-Link OEM Seed Complete ===`); + console.log(` Inserted: ${inserted}`); + console.log(` Updated: ${updated}`); + console.log(` Errors: ${errors}`); + console.log(` Total PIDs: ${DLINK_PIDS.length}\n`); +} + +if (require.main === module) { + scrapeDlinkOem() + .then(() => pool.end()) + .catch((err) => { + console.error("Fatal:", err); + pool.end(); + process.exit(1); + }); +} diff --git a/packages/scraper/src/scrapers/drivenets-oem.ts b/packages/scraper/src/scrapers/drivenets-oem.ts new file mode 100644 index 0000000..07fabbd --- /dev/null +++ b/packages/scraper/src/scrapers/drivenets-oem.ts @@ -0,0 +1,128 @@ +/** + * DriveNets OEM Transceiver Catalog Seed + * + * Seeds DriveNets-branded transceiver PIDs for the Network Cloud (DNOS) + * distributed routing NOS running on white-box hardware (Comcast/Lumen + * Network Cloud deployments, DNOS-on-COTS). + * + * Sources: + * - DriveNets Network Cloud Hardware Guide (drivenets.com) + * - DriveNets DNOS Transceiver Compatibility Matrix + * - DriveNets 400G/800G Data Center Interconnect Deployment Guide + * + * Run: tsx packages/scraper/src/scrapers/drivenets-oem.ts + * Cron: daily at 15:00 + */ + +import { pool, ensureVendor } from "../utils/db"; + +interface DrivenetsPID { + pid: string; + formFactor: string; + speedGbps: number; + speed: string; + reachMeters: number; + reachLabel: string; + fiberType: string; + connector: string; + wavelengths?: string; + standard?: string; + category?: string; + notes?: string; +} + +// ── DriveNets OEM transceiver catalog ─────────────────────────────────────── +// Source: DriveNets Network Cloud HCL and DNOS platform guides +const DRIVENETS_PIDS: DrivenetsPID[] = [ + // ── 1G SFP ────────────────────────────────────────────────────────────── + { pid: "DN-SFP-1G-SX", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 550, reachLabel: "SX", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "1000BASE-SX", notes: "DriveNets 1G MM SFP for DNOS white-box management ports" }, + { pid: "DN-SFP-1G-LX", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 10000, reachLabel: "LX", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "1000BASE-LX", notes: "DriveNets 1G SM SFP 10km for DNOS Network Cloud mgmt" }, + + // ── 10G SFP+ ──────────────────────────────────────────────────────────── + { pid: "DN-SFP-10G-SR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 300, reachLabel: "SR", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "10GBASE-SR", notes: "DriveNets 10G SR SFP+ for DNOS distributed router fabric" }, + { pid: "DN-SFP-10G-LR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 10000, reachLabel: "LR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "10GBASE-LR", notes: "DriveNets 10G LR SFP+ 10km for DNOS inter-cluster links" }, + { pid: "DN-SFP-10G-ER", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 40000, reachLabel: "ER", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "10GBASE-ER", notes: "DriveNets 10G ER 40km for DNOS metro DCI aggregation" }, + { pid: "DN-SFP-10G-ZR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 80000, reachLabel: "ZR", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "10GBASE-ZR", notes: "DriveNets 10G ZR 80km dark-fiber for DNOS edge PoP" }, + + // ── 25G SFP28 ─────────────────────────────────────────────────────────── + { pid: "DN-SFP28-25G-SR", formFactor: "SFP28", speedGbps: 25, speed: "25G", reachMeters: 100, reachLabel: "SR", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "25GBASE-SR", notes: "DriveNets 25G SR SFP28 for DNOS white-box server downlinks" }, + { pid: "DN-SFP28-25G-LR", formFactor: "SFP28", speedGbps: 25, speed: "25G", reachMeters: 10000, reachLabel: "LR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "25GBASE-LR", notes: "DriveNets 25G LR SFP28 for DNOS Network Cloud fabric uplinks" }, + + // ── 100G QSFP28 ───────────────────────────────────────────────────────── + { pid: "DN-QSFP28-100G-SR4", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 100, reachLabel: "SR4", fiberType: "MMF", connector: "MPO", wavelengths: "850nm", standard: "100GBASE-SR4", notes: "DriveNets 100G SR4 QSFP28 for DNOS white-box 100G chassis" }, + { pid: "DN-QSFP28-100G-LR4", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 10000, reachLabel: "LR4", fiberType: "SMF", connector: "LC", wavelengths: "1295-1310nm", standard: "100GBASE-LR4", notes: "DriveNets 100G LR4 QSFP28 for DNOS inter-PoP DCI" }, + { pid: "DN-QSFP28-100G-ZR4", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 80000, reachLabel: "ZR4", fiberType: "SMF", connector: "LC", wavelengths: "C-band", standard: "100G ZR4", category: "Telecom", notes: "DriveNets 100G ZR4 coherent QSFP28 for DNOS long-haul DCI" }, + + // ── 400G QSFP-DD ──────────────────────────────────────────────────────── + { pid: "DN-QSFP-DD-400G-DR4", formFactor: "QSFP-DD", speedGbps: 400, speed: "400G", reachMeters: 500, reachLabel: "DR4", fiberType: "SMF", connector: "MPO", wavelengths: "1310nm", standard: "400GBASE-DR4", notes: "DriveNets 400G DR4 QSFP-DD for DNOS Network Cloud fabric" }, + { pid: "DN-QSFP-DD-400G-SR8", formFactor: "QSFP-DD", speedGbps: 400, speed: "400G", reachMeters: 100, reachLabel: "SR8", fiberType: "MMF", connector: "MPO", wavelengths: "850nm", standard: "400GBASE-SR8", notes: "DriveNets 400G SR8 QSFP-DD for DNOS OM4 cluster fabric" }, + { pid: "DN-QSFP-DD-400G-ZR", formFactor: "QSFP-DD", speedGbps: 400, speed: "400G", reachMeters: 120000, reachLabel: "ZR", fiberType: "SMF", connector: "LC", wavelengths: "C-band", standard: "400ZR", category: "Telecom", notes: "DriveNets 400G ZR coherent QSFP-DD for DNOS open-line DCI" }, + + // ── 800G QSFP-DD ──────────────────────────────────────────────────────── + { pid: "DN-QSFP-DD-800G-DR8", formFactor: "QSFP-DD", speedGbps: 800, speed: "800G", reachMeters: 500, reachLabel: "DR8", fiberType: "SMF", connector: "MPO", wavelengths: "1310nm", standard: "800GBASE-DR8", notes: "DriveNets 800G DR8 QSFP-DD for next-gen DNOS hyper-scale fabric" }, +]; + +// PIDs that use 'Telecom' category (coherent ZR/ZR4) +const TELECOM_PIDS = new Set([ + "DN-QSFP28-100G-ZR4", + "DN-QSFP-DD-400G-ZR", +]); + +export async function scrapeDrivenetsOem(): Promise { + console.log("=== DriveNets OEM Transceiver Seed ===\n"); + + const vendorId = await ensureVendor( + "DriveNets", + "oem", + "https://drivenets.com", + undefined + ); + + let inserted = 0; + let updated = 0; + let errors = 0; + + for (const p of DRIVENETS_PIDS) { + const slug = `drivenets-${p.pid.toLowerCase().replace(/[^a-z0-9]+/g, "-")}`; + const category = p.category ?? (TELECOM_PIDS.has(p.pid) ? "Telecom" : "DataCenter"); + try { + const res = await pool.query( + `INSERT INTO transceivers + (slug, part_number, vendor_id, form_factor, speed, speed_gbps, + reach_meters, reach_label, fiber_type, connector, wavelengths, + dom_support, ieee_reference, market_status, category, notes) + VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,true,$12,'Mainstream',$13,$14) + ON CONFLICT (slug) DO UPDATE SET + speed_gbps = EXCLUDED.speed_gbps, + reach_meters = CASE WHEN EXCLUDED.reach_meters > 0 THEN EXCLUDED.reach_meters ELSE transceivers.reach_meters END, + fiber_type = CASE WHEN EXCLUDED.fiber_type <> '' THEN EXCLUDED.fiber_type ELSE transceivers.fiber_type END, + wavelengths = COALESCE(EXCLUDED.wavelengths, transceivers.wavelengths), + updated_at = NOW() + RETURNING (xmax = 0) as was_inserted`, + [slug, p.pid, vendorId, p.formFactor, p.speed, p.speedGbps, + p.reachMeters, p.reachLabel, p.fiberType, p.connector, + p.wavelengths ?? null, p.standard ?? null, category, p.notes ?? null] + ); + if (res.rows[0]?.was_inserted) inserted++; else updated++; + } catch (err) { + console.warn(` Skip ${p.pid}: ${(err as Error).message.slice(0, 80)}`); + errors++; + } + } + + console.log(`\n=== DriveNets OEM Seed Complete ===`); + console.log(` Inserted: ${inserted}`); + console.log(` Updated: ${updated}`); + console.log(` Errors: ${errors}`); + console.log(` Total PIDs: ${DRIVENETS_PIDS.length}\n`); +} + +if (require.main === module) { + scrapeDrivenetsOem() + .then(() => pool.end()) + .catch((err) => { + console.error("Fatal:", err); + pool.end(); + process.exit(1); + }); +} diff --git a/packages/scraper/src/scrapers/dzs-oem.ts b/packages/scraper/src/scrapers/dzs-oem.ts new file mode 100644 index 0000000..c24354c --- /dev/null +++ b/packages/scraper/src/scrapers/dzs-oem.ts @@ -0,0 +1,129 @@ +/** + * DZS OEM Transceiver Catalog Seed + * + * Seeds DZS-branded transceiver PIDs for FiberXtend, E-series, MXK, + * and MALC fiber access / broadband platforms (formerly Zhone Technologies). + * + * Sources: + * - DZS Product Catalog (dzsi.com) + * - DZS MXK / MALC Hardware Reference Guides + * - DZS FiberXtend Platform Data Sheets + * + * Run: tsx packages/scraper/src/scrapers/dzs-oem.ts + * Cron: daily at 13:45 + */ + +import { pool, ensureVendor } from "../utils/db"; + +interface DzsPID { + pid: string; + formFactor: string; + speedGbps: number; + speed: string; + reachMeters: number; + reachLabel: string; + fiberType: string; + connector: string; + wavelengths?: string; + standard?: string; + notes?: string; +} + +const DZS_PIDS: DzsPID[] = [ + // ── 1G SFP — GPON / EPON OLT ──────────────────────────────────────────── + { pid: "SFP-GPON-CLASS-B+", formFactor: "SFP", speedGbps: 1, speed: "GPON", reachMeters: 20000, reachLabel: "GPON-20K", fiberType: "SMF", connector: "SC", wavelengths: "1490/1310nm", standard: "G.984", notes: "DZS GPON OLT SFP Class B+" }, + { pid: "SFP-GPON-CLASS-C+", formFactor: "SFP", speedGbps: 1, speed: "GPON", reachMeters: 20000, reachLabel: "GPON-C+", fiberType: "SMF", connector: "SC", wavelengths: "1490/1310nm", notes: "DZS GPON OLT SFP Class C+" }, + { pid: "SFP-EPON-1G", formFactor: "SFP", speedGbps: 1, speed: "EPON", reachMeters: 20000, reachLabel: "EPON-20K", fiberType: "SMF", connector: "SC", wavelengths: "1490/1310nm", standard: "802.3ah", notes: "DZS EPON OLT SFP 1G/1G" }, + + // ── 1G SFP — Standard ──────────────────────────────────────────────────── + { pid: "SFP-1G-SX", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 550, reachLabel: "SX", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "1000BASE-SX" }, + { pid: "SFP-1G-LX", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 10000, reachLabel: "LX", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "1000BASE-LX" }, + { pid: "SFP-1G-ZX", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 80000, reachLabel: "ZX", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "1000BASE-ZX" }, + { pid: "SFP-1G-T", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 100, reachLabel: "T", fiberType: "DAC", connector: "RJ45", standard: "1000BASE-T" }, + + // ── 10G SFP+ — XGS-PON OLT ─────────────────────────────────────────────── + { pid: "SFP-XGS-PON", formFactor: "SFP+", speedGbps: 10, speed: "XGS-PON", reachMeters: 20000, reachLabel: "XGS-PON", fiberType: "SMF", connector: "SC", wavelengths: "1577/1270nm", standard: "G.9807.1", notes: "DZS XGS-PON OLT SFP+" }, + + // ── 10G SFP+ — Standard ────────────────────────────────────────────────── + { pid: "SFP-10G-SR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 300, reachLabel: "SR", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "10GBASE-SR" }, + { pid: "SFP-10G-LR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 10000, reachLabel: "LR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "10GBASE-LR" }, + { pid: "SFP-10G-ER", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 40000, reachLabel: "ER", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "10GBASE-ER" }, + { pid: "SFP-10G-ZR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 80000, reachLabel: "ZR", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "10GBASE-ZR" }, + { pid: "SFP-10G-T", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 30, reachLabel: "T", fiberType: "DAC", connector: "RJ45", standard: "10GBASE-T" }, + + // ── 25G SFP28 ──────────────────────────────────────────────────────────── + { pid: "SFP28-25G-SR", formFactor: "SFP28", speedGbps: 25, speed: "25G", reachMeters: 100, reachLabel: "SR", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "25GBASE-SR" }, + { pid: "SFP28-25G-LR", formFactor: "SFP28", speedGbps: 25, speed: "25G", reachMeters: 10000, reachLabel: "LR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "25GBASE-LR" }, + + // ── 40G QSFP+ ──────────────────────────────────────────────────────────── + { pid: "QSFP-40G-SR4", formFactor: "QSFP+", speedGbps: 40, speed: "40G", reachMeters: 150, reachLabel: "SR4", fiberType: "MMF", connector: "MPO", wavelengths: "850nm", standard: "40GBASE-SR4" }, + { pid: "QSFP-40G-LR4", formFactor: "QSFP+", speedGbps: 40, speed: "40G", reachMeters: 10000, reachLabel: "LR4", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "40GBASE-LR4" }, + + // ── 100G QSFP28 ────────────────────────────────────────────────────────── + { pid: "QSFP28-100G-SR4", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 100, reachLabel: "SR4", fiberType: "MMF", connector: "MPO", wavelengths: "850nm", standard: "100GBASE-SR4" }, + { pid: "QSFP28-100G-LR4", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 10000, reachLabel: "LR4", fiberType: "SMF", connector: "LC", wavelengths: "1295-1310nm", standard: "100GBASE-LR4" }, + { pid: "QSFP28-100G-CWDM4", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 2000, reachLabel: "CWDM4", fiberType: "SMF", connector: "LC", wavelengths: "1271-1331nm", standard: "100GBASE-CWDM4" }, + + // ── DAC ────────────────────────────────────────────────────────────────── + { pid: "DAC-10G-1M", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 1, reachLabel: "DAC-1M", fiberType: "DAC", connector: "SFP+" }, + { pid: "DAC-10G-3M", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 3, reachLabel: "DAC-3M", fiberType: "DAC", connector: "SFP+" }, + { pid: "DAC-100G-1M", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 1, reachLabel: "DAC-1M", fiberType: "DAC", connector: "QSFP28" }, +]; + +export async function scrapeDzsOem(): Promise { + console.log("=== DZS OEM Transceiver Seed ===\n"); + + const vendorId = await ensureVendor( + "DZS", + "oem", + "https://www.dzsi.com", + undefined + ); + + let inserted = 0; + let updated = 0; + let errors = 0; + + for (const p of DZS_PIDS) { + const slug = `dzs-${p.pid.toLowerCase().replace(/[^a-z0-9]+/g, "-")}`; + try { + const res = await pool.query( + `INSERT INTO transceivers + (slug, part_number, vendor_id, form_factor, speed, speed_gbps, + reach_meters, reach_label, fiber_type, connector, wavelengths, + dom_support, ieee_reference, market_status, category, notes) + VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,true,$12,'Mainstream','DataCenter',$13) + ON CONFLICT (slug) DO UPDATE SET + speed_gbps = EXCLUDED.speed_gbps, + reach_meters = CASE WHEN EXCLUDED.reach_meters > 0 THEN EXCLUDED.reach_meters ELSE transceivers.reach_meters END, + fiber_type = CASE WHEN EXCLUDED.fiber_type <> '' THEN EXCLUDED.fiber_type ELSE transceivers.fiber_type END, + wavelengths = COALESCE(EXCLUDED.wavelengths, transceivers.wavelengths), + updated_at = NOW() + RETURNING (xmax = 0) as was_inserted`, + [slug, p.pid, vendorId, p.formFactor, p.speed, p.speedGbps, + p.reachMeters, p.reachLabel, p.fiberType, p.connector, + p.wavelengths ?? null, p.standard ?? null, p.notes ?? null] + ); + if (res.rows[0]?.was_inserted) inserted++; else updated++; + } catch (err) { + console.warn(` Skip ${p.pid}: ${(err as Error).message.slice(0, 80)}`); + errors++; + } + } + + console.log(`\n=== DZS OEM Seed Complete ===`); + console.log(` Inserted: ${inserted}`); + console.log(` Updated: ${updated}`); + console.log(` Errors: ${errors}`); + console.log(` Total PIDs: ${DZS_PIDS.length}\n`); +} + +if (require.main === module) { + scrapeDzsOem() + .then(() => pool.end()) + .catch((err) => { + console.error("Fatal:", err); + pool.end(); + process.exit(1); + }); +} diff --git a/packages/scraper/src/scrapers/edgewater-networks-oem.ts b/packages/scraper/src/scrapers/edgewater-networks-oem.ts new file mode 100644 index 0000000..de34e42 --- /dev/null +++ b/packages/scraper/src/scrapers/edgewater-networks-oem.ts @@ -0,0 +1,139 @@ +/** + * Edgewater Networks OEM Transceiver Catalog Seed + * + * Seeds Edgewater Networks (Ribbon EdgeMarc) branded transceiver PIDs for + * session border controller (SBC) and enterprise edge platforms. + * Edgewater Networks / Ribbon EdgeMarc builds session border controllers + * and enterprise edge devices (EdgeMarc 6000/7000 series) used by UCaaS + * providers and enterprises for SIP trunking and unified communications. + * + * Sources: + * - Ribbon EdgeMarc Pluggable Module Compatibility Guide + * - Edgewater Networks SFP/QSFP Interface Data Sheets + * - ribboncommunications.com EdgeMarc product catalogue + * + * Run: tsx packages/scraper/src/scrapers/edgewater-networks-oem.ts + * Cron: daily at 02:00 + */ + +import { pool, ensureVendor } from "../utils/db"; + +interface EdgewaterPID { + pid: string; + formFactor: string; + speedGbps: number; + speed: string; + reachMeters: number; + reachLabel: string; + fiberType: string; + connector: string; + wavelengths?: string; + standard?: string; + category?: string; + notes?: string; +} + +const EDGEWATER_PIDS: EdgewaterPID[] = [ + // ── 1G SFP ────────────────────────────────────────────────────────────── + { pid: "SFP-1G-SX", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 550, reachLabel: "SX", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "1000BASE-SX" }, + { pid: "SFP-1G-LX", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 10000, reachLabel: "LX", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "1000BASE-LX" }, + { pid: "SFP-1G-T", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 100, reachLabel: "T", fiberType: "Cu", connector: "RJ45", standard: "1000BASE-T" }, + { pid: "SFP-GE-T", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 100, reachLabel: "T", fiberType: "Cu", connector: "RJ45", standard: "1000BASE-T", notes: "Edgewater GE copper SFP for EdgeMarc management ports" }, + + // ── 10G SFP+ ──────────────────────────────────────────────────────────── + { pid: "SFP-10G-SR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 300, reachLabel: "SR", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "10GBASE-SR" }, + { pid: "SFP-10G-LR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 10000, reachLabel: "LR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "10GBASE-LR" }, + { pid: "SFP-10G-ER", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 40000, reachLabel: "ER", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "10GBASE-ER" }, + { pid: "SFP-10G-ZR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 80000, reachLabel: "ZR", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "10GBASE-ZR", category: "Telecom", notes: "Edgewater 10G ZR for extended SBC uplinks" }, + + // ── BiDi SFP ───────────────────────────────────────────────────────────── + { pid: "SFP-BIDI-1310-1550", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 40000, reachLabel: "BiDi", fiberType: "SMF", connector: "LC", wavelengths: "1310/1550nm", category: "Telecom", notes: "Edgewater BiDi SFP 1310nm TX / 1550nm RX single-fibre" }, + + // ── SONET/SDH SFP (OC-3 / STM-1) ───────────────────────────────────────── + { pid: "SFP-OC3-SR", formFactor: "SFP", speedGbps: 0.155, speed: "OC3", reachMeters: 2000, reachLabel: "SR", fiberType: "MMF", connector: "LC", wavelengths: "1310nm", standard: "OC-3/STM-1", category: "Telecom", notes: "Edgewater OC-3 short-reach SFP for TDM-over-IP gateway" }, + { pid: "SFP-OC3-LR", formFactor: "SFP", speedGbps: 0.155, speed: "OC3", reachMeters: 15000, reachLabel: "LR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "OC-3/STM-1", category: "Telecom", notes: "Edgewater OC-3 long-reach SFP for TDM-over-IP gateway" }, + + // ── SONET/SDH SFP (OC-12 / STM-4) ──────────────────────────────────────── + { pid: "SFP-OC12-SR", formFactor: "SFP", speedGbps: 0.622, speed: "OC12", reachMeters: 2000, reachLabel: "SR", fiberType: "MMF", connector: "LC", wavelengths: "1310nm", standard: "OC-12/STM-4", category: "Telecom", notes: "Edgewater OC-12 short-reach SFP" }, + + // ── 40G QSFP+ ──────────────────────────────────────────────────────────── + { pid: "QSFP-40G-LR4", formFactor: "QSFP+", speedGbps: 40, speed: "40G", reachMeters: 10000, reachLabel: "LR4", fiberType: "SMF", connector: "LC", wavelengths: "1270-1330nm", standard: "40GBASE-LR4" }, + + // ── 100G QSFP28 ────────────────────────────────────────────────────────── + { pid: "QSFP-100G-LR4", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 10000, reachLabel: "LR4", fiberType: "SMF", connector: "LC", wavelengths: "1295-1310nm", standard: "100GBASE-LR4" }, + + // ── 25G SFP28 ──────────────────────────────────────────────────────────── + { pid: "SFP-25G-LR", formFactor: "SFP28", speedGbps: 25, speed: "25G", reachMeters: 10000, reachLabel: "LR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "25GBASE-LR" }, + + // ── DWDM SFP ───────────────────────────────────────────────────────────── + { pid: "DWDM-SFP-C", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 80000, reachLabel: "DWDM", fiberType: "SMF", connector: "LC", wavelengths: "C-band DWDM", category: "Telecom", notes: "Edgewater ITU-T DWDM C-band SFP for WDM aggregation" }, +]; + +// PIDs that use 'Telecom' category (SONET/SDH, DWDM, BiDi, ZR) +const TELECOM_PIDS = new Set([ + "SFP-10G-ZR", + "SFP-BIDI-1310-1550", + "SFP-OC3-SR", + "SFP-OC3-LR", + "SFP-OC12-SR", + "DWDM-SFP-C", +]); + +export async function scrapeEdgewaterNetworksOem(): Promise { + console.log("=== Edgewater Networks OEM Transceiver Seed ===\n"); + + const vendorId = await ensureVendor( + "Edgewater Networks", + "oem", + "https://www.ribboncommunications.com/products/enterprise-products/edgewater-networks", + undefined + ); + + let inserted = 0; + let updated = 0; + let errors = 0; + + for (const p of EDGEWATER_PIDS) { + const slug = `edgewater-${p.pid.toLowerCase().replace(/[^a-z0-9]+/g, "-")}`; + const category = p.category ?? (TELECOM_PIDS.has(p.pid) ? "Telecom" : "DataCenter"); + try { + const res = await pool.query( + `INSERT INTO transceivers + (slug, part_number, vendor_id, form_factor, speed, speed_gbps, + reach_meters, reach_label, fiber_type, connector, wavelengths, + dom_support, ieee_reference, market_status, category, notes) + VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,true,$12,'Mainstream',$13,$14) + ON CONFLICT (slug) DO UPDATE SET + speed_gbps = EXCLUDED.speed_gbps, + reach_meters = CASE WHEN EXCLUDED.reach_meters > 0 THEN EXCLUDED.reach_meters ELSE transceivers.reach_meters END, + fiber_type = CASE WHEN EXCLUDED.fiber_type <> '' THEN EXCLUDED.fiber_type ELSE transceivers.fiber_type END, + wavelengths = COALESCE(EXCLUDED.wavelengths, transceivers.wavelengths), + updated_at = NOW() + RETURNING (xmax = 0) as was_inserted`, + [slug, p.pid, vendorId, p.formFactor, p.speed, p.speedGbps, + p.reachMeters, p.reachLabel, p.fiberType, p.connector, + p.wavelengths ?? null, p.standard ?? null, category, p.notes ?? null] + ); + if (res.rows[0]?.was_inserted) inserted++; else updated++; + } catch (err) { + console.warn(` Skip ${p.pid}: ${(err as Error).message.slice(0, 80)}`); + errors++; + } + } + + console.log(`\n=== Edgewater Networks OEM Seed Complete ===`); + console.log(` Inserted: ${inserted}`); + console.log(` Updated: ${updated}`); + console.log(` Errors: ${errors}`); + console.log(` Total PIDs: ${EDGEWATER_PIDS.length}\n`); +} + +if (require.main === module) { + scrapeEdgewaterNetworksOem() + .then(() => pool.end()) + .catch((err) => { + console.error("Fatal:", err); + pool.end(); + process.exit(1); + }); +} diff --git a/packages/scraper/src/scrapers/ekinops-oem.ts b/packages/scraper/src/scrapers/ekinops-oem.ts new file mode 100644 index 0000000..7e199af --- /dev/null +++ b/packages/scraper/src/scrapers/ekinops-oem.ts @@ -0,0 +1,132 @@ +/** + * Ekinops OEM Transceiver Catalog Seed + * + * Seeds Ekinops-branded transceiver PIDs for optical transport and access + * equipment platforms: 300 series, 360 series, and OneAccess platforms. + * + * Sources: + * - Ekinops 300 Series Line Card Datasheet + * - Ekinops 360 Series Transceiver Module Guide + * - Ekinops OneAccess Platform Product Portfolio (ekinops.com) + * + * Run: tsx packages/scraper/src/scrapers/ekinops-oem.ts + * Cron: daily at 20:30 + */ + +import { pool, ensureVendor } from "../utils/db"; + +interface EkinopsPID { + pid: string; + formFactor: string; + speedGbps: number; + speed: string; + reachMeters: number; + reachLabel: string; + fiberType: string; + connector: string; + wavelengths?: string; + standard?: string; + category?: string; + notes?: string; +} + +const EKINOPS_PIDS: EkinopsPID[] = [ + // ── 1G SFP ────────────────────────────────────────────────────────────── + { pid: "EK-SFP-1G-SX", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 550, reachLabel: "SX", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "1000BASE-SX" }, + { pid: "EK-SFP-1G-LX", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 10000, reachLabel: "LX", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "1000BASE-LX" }, + { pid: "EK-SFP-1G-ZX", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 80000, reachLabel: "ZX", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "1000BASE-ZX" }, + + // ── 10G SFP+ ──────────────────────────────────────────────────────────── + { pid: "EK-SFP-10G-SR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 300, reachLabel: "SR", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "10GBASE-SR" }, + { pid: "EK-SFP-10G-LR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 10000, reachLabel: "LR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "10GBASE-LR" }, + { pid: "EK-SFP-10G-ER", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 40000, reachLabel: "ER", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "10GBASE-ER" }, + { pid: "EK-SFP-10G-ZR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 80000, reachLabel: "ZR", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "10GBASE-ZR" }, + + // ── 10G DWDM SFP+ ─────────────────────────────────────────────────────── + { pid: "EK-SFP-10G-DW-C-TUNE", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 80000, reachLabel: "DWDM", fiberType: "SMF", connector: "LC", wavelengths: "C-band DWDM", category: "Telecom", notes: "Ekinops 10G DWDM tunable SFP+" }, + + // ── 100G QSFP28 ───────────────────────────────────────────────────────── + { pid: "EK-QSFP28-100G-SR4", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 100, reachLabel: "SR4", fiberType: "MMF", connector: "MPO", wavelengths: "850nm", standard: "100GBASE-SR4" }, + { pid: "EK-QSFP28-100G-LR4", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 10000, reachLabel: "LR4", fiberType: "SMF", connector: "LC", wavelengths: "1295-1310nm", standard: "100GBASE-LR4" }, + { pid: "EK-QSFP28-100G-CWDM4", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 2000, reachLabel: "CWDM4", fiberType: "SMF", connector: "LC", wavelengths: "1271-1331nm", standard: "100GBASE-CWDM4" }, + + // ── 100G CFP2 Coherent ─────────────────────────────────────────────────── + { pid: "EK-CFP2-100G-DCO", formFactor: "CFP2", speedGbps: 100, speed: "100G", reachMeters: 1500000, reachLabel: "DCO", fiberType: "SMF", connector: "LC", wavelengths: "C-band", category: "Telecom", notes: "Ekinops 100G CFP2 DCO coherent" }, + + // ── 400G QSFP-DD ──────────────────────────────────────────────────────── + { pid: "EK-QSFPDD-400G-FR4", formFactor: "QSFP-DD", speedGbps: 400, speed: "400G", reachMeters: 2000, reachLabel: "FR4", fiberType: "SMF", connector: "LC", wavelengths: "1271-1331nm", standard: "400GBASE-FR4" }, + { pid: "EK-QSFPDD-400G-LR4", formFactor: "QSFP-DD", speedGbps: 400, speed: "400G", reachMeters: 10000, reachLabel: "LR4", fiberType: "SMF", connector: "LC", wavelengths: "1295-1310nm", standard: "400GBASE-LR4" }, + { pid: "EK-QSFPDD-400G-ZR", formFactor: "QSFP-DD", speedGbps: 400, speed: "400G", reachMeters: 120000, reachLabel: "ZR", fiberType: "SMF", connector: "LC", wavelengths: "C-band", standard: "400ZR", category: "Telecom", notes: "Ekinops 400G ZR coherent QSFP-DD" }, + { pid: "EK-QSFPDD-400G-ZRP", formFactor: "QSFP-DD", speedGbps: 400, speed: "400G", reachMeters: 3000000, reachLabel: "ZR+", fiberType: "SMF", connector: "LC", wavelengths: "C-band", category: "Telecom", notes: "Ekinops 400G ZR+ coherent QSFP-DD" }, + + // ── DAC ───────────────────────────────────────────────────────────────── + { pid: "EK-DAC-10G-1M", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 1, reachLabel: "DAC-1M", fiberType: "DAC", connector: "SFP+" }, + { pid: "EK-DAC-100G-1M", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 1, reachLabel: "DAC-1M", fiberType: "DAC", connector: "QSFP28" }, +]; + +// PIDs that use 'Telecom' category (coherent/DWDM) +const TELECOM_PIDS = new Set([ + "EK-SFP-10G-DW-C-TUNE", + "EK-CFP2-100G-DCO", + "EK-QSFPDD-400G-ZR", + "EK-QSFPDD-400G-ZRP", +]); + +export async function scrapeEkinopsOem(): Promise { + console.log("=== Ekinops OEM Transceiver Seed ===\n"); + + const vendorId = await ensureVendor( + "Ekinops", + "oem", + "https://www.ekinops.com", + undefined + ); + + let inserted = 0; + let updated = 0; + let errors = 0; + + for (const p of EKINOPS_PIDS) { + const slug = `ekinops-${p.pid.toLowerCase().replace(/[^a-z0-9]+/g, "-")}`; + const category = p.category ?? (TELECOM_PIDS.has(p.pid) ? "Telecom" : "DataCenter"); + try { + const res = await pool.query( + `INSERT INTO transceivers + (slug, part_number, vendor_id, form_factor, speed, speed_gbps, + reach_meters, reach_label, fiber_type, connector, wavelengths, + dom_support, ieee_reference, market_status, category, notes) + VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,true,$12,'Mainstream',$13,$14) + ON CONFLICT (slug) DO UPDATE SET + speed_gbps = EXCLUDED.speed_gbps, + reach_meters = CASE WHEN EXCLUDED.reach_meters > 0 THEN EXCLUDED.reach_meters ELSE transceivers.reach_meters END, + fiber_type = CASE WHEN EXCLUDED.fiber_type <> '' THEN EXCLUDED.fiber_type ELSE transceivers.fiber_type END, + wavelengths = COALESCE(EXCLUDED.wavelengths, transceivers.wavelengths), + updated_at = NOW() + RETURNING (xmax = 0) as was_inserted`, + [slug, p.pid, vendorId, p.formFactor, p.speed, p.speedGbps, + p.reachMeters, p.reachLabel, p.fiberType, p.connector, + p.wavelengths ?? null, p.standard ?? null, category, p.notes ?? null] + ); + if (res.rows[0]?.was_inserted) inserted++; else updated++; + } catch (err) { + console.warn(` Skip ${p.pid}: ${(err as Error).message.slice(0, 80)}`); + errors++; + } + } + + console.log(`\n=== Ekinops OEM Seed Complete ===`); + console.log(` Inserted: ${inserted}`); + console.log(` Updated: ${updated}`); + console.log(` Errors: ${errors}`); + console.log(` Total PIDs: ${EKINOPS_PIDS.length}\n`); +} + +if (require.main === module) { + scrapeEkinopsOem() + .then(() => pool.end()) + .catch((err) => { + console.error("Fatal:", err); + pool.end(); + process.exit(1); + }); +} diff --git a/packages/scraper/src/scrapers/emulex-oem.ts b/packages/scraper/src/scrapers/emulex-oem.ts new file mode 100644 index 0000000..b902957 --- /dev/null +++ b/packages/scraper/src/scrapers/emulex-oem.ts @@ -0,0 +1,342 @@ +/** + * Emulex / Broadcom OEM Transceiver Catalog Seed + * + * Seeds Emulex-branded transceiver PIDs for Fibre Channel HBAs and + * FCoE/Ethernet CNAs. Emulex is now owned by Broadcom but continues + * shipping adapters under the Emulex brand in FC storage markets. + * + * Sources: + * - Broadcom FC Networking products (broadcom.com/products/fibre-channel-networking) + * - Emulex LightPulse HBA optical transceiver guides + * - SFF-8024 Fibre Channel speed codes + * + * Run: tsx packages/scraper/src/scrapers/emulex-oem.ts + * Cron: daily at 05:30 + */ + +import { pool, ensureVendor } from "../utils/db"; + +interface EmulexPID { + pid: string; + formFactor: string; + speedGbps: number; + speed: string; + reachMeters: number; + reachLabel: string; + fiberType: string; + connector: string; + wavelengths?: string; + standard?: string; + notes?: string; +} + +// Fibre Channel line-rate speeds (Gbps): +// 4G = 4.25 Gbps (2x FC) +// 8G = 8.5 Gbps (4x FC) +// 16G = 14.025 Gbps (8x FC) +// 32G = 28.05 Gbps (16x FC) +// 64G = 56.1 Gbps (32x FC) +const EMULEX_PIDS: EmulexPID[] = [ + // ── 4G FC SFP ──────────────────────────────────────────────────────────── + { + pid: "EML-SFP-4G-FC-SW", + formFactor: "SFP", + speedGbps: 4.25, + speed: "4G FC", + reachMeters: 380, + reachLabel: "SW", + fiberType: "MMF", + connector: "LC", + wavelengths: "850nm", + standard: "4GFC", + notes: "4G FC short-wave; OM2/OM3 MMF; Emulex LightPulse LP1150/LP11002 HBAs", + }, + // ── 8G FC SFP ──────────────────────────────────────────────────────────── + { + pid: "EML-SFP-8G-FC-SW", + formFactor: "SFP", + speedGbps: 8.5, + speed: "8G FC", + reachMeters: 150, + reachLabel: "SW", + fiberType: "MMF", + connector: "LC", + wavelengths: "850nm", + standard: "8GFC", + notes: "8G FC short-wave; OM3/OM4 MMF; Emulex LightPulse LPe12000 HBAs", + }, + { + pid: "EML-SFP-8G-FC-LW", + formFactor: "SFP", + speedGbps: 8.5, + speed: "8G FC", + reachMeters: 10000, + reachLabel: "LW", + fiberType: "SMF", + connector: "LC", + wavelengths: "1310nm", + standard: "8GFC", + notes: "8G FC long-wave; OS2 SMF; extended-distance SAN trunks", + }, + // ── 16G FC SFP ─────────────────────────────────────────────────────────── + { + pid: "EML-SFP-16G-FC-SW", + formFactor: "SFP", + speedGbps: 14.025, + speed: "16G FC", + reachMeters: 125, + reachLabel: "SW", + fiberType: "MMF", + connector: "LC", + wavelengths: "850nm", + standard: "16GFC", + notes: "16G FC short-wave; OM4 MMF; Emulex LightPulse LPe16000 HBAs", + }, + { + pid: "EML-SFP-16G-FC-LW", + formFactor: "SFP", + speedGbps: 14.025, + speed: "16G FC", + reachMeters: 10000, + reachLabel: "LW", + fiberType: "SMF", + connector: "LC", + wavelengths: "1310nm", + standard: "16GFC", + notes: "16G FC long-wave; OS2 SMF; inter-building SAN connectivity", + }, + // ── 32G FC SFP+ ────────────────────────────────────────────────────────── + { + pid: "EML-SFP-32G-FC-SW", + formFactor: "SFP+", + speedGbps: 28.05, + speed: "32G FC", + reachMeters: 100, + reachLabel: "SW", + fiberType: "MMF", + connector: "LC", + wavelengths: "850nm", + standard: "32GFC", + notes: "32G FC short-wave; OM4/OM5 MMF; Emulex LightPulse LPe32000 HBAs", + }, + { + pid: "EML-SFP-32G-FC-LW", + formFactor: "SFP+", + speedGbps: 28.05, + speed: "32G FC", + reachMeters: 10000, + reachLabel: "LW", + fiberType: "SMF", + connector: "LC", + wavelengths: "1310nm", + standard: "32GFC", + notes: "32G FC long-wave; OS2 SMF; campus SAN interconnect", + }, + // ── 64G FC SFP28 ───────────────────────────────────────────────────────── + { + pid: "EML-SFP28-64G-FC-SW", + formFactor: "SFP28", + speedGbps: 56.1, + speed: "64G FC", + reachMeters: 100, + reachLabel: "SW", + fiberType: "MMF", + connector: "LC", + wavelengths: "850nm", + standard: "64GFC", + notes: "64G FC short-wave; OM4/OM5 MMF; Broadcom/Emulex LPe36000 NVMe/FC HBAs", + }, + // ── FCoE SFP+ ──────────────────────────────────────────────────────────── + { + pid: "EML-SFP-FCoE-10G-SR", + formFactor: "SFP+", + speedGbps: 10, + speed: "10G", + reachMeters: 300, + reachLabel: "SR", + fiberType: "MMF", + connector: "LC", + wavelengths: "850nm", + standard: "10GBASE-SR", + notes: "10GbE SFP+ SR for Emulex OneConnect OCe10100 FCoE CNA", + }, + { + pid: "EML-SFP-FCoE-10G-LR", + formFactor: "SFP+", + speedGbps: 10, + speed: "10G", + reachMeters: 10000, + reachLabel: "LR", + fiberType: "SMF", + connector: "LC", + wavelengths: "1310nm", + standard: "10GBASE-LR", + notes: "10GbE SFP+ LR for Emulex OneConnect FCoE CNA", + }, + // ── 10G Ethernet SFP+ ──────────────────────────────────────────────────── + { + pid: "EML-SFP-10G-SR", + formFactor: "SFP+", + speedGbps: 10, + speed: "10G", + reachMeters: 300, + reachLabel: "SR", + fiberType: "MMF", + connector: "LC", + wavelengths: "850nm", + standard: "10GBASE-SR", + notes: "10GbE SFP+ SR for Emulex OneConnect 10GbE NIC", + }, + { + pid: "EML-SFP-10G-LR", + formFactor: "SFP+", + speedGbps: 10, + speed: "10G", + reachMeters: 10000, + reachLabel: "LR", + fiberType: "SMF", + connector: "LC", + wavelengths: "1310nm", + standard: "10GBASE-LR", + notes: "10GbE SFP+ LR for Emulex OneConnect 10GbE NIC", + }, + // ── 25G Ethernet SFP28 ─────────────────────────────────────────────────── + { + pid: "EML-SFP-25G-SR", + formFactor: "SFP28", + speedGbps: 25, + speed: "25G", + reachMeters: 100, + reachLabel: "SR", + fiberType: "MMF", + connector: "LC", + wavelengths: "850nm", + standard: "25GBASE-SR", + notes: "25GbE SFP28 SR for Broadcom/Emulex Ethernet CNA", + }, + { + pid: "EML-SFP-25G-LR", + formFactor: "SFP28", + speedGbps: 25, + speed: "25G", + reachMeters: 10000, + reachLabel: "LR", + fiberType: "SMF", + connector: "LC", + wavelengths: "1310nm", + standard: "25GBASE-LR", + notes: "25GbE SFP28 LR for Broadcom/Emulex Ethernet CNA", + }, + // ── 100G QSFP28 ────────────────────────────────────────────────────────── + { + pid: "EML-QSFP28-100G-SR4", + formFactor: "QSFP28", + speedGbps: 100, + speed: "100G", + reachMeters: 100, + reachLabel: "SR4", + fiberType: "MMF", + connector: "MPO", + wavelengths: "850nm", + standard: "100GBASE-SR4", + notes: "100GbE QSFP28 SR4; Broadcom/Emulex 100G CNA modules", + }, + { + pid: "EML-QSFP28-100G-LR4", + formFactor: "QSFP28", + speedGbps: 100, + speed: "100G", + reachMeters: 10000, + reachLabel: "LR4", + fiberType: "SMF", + connector: "LC", + wavelengths: "1295-1310nm", + standard: "100GBASE-LR4", + notes: "100GbE QSFP28 LR4; Broadcom/Emulex 100G CNA modules", + }, + // ── 1G Ethernet SFP ────────────────────────────────────────────────────── + { + pid: "EML-SFP-1G-SX", + formFactor: "SFP", + speedGbps: 1, + speed: "1G", + reachMeters: 550, + reachLabel: "SX", + fiberType: "MMF", + connector: "LC", + wavelengths: "850nm", + standard: "1000BASE-SX", + notes: "1GbE SFP SX for Emulex management and iSCSI ports", + }, + { + pid: "EML-SFP-1G-LX", + formFactor: "SFP", + speedGbps: 1, + speed: "1G", + reachMeters: 10000, + reachLabel: "LX", + fiberType: "SMF", + connector: "LC", + wavelengths: "1310nm", + standard: "1000BASE-LX", + notes: "1GbE SFP LX for Emulex management and iSCSI ports", + }, +]; + +export async function scrapeEmulexOem(): Promise { + console.log("=== Emulex / Broadcom OEM Transceiver Seed ===\n"); + + const vendorId = await ensureVendor( + "Emulex", + "oem", + "https://www.broadcom.com/products/fibre-channel-networking/", + undefined + ); + + let inserted = 0; + let updated = 0; + let errors = 0; + + for (const p of EMULEX_PIDS) { + const slug = `emulex-${p.pid.toLowerCase().replace(/[^a-z0-9]+/g, "-")}`; + try { + const res = await pool.query( + `INSERT INTO transceivers + (slug, part_number, vendor_id, form_factor, speed, speed_gbps, + reach_meters, reach_label, fiber_type, connector, wavelengths, + dom_support, ieee_reference, market_status, category, notes) + VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,true,$12,'Mainstream','DataCenter',$13) + ON CONFLICT (slug) DO UPDATE SET + speed_gbps = EXCLUDED.speed_gbps, + reach_meters = CASE WHEN EXCLUDED.reach_meters > 0 THEN EXCLUDED.reach_meters ELSE transceivers.reach_meters END, + fiber_type = CASE WHEN EXCLUDED.fiber_type <> '' THEN EXCLUDED.fiber_type ELSE transceivers.fiber_type END, + wavelengths = COALESCE(EXCLUDED.wavelengths, transceivers.wavelengths), + updated_at = NOW() + RETURNING (xmax = 0) as was_inserted`, + [slug, p.pid, vendorId, p.formFactor, p.speed, p.speedGbps, + p.reachMeters, p.reachLabel, p.fiberType, p.connector, + p.wavelengths ?? null, p.standard ?? null, p.notes ?? null] + ); + if (res.rows[0]?.was_inserted) inserted++; else updated++; + } catch (err) { + console.warn(` Skip ${p.pid}: ${(err as Error).message.slice(0, 80)}`); + errors++; + } + } + + console.log(`\n=== Emulex OEM Seed Complete ===`); + console.log(` Inserted: ${inserted}`); + console.log(` Updated: ${updated}`); + console.log(` Errors: ${errors}`); + console.log(` Total PIDs: ${EMULEX_PIDS.length}\n`); +} + +if (require.main === module) { + scrapeEmulexOem() + .then(() => pool.end()) + .catch((err) => { + console.error("Fatal:", err); + pool.end(); + process.exit(1); + }); +} diff --git a/packages/scraper/src/scrapers/ericsson-oem.ts b/packages/scraper/src/scrapers/ericsson-oem.ts new file mode 100644 index 0000000..8a48a54 --- /dev/null +++ b/packages/scraper/src/scrapers/ericsson-oem.ts @@ -0,0 +1,138 @@ +/** + * Ericsson OEM Transceiver Catalog Seed + * + * Seeds Ericsson-branded transceiver PIDs for MINI-LINK, Router 6000, + * and SAOS-based platforms (formerly Corecess/Zhone). + * + * Sources: + * - Ericsson Transceiver Module Product Guide (ericsson.com) + * - Ericsson Router 6000 Hardware Guide + * - Ericsson SAOS Platform Hardware Reference + * + * Run: tsx packages/scraper/src/scrapers/ericsson-oem.ts + * Cron: daily at 06:45 + */ + +import { pool, ensureVendor } from "../utils/db"; + +interface EricssonPID { + pid: string; + formFactor: string; + speedGbps: number; + speed: string; + reachMeters: number; + reachLabel: string; + fiberType: string; + connector: string; + wavelengths?: string; + standard?: string; + notes?: string; +} + +const ERICSSON_PIDS: EricssonPID[] = [ + // ── 1G SFP ────────────────────────────────────────────────────────────── + { pid: "ROF137 R1A", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 550, reachLabel: "SX", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "1000BASE-SX", notes: "Ericsson 1G SX SFP" }, + { pid: "ROF137 R2A", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 10000, reachLabel: "LX", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "1000BASE-LX", notes: "Ericsson 1G LX SFP" }, + { pid: "ROF137 R3A", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 40000, reachLabel: "LH40", fiberType: "SMF", connector: "LC", wavelengths: "1310nm" }, + { pid: "ROF137 R4A", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 80000, reachLabel: "ZX", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "1000BASE-ZX" }, + { pid: "ROF137 R5A", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 100, reachLabel: "T", fiberType: "DAC", connector: "RJ45", standard: "1000BASE-T" }, + + // ── 10G SFP+ ──────────────────────────────────────────────────────────── + { pid: "ROF155 R1A", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 300, reachLabel: "SR", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "10GBASE-SR", notes: "Ericsson 10G SR SFP+" }, + { pid: "ROF155 R2A", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 10000, reachLabel: "LR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "10GBASE-LR", notes: "Ericsson 10G LR SFP+" }, + { pid: "ROF155 R3A", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 40000, reachLabel: "ER", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "10GBASE-ER" }, + { pid: "ROF155 R4A", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 80000, reachLabel: "ZR", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "10GBASE-ZR" }, + { pid: "ROF155 R5A", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 220, reachLabel: "LRM", fiberType: "MMF", connector: "LC", wavelengths: "1310nm", standard: "10GBASE-LRM" }, + { pid: "ROF155 R6A", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 30, reachLabel: "T", fiberType: "DAC", connector: "RJ45", standard: "10GBASE-T" }, + + // ── 10G DWDM SFP+ ─────────────────────────────────────────────────────── + { pid: "ROF155 D1A", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 80000, reachLabel: "DWDM", fiberType: "SMF", connector: "LC", wavelengths: "C-band", notes: "10G DWDM tunable SFP+ for Router 6000" }, + + // ── 25G SFP28 ─────────────────────────────────────────────────────────── + { pid: "ROF166 R1A", formFactor: "SFP28", speedGbps: 25, speed: "25G", reachMeters: 100, reachLabel: "SR", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "25GBASE-SR" }, + { pid: "ROF166 R2A", formFactor: "SFP28", speedGbps: 25, speed: "25G", reachMeters: 10000, reachLabel: "LR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "25GBASE-LR" }, + { pid: "ROF166 R3A", formFactor: "SFP28", speedGbps: 25, speed: "25G", reachMeters: 30000, reachLabel: "ER", fiberType: "SMF", connector: "LC", wavelengths: "1310nm" }, + + // ── 40G QSFP+ ─────────────────────────────────────────────────────────── + { pid: "ROF177 R1A", formFactor: "QSFP+", speedGbps: 40, speed: "40G", reachMeters: 150, reachLabel: "SR4", fiberType: "MMF", connector: "MPO", wavelengths: "850nm", standard: "40GBASE-SR4" }, + { pid: "ROF177 R2A", formFactor: "QSFP+", speedGbps: 40, speed: "40G", reachMeters: 10000, reachLabel: "LR4", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "40GBASE-LR4" }, + { pid: "ROF177 R3A", formFactor: "QSFP+", speedGbps: 40, speed: "40G", reachMeters: 10000, reachLabel: "PLR4", fiberType: "SMF", connector: "MPO", wavelengths: "1310nm", notes: "PSM4 parallel single-mode" }, + + // ── 100G QSFP28 ───────────────────────────────────────────────────────── + { pid: "ROF188 R1A", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 100, reachLabel: "SR4", fiberType: "MMF", connector: "MPO", wavelengths: "850nm", standard: "100GBASE-SR4" }, + { pid: "ROF188 R2A", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 10000, reachLabel: "LR4", fiberType: "SMF", connector: "LC", wavelengths: "1295-1310nm", standard: "100GBASE-LR4" }, + { pid: "ROF188 R3A", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 2000, reachLabel: "CWDM4", fiberType: "SMF", connector: "LC", wavelengths: "1271-1331nm", standard: "100GBASE-CWDM4" }, + { pid: "ROF188 R4A", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 500, reachLabel: "DR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "100GBASE-DR" }, + { pid: "ROF188 R5A", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 2000, reachLabel: "FR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "100GBASE-FR" }, + + // ── 400G QSFP-DD ──────────────────────────────────────────────────────── + { pid: "ROF199 R1A", formFactor: "QSFP-DD",speedGbps: 400, speed: "400G", reachMeters: 100, reachLabel: "SR8", fiberType: "MMF", connector: "MPO", wavelengths: "850nm", standard: "400GBASE-SR8" }, + { pid: "ROF199 R2A", formFactor: "QSFP-DD",speedGbps: 400, speed: "400G", reachMeters: 500, reachLabel: "DR4", fiberType: "SMF", connector: "MPO", wavelengths: "1310nm", standard: "400GBASE-DR4" }, + { pid: "ROF199 R3A", formFactor: "QSFP-DD",speedGbps: 400, speed: "400G", reachMeters: 2000, reachLabel: "FR4", fiberType: "SMF", connector: "LC", wavelengths: "1271-1331nm", standard: "400GBASE-FR4" }, + { pid: "ROF199 R4A", formFactor: "QSFP-DD",speedGbps: 400, speed: "400G", reachMeters: 10000, reachLabel: "LR4", fiberType: "SMF", connector: "LC", wavelengths: "1295-1310nm", standard: "400GBASE-LR4" }, + + // ── DAC ───────────────────────────────────────────────────────────────── + { pid: "ROF155 D10-1M", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 1, reachLabel: "DAC-1M",fiberType: "DAC", connector: "SFP+", notes: "10G DAC 1m" }, + { pid: "ROF155 D10-3M", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 3, reachLabel: "DAC-3M",fiberType: "DAC", connector: "SFP+", notes: "10G DAC 3m" }, + { pid: "ROF188 D100-1M", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 1, reachLabel: "DAC-1M",fiberType: "DAC", connector: "QSFP28", notes: "100G DAC 1m" }, + { pid: "ROF188 D100-3M", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 3, reachLabel: "DAC-3M",fiberType: "DAC", connector: "QSFP28", notes: "100G DAC 3m" }, + { pid: "ROF199 D400-1M", formFactor: "QSFP-DD",speedGbps: 400, speed: "400G", reachMeters: 1, reachLabel: "DAC-1M",fiberType: "DAC", connector: "QSFP-DD",notes: "400G DAC 1m" }, +]; + +export async function scrapeEricssonOem(): Promise { + console.log("=== Ericsson OEM Transceiver Seed ===\n"); + + const vendorId = await ensureVendor( + "Ericsson", + "oem", + "https://www.ericsson.com", + undefined + ); + + let inserted = 0; + let updated = 0; + let errors = 0; + + for (const p of ERICSSON_PIDS) { + const slug = `ericsson-${p.pid.toLowerCase().replace(/[^a-z0-9]+/g, "-")}`; + try { + const res = await pool.query( + `INSERT INTO transceivers + (slug, part_number, vendor_id, form_factor, speed, speed_gbps, + reach_meters, reach_label, fiber_type, connector, wavelengths, + dom_support, ieee_reference, market_status, category, notes) + VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,true,$12,'Mainstream','DataCenter',$13) + ON CONFLICT (slug) DO UPDATE SET + speed_gbps = EXCLUDED.speed_gbps, + reach_meters = CASE WHEN EXCLUDED.reach_meters > 0 THEN EXCLUDED.reach_meters ELSE transceivers.reach_meters END, + fiber_type = CASE WHEN EXCLUDED.fiber_type <> '' THEN EXCLUDED.fiber_type ELSE transceivers.fiber_type END, + wavelengths = COALESCE(EXCLUDED.wavelengths, transceivers.wavelengths), + updated_at = NOW() + RETURNING (xmax = 0) as was_inserted`, + [slug, p.pid, vendorId, p.formFactor, p.speed, p.speedGbps, + p.reachMeters, p.reachLabel, p.fiberType, p.connector, + p.wavelengths ?? null, p.standard ?? null, p.notes ?? null] + ); + if (res.rows[0]?.was_inserted) inserted++; else updated++; + } catch (err) { + console.warn(` Skip ${p.pid}: ${(err as Error).message.slice(0, 80)}`); + errors++; + } + } + + console.log(`\n=== Ericsson OEM Seed Complete ===`); + console.log(` Inserted: ${inserted}`); + console.log(` Updated: ${updated}`); + console.log(` Errors: ${errors}`); + console.log(` Total PIDs: ${ERICSSON_PIDS.length}\n`); +} + +if (require.main === module) { + scrapeEricssonOem() + .then(() => pool.end()) + .catch((err) => { + console.error("Fatal:", err); + pool.end(); + process.exit(1); + }); +} diff --git a/packages/scraper/src/scrapers/ericsson-ran-oem.ts b/packages/scraper/src/scrapers/ericsson-ran-oem.ts new file mode 100644 index 0000000..1a05abc --- /dev/null +++ b/packages/scraper/src/scrapers/ericsson-ran-oem.ts @@ -0,0 +1,135 @@ +/** + * Ericsson Radio OEM Transceiver Catalog Seed + * + * Seeds Ericsson Radio System-branded transceiver PIDs used in CPRI and + * eCPRI fronthaul deployments for Ericsson RRUS (Remote Radio Unit System), + * RADIO (AIR series), and baseband (BBU6630/BBU6648/vDU) units. + * + * CPRI option / speed mapping: + * Option 1/2: 614.4 Mbps | Option 3: 1228.8 Mbps + * Option 4: 2457.6 Mbps | Option 5: 4915.2 Mbps + * Option 6: 9830.4 Mbps | Option 7: 10137.6 Mbps + * + * Sources: + * - Ericsson Radio System product portfolio (ericsson.com) + * - CPRI Specification v7.0 + * - eCPRI Specification v2.0 + * - Ericsson 5G NR fronthaul transport guidelines + * + * Run: tsx packages/scraper/src/scrapers/ericsson-ran-oem.ts + * Cron: daily at 09:45 + */ + +import { pool, ensureVendor } from "../utils/db"; + +interface EricssonRanPID { + pid: string; + formFactor: string; + speedGbps: number; + speed: string; + reachMeters: number; + reachLabel: string; + fiberType: string; + connector: string; + wavelengths?: string; + standard?: string; + notes?: string; +} + +const ERICSSON_RAN_PIDS: EricssonRanPID[] = [ + // ── CPRI Option 1/2 — 614.4 Mbps ──────────────────────────────────────── + { pid: "ER-SFP-CPRI-614M", formFactor: "SFP", speedGbps: 0.6144, speed: "0.6G", reachMeters: 10000, reachLabel: "LX", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "1000BASE-LX", notes: "Ericsson RRUS CPRI option 1 (614.4 Mbps) / option 2 SFP — narrow-band LTE remote radio" }, + + // ── CPRI Option 3 — 1228.8 Mbps ───────────────────────────────────────── + { pid: "ER-SFP-CPRI-1228M", formFactor: "SFP", speedGbps: 1.2288, speed: "1.2G", reachMeters: 10000, reachLabel: "LX", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "1000BASE-LX", notes: "Ericsson RRUS CPRI option 3 (1228.8 Mbps) SFP — 2x10 MHz LTE carrier fronthaul" }, + + // ── CPRI Option 4 — 2457.6 Mbps ───────────────────────────────────────── + { pid: "ER-SFP-CPRI-2457M", formFactor: "SFP", speedGbps: 2.4576, speed: "2.5G", reachMeters: 10000, reachLabel: "LX", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "OTN", notes: "Ericsson RRUS CPRI option 4 (2457.6 Mbps) SFP — 4x10 MHz LTE carrier fronthaul" }, + + // ── CPRI Option 5 — 4915.2 Mbps ───────────────────────────────────────── + { pid: "ER-SFP-CPRI-4915M", formFactor: "SFP", speedGbps: 4.9152, speed: "4.9G", reachMeters: 10000, reachLabel: "LR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "OTN", notes: "Ericsson RRUS CPRI option 5 (4915.2 Mbps) SFP — 4x20 MHz LTE carrier, typical RRU 2T2R" }, + + // ── CPRI Option 6 — 9830.4 Mbps ───────────────────────────────────────── + { pid: "ER-SFP-CPRI-9830M", formFactor: "SFP+", speedGbps: 9.83, speed: "9.8G", reachMeters: 10000, reachLabel: "LR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "10GBASE-LR", notes: "Ericsson RRUS CPRI option 6 (9830.4 Mbps) SFP+ — 4T4R LTE or 2T2R 4-carrier fronthaul" }, + + // ── CPRI Option 7 — 10137.6 Mbps ──────────────────────────────────────── + { pid: "ER-SFP-CPRI-10G-SR", formFactor: "SFP+", speedGbps: 10.137, speed: "10G", reachMeters: 300, reachLabel: "SR", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "10GBASE-SR", notes: "Ericsson RRUS CPRI option 7 (10137.6 Mbps) SFP+ SR — high-capacity LTE/5G NR fronthaul" }, + { pid: "ER-SFP-CPRI-10G-LR", formFactor: "SFP+", speedGbps: 10.137, speed: "10G", reachMeters: 10000, reachLabel: "LR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "10GBASE-LR", notes: "Ericsson RRUS CPRI option 7 SFP+ LR — long-reach fronthaul up to 10 km" }, + + // ── eCPRI — 25G SFP28 ─────────────────────────────────────────────────── + { pid: "ER-SFP28-ECPRI-25G-SR", formFactor: "SFP28", speedGbps: 25, speed: "25G", reachMeters: 100, reachLabel: "SR", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "25GBASE-SR", notes: "Ericsson AIR eCPRI 25G SFP28 SR for 5G NR O-RAN split 7-2x fronthaul" }, + { pid: "ER-SFP28-ECPRI-25G-LR", formFactor: "SFP28", speedGbps: 25, speed: "25G", reachMeters: 10000, reachLabel: "LR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "25GBASE-LR", notes: "Ericsson AIR eCPRI 25G SFP28 LR for long-reach 5G NR fronthaul" }, + + // ── eCPRI — 100G QSFP28 ───────────────────────────────────────────────── + { pid: "ER-QSFP28-ECPRI-100G-SR4", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 100, reachLabel: "SR4", fiberType: "MMF", connector: "MPO", wavelengths: "850nm", standard: "100GBASE-SR4", notes: "Ericsson AIR eCPRI 100G QSFP28 SR4 for massive MIMO (64T64R) aggregated fronthaul" }, + + // ── Standard data-plane SFP+ ──────────────────────────────────────────── + { pid: "ER-SFP-10G-SR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 300, reachLabel: "SR", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "10GBASE-SR", notes: "Ericsson Radio System standard 10G SFP+ SR for BBU uplink / transport" }, + { pid: "ER-SFP-10G-LR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 10000, reachLabel: "LR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "10GBASE-LR" }, + + // ── 40G / 100G data-plane ─────────────────────────────────────────────── + { pid: "ER-QSFP-40G-LR4", formFactor: "QSFP+", speedGbps: 40, speed: "40G", reachMeters: 10000, reachLabel: "LR4", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "40GBASE-LR4" }, + { pid: "ER-QSFP-100G-LR4", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 10000, reachLabel: "LR4", fiberType: "SMF", connector: "LC", wavelengths: "1295-1310nm", standard: "100GBASE-LR4", notes: "Ericsson Radio 100G QSFP28 LR4 for midhaul/backhaul aggregation" }, + + // ── 1G SFP management / cell site ─────────────────────────────────────── + { pid: "ER-SFP-GE-SX", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 550, reachLabel: "SX", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "1000BASE-SX" }, + { pid: "ER-SFP-GE-LX", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 10000, reachLabel: "LX", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "1000BASE-LX" }, +]; + +export async function scrapeEricssonRanOem(): Promise { + console.log("=== Ericsson Radio OEM Transceiver Seed ===\n"); + + const vendorId = await ensureVendor( + "Ericsson Radio", + "oem", + "https://www.ericsson.com/en/portfolio/networks/ericsson-radio-system", + undefined + ); + + let inserted = 0; + let updated = 0; + let errors = 0; + + for (const p of ERICSSON_RAN_PIDS) { + const slug = `ericsson-r-${p.pid.toLowerCase().replace(/[^a-z0-9]+/g, "-")}`; + try { + const res = await pool.query( + `INSERT INTO transceivers + (slug, part_number, vendor_id, form_factor, speed, speed_gbps, + reach_meters, reach_label, fiber_type, connector, wavelengths, + dom_support, ieee_reference, market_status, category, notes) + VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,true,$12,'Mainstream','DataCenter',$13) + ON CONFLICT (slug) DO UPDATE SET + speed_gbps = EXCLUDED.speed_gbps, + reach_meters = CASE WHEN EXCLUDED.reach_meters > 0 THEN EXCLUDED.reach_meters ELSE transceivers.reach_meters END, + fiber_type = CASE WHEN EXCLUDED.fiber_type <> '' THEN EXCLUDED.fiber_type ELSE transceivers.fiber_type END, + wavelengths = COALESCE(EXCLUDED.wavelengths, transceivers.wavelengths), + updated_at = NOW() + RETURNING (xmax = 0) as was_inserted`, + [slug, p.pid, vendorId, p.formFactor, p.speed, p.speedGbps, + p.reachMeters, p.reachLabel, p.fiberType, p.connector, + p.wavelengths ?? null, p.standard ?? null, p.notes ?? null] + ); + if (res.rows[0]?.was_inserted) inserted++; else updated++; + } catch (err) { + console.warn(` Skip ${p.pid}: ${(err as Error).message.slice(0, 80)}`); + errors++; + } + } + + console.log(`\n=== Ericsson Radio OEM Seed Complete ===`); + console.log(` Inserted: ${inserted}`); + console.log(` Updated: ${updated}`); + console.log(` Errors: ${errors}`); + console.log(` Total PIDs: ${ERICSSON_RAN_PIDS.length}\n`); +} + +if (require.main === module) { + scrapeEricssonRanOem() + .then(() => pool.end()) + .catch((err) => { + console.error("Fatal:", err); + pool.end(); + process.exit(1); + }); +} diff --git a/packages/scraper/src/scrapers/ericsson-transport-oem.ts b/packages/scraper/src/scrapers/ericsson-transport-oem.ts new file mode 100644 index 0000000..bc9fc87 --- /dev/null +++ b/packages/scraper/src/scrapers/ericsson-transport-oem.ts @@ -0,0 +1,155 @@ +/** + * Ericsson Transport OEM Transceiver Catalog Seed + * + * Seeds Ericsson-branded transceiver PIDs for MINI-LINK transport and + * IP/optical networking platforms: MINI-LINK 6352, 6372, TN, E, and + * Ericsson DWDM/coherent optics for ASON/WSON networks. + * + * Note: ericsson-oem.ts covers general Ericsson router/switch PIDs. + * This file focuses on transport, telecom, and MINI-LINK specific optics + * including SONET/SDH, OTN, CFP2, and tunable DWDM variants. + * + * Sources: + * - Ericsson MINI-LINK Product Portfolio (ericsson.com/en/portfolio/networks/transport) + * - Ericsson Optical Networking Hardware Overview + * - Ericsson MINI-LINK 6352/6372 Transceiver Compatibility Guide + * - Ericsson OTN/SDH Platform Optics Specification + * + * Run: tsx packages/scraper/src/scrapers/ericsson-transport-oem.ts + * Cron: daily at 00:15 + */ + +import { pool, ensureVendor } from "../utils/db"; + +interface EricssonTransportPID { + pid: string; + formFactor: string; + speedGbps: number; + speed: string; + reachMeters: number; + reachLabel: string; + fiberType: string; + connector: string; + wavelengths?: string; + standard?: string; + category?: string; + notes?: string; +} + +const ERICSSON_TRANSPORT_PIDS: EricssonTransportPID[] = [ + // ── 1G SFP ────────────────────────────────────────────────────────────── + { pid: "SFP-1G-SX", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 550, reachLabel: "SX", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "1000BASE-SX" }, + { pid: "SFP-1G-LX", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 10000, reachLabel: "LX", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "1000BASE-LX" }, + { pid: "SFP-GE-T", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 100, reachLabel: "1000BASE-T", fiberType: "Cu", connector: "RJ45" }, + + // ── 10G SFP+ ──────────────────────────────────────────────────────────── + { pid: "SFP-10G-SR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 300, reachLabel: "SR", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "10GBASE-SR" }, + { pid: "SFP-10G-LR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 10000, reachLabel: "LR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "10GBASE-LR" }, + { pid: "SFP-10G-ER", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 40000, reachLabel: "ER", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "10GBASE-ER" }, + { pid: "SFP-10G-ZR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 80000, reachLabel: "ZR", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "10GBASE-ZR", category: "Telecom" }, + + // ── SDH/SONET SFP (MINI-LINK transport) ────────────────────────────────── + { pid: "SFP-OC3-SR", formFactor: "SFP", speedGbps: 0.155, speed: "OC-3/STM-1", reachMeters: 2000, reachLabel: "SR", fiberType: "MMF", connector: "LC", wavelengths: "1310nm", standard: "OC-3/STM-1", category: "Telecom", notes: "Ericsson MINI-LINK OC-3 / STM-1 short reach" }, + { pid: "SFP-OC3-LR", formFactor: "SFP", speedGbps: 0.155, speed: "OC-3/STM-1", reachMeters: 40000, reachLabel: "LR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "OC-3/STM-1", category: "Telecom", notes: "Ericsson MINI-LINK OC-3 / STM-1 long reach" }, + { pid: "SFP-STM1-SR", formFactor: "SFP", speedGbps: 0.155, speed: "STM-1", reachMeters: 2000, reachLabel: "SR", fiberType: "MMF", connector: "LC", wavelengths: "1310nm", standard: "STM-1", category: "Telecom", notes: "Ericsson SDH STM-1 short reach SFP" }, + { pid: "SFP-OC12-SR", formFactor: "SFP", speedGbps: 0.622, speed: "OC-12/STM-4", reachMeters: 2000, reachLabel: "SR", fiberType: "MMF", connector: "LC", wavelengths: "1310nm", standard: "OC-12/STM-4", category: "Telecom", notes: "Ericsson MINI-LINK OC-12 / STM-4 short reach" }, + { pid: "SFP-OC12-LR", formFactor: "SFP", speedGbps: 0.622, speed: "OC-12/STM-4", reachMeters: 40000, reachLabel: "LR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "OC-12/STM-4", category: "Telecom", notes: "Ericsson MINI-LINK OC-12 / STM-4 long reach" }, + { pid: "SFP-STM4-LR", formFactor: "SFP", speedGbps: 0.622, speed: "STM-4", reachMeters: 40000, reachLabel: "LR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "STM-4", category: "Telecom", notes: "Ericsson SDH STM-4 long reach SFP" }, + { pid: "SFP-OC48-SR", formFactor: "SFP", speedGbps: 2.488, speed: "OC-48/STM-16", reachMeters: 2000, reachLabel: "SR", fiberType: "MMF", connector: "LC", wavelengths: "1310nm", standard: "OC-48/STM-16", category: "Telecom", notes: "Ericsson MINI-LINK OC-48 / STM-16 short reach" }, + { pid: "SFP-STM16-LR", formFactor: "SFP", speedGbps: 2.488, speed: "STM-16", reachMeters: 40000, reachLabel: "LR", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "STM-16", category: "Telecom", notes: "Ericsson SDH STM-16 long reach SFP" }, + + // ── OTN SFP+ ───────────────────────────────────────────────────────────── + { pid: "SFP-OTU2-10G", formFactor: "SFP+", speedGbps: 10, speed: "OTU2", reachMeters: 40000, reachLabel: "OTU2", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "OTU2", category: "Telecom", notes: "Ericsson 10G OTN OTU2 SFP+ for MINI-LINK TN" }, + + // ── 25G SFP28 ─────────────────────────────────────────────────────────── + { pid: "SFP-25G-LR", formFactor: "SFP28", speedGbps: 25, speed: "25G", reachMeters: 10000, reachLabel: "LR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "25GBASE-LR" }, + + // ── 40G QSFP+ ─────────────────────────────────────────────────────────── + { pid: "QSFP-40G-LR4", formFactor: "QSFP+", speedGbps: 40, speed: "40G", reachMeters: 10000, reachLabel: "LR4", fiberType: "SMF", connector: "LC", wavelengths: "1270-1330nm", standard: "40GBASE-LR4" }, + + // ── 100G QSFP28 ───────────────────────────────────────────────────────── + { pid: "QSFP-100G-LR4", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 10000, reachLabel: "LR4", fiberType: "SMF", connector: "LC", wavelengths: "1295-1310nm", standard: "100GBASE-LR4" }, + + // ── 100G CFP2 Coherent ─────────────────────────────────────────────────── + { pid: "CFP2-100G-LR4", formFactor: "CFP2", speedGbps: 100, speed: "100G", reachMeters: 10000, reachLabel: "LR4", fiberType: "SMF", connector: "LC", wavelengths: "1295-1310nm", standard: "100GBASE-LR4", category: "Telecom", notes: "Ericsson CFP2 100G LR4 for optical transport" }, + + // ── DWDM SFP+ tunable ─────────────────────────────────────────────────── + { pid: "DWDM-SFP-C", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 80000, reachLabel: "DWDM", fiberType: "SMF", connector: "LC", wavelengths: "C-band DWDM", category: "Telecom", notes: "Ericsson C-band DWDM SFP+ fixed-wavelength for WDM transport" }, + + // ── 400G QSFP-DD coherent ZR ───────────────────────────────────────────── + { pid: "QSFP-DD-400G-ZR", formFactor: "QSFP-DD", speedGbps: 400, speed: "400G", reachMeters: 120000, reachLabel: "ZR", fiberType: "SMF", connector: "LC", wavelengths: "C-band", standard: "400ZR", category: "Telecom", notes: "Ericsson 400G ZR coherent QSFP-DD for DWDM long haul" }, +]; + +// PIDs that belong to the Telecom category (SDH/SONET, OTN, DWDM, ZR, CFP2) +const TELECOM_PIDS = new Set([ + "SFP-10G-ZR", + "SFP-OC3-SR", "SFP-OC3-LR", + "SFP-STM1-SR", + "SFP-OC12-SR", "SFP-OC12-LR", + "SFP-STM4-LR", + "SFP-OC48-SR", + "SFP-STM16-LR", + "SFP-OTU2-10G", + "CFP2-100G-LR4", + "DWDM-SFP-C", + "QSFP-DD-400G-ZR", +]); + +export async function scrapeEricssonTransportOem(): Promise { + console.log("=== Ericsson Transport OEM Transceiver Seed ===\n"); + + const vendorId = await ensureVendor( + "Ericsson", + "oem", + "https://www.ericsson.com", + undefined + ); + + let inserted = 0; + let updated = 0; + let errors = 0; + + for (const p of ERICSSON_TRANSPORT_PIDS) { + const slug = `ericsson-t-${p.pid.toLowerCase().replace(/[^a-z0-9]+/g, "-")}`; + const category = p.category ?? (TELECOM_PIDS.has(p.pid) ? "Telecom" : "DataCenter"); + try { + const res = await pool.query( + `INSERT INTO transceivers + (slug, part_number, vendor_id, form_factor, speed, speed_gbps, + reach_meters, reach_label, fiber_type, connector, wavelengths, + dom_support, ieee_reference, market_status, category, notes) + VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,true,$12,'Mainstream',$13,$14) + ON CONFLICT (slug) DO UPDATE SET + speed_gbps = EXCLUDED.speed_gbps, + reach_meters = CASE WHEN EXCLUDED.reach_meters > 0 THEN EXCLUDED.reach_meters ELSE transceivers.reach_meters END, + fiber_type = CASE WHEN EXCLUDED.fiber_type <> '' THEN EXCLUDED.fiber_type ELSE transceivers.fiber_type END, + wavelengths = COALESCE(EXCLUDED.wavelengths, transceivers.wavelengths), + updated_at = NOW() + RETURNING (xmax = 0) as was_inserted`, + [slug, p.pid, vendorId, p.formFactor, p.speed, p.speedGbps, + p.reachMeters, p.reachLabel, p.fiberType, p.connector, + p.wavelengths ?? null, p.standard ?? null, category, p.notes ?? null] + ); + if (res.rows[0]?.was_inserted) inserted++; else updated++; + } catch (err) { + console.warn(` Skip ${p.pid}: ${(err as Error).message.slice(0, 80)}`); + errors++; + } + } + + console.log(`\n=== Ericsson Transport OEM Seed Complete ===`); + console.log(` Inserted: ${inserted}`); + console.log(` Updated: ${updated}`); + console.log(` Errors: ${errors}`); + console.log(` Total PIDs: ${ERICSSON_TRANSPORT_PIDS.length}\n`); +} + +if (require.main === module) { + scrapeEricssonTransportOem() + .then(() => pool.end()) + .catch((err) => { + console.error("Fatal:", err); + pool.end(); + process.exit(1); + }); +} diff --git a/packages/scraper/src/scrapers/etherwan-oem.ts b/packages/scraper/src/scrapers/etherwan-oem.ts new file mode 100644 index 0000000..8d018af --- /dev/null +++ b/packages/scraper/src/scrapers/etherwan-oem.ts @@ -0,0 +1,116 @@ +/** + * EtherWAN OEM Transceiver Catalog Seed + * + * Seeds transceiver PIDs for EtherWAN industrial-grade SFP modules used in + * EX/FX series managed switches for harsh environment deployments. + * + * Sources: + * - EtherWAN SFP module product pages (etherwan.com) + * - EtherWAN EX series hardware datasheets + * + * Run: tsx packages/scraper/src/scrapers/etherwan-oem.ts + * Cron: daily at 16:30 + */ + +import { pool, ensureVendor } from "../utils/db"; + +interface EtherwanPID { + pid: string; + formFactor: string; + speedGbps: number; + speed: string; + reachMeters: number; + reachLabel: string; + fiberType: string; + connector: string; + wavelengths?: string; + standard?: string; + notes?: string; +} + +const ETHERWAN_PIDS: EtherwanPID[] = [ + // ── 100M SFP ──────────────────────────────────────────────────────────── + { pid: "EX44018", formFactor: "SFP", speedGbps: 0.1, speed: "100M", reachMeters: 2000, reachLabel: "FX", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "100BASE-FX" }, + { pid: "EX44019", formFactor: "SFP", speedGbps: 0.1, speed: "100M", reachMeters: 15000, reachLabel: "LFX", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "100BASE-LFX" }, + { pid: "EX44020", formFactor: "SFP", speedGbps: 0.1, speed: "100M", reachMeters: 40000, reachLabel: "LFX-40K", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", notes: "EtherWAN 100M SM SFP 40km" }, + { pid: "EX44021", formFactor: "SFP", speedGbps: 0.1, speed: "100M", reachMeters: 20000, reachLabel: "BiDi-20K",fiberType: "SMF", connector: "LC", wavelengths: "TX1310/RX1550", notes: "EtherWAN 100M BiDi SFP" }, + + // ── 1G SFP ────────────────────────────────────────────────────────────── + { pid: "EX45000", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 550, reachLabel: "SX", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "1000BASE-SX" }, + { pid: "EX45001", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 10000, reachLabel: "LX", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "1000BASE-LX" }, + { pid: "EX45002", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 20000, reachLabel: "LH20", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", notes: "EtherWAN 1G SM SFP 20km" }, + { pid: "EX45003", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 40000, reachLabel: "LH40", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", notes: "EtherWAN 1G SM SFP 40km" }, + { pid: "EX45004", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 80000, reachLabel: "ZX", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "1000BASE-ZX" }, + { pid: "EX45005", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 100, reachLabel: "T", fiberType: "DAC", connector: "RJ45", standard: "1000BASE-T" }, + { pid: "EX45006", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 20000, reachLabel: "BiDi-U", fiberType: "SMF", connector: "LC", wavelengths: "TX1310/RX1550", notes: "EtherWAN 1G BiDi SFP upstream" }, + { pid: "EX45007", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 20000, reachLabel: "BiDi-D", fiberType: "SMF", connector: "LC", wavelengths: "TX1550/RX1310", notes: "EtherWAN 1G BiDi SFP downstream" }, + + // ── 10G SFP+ ──────────────────────────────────────────────────────────── + { pid: "EX46000", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 300, reachLabel: "SR", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "10GBASE-SR" }, + { pid: "EX46001", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 10000, reachLabel: "LR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "10GBASE-LR" }, + { pid: "EX46002", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 40000, reachLabel: "ER", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "10GBASE-ER" }, + { pid: "EX46003", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 80000, reachLabel: "ZR", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "10GBASE-ZR" }, + { pid: "EX46004", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 10000, reachLabel: "BiDi-U", fiberType: "SMF", connector: "LC", wavelengths: "TX1270/RX1330", notes: "EtherWAN 10G BiDi SFP+ upstream" }, + + // ── DAC ───────────────────────────────────────────────────────────────── + { pid: "EX46010", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 1, reachLabel: "DAC-1M", fiberType: "DAC", connector: "SFP+" }, + { pid: "EX46011", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 3, reachLabel: "DAC-3M", fiberType: "DAC", connector: "SFP+" }, +]; + +export async function scrapeEtherwanOem(): Promise { + console.log("=== EtherWAN OEM Transceiver Seed ===\n"); + + const vendorId = await ensureVendor( + "EtherWAN Systems", + "oem", + "https://www.etherwan.com", + undefined + ); + + let inserted = 0; + let updated = 0; + let errors = 0; + + for (const p of ETHERWAN_PIDS) { + const slug = `etherwan-${p.pid.toLowerCase().replace(/[^a-z0-9]+/g, "-")}`; + try { + const res = await pool.query( + `INSERT INTO transceivers + (slug, part_number, vendor_id, form_factor, speed, speed_gbps, + reach_meters, reach_label, fiber_type, connector, wavelengths, + dom_support, ieee_reference, market_status, category, notes) + VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,true,$12,'Mainstream','Industrial',$13) + ON CONFLICT (slug) DO UPDATE SET + speed_gbps = EXCLUDED.speed_gbps, + reach_meters = CASE WHEN EXCLUDED.reach_meters > 0 THEN EXCLUDED.reach_meters ELSE transceivers.reach_meters END, + fiber_type = CASE WHEN EXCLUDED.fiber_type <> '' THEN EXCLUDED.fiber_type ELSE transceivers.fiber_type END, + wavelengths = COALESCE(EXCLUDED.wavelengths, transceivers.wavelengths), + updated_at = NOW() + RETURNING (xmax = 0) as was_inserted`, + [slug, p.pid, vendorId, p.formFactor, p.speed, p.speedGbps, + p.reachMeters, p.reachLabel, p.fiberType, p.connector, + p.wavelengths ?? null, p.standard ?? null, p.notes ?? null] + ); + if (res.rows[0]?.was_inserted) inserted++; else updated++; + } catch (err) { + console.warn(` Skip ${p.pid}: ${(err as Error).message.slice(0, 80)}`); + errors++; + } + } + + console.log(`\n=== EtherWAN OEM Seed Complete ===`); + console.log(` Inserted: ${inserted}`); + console.log(` Updated: ${updated}`); + console.log(` Errors: ${errors}`); + console.log(` Total PIDs: ${ETHERWAN_PIDS.length}\n`); +} + +if (require.main === module) { + scrapeEtherwanOem() + .then(() => pool.end()) + .catch((err) => { + console.error("Fatal:", err); + pool.end(); + process.exit(1); + }); +} diff --git a/packages/scraper/src/scrapers/evertz-oem.ts b/packages/scraper/src/scrapers/evertz-oem.ts new file mode 100644 index 0000000..561f525 --- /dev/null +++ b/packages/scraper/src/scrapers/evertz-oem.ts @@ -0,0 +1,139 @@ +/** + * Evertz Microsystems OEM Transceiver Catalog Seed + * + * Seeds Evertz-branded transceiver PIDs for broadcast infrastructure: + * EXE modular chassis, 570IPG/7700 series SDI-over-IP, and MAGNUM SDN + * orchestration platforms. + * + * Sources: + * - Evertz Product Catalog (evertz.com) + * - Evertz EXE-1000/EXE-2000 Hardware Reference + * - Evertz 570IPG-X19-25G Platform Transceiver Guide + * - Evertz MAGNUM SDN Controller Compatibility Notes + * + * Run: tsx packages/scraper/src/scrapers/evertz-oem.ts + * Cron: daily at 18:15 + */ + +import { pool, ensureVendor } from "../utils/db"; + +interface EvertzPID { + pid: string; + formFactor: string; + speedGbps: number; + speed: string; + reachMeters: number; + reachLabel: string; + fiberType: string; + connector: string; + wavelengths?: string; + standard?: string; + category?: string; + notes?: string; +} + +const EVERTZ_PIDS: EvertzPID[] = [ + // ── 1G SFP ────────────────────────────────────────────────────────────── + { pid: "EVZ-SFP-GE-SX", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 550, reachLabel: "SX", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "1000BASE-SX", notes: "Evertz 1G SX SFP for EXE chassis and 7700 series" }, + { pid: "EVZ-SFP-GE-LX", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 10000, reachLabel: "LX", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "1000BASE-LX", notes: "Evertz 1G LX SFP for EXE chassis management" }, + { pid: "EVZ-SFP-GE-T", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 100, reachLabel: "T", fiberType: "DAC", connector: "RJ45", standard: "1000BASE-T", notes: "Evertz 1G copper SFP for out-of-band management" }, + + // ── 10G SFP+ ──────────────────────────────────────────────────────────── + { pid: "EVZ-SFP-10G-SR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 300, reachLabel: "SR", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "10GBASE-SR" }, + { pid: "EVZ-SFP-10G-LR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 10000, reachLabel: "LR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "10GBASE-LR" }, + { pid: "EVZ-SFP-10G-ER", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 40000, reachLabel: "ER", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "10GBASE-ER" }, + { pid: "EVZ-SFP-10G-ZR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 80000, reachLabel: "ZR", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "10GBASE-ZR", category: "Telecom", notes: "Evertz 10G ZR SFP+ for broadcast contribution over dark fiber" }, + + // ── SONET/SDH SFP (SDI-over-fiber / broadcast contribution) ───────────── + { pid: "EVZ-SFP-OC3-SR", formFactor: "SFP", speedGbps: 0.155, speed: "155M", reachMeters: 2000, reachLabel: "SR", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "OC-3/STM-1", category: "Telecom", notes: "Evertz OC-3 SFP for SDI-over-fiber broadcast ring" }, + { pid: "EVZ-SFP-OC12-SR", formFactor: "SFP", speedGbps: 0.622, speed: "622M", reachMeters: 2000, reachLabel: "SR", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "OC-12/STM-4", category: "Telecom", notes: "Evertz OC-12 SFP for broadcast contribution networks" }, + + // ── 25G SFP28 ─────────────────────────────────────────────────────────── + { pid: "EVZ-SFP28-25G-SR", formFactor: "SFP28", speedGbps: 25, speed: "25G", reachMeters: 100, reachLabel: "SR", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "25GBASE-SR", notes: "Evertz 25G SR for 570IPG-X19-25G SDI-over-IP blade" }, + { pid: "EVZ-SFP28-25G-LR", formFactor: "SFP28", speedGbps: 25, speed: "25G", reachMeters: 10000, reachLabel: "LR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "25GBASE-LR", notes: "Evertz 25G LR for long-reach SDI-over-IP links" }, + + // ── 40G QSFP+ ─────────────────────────────────────────────────────────── + { pid: "EVZ-QSFP-40G-SR4", formFactor: "QSFP+", speedGbps: 40, speed: "40G", reachMeters: 150, reachLabel: "SR4", fiberType: "MMF", connector: "MPO", wavelengths: "850nm", standard: "40GBASE-SR4" }, + { pid: "EVZ-QSFP-40G-LR4", formFactor: "QSFP+", speedGbps: 40, speed: "40G", reachMeters: 10000, reachLabel: "LR4", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "40GBASE-LR4" }, + + // ── 100G QSFP28 ───────────────────────────────────────────────────────── + { pid: "EVZ-QSFP28-100G-SR4", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 100, reachLabel: "SR4", fiberType: "MMF", connector: "MPO", wavelengths: "850nm", standard: "100GBASE-SR4" }, + { pid: "EVZ-QSFP28-100G-LR4", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 10000, reachLabel: "LR4", fiberType: "SMF", connector: "LC", wavelengths: "1295-1310nm", standard: "100GBASE-LR4" }, + + // ── 100G CFP2 (broadcast 100G contribution) ───────────────────────────── + { pid: "EVZ-CFP2-100G-LR4", formFactor: "CFP2", speedGbps: 100, speed: "100G", reachMeters: 10000, reachLabel: "LR4", fiberType: "SMF", connector: "LC", wavelengths: "1295-1310nm", standard: "100GBASE-LR4", category: "Telecom", notes: "Evertz CFP2 100G LR4 for high-density broadcast contribution" }, + + // ── DWDM SFP (broadcast DWDM contribution ring) ────────────────────────── + { pid: "EVZ-DWDM-SFP-C", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 80000, reachLabel: "DWDM", fiberType: "SMF", connector: "LC", wavelengths: "C-band", category: "Telecom", notes: "Evertz 10G DWDM SFP+ tunable C-band for broadcast contribution DWDM ring" }, + + // ── 400G QSFP-DD ──────────────────────────────────────────────────────── + { pid: "EVZ-QSFP-DD-400G-DR4", formFactor: "QSFP-DD", speedGbps: 400, speed: "400G", reachMeters: 500, reachLabel: "DR4", fiberType: "SMF", connector: "MPO", wavelengths: "1310nm", standard: "400GBASE-DR4", notes: "Evertz 400G DR4 for next-gen MAGNUM SDN fabric interconnect" }, +]; + +// PIDs that belong to the Telecom category (SONET/SDH, DWDM, ZR, CFP2) +const TELECOM_PIDS = new Set([ + "EVZ-SFP-10G-ZR", + "EVZ-SFP-OC3-SR", + "EVZ-SFP-OC12-SR", + "EVZ-CFP2-100G-LR4", + "EVZ-DWDM-SFP-C", +]); + +export async function scrapeEvertzOem(): Promise { + console.log("=== Evertz Microsystems OEM Transceiver Seed ===\n"); + + const vendorId = await ensureVendor( + "Evertz Microsystems", + "oem", + "https://www.evertz.com", + undefined + ); + + let inserted = 0; + let updated = 0; + let errors = 0; + + for (const p of EVERTZ_PIDS) { + const slug = `evertz-${p.pid.toLowerCase().replace(/[^a-z0-9]+/g, "-")}`; + const category = p.category ?? (TELECOM_PIDS.has(p.pid) ? "Telecom" : "DataCenter"); + try { + const res = await pool.query( + `INSERT INTO transceivers + (slug, part_number, vendor_id, form_factor, speed, speed_gbps, + reach_meters, reach_label, fiber_type, connector, wavelengths, + dom_support, ieee_reference, market_status, category, notes) + VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,true,$12,'Mainstream',$13,$14) + ON CONFLICT (slug) DO UPDATE SET + speed_gbps = EXCLUDED.speed_gbps, + reach_meters = CASE WHEN EXCLUDED.reach_meters > 0 THEN EXCLUDED.reach_meters ELSE transceivers.reach_meters END, + fiber_type = CASE WHEN EXCLUDED.fiber_type <> '' THEN EXCLUDED.fiber_type ELSE transceivers.fiber_type END, + wavelengths = COALESCE(EXCLUDED.wavelengths, transceivers.wavelengths), + updated_at = NOW() + RETURNING (xmax = 0) as was_inserted`, + [slug, p.pid, vendorId, p.formFactor, p.speed, p.speedGbps, + p.reachMeters, p.reachLabel, p.fiberType, p.connector, + p.wavelengths ?? null, p.standard ?? null, category, p.notes ?? null] + ); + if (res.rows[0]?.was_inserted) inserted++; else updated++; + } catch (err) { + console.warn(` Skip ${p.pid}: ${(err as Error).message.slice(0, 80)}`); + errors++; + } + } + + console.log(`\n=== Evertz OEM Seed Complete ===`); + console.log(` Inserted: ${inserted}`); + console.log(` Updated: ${updated}`); + console.log(` Errors: ${errors}`); + console.log(` Total PIDs: ${EVERTZ_PIDS.length}\n`); +} + +if (require.main === module) { + scrapeEvertzOem() + .then(() => pool.end()) + .catch((err) => { + console.error("Fatal:", err); + pool.end(); + process.exit(1); + }); +} diff --git a/packages/scraper/src/scrapers/exfo-network-oem.ts b/packages/scraper/src/scrapers/exfo-network-oem.ts new file mode 100644 index 0000000..fef62a5 --- /dev/null +++ b/packages/scraper/src/scrapers/exfo-network-oem.ts @@ -0,0 +1,135 @@ +/** + * EXFO Network OEM Transceiver Catalog Seed + * + * Seeds EXFO-branded transceiver PIDs for EXFO network test and + * service assurance platforms (FTB, EX, and OTDR series). + * + * Sources: + * - EXFO Network Test Instruments (exfo.com) + * - EXFO FTBx Platform Module Data Sheets + * - EXFO Service Assurance Platform Hardware Guides + * + * Run: tsx packages/scraper/src/scrapers/exfo-network-oem.ts + * Cron: daily at 10:30 + */ + +import { pool, ensureVendor } from "../utils/db"; + +interface ExfoNetworkPID { + pid: string; + formFactor: string; + speedGbps: number; + speed: string; + reachMeters: number; + reachLabel: string; + fiberType: string; + connector: string; + wavelengths?: string; + standard?: string; + notes?: string; +} + +// PIDs requiring TELECOM/ITU-T classification (CFP2, OC-3/12/48, ZR, ER4) +const TELECOM_PIDS = new Set([ + "EXFO-CFP2-100G-LR4", + "EXFO-SFP-OC3-SR", + "EXFO-SFP-OC12-SR", + "EXFO-SFP-OC48-SR", + "EXFO-SFP-10G-ZR", + "EXFO-QSFP28-100G-ER4", +]); + +const EXFO_NETWORK_PIDS: ExfoNetworkPID[] = [ + // ── 1G SFP ────────────────────────────────────────────────────────────── + { pid: "EXFO-SFP-1G-SX", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 550, reachLabel: "SX", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "1000BASE-SX" }, + { pid: "EXFO-SFP-1G-LX", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 10000, reachLabel: "LX", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "1000BASE-LX" }, + + // ── 10G SFP+ ──────────────────────────────────────────────────────────── + { pid: "EXFO-SFP-10G-SR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 300, reachLabel: "SR", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "10GBASE-SR" }, + { pid: "EXFO-SFP-10G-LR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 10000, reachLabel: "LR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "10GBASE-LR" }, + { pid: "EXFO-SFP-10G-ER", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 40000, reachLabel: "ER", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "10GBASE-ER" }, + { pid: "EXFO-SFP-10G-ZR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 80000, reachLabel: "ZR", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "10GBASE-ZR", notes: "DWDM extended reach, ITU-T G.694.1" }, + + // ── 25G SFP28 ─────────────────────────────────────────────────────────── + { pid: "EXFO-SFP28-25G-SR", formFactor: "SFP28", speedGbps: 25, speed: "25G", reachMeters: 100, reachLabel: "SR", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "25GBASE-SR" }, + { pid: "EXFO-SFP28-25G-LR", formFactor: "SFP28", speedGbps: 25, speed: "25G", reachMeters: 10000, reachLabel: "LR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "25GBASE-LR" }, + + // ── 40G QSFP+ ─────────────────────────────────────────────────────────── + { pid: "EXFO-QSFP-40G-SR4", formFactor: "QSFP+", speedGbps: 40, speed: "40G", reachMeters: 150, reachLabel: "SR4", fiberType: "MMF", connector: "MPO", wavelengths: "850nm", standard: "40GBASE-SR4" }, + { pid: "EXFO-QSFP-40G-LR4", formFactor: "QSFP+", speedGbps: 40, speed: "40G", reachMeters: 10000, reachLabel: "LR4", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "40GBASE-LR4" }, + + // ── 100G QSFP28 ───────────────────────────────────────────────────────── + { pid: "EXFO-QSFP28-100G-SR4", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 100, reachLabel: "SR4", fiberType: "MMF", connector: "MPO", wavelengths: "850nm", standard: "100GBASE-SR4" }, + { pid: "EXFO-QSFP28-100G-LR4", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 10000, reachLabel: "LR4", fiberType: "SMF", connector: "LC", wavelengths: "1295-1310nm", standard: "100GBASE-LR4" }, + { pid: "EXFO-QSFP28-100G-ER4", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 40000, reachLabel: "ER4", fiberType: "SMF", connector: "LC", wavelengths: "1295-1310nm", standard: "100GBASE-ER4", notes: "Extended reach, ITU-T G.694 WDM" }, + + // ── 400G QSFP-DD ──────────────────────────────────────────────────────── + { pid: "EXFO-QSFP-DD-400G-DR4", formFactor: "QSFP-DD", speedGbps: 400, speed: "400G", reachMeters: 500, reachLabel: "DR4", fiberType: "SMF", connector: "MPO", wavelengths: "1310nm", standard: "400GBASE-DR4" }, + + // ── 100G CFP2 (Telecom) ────────────────────────────────────────────────── + { pid: "EXFO-CFP2-100G-LR4", formFactor: "CFP2", speedGbps: 100, speed: "100G", reachMeters: 10000, reachLabel: "LR4", fiberType: "SMF", connector: "LC", wavelengths: "1295-1310nm", standard: "100GBASE-LR4", notes: "CFP2 MSA, OTU4, ITU-T G.709" }, + + // ── SONET/SDH SFP (Telecom) ────────────────────────────────────────────── + { pid: "EXFO-SFP-OC3-SR", formFactor: "SFP", speedGbps: 0.155, speed: "OC-3", reachMeters: 2000, reachLabel: "SR", fiberType: "MMF", connector: "LC", wavelengths: "1310nm", standard: "OC-3/STM-1", notes: "155 Mbps SONET OC-3 / SDH STM-1" }, + { pid: "EXFO-SFP-OC12-SR", formFactor: "SFP", speedGbps: 0.622, speed: "OC-12", reachMeters: 2000, reachLabel: "SR", fiberType: "MMF", connector: "LC", wavelengths: "1310nm", standard: "OC-12/STM-4", notes: "622 Mbps SONET OC-12 / SDH STM-4" }, + { pid: "EXFO-SFP-OC48-SR", formFactor: "SFP", speedGbps: 2.488, speed: "OC-48", reachMeters: 2000, reachLabel: "SR", fiberType: "MMF", connector: "LC", wavelengths: "1310nm", standard: "OC-48/STM-16", notes: "2.488 Gbps SONET OC-48 / SDH STM-16" }, +]; + +export async function scrapeExfoNetworkOem(): Promise { + console.log("=== EXFO Network OEM Transceiver Seed ===\n"); + + const vendorId = await ensureVendor( + "EXFO Network", + "oem", + "https://www.exfo.com", + undefined + ); + + let inserted = 0; + let updated = 0; + let errors = 0; + + for (const p of EXFO_NETWORK_PIDS) { + const slug = `exfo-net-${p.pid.toLowerCase().replace(/[^a-z0-9]+/g, "-")}`; + const category = TELECOM_PIDS.has(p.pid) ? "Telecom" : "DataCenter"; + try { + const res = await pool.query( + `INSERT INTO transceivers + (slug, part_number, vendor_id, form_factor, speed, speed_gbps, + reach_meters, reach_label, fiber_type, connector, wavelengths, + dom_support, ieee_reference, market_status, category, notes) + VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,true,$12,'Mainstream',$13,$14) + ON CONFLICT (slug) DO UPDATE SET + speed_gbps = EXCLUDED.speed_gbps, + reach_meters = CASE WHEN EXCLUDED.reach_meters > 0 THEN EXCLUDED.reach_meters ELSE transceivers.reach_meters END, + fiber_type = CASE WHEN EXCLUDED.fiber_type <> '' THEN EXCLUDED.fiber_type ELSE transceivers.fiber_type END, + wavelengths = COALESCE(EXCLUDED.wavelengths, transceivers.wavelengths), + updated_at = NOW() + RETURNING (xmax = 0) as was_inserted`, + [slug, p.pid, vendorId, p.formFactor, p.speed, p.speedGbps, + p.reachMeters, p.reachLabel, p.fiberType, p.connector, + p.wavelengths ?? null, p.standard ?? null, category, p.notes ?? null] + ); + if (res.rows[0]?.was_inserted) inserted++; else updated++; + } catch (err) { + console.warn(` Skip ${p.pid}: ${(err as Error).message.slice(0, 80)}`); + errors++; + } + } + + console.log(`\n=== EXFO Network OEM Seed Complete ===`); + console.log(` Inserted: ${inserted}`); + console.log(` Updated: ${updated}`); + console.log(` Errors: ${errors}`); + console.log(` Total PIDs: ${EXFO_NETWORK_PIDS.length}\n`); +} + +if (require.main === module) { + scrapeExfoNetworkOem() + .then(() => pool.end()) + .catch((err) => { + console.error("Fatal:", err); + pool.end(); + process.exit(1); + }); +} diff --git a/packages/scraper/src/scrapers/exfo-oem.ts b/packages/scraper/src/scrapers/exfo-oem.ts new file mode 100644 index 0000000..e700bfd --- /dev/null +++ b/packages/scraper/src/scrapers/exfo-oem.ts @@ -0,0 +1,144 @@ +/** + * EXFO OEM Transceiver Catalog Seed + * + * Seeds EXFO-branded transceiver PIDs used with optical test equipment + * and network deployment platforms (FTB series, T-BERD/MTS). + * Covers DataCenter and Telecom (coherent/DWDM) form factors. + * + * Sources: + * - EXFO FTB-1 Pro Modular Test Platform Hardware Guide + * - EXFO T-BERD/MTS Platform Transceiver Compatibility List + * - EXFO Optical Transceiver Portfolio (exfo.com) + * + * Run: tsx packages/scraper/src/scrapers/exfo-oem.ts + * Cron: daily at 14:45 + */ + +import { pool, ensureVendor } from "../utils/db"; + +interface ExfoPID { + pid: string; + formFactor: string; + speedGbps: number; + speed: string; + reachMeters: number; + reachLabel: string; + fiberType: string; + connector: string; + wavelengths?: string; + standard?: string; + category?: string; + notes?: string; +} + +const EXFO_PIDS: ExfoPID[] = [ + // ── 1G SFP ────────────────────────────────────────────────────────────── + { pid: "FTB-SFP-GE-SX", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 550, reachLabel: "SX", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "1000BASE-SX" }, + { pid: "FTB-SFP-GE-LX", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 10000, reachLabel: "LX", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "1000BASE-LX" }, + { pid: "FTB-SFP-GE-ZX", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 80000, reachLabel: "ZX", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "1000BASE-ZX" }, + { pid: "FTB-SFP-GE-T", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 100, reachLabel: "T", fiberType: "DAC", connector: "RJ45", standard: "1000BASE-T" }, + + // ── 10G SFP+ ──────────────────────────────────────────────────────────── + { pid: "FTB-SFP-10G-SR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 300, reachLabel: "SR", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "10GBASE-SR" }, + { pid: "FTB-SFP-10G-LR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 10000, reachLabel: "LR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "10GBASE-LR" }, + { pid: "FTB-SFP-10G-ER", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 40000, reachLabel: "ER", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "10GBASE-ER" }, + { pid: "FTB-SFP-10G-ZR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 80000, reachLabel: "ZR", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "10GBASE-ZR" }, + + // ── 10G DWDM SFP+ ─────────────────────────────────────────────────────── + { pid: "FTB-SFP-10G-DW-TUNE", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 80000, reachLabel: "DWDM", fiberType: "SMF", connector: "LC", wavelengths: "C-band DWDM", category: "Telecom", notes: "EXFO 10G DWDM tunable SFP+" }, + + // ── 25G SFP28 ─────────────────────────────────────────────────────────── + { pid: "FTB-SFP28-25G-SR", formFactor: "SFP28", speedGbps: 25, speed: "25G", reachMeters: 100, reachLabel: "SR", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "25GBASE-SR" }, + { pid: "FTB-SFP28-25G-LR", formFactor: "SFP28", speedGbps: 25, speed: "25G", reachMeters: 10000, reachLabel: "LR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "25GBASE-LR" }, + + // ── 40G QSFP+ ─────────────────────────────────────────────────────────── + { pid: "FTB-QSFP-40G-SR4", formFactor: "QSFP+", speedGbps: 40, speed: "40G", reachMeters: 150, reachLabel: "SR4", fiberType: "MMF", connector: "MPO", wavelengths: "850nm", standard: "40GBASE-SR4" }, + { pid: "FTB-QSFP-40G-LR4", formFactor: "QSFP+", speedGbps: 40, speed: "40G", reachMeters: 10000, reachLabel: "LR4", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "40GBASE-LR4" }, + + // ── 100G QSFP28 ───────────────────────────────────────────────────────── + { pid: "FTB-QSFP28-100G-SR4", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 100, reachLabel: "SR4", fiberType: "MMF", connector: "MPO", wavelengths: "850nm", standard: "100GBASE-SR4" }, + { pid: "FTB-QSFP28-100G-LR4", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 10000, reachLabel: "LR4", fiberType: "SMF", connector: "LC", wavelengths: "1295-1310nm", standard: "100GBASE-LR4" }, + { pid: "FTB-QSFP28-100G-CWDM4", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 2000, reachLabel: "CWDM4", fiberType: "SMF", connector: "LC", wavelengths: "1271-1331nm", standard: "100GBASE-CWDM4" }, + { pid: "FTB-QSFP28-100G-DR", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 500, reachLabel: "DR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "100GBASE-DR" }, + + // ── 100G CFP2 Coherent ─────────────────────────────────────────────────── + { pid: "FTB-CFP2-100G-DCO", formFactor: "CFP2", speedGbps: 100, speed: "100G", reachMeters: 1500000, reachLabel: "DCO", fiberType: "SMF", connector: "LC", wavelengths: "C-band", category: "Telecom", notes: "EXFO 100G CFP2 DCO coherent test transceiver" }, + + // ── 400G QSFP-DD ──────────────────────────────────────────────────────── + { pid: "FTB-QSFPDD-400G-SR8", formFactor: "QSFP-DD", speedGbps: 400, speed: "400G", reachMeters: 100, reachLabel: "SR8", fiberType: "MMF", connector: "MPO", wavelengths: "850nm", standard: "400GBASE-SR8" }, + { pid: "FTB-QSFPDD-400G-DR4", formFactor: "QSFP-DD", speedGbps: 400, speed: "400G", reachMeters: 500, reachLabel: "DR4", fiberType: "SMF", connector: "MPO", wavelengths: "1310nm", standard: "400GBASE-DR4" }, + { pid: "FTB-QSFPDD-400G-FR4", formFactor: "QSFP-DD", speedGbps: 400, speed: "400G", reachMeters: 2000, reachLabel: "FR4", fiberType: "SMF", connector: "LC", wavelengths: "1271-1331nm", standard: "400GBASE-FR4" }, + { pid: "FTB-QSFPDD-400G-ZR", formFactor: "QSFP-DD", speedGbps: 400, speed: "400G", reachMeters: 120000, reachLabel: "ZR", fiberType: "SMF", connector: "LC", wavelengths: "C-band", standard: "400ZR", category: "Telecom", notes: "EXFO 400G ZR coherent QSFP-DD" }, + + // ── DAC ───────────────────────────────────────────────────────────────── + { pid: "FTB-DAC-10G-1M", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 1, reachLabel: "DAC-1M", fiberType: "DAC", connector: "SFP+" }, + { pid: "FTB-DAC-10G-3M", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 3, reachLabel: "DAC-3M", fiberType: "DAC", connector: "SFP+" }, + { pid: "FTB-DAC-100G-1M", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 1, reachLabel: "DAC-1M", fiberType: "DAC", connector: "QSFP28" }, + { pid: "FTB-DAC-400G-1M", formFactor: "QSFP-DD", speedGbps: 400, speed: "400G", reachMeters: 1, reachLabel: "DAC-1M", fiberType: "DAC", connector: "QSFP-DD" }, +]; + +// PIDs that use 'Telecom' category (coherent/DWDM) +const TELECOM_PIDS = new Set([ + "FTB-SFP-10G-DW-TUNE", + "FTB-CFP2-100G-DCO", + "FTB-QSFPDD-400G-ZR", +]); + +export async function scrapeExfoOem(): Promise { + console.log("=== EXFO OEM Transceiver Seed ===\n"); + + const vendorId = await ensureVendor( + "EXFO", + "oem", + "https://www.exfo.com", + undefined + ); + + let inserted = 0; + let updated = 0; + let errors = 0; + + for (const p of EXFO_PIDS) { + const slug = `exfo-${p.pid.toLowerCase().replace(/[^a-z0-9]+/g, "-")}`; + const category = p.category ?? (TELECOM_PIDS.has(p.pid) ? "Telecom" : "DataCenter"); + try { + const res = await pool.query( + `INSERT INTO transceivers + (slug, part_number, vendor_id, form_factor, speed, speed_gbps, + reach_meters, reach_label, fiber_type, connector, wavelengths, + dom_support, ieee_reference, market_status, category, notes) + VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,true,$12,'Mainstream',$13,$14) + ON CONFLICT (slug) DO UPDATE SET + speed_gbps = EXCLUDED.speed_gbps, + reach_meters = CASE WHEN EXCLUDED.reach_meters > 0 THEN EXCLUDED.reach_meters ELSE transceivers.reach_meters END, + fiber_type = CASE WHEN EXCLUDED.fiber_type <> '' THEN EXCLUDED.fiber_type ELSE transceivers.fiber_type END, + wavelengths = COALESCE(EXCLUDED.wavelengths, transceivers.wavelengths), + updated_at = NOW() + RETURNING (xmax = 0) as was_inserted`, + [slug, p.pid, vendorId, p.formFactor, p.speed, p.speedGbps, + p.reachMeters, p.reachLabel, p.fiberType, p.connector, + p.wavelengths ?? null, p.standard ?? null, category, p.notes ?? null] + ); + if (res.rows[0]?.was_inserted) inserted++; else updated++; + } catch (err) { + console.warn(` Skip ${p.pid}: ${(err as Error).message.slice(0, 80)}`); + errors++; + } + } + + console.log(`\n=== EXFO OEM Seed Complete ===`); + console.log(` Inserted: ${inserted}`); + console.log(` Updated: ${updated}`); + console.log(` Errors: ${errors}`); + console.log(` Total PIDs: ${EXFO_PIDS.length}\n`); +} + +if (require.main === module) { + scrapeExfoOem() + .then(() => pool.end()) + .catch((err) => { + console.error("Fatal:", err); + pool.end(); + process.exit(1); + }); +} diff --git a/packages/scraper/src/scrapers/extreme-campus-oem.ts b/packages/scraper/src/scrapers/extreme-campus-oem.ts new file mode 100644 index 0000000..5e7fc05 --- /dev/null +++ b/packages/scraper/src/scrapers/extreme-campus-oem.ts @@ -0,0 +1,122 @@ +/** + * Extreme Campus OEM Transceiver Catalog Seed + * + * Seeds Extreme Networks campus-branded transceiver PIDs for EXOS and + * VOSS platforms including X440-G2, X450-G2, X460-G2, X620, X690, + * X870, and VSP series switches. + * + * Sources: + * - Extreme Networks Optics Compatibility Matrix + * - Extreme Networks Transceiver Module Data Sheet + * - Extreme Networks Summit Switch Optics Selection Guide + * - ExtremeXOS Hardware Compatibility Table (EXOS HCT) + * + * Run: tsx packages/scraper/src/scrapers/extreme-campus-oem.ts + * Cron: daily at 14:00 + */ + +import { pool, ensureVendor } from "../utils/db"; + +interface ExtremeCampusPID { + pid: string; + formFactor: string; + speedGbps: number; + speed: string; + reachMeters: number; + reachLabel: string; + fiberType: string; + connector: string; + wavelengths?: string; + standard?: string; + notes?: string; +} + +const EXTREME_CAMPUS_PIDS: ExtremeCampusPID[] = [ + // ── 1G SFP ────────────────────────────────────────────────────────────── + { pid: "10301", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 550, reachLabel: "SX", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "1000BASE-SX", notes: "Extreme Networks 1GbE SX SFP 550m MMF (PN 10301)" }, + { pid: "10302", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 10000, reachLabel: "LX", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "1000BASE-LX", notes: "Extreme Networks 1GbE LX SFP 10km SMF (PN 10302)" }, + { pid: "10303", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 100, reachLabel: "T", fiberType: "DAC", connector: "RJ45", standard: "1000BASE-T", notes: "Extreme Networks 1GbE copper SFP RJ45 (PN 10303)" }, + { pid: "10303T", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 100, reachLabel: "T", fiberType: "DAC", connector: "RJ45", standard: "1000BASE-T", notes: "Extreme Networks 1GbE copper SFP RJ45 alt SKU (PN 10303T)" }, + { pid: "10304", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 70000, reachLabel: "ZX-70km", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "1000BASE-ZX", notes: "Extreme Networks 1GbE ZX SFP 70km SMF (PN 10304)" }, + + // ── 10G SFP+ ──────────────────────────────────────────────────────────── + { pid: "10305", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 300, reachLabel: "SR", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "10GBASE-SR", notes: "Extreme Networks 10GbE SR SFP+ 300m MMF (PN 10305)" }, + { pid: "10306", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 10000, reachLabel: "LR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "10GBASE-LR", notes: "Extreme Networks 10GbE LR SFP+ 10km SMF (PN 10306)" }, + { pid: "10307", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 40000, reachLabel: "ER", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "10GBASE-ER", notes: "Extreme Networks 10GbE ER SFP+ 40km SMF (PN 10307)" }, + { pid: "10308", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 80000, reachLabel: "ZR", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "10GBASE-ZR", notes: "Extreme Networks 10GbE ZR SFP+ 80km SMF (PN 10308)" }, + { pid: "10309", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 220, reachLabel: "LRM", fiberType: "MMF", connector: "LC", wavelengths: "1310nm", standard: "10GBASE-LRM", notes: "Extreme Networks 10GbE LRM SFP+ 220m MMF (PN 10309)" }, + + // ── 40G QSFP+ ─────────────────────────────────────────────────────────── + { pid: "10321", formFactor: "QSFP+", speedGbps: 40, speed: "40G", reachMeters: 150, reachLabel: "SR4", fiberType: "MMF", connector: "MPO", wavelengths: "850nm", standard: "40GBASE-SR4", notes: "Extreme Networks 40GbE SR4 QSFP+ 150m MMF (PN 10321)" }, + { pid: "10322", formFactor: "QSFP+", speedGbps: 40, speed: "40G", reachMeters: 10000, reachLabel: "LR4", fiberType: "SMF", connector: "LC", wavelengths: "1295-1310nm", standard: "40GBASE-LR4", notes: "Extreme Networks 40GbE LR4 QSFP+ 10km SMF (PN 10322)" }, + + // ── 25G SFP28 ─────────────────────────────────────────────────────────── + { pid: "10323", formFactor: "SFP28", speedGbps: 25, speed: "25G", reachMeters: 100, reachLabel: "SR", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "25GBASE-SR", notes: "Extreme Networks 25GbE SR SFP28 100m MMF (PN 10323)" }, + { pid: "10324", formFactor: "SFP28", speedGbps: 25, speed: "25G", reachMeters: 10000, reachLabel: "LR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "25GBASE-LR", notes: "Extreme Networks 25GbE LR SFP28 10km SMF (PN 10324)" }, + + // ── 100G QSFP28 ───────────────────────────────────────────────────────── + { pid: "10331", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 100, reachLabel: "SR4", fiberType: "MMF", connector: "MPO", wavelengths: "850nm", standard: "100GBASE-SR4", notes: "Extreme Networks 100GbE SR4 QSFP28 100m MMF (PN 10331)" }, + { pid: "10332", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 10000, reachLabel: "LR4", fiberType: "SMF", connector: "LC", wavelengths: "1295-1310nm", standard: "100GBASE-LR4", notes: "Extreme Networks 100GbE LR4 QSFP28 10km SMF (PN 10332)" }, + + // ── 400G QSFP-DD ──────────────────────────────────────────────────────── + { pid: "10340", formFactor: "QSFP-DD", speedGbps: 400, speed: "400G", reachMeters: 500, reachLabel: "DR4", fiberType: "SMF", connector: "MPO", wavelengths: "1310nm", standard: "400GBASE-DR4", notes: "Extreme Networks 400GbE DR4 QSFP-DD 500m SMF (PN 10340)" }, + { pid: "10341", formFactor: "QSFP-DD", speedGbps: 400, speed: "400G", reachMeters: 100, reachLabel: "SR8", fiberType: "MMF", connector: "MPO", wavelengths: "850nm", standard: "400GBASE-SR8", notes: "Extreme Networks 400GbE SR8 QSFP-DD 100m MMF (PN 10341)" }, +]; + +export async function scrapeExtremeCampusOem(): Promise { + console.log("=== Extreme Campus OEM Transceiver Seed ===\n"); + + const vendorId = await ensureVendor( + "Extreme Campus", + "oem", + "https://www.extremenetworks.com/products/switches/", + undefined + ); + + let inserted = 0; + let updated = 0; + let errors = 0; + + for (const p of EXTREME_CAMPUS_PIDS) { + const slug = `extreme-campus-${p.pid.toLowerCase().replace(/[^a-z0-9]+/g, "-")}`; + try { + const res = await pool.query( + `INSERT INTO transceivers + (slug, part_number, vendor_id, form_factor, speed, speed_gbps, + reach_meters, reach_label, fiber_type, connector, wavelengths, + dom_support, ieee_reference, market_status, category, notes) + VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,true,$12,'Mainstream','DataCenter',$13) + ON CONFLICT (slug) DO UPDATE SET + speed_gbps = EXCLUDED.speed_gbps, + reach_meters = CASE WHEN EXCLUDED.reach_meters > 0 THEN EXCLUDED.reach_meters ELSE transceivers.reach_meters END, + fiber_type = CASE WHEN EXCLUDED.fiber_type <> '' THEN EXCLUDED.fiber_type ELSE transceivers.fiber_type END, + wavelengths = COALESCE(EXCLUDED.wavelengths, transceivers.wavelengths), + updated_at = NOW() + RETURNING (xmax = 0) as was_inserted`, + [slug, p.pid, vendorId, p.formFactor, p.speed, p.speedGbps, + p.reachMeters, p.reachLabel, p.fiberType, p.connector, + p.wavelengths ?? null, p.standard ?? null, p.notes ?? null] + ); + if (res.rows[0]?.was_inserted) inserted++; else updated++; + } catch (err) { + console.warn(` Skip ${p.pid}: ${(err as Error).message.slice(0, 80)}`); + errors++; + } + } + + console.log(`\n=== Extreme Campus OEM Seed Complete ===`); + console.log(` Inserted: ${inserted}`); + console.log(` Updated: ${updated}`); + console.log(` Errors: ${errors}`); + console.log(` Total PIDs: ${EXTREME_CAMPUS_PIDS.length}\n`); +} + +if (require.main === module) { + scrapeExtremeCampusOem() + .then(() => pool.end()) + .catch((err) => { + console.error("Fatal:", err); + pool.end(); + process.exit(1); + }); +} diff --git a/packages/scraper/src/scrapers/f5-oem.ts b/packages/scraper/src/scrapers/f5-oem.ts new file mode 100644 index 0000000..86fdfef --- /dev/null +++ b/packages/scraper/src/scrapers/f5-oem.ts @@ -0,0 +1,120 @@ +/** + * F5 Networks OEM Transceiver Catalog Seed + * Seeds F5-branded transceiver PIDs for BIG-IP i-series, rSeries, and VELOS chassis. + * Sources: F5 Hardware and Software Compatibility Matrix (support.f5.com) + * Run: tsx packages/scraper/src/scrapers/f5-oem.ts + * Cron: daily at 07:30 + */ +import { pool, ensureVendor } from "../utils/db"; + +interface F5PID { + pid: string; + formFactor: string; + speedGbps: number; + speed: string; + reachMeters: number; + reachLabel: string; + fiberType: string; + connector: string; + wavelengths?: string; + standard?: string; + notes?: string; +} + +const F5_PIDS: F5PID[] = [ + // ── 1G SFP ────────────────────────────────────────────────────────────── + { pid: "OPT-0010-00", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 550, reachLabel: "SX", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "1000BASE-SX" }, + { pid: "OPT-0011-00", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 10000, reachLabel: "LX", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "1000BASE-LX" }, + { pid: "OPT-0016-00", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 80000, reachLabel: "ZX", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "1000BASE-ZX" }, + { pid: "OPT-0019-00", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 100, reachLabel: "T", fiberType: "DAC", connector: "RJ45", standard: "1000BASE-T" }, + + // ── 10G SFP+ ──────────────────────────────────────────────────────────── + { pid: "OPT-0030-00", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 300, reachLabel: "SR", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "10GBASE-SR" }, + { pid: "OPT-0031-00", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 10000, reachLabel: "LR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "10GBASE-LR" }, + { pid: "OPT-0032-00", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 40000, reachLabel: "ER", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "10GBASE-ER" }, + { pid: "OPT-0033-00", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 80000, reachLabel: "ZR", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "10GBASE-ZR" }, + { pid: "OPT-0039-00", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 30, reachLabel: "T", fiberType: "DAC", connector: "RJ45", standard: "10GBASE-T" }, + + // ── 25G SFP28 ─────────────────────────────────────────────────────────── + { pid: "OPT-0050-00", formFactor: "SFP28", speedGbps: 25, speed: "25G", reachMeters: 100, reachLabel: "SR", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "25GBASE-SR" }, + { pid: "OPT-0051-00", formFactor: "SFP28", speedGbps: 25, speed: "25G", reachMeters: 10000, reachLabel: "LR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "25GBASE-LR" }, + + // ── 40G QSFP+ ─────────────────────────────────────────────────────────── + { pid: "OPT-0040-00", formFactor: "QSFP+", speedGbps: 40, speed: "40G", reachMeters: 150, reachLabel: "SR4", fiberType: "MMF", connector: "MPO", wavelengths: "850nm", standard: "40GBASE-SR4" }, + { pid: "OPT-0041-00", formFactor: "QSFP+", speedGbps: 40, speed: "40G", reachMeters: 10000, reachLabel: "LR4", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "40GBASE-LR4" }, + + // ── 100G QSFP28 ───────────────────────────────────────────────────────── + { pid: "OPT-0060-00", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 100, reachLabel: "SR4", fiberType: "MMF", connector: "MPO", wavelengths: "850nm", standard: "100GBASE-SR4" }, + { pid: "OPT-0061-00", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 10000, reachLabel: "LR4", fiberType: "SMF", connector: "LC", wavelengths: "1295-1310nm", standard: "100GBASE-LR4" }, + { pid: "OPT-0062-00", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 2000, reachLabel: "CWDM4", fiberType: "SMF", connector: "LC", wavelengths: "1271-1331nm", standard: "100GBASE-CWDM4" }, + { pid: "OPT-0063-00", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 500, reachLabel: "DR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "100GBASE-DR" }, + + // ── 400G QSFP-DD (VELOS chassis) ──────────────────────────────────────── + { pid: "OPT-0080-00", formFactor: "QSFP-DD", speedGbps: 400, speed: "400G", reachMeters: 100, reachLabel: "SR8", fiberType: "MMF", connector: "MPO", wavelengths: "850nm", standard: "400GBASE-SR8" }, + { pid: "OPT-0081-00", formFactor: "QSFP-DD", speedGbps: 400, speed: "400G", reachMeters: 500, reachLabel: "DR4", fiberType: "SMF", connector: "MPO", wavelengths: "1310nm", standard: "400GBASE-DR4" }, + { pid: "OPT-0082-00", formFactor: "QSFP-DD", speedGbps: 400, speed: "400G", reachMeters: 2000, reachLabel: "FR4", fiberType: "SMF", connector: "LC", wavelengths: "1271-1331nm", standard: "400GBASE-FR4" }, + + // ── DAC ───────────────────────────────────────────────────────────────── + { pid: "CBL-0010-01", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 1, reachLabel: "DAC-1M", fiberType: "DAC", connector: "SFP+" }, + { pid: "CBL-0010-03", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 3, reachLabel: "DAC-3M", fiberType: "DAC", connector: "SFP+" }, + { pid: "CBL-0060-01", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 1, reachLabel: "DAC-1M", fiberType: "DAC", connector: "QSFP28" }, + { pid: "CBL-0060-03", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 3, reachLabel: "DAC-3M", fiberType: "DAC", connector: "QSFP28" }, +]; + +export async function scrapeF5Oem(): Promise { + console.log("=== F5 Networks OEM Transceiver Seed ===\n"); + + const vendorId = await ensureVendor( + "F5 Networks", + "oem", + "https://www.f5.com", + undefined + ); + + let inserted = 0; + let updated = 0; + let errors = 0; + + for (const p of F5_PIDS) { + const slug = `f5-${p.pid.toLowerCase().replace(/[^a-z0-9]+/g, "-")}`; + try { + const res = await pool.query( + `INSERT INTO transceivers + (slug, part_number, vendor_id, form_factor, speed, speed_gbps, + reach_meters, reach_label, fiber_type, connector, wavelengths, + dom_support, ieee_reference, market_status, category, notes) + VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,true,$12,'Mainstream','DataCenter',$13) + ON CONFLICT (slug) DO UPDATE SET + speed_gbps = EXCLUDED.speed_gbps, + reach_meters = CASE WHEN EXCLUDED.reach_meters > 0 THEN EXCLUDED.reach_meters ELSE transceivers.reach_meters END, + fiber_type = CASE WHEN EXCLUDED.fiber_type <> '' THEN EXCLUDED.fiber_type ELSE transceivers.fiber_type END, + wavelengths = COALESCE(EXCLUDED.wavelengths, transceivers.wavelengths), + updated_at = NOW() + RETURNING (xmax = 0) as was_inserted`, + [slug, p.pid, vendorId, p.formFactor, p.speed, p.speedGbps, + p.reachMeters, p.reachLabel, p.fiberType, p.connector, + p.wavelengths ?? null, p.standard ?? null, p.notes ?? null] + ); + if (res.rows[0]?.was_inserted) inserted++; else updated++; + } catch (err) { + console.warn(` Skip ${p.pid}: ${(err as Error).message.slice(0, 80)}`); + errors++; + } + } + + console.log(`\n=== F5 Networks OEM Seed Complete ===`); + console.log(` Inserted: ${inserted}`); + console.log(` Updated: ${updated}`); + console.log(` Errors: ${errors}`); + console.log(` Total PIDs: ${F5_PIDS.length}\n`); +} + +if (require.main === module) { + scrapeF5Oem() + .then(() => pool.end()) + .catch((err) => { + console.error("Fatal:", err); + pool.end(); + process.exit(1); + }); +} diff --git a/packages/scraper/src/scrapers/fiberhome-oem.ts b/packages/scraper/src/scrapers/fiberhome-oem.ts new file mode 100644 index 0000000..47c0854 --- /dev/null +++ b/packages/scraper/src/scrapers/fiberhome-oem.ts @@ -0,0 +1,144 @@ +/** + * FiberHome Technologies OEM Transceiver Catalog Seed + * + * Seeds FiberHome-branded transceiver PIDs covering PON access, metro + * transport, DWDM/CWDM, and data-center switching platforms from + * FiberHome Technologies Group (Wuhan, China). + * + * Sources: + * - FiberHome Optical Transceiver Product Overview (fiberhome.com) + * - FiberHome AN6000 / TN55 / TN22 Compatibility Guide + * - FiberHome PON OLT Transceiver Specification Sheets + * + * Run: tsx packages/scraper/src/scrapers/fiberhome-oem.ts + * Cron: daily at 19:15 + */ + +import { pool, ensureVendor } from "../utils/db"; + +interface FiberhomePID { + pid: string; + formFactor: string; + speedGbps: number; + speed: string; + reachMeters: number; + reachLabel: string; + fiberType: string; + connector: string; + wavelengths?: string; + standard?: string; + notes?: string; + isTelecom?: boolean; +} + +// PIDs that belong to TELECOM category (PON, BiDi, CWDM, DWDM, CFP2-DCO, ZR) +const TELECOM_PIDS = new Set([ + "FH-SFP-GPON-OLT", + "FH-SFP-XGS-PON-OLT", + "FH-SFP-GE-BIDI-1310", + "FH-SFP-CWDM-1550", + "FH-DWDM-SFP-C", + "FH-CFP2-DCO-100G", + "FH-SFP-10G-ZR", +]); + +const FIBERHOME_PIDS: FiberhomePID[] = [ + // ── 1G SFP ────────────────────────────────────────────────────────────── + { pid: "FH-SFP-GE-SX", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 550, reachLabel: "SX", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "1000BASE-SX", notes: "FiberHome 1G SFP SX 550m MMF" }, + { pid: "FH-SFP-GE-LX", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 10000, reachLabel: "LX", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "1000BASE-LX", notes: "FiberHome 1G SFP LX 10km SMF" }, + { pid: "FH-SFP-GE-T", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 100, reachLabel: "T", fiberType: "DAC", connector: "RJ45", standard: "1000BASE-T", notes: "FiberHome 1G SFP copper RJ45" }, + { pid: "FH-SFP-GE-BIDI-1310", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 20000, reachLabel: "BiDi", fiberType: "SMF", connector: "LC", wavelengths: "1310/1490nm", standard: "1000BASE-BX10", notes: "FiberHome 1G SFP BiDi TX1310/RX1490 20km SMF" }, + + // ── 10G SFP+ ──────────────────────────────────────────────────────────── + { pid: "FH-SFP-10G-SR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 300, reachLabel: "SR", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "10GBASE-SR", notes: "FiberHome 10G SFP+ SR 300m MMF" }, + { pid: "FH-SFP-10G-LR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 10000, reachLabel: "LR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "10GBASE-LR", notes: "FiberHome 10G SFP+ LR 10km SMF" }, + { pid: "FH-SFP-10G-ER", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 40000, reachLabel: "ER", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "10GBASE-ER", notes: "FiberHome 10G SFP+ ER 40km SMF" }, + { pid: "FH-SFP-10G-ZR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 80000, reachLabel: "ZR", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "10GBASE-ZR", notes: "FiberHome 10G SFP+ ZR 80km SMF" }, + + // ── 25G SFP28 ─────────────────────────────────────────────────────────── + { pid: "FH-SFP28-25G-SR", formFactor: "SFP28", speedGbps: 25, speed: "25G", reachMeters: 100, reachLabel: "SR", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "25GBASE-SR", notes: "FiberHome 25G SFP28 SR 100m MMF" }, + { pid: "FH-SFP28-25G-LR", formFactor: "SFP28", speedGbps: 25, speed: "25G", reachMeters: 10000, reachLabel: "LR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "25GBASE-LR", notes: "FiberHome 25G SFP28 LR 10km SMF" }, + + // ── 40G QSFP+ ─────────────────────────────────────────────────────────── + { pid: "FH-QSFP-40G-SR4", formFactor: "QSFP+", speedGbps: 40, speed: "40G", reachMeters: 150, reachLabel: "SR4", fiberType: "MMF", connector: "MPO", wavelengths: "850nm", standard: "40GBASE-SR4", notes: "FiberHome 40G QSFP+ SR4 150m MMF" }, + { pid: "FH-QSFP-40G-LR4", formFactor: "QSFP+", speedGbps: 40, speed: "40G", reachMeters: 10000, reachLabel: "LR4", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "40GBASE-LR4", notes: "FiberHome 40G QSFP+ LR4 10km SMF" }, + + // ── 100G QSFP28 ───────────────────────────────────────────────────────── + { pid: "FH-QSFP28-100G-SR4", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 100, reachLabel: "SR4", fiberType: "MMF", connector: "MPO", wavelengths: "850nm", standard: "100GBASE-SR4", notes: "FiberHome 100G QSFP28 SR4 100m MMF" }, + { pid: "FH-QSFP28-100G-LR4", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 10000, reachLabel: "LR4", fiberType: "SMF", connector: "LC", wavelengths: "1295-1310nm", standard: "100GBASE-LR4", notes: "FiberHome 100G QSFP28 LR4 10km SMF" }, + + // ── 400G QSFP-DD ──────────────────────────────────────────────────────── + { pid: "FH-QSFP-DD-400G-DR4", formFactor: "QSFP-DD", speedGbps: 400, speed: "400G", reachMeters: 500, reachLabel: "DR4", fiberType: "SMF", connector: "MPO", wavelengths: "1310nm", standard: "400GBASE-DR4", notes: "FiberHome 400G QSFP-DD DR4 500m SMF" }, + + // ── PON / Access (Telecom) ─────────────────────────────────────────────── + { pid: "FH-SFP-GPON-OLT", formFactor: "SFP", speedGbps: 2.5, speed: "2.5G", reachMeters: 20000, reachLabel: "GPON", fiberType: "SMF", connector: "SC", wavelengths: "1490/1310nm", standard: "ITU-T G.984", notes: "FiberHome GPON OLT SFP TX1490/RX1310 20km" }, + { pid: "FH-SFP-XGS-PON-OLT", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 20000, reachLabel: "XGS-PON",fiberType: "SMF", connector: "SC", wavelengths: "1577/1270nm", standard: "ITU-T G.9807", notes: "FiberHome XGS-PON OLT SFP+ TX1577/RX1270 20km" }, + + // ── CWDM (Telecom) ─────────────────────────────────────────────────────── + { pid: "FH-SFP-CWDM-1550", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 80000, reachLabel: "CWDM", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "ITU-T G.694.2", notes: "FiberHome 10G CWDM SFP+ 1550nm 80km SMF" }, + + // ── DWDM (Telecom) ─────────────────────────────────────────────────────── + { pid: "FH-DWDM-SFP-C", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 80000, reachLabel: "DWDM", fiberType: "SMF", connector: "LC", wavelengths: "C-band tunable", standard: "ITU-T G.694.1", notes: "FiberHome 10G DWDM SFP+ C-band tunable 80km" }, + + // ── CFP2-DCO (Telecom) ─────────────────────────────────────────────────── + { pid: "FH-CFP2-DCO-100G", formFactor: "CFP2", speedGbps: 100, speed: "100G", reachMeters: 1000000,reachLabel: "DCO", fiberType: "SMF", connector: "LC", wavelengths: "C-band tunable", standard: "OIF CFP2-DCO", notes: "FiberHome 100G CFP2 DCO coherent C-band, 1000km span" }, +]; + +export async function scrapeFiberhomeOem(): Promise { + console.log("=== FiberHome Technologies OEM Transceiver Seed ===\n"); + + const vendorId = await ensureVendor( + "FiberHome Technologies", + "oem", + "https://www.fiberhome.com", + undefined + ); + + let inserted = 0; + let updated = 0; + let errors = 0; + + for (const p of FIBERHOME_PIDS) { + const slug = `fiberhome-${p.pid.toLowerCase().replace(/[^a-z0-9]+/g, "-")}`; + const category = TELECOM_PIDS.has(p.pid) ? "Telecom" : "DataCenter"; + try { + const res = await pool.query( + `INSERT INTO transceivers + (slug, part_number, vendor_id, form_factor, speed, speed_gbps, + reach_meters, reach_label, fiber_type, connector, wavelengths, + dom_support, ieee_reference, market_status, category, notes) + VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,true,$12,'Mainstream',$13,$14) + ON CONFLICT (slug) DO UPDATE SET + speed_gbps = EXCLUDED.speed_gbps, + reach_meters = CASE WHEN EXCLUDED.reach_meters > 0 THEN EXCLUDED.reach_meters ELSE transceivers.reach_meters END, + fiber_type = CASE WHEN EXCLUDED.fiber_type <> '' THEN EXCLUDED.fiber_type ELSE transceivers.fiber_type END, + wavelengths = COALESCE(EXCLUDED.wavelengths, transceivers.wavelengths), + updated_at = NOW() + RETURNING (xmax = 0) as was_inserted`, + [slug, p.pid, vendorId, p.formFactor, p.speed, p.speedGbps, + p.reachMeters, p.reachLabel, p.fiberType, p.connector, + p.wavelengths ?? null, p.standard ?? null, category, p.notes ?? null] + ); + if (res.rows[0]?.was_inserted) inserted++; else updated++; + } catch (err) { + console.warn(` Skip ${p.pid}: ${(err as Error).message.slice(0, 80)}`); + errors++; + } + } + + console.log(`\n=== FiberHome Technologies OEM Seed Complete ===`); + console.log(` Inserted: ${inserted}`); + console.log(` Updated: ${updated}`); + console.log(` Errors: ${errors}`); + console.log(` Total PIDs: ${FIBERHOME_PIDS.length}\n`); +} + +if (require.main === module) { + scrapeFiberhomeOem() + .then(() => pool.end()) + .catch((err) => { + console.error("Fatal:", err); + pool.end(); + process.exit(1); + }); +} diff --git a/packages/scraper/src/scrapers/fortinet-oem.ts b/packages/scraper/src/scrapers/fortinet-oem.ts new file mode 100644 index 0000000..1899162 --- /dev/null +++ b/packages/scraper/src/scrapers/fortinet-oem.ts @@ -0,0 +1,121 @@ +/** + * Fortinet OEM Transceiver Catalog Seed + * + * Seeds Fortinet-branded transceiver PIDs for FortiGate firewalls and + * FortiSwitch series. All PIDs use the real-world FG-TRAN- naming convention + * matching Fortinet's hardware compatibility lists. + * + * Sources: + * - Fortinet Transceiver Module Data Sheet (fortinet.com) + * - FortiGate 7000/6000/3000 Series Chassis Hardware Guide + * - FortiSwitch 200/400/500/600 Series Hardware Reference + * - Fortinet Compatibility Matrix (HCL) + * + * Run: tsx packages/scraper/src/scrapers/fortinet-oem.ts + * Cron: daily at 22:45 + */ + +import { pool, ensureVendor } from "../utils/db"; + +interface FortinetPID { + pid: string; + formFactor: string; + speedGbps: number; + speed: string; + reachMeters: number; + reachLabel: string; + fiberType: string; + connector: string; + wavelengths?: string; + standard?: string; + notes?: string; +} + +const FORTINET_PIDS: FortinetPID[] = [ + // ── 1G SFP ────────────────────────────────────────────────────────────── + { pid: "FG-TRAN-GE-SX", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 550, reachLabel: "SX", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "1000BASE-SX" }, + { pid: "FG-TRAN-GE-LX", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 10000, reachLabel: "LX", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "1000BASE-LX" }, + { pid: "FG-TRAN-GE-T", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 100, reachLabel: "T", fiberType: "DAC", connector: "RJ45", standard: "1000BASE-T", notes: "Copper RJ45 1G SFP for FortiGate/FortiSwitch" }, + + // ── 10G SFP+ ──────────────────────────────────────────────────────────── + { pid: "FG-TRAN-SFP+SR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 300, reachLabel: "SR", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "10GBASE-SR" }, + { pid: "FG-TRAN-SFP+LR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 10000, reachLabel: "LR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "10GBASE-LR" }, + { pid: "FG-TRAN-SFP+ER", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 40000, reachLabel: "ER", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "10GBASE-ER" }, + { pid: "FG-TRAN-SFP+BIDI", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 20000, reachLabel: "BiDi", fiberType: "SMF", connector: "LC", wavelengths: "1310/1490nm", notes: "10G BiDi single-fiber, 1310Tx/1490Rx, 20km" }, + + // ── 25G SFP28 ─────────────────────────────────────────────────────────── + { pid: "FG-TRAN-SFP28-SR", formFactor: "SFP28", speedGbps: 25, speed: "25G", reachMeters: 100, reachLabel: "SR", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "25GBASE-SR" }, + { pid: "FG-TRAN-SFP28-LR", formFactor: "SFP28", speedGbps: 25, speed: "25G", reachMeters: 10000, reachLabel: "LR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "25GBASE-LR" }, + + // ── 40G QSFP+ ─────────────────────────────────────────────────────────── + { pid: "FG-TRAN-QSFP+SR4", formFactor: "QSFP+", speedGbps: 40, speed: "40G", reachMeters: 150, reachLabel: "SR4", fiberType: "MMF", connector: "MPO", wavelengths: "850nm", standard: "40GBASE-SR4" }, + { pid: "FG-TRAN-QSFP+LR4", formFactor: "QSFP+", speedGbps: 40, speed: "40G", reachMeters: 10000, reachLabel: "LR4", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "40GBASE-LR4" }, + + // ── 100G QSFP28 ───────────────────────────────────────────────────────── + { pid: "FG-TRAN-QSFP28-SR4", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 100, reachLabel: "SR4", fiberType: "MMF", connector: "MPO", wavelengths: "850nm", standard: "100GBASE-SR4" }, + { pid: "FG-TRAN-QSFP28-LR4", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 10000, reachLabel: "LR4", fiberType: "SMF", connector: "LC", wavelengths: "1295-1310nm", standard: "100GBASE-LR4" }, + + // ── DAC ───────────────────────────────────────────────────────────────── + { pid: "FG-TRAN-DAC10G-1M", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 1, reachLabel: "DAC-1M", fiberType: "DAC", connector: "SFP+" }, + { pid: "FG-TRAN-DAC10G-3M", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 3, reachLabel: "DAC-3M", fiberType: "DAC", connector: "SFP+" }, + { pid: "FG-TRAN-DAC40G-1M", formFactor: "QSFP+", speedGbps: 40, speed: "40G", reachMeters: 1, reachLabel: "DAC-1M", fiberType: "DAC", connector: "QSFP+" }, + { pid: "FG-TRAN-DAC100G-1M", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 1, reachLabel: "DAC-1M", fiberType: "DAC", connector: "QSFP28" }, +]; + +export async function scrapeFortinetOem(): Promise { + console.log("=== Fortinet OEM Transceiver Seed ===\n"); + + const vendorId = await ensureVendor( + "Fortinet", + "oem", + "https://www.fortinet.com", + undefined + ); + + let inserted = 0; + let updated = 0; + let errors = 0; + + for (const p of FORTINET_PIDS) { + const slug = `fortinet-${p.pid.toLowerCase().replace(/[^a-z0-9]+/g, "-")}`; + try { + const res = await pool.query( + `INSERT INTO transceivers + (slug, part_number, vendor_id, form_factor, speed, speed_gbps, + reach_meters, reach_label, fiber_type, connector, wavelengths, + dom_support, ieee_reference, market_status, category, notes) + VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,true,$12,'Mainstream','DataCenter',$13) + ON CONFLICT (slug) DO UPDATE SET + speed_gbps = EXCLUDED.speed_gbps, + reach_meters = CASE WHEN EXCLUDED.reach_meters > 0 THEN EXCLUDED.reach_meters ELSE transceivers.reach_meters END, + fiber_type = CASE WHEN EXCLUDED.fiber_type <> '' THEN EXCLUDED.fiber_type ELSE transceivers.fiber_type END, + wavelengths = COALESCE(EXCLUDED.wavelengths, transceivers.wavelengths), + updated_at = NOW() + RETURNING (xmax = 0) as was_inserted`, + [slug, p.pid, vendorId, p.formFactor, p.speed, p.speedGbps, + p.reachMeters, p.reachLabel, p.fiberType, p.connector, + p.wavelengths ?? null, p.standard ?? null, p.notes ?? null] + ); + if (res.rows[0]?.was_inserted) inserted++; else updated++; + } catch (err) { + console.warn(` Skip ${p.pid}: ${(err as Error).message.slice(0, 80)}`); + errors++; + } + } + + console.log(`\n=== Fortinet OEM Seed Complete ===`); + console.log(` Inserted: ${inserted}`); + console.log(` Updated: ${updated}`); + console.log(` Errors: ${errors}`); + console.log(` Total PIDs: ${FORTINET_PIDS.length}\n`); +} + +if (require.main === module) { + scrapeFortinetOem() + .then(() => pool.end()) + .catch((err) => { + console.error("Fatal:", err); + pool.end(); + process.exit(1); + }); +} diff --git a/packages/scraper/src/scrapers/fujitsu-oem.ts b/packages/scraper/src/scrapers/fujitsu-oem.ts new file mode 100644 index 0000000..c1d7318 --- /dev/null +++ b/packages/scraper/src/scrapers/fujitsu-oem.ts @@ -0,0 +1,134 @@ +/** + * Fujitsu Network Communications OEM Transceiver Catalog Seed + * + * Seeds Fujitsu-branded transceiver PIDs for optical transport platforms: + * FLASHWAVE series and 1FINITY platforms. + * + * Sources: + * - Fujitsu 1FINITY Transceiver Module Guide + * - Fujitsu FLASHWAVE Platform Hardware Installation Guide + * - Fujitsu Network Communications Product Portfolio (fujitsu.com) + * + * Run: tsx packages/scraper/src/scrapers/fujitsu-oem.ts + * Cron: daily at 18:30 + */ + +import { pool, ensureVendor } from "../utils/db"; + +interface FujitsuPID { + pid: string; + formFactor: string; + speedGbps: number; + speed: string; + reachMeters: number; + reachLabel: string; + fiberType: string; + connector: string; + wavelengths?: string; + standard?: string; + category?: string; + notes?: string; +} + +const FUJITSU_PIDS: FujitsuPID[] = [ + // ── 1G SFP ────────────────────────────────────────────────────────────── + { pid: "FC-SFP-1G-SX", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 550, reachLabel: "SX", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "1000BASE-SX" }, + { pid: "FC-SFP-1G-LX", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 10000, reachLabel: "LX", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "1000BASE-LX" }, + { pid: "FC-SFP-1G-ZX", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 80000, reachLabel: "ZX", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "1000BASE-ZX" }, + + // ── 10G SFP+ Ethernet ─────────────────────────────────────────────────── + { pid: "FC-SFP-10G-SR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 300, reachLabel: "SR", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "10GBASE-SR" }, + { pid: "FC-SFP-10G-LR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 10000, reachLabel: "LR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "10GBASE-LR" }, + { pid: "FC-SFP-10G-ER", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 40000, reachLabel: "ER", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "10GBASE-ER" }, + { pid: "FC-SFP-10G-ZR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 80000, reachLabel: "ZR", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "10GBASE-ZR" }, + + // ── 10G DWDM SFP+ ─────────────────────────────────────────────────────── + { pid: "FC-SFP-10G-DWDM-TUNE", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 80000, reachLabel: "DWDM", fiberType: "SMF", connector: "LC", wavelengths: "C-band DWDM", category: "Telecom", notes: "Fujitsu 10G DWDM tunable SFP+ for FLASHWAVE" }, + + // ── 100G QSFP28 ───────────────────────────────────────────────────────── + { pid: "FC-QSFP28-100G-SR4", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 100, reachLabel: "SR4", fiberType: "MMF", connector: "MPO", wavelengths: "850nm", standard: "100GBASE-SR4" }, + { pid: "FC-QSFP28-100G-LR4", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 10000, reachLabel: "LR4", fiberType: "SMF", connector: "LC", wavelengths: "1295-1310nm", standard: "100GBASE-LR4" }, + { pid: "FC-QSFP28-100G-CWDM4", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 2000, reachLabel: "CWDM4", fiberType: "SMF", connector: "LC", wavelengths: "1271-1331nm", standard: "100GBASE-CWDM4" }, + + // ── 100G CFP2 Coherent ─────────────────────────────────────────────────── + { pid: "FC-CFP2-100G-DCO", formFactor: "CFP2", speedGbps: 100, speed: "100G", reachMeters: 1500000, reachLabel: "DCO", fiberType: "SMF", connector: "LC", wavelengths: "C-band", category: "Telecom", notes: "Fujitsu 100G CFP2 DCO coherent" }, + + // ── 400G QSFP-DD ──────────────────────────────────────────────────────── + { pid: "FC-QSFPDD-400G-SR8", formFactor: "QSFP-DD", speedGbps: 400, speed: "400G", reachMeters: 100, reachLabel: "SR8", fiberType: "MMF", connector: "MPO", wavelengths: "850nm", standard: "400GBASE-SR8" }, + { pid: "FC-QSFPDD-400G-DR4", formFactor: "QSFP-DD", speedGbps: 400, speed: "400G", reachMeters: 500, reachLabel: "DR4", fiberType: "SMF", connector: "MPO", wavelengths: "1310nm", standard: "400GBASE-DR4" }, + { pid: "FC-QSFPDD-400G-FR4", formFactor: "QSFP-DD", speedGbps: 400, speed: "400G", reachMeters: 2000, reachLabel: "FR4", fiberType: "SMF", connector: "LC", wavelengths: "1271-1331nm", standard: "400GBASE-FR4" }, + { pid: "FC-QSFPDD-400G-LR4", formFactor: "QSFP-DD", speedGbps: 400, speed: "400G", reachMeters: 10000, reachLabel: "LR4", fiberType: "SMF", connector: "LC", wavelengths: "1295-1310nm", standard: "400GBASE-LR4" }, + { pid: "FC-QSFPDD-400G-ZR", formFactor: "QSFP-DD", speedGbps: 400, speed: "400G", reachMeters: 120000, reachLabel: "ZR", fiberType: "SMF", connector: "LC", wavelengths: "C-band", standard: "400ZR", category: "Telecom", notes: "Fujitsu 400G ZR coherent QSFP-DD" }, + + // ── DAC ───────────────────────────────────────────────────────────────── + { pid: "FC-DAC-10G-1M", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 1, reachLabel: "DAC-1M", fiberType: "DAC", connector: "SFP+" }, + { pid: "FC-DAC-10G-3M", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 3, reachLabel: "DAC-3M", fiberType: "DAC", connector: "SFP+" }, + { pid: "FC-DAC-100G-1M", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 1, reachLabel: "DAC-1M", fiberType: "DAC", connector: "QSFP28" }, + { pid: "FC-DAC-400G-1M", formFactor: "QSFP-DD", speedGbps: 400, speed: "400G", reachMeters: 1, reachLabel: "DAC-1M", fiberType: "DAC", connector: "QSFP-DD" }, +]; + +// PIDs that use 'Telecom' category (coherent/DWDM) +const TELECOM_PIDS = new Set([ + "FC-SFP-10G-DWDM-TUNE", + "FC-CFP2-100G-DCO", + "FC-QSFPDD-400G-ZR", +]); + +export async function scrapeFujitsuOem(): Promise { + console.log("=== Fujitsu Network Communications OEM Transceiver Seed ===\n"); + + const vendorId = await ensureVendor( + "Fujitsu Network Communications", + "oem", + "https://www.fujitsu.com/us/products/network/", + undefined + ); + + let inserted = 0; + let updated = 0; + let errors = 0; + + for (const p of FUJITSU_PIDS) { + const slug = `fujitsu-${p.pid.toLowerCase().replace(/[^a-z0-9]+/g, "-")}`; + const category = p.category ?? (TELECOM_PIDS.has(p.pid) ? "Telecom" : "DataCenter"); + try { + const res = await pool.query( + `INSERT INTO transceivers + (slug, part_number, vendor_id, form_factor, speed, speed_gbps, + reach_meters, reach_label, fiber_type, connector, wavelengths, + dom_support, ieee_reference, market_status, category, notes) + VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,true,$12,'Mainstream',$13,$14) + ON CONFLICT (slug) DO UPDATE SET + speed_gbps = EXCLUDED.speed_gbps, + reach_meters = CASE WHEN EXCLUDED.reach_meters > 0 THEN EXCLUDED.reach_meters ELSE transceivers.reach_meters END, + fiber_type = CASE WHEN EXCLUDED.fiber_type <> '' THEN EXCLUDED.fiber_type ELSE transceivers.fiber_type END, + wavelengths = COALESCE(EXCLUDED.wavelengths, transceivers.wavelengths), + updated_at = NOW() + RETURNING (xmax = 0) as was_inserted`, + [slug, p.pid, vendorId, p.formFactor, p.speed, p.speedGbps, + p.reachMeters, p.reachLabel, p.fiberType, p.connector, + p.wavelengths ?? null, p.standard ?? null, category, p.notes ?? null] + ); + if (res.rows[0]?.was_inserted) inserted++; else updated++; + } catch (err) { + console.warn(` Skip ${p.pid}: ${(err as Error).message.slice(0, 80)}`); + errors++; + } + } + + console.log(`\n=== Fujitsu OEM Seed Complete ===`); + console.log(` Inserted: ${inserted}`); + console.log(` Updated: ${updated}`); + console.log(` Errors: ${errors}`); + console.log(` Total PIDs: ${FUJITSU_PIDS.length}\n`); +} + +if (require.main === module) { + scrapeFujitsuOem() + .then(() => pool.end()) + .catch((err) => { + console.error("Fatal:", err); + pool.end(); + process.exit(1); + }); +} diff --git a/packages/scraper/src/scrapers/ge-grid-oem.ts b/packages/scraper/src/scrapers/ge-grid-oem.ts new file mode 100644 index 0000000..5507a24 --- /dev/null +++ b/packages/scraper/src/scrapers/ge-grid-oem.ts @@ -0,0 +1,118 @@ +/** + * GE Grid Solutions OEM Transceiver Catalog Seed + * + * Seeds transceiver PIDs for GE Grid Solutions industrial SFP/SFP+/SFP28/QSFP+ + * modules used in power grid protection, substation automation, and SCADA + * communication hardware (e.g. Multilin, UR-series, MiCOM relay platforms). + * + * Sources: + * - GE Grid Solutions product catalog (gegridsolutions.com) + * - GE Multilin / UR-series networking datasheets + * + * Run: tsx packages/scraper/src/scrapers/ge-grid-oem.ts + * Cron: daily at 17:15 + */ + +import { pool, ensureVendor } from "../utils/db"; + +interface GeGridPID { + pid: string; + formFactor: string; + speedGbps: number; + speed: string; + reachMeters: number; + reachLabel: string; + fiberType: string; + connector: string; + wavelengths?: string; + standard?: string; + notes?: string; +} + +const GE_GRID_PIDS: GeGridPID[] = [ + // ── 1G SFP ────────────────────────────────────────────────────────────── + { pid: "GEG-SFP-1G-SX", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 550, reachLabel: "SX", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "1000BASE-SX", notes: "GE Grid Solutions SFP 1G SX substation/power grid" }, + { pid: "GEG-SFP-1G-LX", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 10000, reachLabel: "LX", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "1000BASE-LX", notes: "GE Grid Solutions SFP 1G LX substation/power grid" }, + { pid: "GEG-SFP-1G-ZX", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 80000, reachLabel: "ZX", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "1000BASE-ZX", notes: "GE Grid Solutions SFP 1G ZX 80km long-haul substation" }, + { pid: "GEG-SFP-1G-T", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 100, reachLabel: "T", fiberType: "DAC", connector: "RJ45", standard: "1000BASE-T", notes: "GE Grid Solutions SFP 1G copper RJ45" }, + { pid: "GEG-SFP-GE-T", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 100, reachLabel: "T", fiberType: "DAC", connector: "RJ45", standard: "1000BASE-T", notes: "GE Grid Solutions SFP GE copper industrial" }, + + // ── 1G SFP BiDi ───────────────────────────────────────────────────────── + { pid: "GEG-SFP-1G-BIDI-1310", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 20000, reachLabel: "BiDi-TX1310", fiberType: "SMF", connector: "LC", wavelengths: "TX1310/RX1550nm", notes: "GE Grid Solutions SFP 1G BiDi TX1310 single fiber" }, + { pid: "GEG-SFP-1G-BIDI-1550", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 20000, reachLabel: "BiDi-TX1550", fiberType: "SMF", connector: "LC", wavelengths: "TX1550/RX1310nm", notes: "GE Grid Solutions SFP 1G BiDi TX1550 single fiber" }, + + // ── 10G SFP+ ──────────────────────────────────────────────────────────── + { pid: "GEG-SFP-10G-SR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 300, reachLabel: "SR", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "10GBASE-SR", notes: "GE Grid Solutions SFP+ 10G SR" }, + { pid: "GEG-SFP-10G-LR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 10000, reachLabel: "LR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "10GBASE-LR", notes: "GE Grid Solutions SFP+ 10G LR" }, + { pid: "GEG-SFP-10G-ER", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 40000, reachLabel: "ER", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "10GBASE-ER", notes: "GE Grid Solutions SFP+ 10G ER" }, + + // ── 1G CWDM SFP (substation/protection rings) ─────────────────────────── + { pid: "GEG-SFP-CWDM-1470", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 40000, reachLabel: "CWDM-1470", fiberType: "SMF", connector: "LC", wavelengths: "1470nm", notes: "GE Grid Solutions SFP CWDM 1470nm 40km substation ring" }, + { pid: "GEG-SFP-CWDM-1530", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 40000, reachLabel: "CWDM-1530", fiberType: "SMF", connector: "LC", wavelengths: "1530nm", notes: "GE Grid Solutions SFP CWDM 1530nm 40km substation ring" }, + { pid: "GEG-SFP-CWDM-1550", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 40000, reachLabel: "CWDM-1550", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", notes: "GE Grid Solutions SFP CWDM 1550nm 40km substation ring" }, + { pid: "GEG-SFP-CWDM-1590", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 40000, reachLabel: "CWDM-1590", fiberType: "SMF", connector: "LC", wavelengths: "1590nm", notes: "GE Grid Solutions SFP CWDM 1590nm 40km substation ring" }, + + // ── 40G QSFP+ ─────────────────────────────────────────────────────────── + { pid: "GEG-QSFP-40G-LR4", formFactor: "QSFP+", speedGbps: 40, speed: "40G", reachMeters: 10000, reachLabel: "LR4", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "40GBASE-LR4", notes: "GE Grid Solutions QSFP+ 40G LR4" }, + + // ── 25G SFP28 ─────────────────────────────────────────────────────────── + { pid: "GEG-SFP28-25G-LR", formFactor: "SFP28", speedGbps: 25, speed: "25G", reachMeters: 10000, reachLabel: "LR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "25GBASE-LR", notes: "GE Grid Solutions SFP28 25G LR industrial" }, +]; + +export async function scrapeGeGridOem(): Promise { + console.log("=== GE Grid Solutions OEM Transceiver Seed ===\n"); + + const vendorId = await ensureVendor( + "GE Grid Solutions", + "oem", + "https://www.gegridsolutions.com", + undefined + ); + + let inserted = 0; + let updated = 0; + let errors = 0; + + for (const p of GE_GRID_PIDS) { + const slug = `ge-grid-${p.pid.toLowerCase().replace(/[^a-z0-9]+/g, "-")}`; + try { + const res = await pool.query( + `INSERT INTO transceivers + (slug, part_number, vendor_id, form_factor, speed, speed_gbps, + reach_meters, reach_label, fiber_type, connector, wavelengths, + dom_support, ieee_reference, market_status, category, notes) + VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,true,$12,'Mainstream','Industrial',$13) + ON CONFLICT (slug) DO UPDATE SET + speed_gbps = EXCLUDED.speed_gbps, + reach_meters = CASE WHEN EXCLUDED.reach_meters > 0 THEN EXCLUDED.reach_meters ELSE transceivers.reach_meters END, + fiber_type = CASE WHEN EXCLUDED.fiber_type <> '' THEN EXCLUDED.fiber_type ELSE transceivers.fiber_type END, + wavelengths = COALESCE(EXCLUDED.wavelengths, transceivers.wavelengths), + updated_at = NOW() + RETURNING (xmax = 0) as was_inserted`, + [slug, p.pid, vendorId, p.formFactor, p.speed, p.speedGbps, + p.reachMeters, p.reachLabel, p.fiberType, p.connector, + p.wavelengths ?? null, p.standard ?? null, p.notes ?? null] + ); + if (res.rows[0]?.was_inserted) inserted++; else updated++; + } catch (err) { + console.warn(` Skip ${p.pid}: ${(err as Error).message.slice(0, 80)}`); + errors++; + } + } + + console.log(`\n=== GE Grid Solutions OEM Seed Complete ===`); + console.log(` Inserted: ${inserted}`); + console.log(` Updated: ${updated}`); + console.log(` Errors: ${errors}`); + console.log(` Total PIDs: ${GE_GRID_PIDS.length}\n`); +} + +if (require.main === module) { + scrapeGeGridOem() + .then(() => pool.end()) + .catch((err) => { + console.error("Fatal:", err); + pool.end(); + process.exit(1); + }); +} diff --git a/packages/scraper/src/scrapers/google-cloud-oem.ts b/packages/scraper/src/scrapers/google-cloud-oem.ts new file mode 100644 index 0000000..ec5c227 --- /dev/null +++ b/packages/scraper/src/scrapers/google-cloud-oem.ts @@ -0,0 +1,333 @@ +/** + * Google Cloud OEM Transceiver Catalog Seed + * + * Seeds Google Cloud-branded transceiver PIDs used in Cloud Interconnect + * dedicated/partner connections and Google-designed datacenter hardware + * (Jupiter fabric switches, Titan network ASICs). Google uses a GCP- prefix + * for SFP/QSFP optics validated in its open-source SONiC-based switching + * infrastructure. + * + * Sources: + * - Google Cloud Interconnect hardware requirements + * (cloud.google.com/network-connectivity/docs/interconnect) + * - Google datacenter hardware engineering publications + * - SFF-8024 / IEEE 802.3 speed codes + * + * Run: tsx packages/scraper/src/scrapers/google-cloud-oem.ts + * Cron: daily at 07:45 + */ + +import { pool, ensureVendor } from "../utils/db"; + +interface GcpPID { + pid: string; + formFactor: string; + speedGbps: number; + speed: string; + reachMeters: number; + reachLabel: string; + fiberType: string; + connector: string; + wavelengths?: string; + standard?: string; + category?: string; + notes?: string; +} + +// PIDs that map to telecom / DWDM variants (ZR, ZR4) +const TELECOM_PIDS = new Set([ + "GCP-SFP-10G-ZR", + "GCP-QSFP28-100G-ZR4", +]); + +const GCP_PIDS: GcpPID[] = [ + // ── 1G SFP ─────────────────────────────────────────────────────────────── + { + pid: "GCP-SFP-1G-SX", + formFactor: "SFP", + speedGbps: 1, + speed: "1G", + reachMeters: 550, + reachLabel: "SX", + fiberType: "MMF", + connector: "LC", + wavelengths: "850nm", + standard: "1000BASE-SX", + category: "DataCenter", + notes: "1GbE SFP SX; Google Cloud datacenter management port; OM2/OM3 MMF up to 550m", + }, + { + pid: "GCP-SFP-1G-LX", + formFactor: "SFP", + speedGbps: 1, + speed: "1G", + reachMeters: 10000, + reachLabel: "LX", + fiberType: "SMF", + connector: "LC", + wavelengths: "1310nm", + standard: "1000BASE-LX", + category: "DataCenter", + notes: "1GbE SFP LX; Google Cloud datacenter management port; OS2 SMF up to 10km", + }, + // ── 1G Copper SFP ──────────────────────────────────────────────────────── + { + pid: "GCP-SFP-GE-T", + formFactor: "SFP", + speedGbps: 1, + speed: "1G", + reachMeters: 100, + reachLabel: "T", + fiberType: "DAC", + connector: "RJ45", + standard: "1000BASE-T", + category: "DataCenter", + notes: "1GbE copper SFP RJ45; Google Cloud server management copper option; Cat5e/6", + }, + // ── 10G SFP+ ───────────────────────────────────────────────────────────── + { + pid: "GCP-SFP-10G-SR", + formFactor: "SFP+", + speedGbps: 10, + speed: "10G", + reachMeters: 300, + reachLabel: "SR", + fiberType: "MMF", + connector: "LC", + wavelengths: "850nm", + standard: "10GBASE-SR", + category: "DataCenter", + notes: "10GbE SFP+ SR; Google Cloud Jupiter fabric server uplink; OM3/OM4 MMF up to 300m", + }, + { + pid: "GCP-SFP-10G-LR", + formFactor: "SFP+", + speedGbps: 10, + speed: "10G", + reachMeters: 10000, + reachLabel: "LR", + fiberType: "SMF", + connector: "LC", + wavelengths: "1310nm", + standard: "10GBASE-LR", + category: "DataCenter", + notes: "10GbE SFP+ LR; Google Cloud Interconnect 10G dedicated port; OS2 SMF up to 10km", + }, + { + pid: "GCP-SFP-10G-ER", + formFactor: "SFP+", + speedGbps: 10, + speed: "10G", + reachMeters: 40000, + reachLabel: "ER", + fiberType: "SMF", + connector: "LC", + wavelengths: "1550nm", + standard: "10GBASE-ER", + category: "DataCenter", + notes: "10GbE SFP+ ER; Google Cloud Interconnect extended-reach; OS2 SMF up to 40km", + }, + { + pid: "GCP-SFP-10G-ZR", + formFactor: "SFP+", + speedGbps: 10, + speed: "10G", + reachMeters: 80000, + reachLabel: "ZR", + fiberType: "SMF", + connector: "LC", + wavelengths: "1550nm", + standard: "10GBASE-ZR", + category: "Telecom", + notes: "10GbE SFP+ ZR; Google Cloud Interconnect DWDM long-haul 80km; OS2 SMF", + }, + // ── 25G SFP28 ──────────────────────────────────────────────────────────── + { + pid: "GCP-SFP28-25G-SR", + formFactor: "SFP28", + speedGbps: 25, + speed: "25G", + reachMeters: 100, + reachLabel: "SR", + fiberType: "MMF", + connector: "LC", + wavelengths: "850nm", + standard: "25GBASE-SR", + category: "DataCenter", + notes: "25GbE SFP28 SR; Google Jupiter v2 fabric server ToR port; OM4 MMF up to 100m", + }, + { + pid: "GCP-SFP28-25G-LR", + formFactor: "SFP28", + speedGbps: 25, + speed: "25G", + reachMeters: 10000, + reachLabel: "LR", + fiberType: "SMF", + connector: "LC", + wavelengths: "1310nm", + standard: "25GBASE-LR", + category: "DataCenter", + notes: "25GbE SFP28 LR; Google Jupiter v2 fabric server ToR port; OS2 SMF up to 10km", + }, + // ── 40G QSFP+ ──────────────────────────────────────────────────────────── + { + pid: "GCP-QSFP-40G-SR4", + formFactor: "QSFP+", + speedGbps: 40, + speed: "40G", + reachMeters: 150, + reachLabel: "SR4", + fiberType: "MMF", + connector: "MPO", + wavelengths: "850nm", + standard: "40GBASE-SR4", + category: "DataCenter", + notes: "40GbE QSFP+ SR4; Google Jupiter fabric aggregation uplink; OM3/OM4 MPO-12 up to 150m", + }, + { + pid: "GCP-QSFP-40G-LR4", + formFactor: "QSFP+", + speedGbps: 40, + speed: "40G", + reachMeters: 10000, + reachLabel: "LR4", + fiberType: "SMF", + connector: "LC", + wavelengths: "1270-1330nm", + standard: "40GBASE-LR4", + category: "DataCenter", + notes: "40GbE QSFP+ LR4; Google Cloud Interconnect 40G dedicated port; OS2 SMF up to 10km", + }, + // ── 100G QSFP28 ────────────────────────────────────────────────────────── + { + pid: "GCP-QSFP28-100G-SR4", + formFactor: "QSFP28", + speedGbps: 100, + speed: "100G", + reachMeters: 100, + reachLabel: "SR4", + fiberType: "MMF", + connector: "MPO", + wavelengths: "850nm", + standard: "100GBASE-SR4", + category: "DataCenter", + notes: "100GbE QSFP28 SR4; Google Cloud Interconnect 100G / Jupiter fabric; OM4 MPO-12 up to 100m", + }, + { + pid: "GCP-QSFP28-100G-LR4", + formFactor: "QSFP28", + speedGbps: 100, + speed: "100G", + reachMeters: 10000, + reachLabel: "LR4", + fiberType: "SMF", + connector: "LC", + wavelengths: "1295-1310nm", + standard: "100GBASE-LR4", + category: "DataCenter", + notes: "100GbE QSFP28 LR4; Google Cloud Interconnect 100G dedicated connection; OS2 SMF up to 10km", + }, + { + pid: "GCP-QSFP28-100G-ZR4", + formFactor: "QSFP28", + speedGbps: 100, + speed: "100G", + reachMeters: 80000, + reachLabel: "ZR4", + fiberType: "SMF", + connector: "LC", + wavelengths: "1271-1331nm", + standard: "100G-ZR4", + category: "Telecom", + notes: "100G QSFP28 ZR4; Google Cloud Interconnect DWDM long-haul 80km; coherent-lite; OS2 SMF", + }, + // ── 400G QSFP-DD ───────────────────────────────────────────────────────── + { + pid: "GCP-QSFP-DD-400G-DR4", + formFactor: "QSFP-DD", + speedGbps: 400, + speed: "400G", + reachMeters: 500, + reachLabel: "DR4", + fiberType: "SMF", + connector: "MPO", + wavelengths: "1310nm", + standard: "400GBASE-DR4", + category: "DataCenter", + notes: "400GbE QSFP-DD DR4; Google Jupiter Falcon fabric spine interconnect; OS2 SMF up to 500m", + }, + { + pid: "GCP-QSFP-DD-400G-SR8", + formFactor: "QSFP-DD", + speedGbps: 400, + speed: "400G", + reachMeters: 100, + reachLabel: "SR8", + fiberType: "MMF", + connector: "MPO", + wavelengths: "850nm", + standard: "400GBASE-SR8", + category: "DataCenter", + notes: "400GbE QSFP-DD SR8; Google Jupiter Falcon fabric spine interconnect; OM4/OM5 MPO-16 up to 100m", + }, +]; + +export async function scrapeGoogleCloudOem(): Promise { + console.log("=== Google Cloud OEM Transceiver Seed ===\n"); + + const vendorId = await ensureVendor( + "Google Cloud", + "oem", + "https://cloud.google.com/network-connectivity/docs/interconnect", + undefined + ); + + let inserted = 0; + let updated = 0; + let errors = 0; + + for (const p of GCP_PIDS) { + const slug = `gcp-${p.pid.toLowerCase().replace(/[^a-z0-9]+/g, "-")}`; + const category = TELECOM_PIDS.has(p.pid) ? "Telecom" : (p.category ?? "DataCenter"); + try { + const res = await pool.query( + `INSERT INTO transceivers + (slug, part_number, vendor_id, form_factor, speed, speed_gbps, + reach_meters, reach_label, fiber_type, connector, wavelengths, + dom_support, ieee_reference, market_status, category, notes) + VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,true,$12,'Mainstream',$13,$14) + ON CONFLICT (slug) DO UPDATE SET + speed_gbps = EXCLUDED.speed_gbps, + reach_meters = CASE WHEN EXCLUDED.reach_meters > 0 THEN EXCLUDED.reach_meters ELSE transceivers.reach_meters END, + fiber_type = CASE WHEN EXCLUDED.fiber_type <> '' THEN EXCLUDED.fiber_type ELSE transceivers.fiber_type END, + wavelengths = COALESCE(EXCLUDED.wavelengths, transceivers.wavelengths), + updated_at = NOW() + RETURNING (xmax = 0) as was_inserted`, + [slug, p.pid, vendorId, p.formFactor, p.speed, p.speedGbps, + p.reachMeters, p.reachLabel, p.fiberType, p.connector, + p.wavelengths ?? null, p.standard ?? null, category, p.notes ?? null] + ); + if (res.rows[0]?.was_inserted) inserted++; else updated++; + } catch (err) { + console.warn(` Skip ${p.pid}: ${(err as Error).message.slice(0, 80)}`); + errors++; + } + } + + console.log(`\n=== Google Cloud OEM Seed Complete ===`); + console.log(` Inserted: ${inserted}`); + console.log(` Updated: ${updated}`); + console.log(` Errors: ${errors}`); + console.log(` Total PIDs: ${GCP_PIDS.length}\n`); +} + +if (require.main === module) { + scrapeGoogleCloudOem() + .then(() => pool.end()) + .catch((err) => { + console.error("Fatal:", err); + pool.end(); + process.exit(1); + }); +} diff --git a/packages/scraper/src/scrapers/grass-valley-oem.ts b/packages/scraper/src/scrapers/grass-valley-oem.ts new file mode 100644 index 0000000..6b79d06 --- /dev/null +++ b/packages/scraper/src/scrapers/grass-valley-oem.ts @@ -0,0 +1,133 @@ +/** + * Grass Valley OEM Transceiver Catalog Seed + * + * Seeds Grass Valley-branded transceiver PIDs for broadcast production + * infrastructure: GV Orbit, Densité 3+, MV-821/MV-851 multiviewers, + * and IQUCP/IPG-3901 IP gateway cards. + * + * Sources: + * - Grass Valley Product Catalog (grassvalley.com) + * - GV Orbit Control System Hardware Reference + * - Densité 3+ Frame and Card Transceiver Compatibility Guide + * - GV Fabric IP Switching Platform Hardware Notes + * + * Run: tsx packages/scraper/src/scrapers/grass-valley-oem.ts + * Cron: daily at 18:30 + */ + +import { pool, ensureVendor } from "../utils/db"; + +interface GrassValleyPID { + pid: string; + formFactor: string; + speedGbps: number; + speed: string; + reachMeters: number; + reachLabel: string; + fiberType: string; + connector: string; + wavelengths?: string; + standard?: string; + category?: string; + notes?: string; +} + +const GRASS_VALLEY_PIDS: GrassValleyPID[] = [ + // ── 1G SFP ────────────────────────────────────────────────────────────── + { pid: "GV-SFP-1G-SX", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 550, reachLabel: "SX", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "1000BASE-SX", notes: "Grass Valley 1G SX SFP for Densité 3+ frame and GV Orbit" }, + { pid: "GV-SFP-1G-LX", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 10000, reachLabel: "LX", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "1000BASE-LX", notes: "Grass Valley 1G LX SFP for inter-frame Densité management" }, + { pid: "GV-SFP-GE-T", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 100, reachLabel: "T", fiberType: "DAC", connector: "RJ45", standard: "1000BASE-T", notes: "Grass Valley 1G copper SFP for out-of-band management" }, + + // ── 10G SFP+ ──────────────────────────────────────────────────────────── + { pid: "GV-SFP-10G-SR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 300, reachLabel: "SR", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "10GBASE-SR" }, + { pid: "GV-SFP-10G-LR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 10000, reachLabel: "LR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "10GBASE-LR" }, + { pid: "GV-SFP-10G-ER", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 40000, reachLabel: "ER", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "10GBASE-ER" }, + { pid: "GV-SFP-10G-ZR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 80000, reachLabel: "ZR", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "10GBASE-ZR", category: "Telecom", notes: "Grass Valley 10G ZR SFP+ for broadcast contribution over dark fiber" }, + + // ── SONET/SDH SFP (broadcast SDH / contribution) ──────────────────────── + { pid: "GV-SFP-OC3-SR", formFactor: "SFP", speedGbps: 0.155, speed: "155M", reachMeters: 2000, reachLabel: "SR", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "OC-3/STM-1", category: "Telecom", notes: "Grass Valley OC-3 SFP for legacy SDH broadcast ring" }, + + // ── 25G SFP28 ─────────────────────────────────────────────────────────── + { pid: "GV-SFP28-25G-SR", formFactor: "SFP28", speedGbps: 25, speed: "25G", reachMeters: 100, reachLabel: "SR", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "25GBASE-SR", notes: "Grass Valley 25G SR for GV Fabric IP switching and IQUCP25" }, + { pid: "GV-SFP28-25G-LR", formFactor: "SFP28", speedGbps: 25, speed: "25G", reachMeters: 10000, reachLabel: "LR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "25GBASE-LR", notes: "Grass Valley 25G LR for long-reach GV Fabric interconnect" }, + + // ── 40G QSFP+ ─────────────────────────────────────────────────────────── + { pid: "GV-QSFP-40G-SR4", formFactor: "QSFP+", speedGbps: 40, speed: "40G", reachMeters: 150, reachLabel: "SR4", fiberType: "MMF", connector: "MPO", wavelengths: "850nm", standard: "40GBASE-SR4" }, + { pid: "GV-QSFP-40G-LR4", formFactor: "QSFP+", speedGbps: 40, speed: "40G", reachMeters: 10000, reachLabel: "LR4", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "40GBASE-LR4" }, + + // ── 100G QSFP28 ───────────────────────────────────────────────────────── + { pid: "GV-QSFP28-100G-SR4", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 100, reachLabel: "SR4", fiberType: "MMF", connector: "MPO", wavelengths: "850nm", standard: "100GBASE-SR4" }, + { pid: "GV-QSFP28-100G-LR4", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 10000, reachLabel: "LR4", fiberType: "SMF", connector: "LC", wavelengths: "1295-1310nm", standard: "100GBASE-LR4" }, + + // ── 100G CFP (broadcast 100G contribution) ────────────────────────────── + { pid: "GV-CFP-100G-LR4", formFactor: "CFP", speedGbps: 100, speed: "100G", reachMeters: 10000, reachLabel: "LR4", fiberType: "SMF", connector: "LC", wavelengths: "1295-1310nm", standard: "100GBASE-LR4", category: "Telecom", notes: "Grass Valley CFP 100G LR4 for high-density GV Orbit broadcast fabric" }, + + // ── 400G QSFP-DD ──────────────────────────────────────────────────────── + { pid: "GV-QSFP-DD-400G-DR4", formFactor: "QSFP-DD", speedGbps: 400, speed: "400G", reachMeters: 500, reachLabel: "DR4", fiberType: "SMF", connector: "MPO", wavelengths: "1310nm", standard: "400GBASE-DR4", notes: "Grass Valley 400G DR4 for next-generation GV Fabric spine interconnect" }, +]; + +// PIDs that belong to the Telecom category (SONET/SDH, CFP coherent, ZR) +const TELECOM_PIDS = new Set([ + "GV-SFP-10G-ZR", + "GV-SFP-OC3-SR", + "GV-CFP-100G-LR4", +]); + +export async function scrapeGrassValleyOem(): Promise { + console.log("=== Grass Valley OEM Transceiver Seed ===\n"); + + const vendorId = await ensureVendor( + "Grass Valley", + "oem", + "https://www.grassvalley.com", + undefined + ); + + let inserted = 0; + let updated = 0; + let errors = 0; + + for (const p of GRASS_VALLEY_PIDS) { + const slug = `grass-valley-${p.pid.toLowerCase().replace(/[^a-z0-9]+/g, "-")}`; + const category = p.category ?? (TELECOM_PIDS.has(p.pid) ? "Telecom" : "DataCenter"); + try { + const res = await pool.query( + `INSERT INTO transceivers + (slug, part_number, vendor_id, form_factor, speed, speed_gbps, + reach_meters, reach_label, fiber_type, connector, wavelengths, + dom_support, ieee_reference, market_status, category, notes) + VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,true,$12,'Mainstream',$13,$14) + ON CONFLICT (slug) DO UPDATE SET + speed_gbps = EXCLUDED.speed_gbps, + reach_meters = CASE WHEN EXCLUDED.reach_meters > 0 THEN EXCLUDED.reach_meters ELSE transceivers.reach_meters END, + fiber_type = CASE WHEN EXCLUDED.fiber_type <> '' THEN EXCLUDED.fiber_type ELSE transceivers.fiber_type END, + wavelengths = COALESCE(EXCLUDED.wavelengths, transceivers.wavelengths), + updated_at = NOW() + RETURNING (xmax = 0) as was_inserted`, + [slug, p.pid, vendorId, p.formFactor, p.speed, p.speedGbps, + p.reachMeters, p.reachLabel, p.fiberType, p.connector, + p.wavelengths ?? null, p.standard ?? null, category, p.notes ?? null] + ); + if (res.rows[0]?.was_inserted) inserted++; else updated++; + } catch (err) { + console.warn(` Skip ${p.pid}: ${(err as Error).message.slice(0, 80)}`); + errors++; + } + } + + console.log(`\n=== Grass Valley OEM Seed Complete ===`); + console.log(` Inserted: ${inserted}`); + console.log(` Updated: ${updated}`); + console.log(` Errors: ${errors}`); + console.log(` Total PIDs: ${GRASS_VALLEY_PIDS.length}\n`); +} + +if (require.main === module) { + scrapeGrassValleyOem() + .then(() => pool.end()) + .catch((err) => { + console.error("Fatal:", err); + pool.end(); + process.exit(1); + }); +} diff --git a/packages/scraper/src/scrapers/h3c-oem.ts b/packages/scraper/src/scrapers/h3c-oem.ts new file mode 100644 index 0000000..f212b69 --- /dev/null +++ b/packages/scraper/src/scrapers/h3c-oem.ts @@ -0,0 +1,122 @@ +/** + * H3C OEM Transceiver Catalog Seed + * + * Seeds H3C-branded transceiver PIDs for S-series, CR-series, and + * NE-series switches and routers from New H3C Group. + * + * Sources: + * - H3C Transceiver Module Compatibility Guide (h3c.com) + * - H3C Optical Transceiver Module Technical Overview + * - H3C S12500/S6800/CR16000 Hardware Compatibility Matrix + * + * Run: tsx packages/scraper/src/scrapers/h3c-oem.ts + * Cron: daily at 11:15 + */ + +import { pool, ensureVendor } from "../utils/db"; + +interface H3cPID { + pid: string; + formFactor: string; + speedGbps: number; + speed: string; + reachMeters: number; + reachLabel: string; + fiberType: string; + connector: string; + wavelengths?: string; + standard?: string; + notes?: string; +} + +const H3C_PIDS: H3cPID[] = [ + // ── 1G SFP ────────────────────────────────────────────────────────────── + { pid: "H3C-SFP-GE-SX-MM850", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 550, reachLabel: "SX", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "1000BASE-SX", notes: "H3C 1G SFP SX 550m MMF" }, + { pid: "H3C-SFP-GE-LX-SM1310", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 10000, reachLabel: "LX", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "1000BASE-LX", notes: "H3C 1G SFP LX 10km SMF" }, + { pid: "H3C-SFP-GE-ZX-SM1550", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 80000, reachLabel: "ZX", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "1000BASE-ZX", notes: "H3C 1G SFP ZX 80km SMF" }, + { pid: "H3C-SFP-GE-T", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 100, reachLabel: "T", fiberType: "DAC", connector: "RJ45", standard: "1000BASE-T", notes: "H3C 1G SFP copper RJ45" }, + { pid: "H3C-SFP-GE-BIDI-1310", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 10000, reachLabel: "BiDi", fiberType: "SMF", connector: "LC", wavelengths: "1310/1490nm", standard: "1000BASE-BX", notes: "H3C 1G SFP BiDi TX1310/RX1490" }, + + // ── 10G SFP+ ──────────────────────────────────────────────────────────── + { pid: "H3C-SFP-XG-SR-MM850", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 300, reachLabel: "SR", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "10GBASE-SR", notes: "H3C 10G SFP+ SR 300m MMF" }, + { pid: "H3C-SFP-XG-LR-SM1310", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 10000, reachLabel: "LR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "10GBASE-LR", notes: "H3C 10G SFP+ LR 10km SMF" }, + { pid: "H3C-SFP-XG-ER-SM1550", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 40000, reachLabel: "ER", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "10GBASE-ER", notes: "H3C 10G SFP+ ER 40km SMF" }, + { pid: "H3C-SFP-XG-ZR-SM1550", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 80000, reachLabel: "ZR", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "10GBASE-ZR", notes: "H3C 10G SFP+ ZR 80km SMF" }, + { pid: "H3C-SFP-XG-BIDI-1270", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 10000, reachLabel: "BiDi", fiberType: "SMF", connector: "LC", wavelengths: "1270/1330nm", standard: "10GBASE-BX", notes: "H3C 10G SFP+ BiDi TX1270/RX1330" }, + + // ── 25G SFP28 ─────────────────────────────────────────────────────────── + { pid: "H3C-SFP28-25G-SR", formFactor: "SFP28", speedGbps: 25, speed: "25G", reachMeters: 100, reachLabel: "SR", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "25GBASE-SR", notes: "H3C 25G SFP28 SR 100m MMF" }, + { pid: "H3C-SFP28-25G-LR", formFactor: "SFP28", speedGbps: 25, speed: "25G", reachMeters: 10000, reachLabel: "LR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "25GBASE-LR", notes: "H3C 25G SFP28 LR 10km SMF" }, + + // ── 40G QSFP+ ─────────────────────────────────────────────────────────── + { pid: "H3C-QSFP-40G-SR4", formFactor: "QSFP+", speedGbps: 40, speed: "40G", reachMeters: 150, reachLabel: "SR4", fiberType: "MMF", connector: "MPO", wavelengths: "850nm", standard: "40GBASE-SR4", notes: "H3C 40G QSFP+ SR4 150m MMF" }, + { pid: "H3C-QSFP-40G-LR4", formFactor: "QSFP+", speedGbps: 40, speed: "40G", reachMeters: 10000, reachLabel: "LR4", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "40GBASE-LR4", notes: "H3C 40G QSFP+ LR4 10km SMF" }, + + // ── 100G QSFP28 ───────────────────────────────────────────────────────── + { pid: "H3C-QSFP28-100G-SR4", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 100, reachLabel: "SR4", fiberType: "MMF", connector: "MPO", wavelengths: "850nm", standard: "100GBASE-SR4", notes: "H3C 100G QSFP28 SR4 100m MMF" }, + { pid: "H3C-QSFP28-100G-LR4", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 10000, reachLabel: "LR4", fiberType: "SMF", connector: "LC", wavelengths: "1295-1310nm", standard: "100GBASE-LR4", notes: "H3C 100G QSFP28 LR4 10km SMF" }, + { pid: "H3C-QSFP28-100G-ER4", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 40000, reachLabel: "ER4", fiberType: "SMF", connector: "LC", wavelengths: "1295-1310nm", standard: "100GBASE-ER4", notes: "H3C 100G QSFP28 ER4 40km SMF" }, + { pid: "H3C-QSFP28-100G-CWDM4", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 2000, reachLabel: "CWDM4", fiberType: "SMF", connector: "LC", wavelengths: "1271-1331nm", standard: "100GBASE-CWDM4", notes: "H3C 100G QSFP28 CWDM4 2km SMF" }, + + // ── 400G QSFP-DD ──────────────────────────────────────────────────────── + { pid: "H3C-QSFP-DD-400G-DR4", formFactor: "QSFP-DD",speedGbps: 400, speed: "400G", reachMeters: 500, reachLabel: "DR4", fiberType: "SMF", connector: "MPO", wavelengths: "1310nm", standard: "400GBASE-DR4", notes: "H3C 400G QSFP-DD DR4 500m SMF" }, + { pid: "H3C-QSFP-DD-400G-SR8", formFactor: "QSFP-DD",speedGbps: 400, speed: "400G", reachMeters: 100, reachLabel: "SR8", fiberType: "MMF", connector: "MPO", wavelengths: "850nm", standard: "400GBASE-SR8", notes: "H3C 400G QSFP-DD SR8 100m MMF" }, +]; + +export async function scrapeH3cOem(): Promise { + console.log("=== H3C OEM Transceiver Seed ===\n"); + + const vendorId = await ensureVendor( + "H3C", + "oem", + "https://www.h3c.com", + undefined + ); + + let inserted = 0; + let updated = 0; + let errors = 0; + + for (const p of H3C_PIDS) { + const slug = `h3c-${p.pid.toLowerCase().replace(/[^a-z0-9]+/g, "-")}`; + try { + const res = await pool.query( + `INSERT INTO transceivers + (slug, part_number, vendor_id, form_factor, speed, speed_gbps, + reach_meters, reach_label, fiber_type, connector, wavelengths, + dom_support, ieee_reference, market_status, category, notes) + VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,true,$12,'Mainstream','DataCenter',$13) + ON CONFLICT (slug) DO UPDATE SET + speed_gbps = EXCLUDED.speed_gbps, + reach_meters = CASE WHEN EXCLUDED.reach_meters > 0 THEN EXCLUDED.reach_meters ELSE transceivers.reach_meters END, + fiber_type = CASE WHEN EXCLUDED.fiber_type <> '' THEN EXCLUDED.fiber_type ELSE transceivers.fiber_type END, + wavelengths = COALESCE(EXCLUDED.wavelengths, transceivers.wavelengths), + updated_at = NOW() + RETURNING (xmax = 0) as was_inserted`, + [slug, p.pid, vendorId, p.formFactor, p.speed, p.speedGbps, + p.reachMeters, p.reachLabel, p.fiberType, p.connector, + p.wavelengths ?? null, p.standard ?? null, p.notes ?? null] + ); + if (res.rows[0]?.was_inserted) inserted++; else updated++; + } catch (err) { + console.warn(` Skip ${p.pid}: ${(err as Error).message.slice(0, 80)}`); + errors++; + } + } + + console.log(`\n=== H3C OEM Seed Complete ===`); + console.log(` Inserted: ${inserted}`); + console.log(` Updated: ${updated}`); + console.log(` Errors: ${errors}`); + console.log(` Total PIDs: ${H3C_PIDS.length}\n`); +} + +if (require.main === module) { + scrapeH3cOem() + .then(() => pool.end()) + .catch((err) => { + console.error("Fatal:", err); + pool.end(); + process.exit(1); + }); +} diff --git a/packages/scraper/src/scrapers/haivision-oem.ts b/packages/scraper/src/scrapers/haivision-oem.ts new file mode 100644 index 0000000..3676354 --- /dev/null +++ b/packages/scraper/src/scrapers/haivision-oem.ts @@ -0,0 +1,120 @@ +/** + * Haivision OEM Transceiver Catalog Seed + * + * Seeds Haivision-branded transceiver PIDs for video streaming and + * broadcast encoding infrastructure: Makito X4 HEVC encoder/decoder, + * KB/KBe series encoders, SRT Gateway, and CoolSign signage platforms. + * + * Sources: + * - Haivision Product Catalog (haivision.com) + * - Makito X4 Encoder/Decoder Hardware Reference + * - Haivision SRT Gateway Platform Transceiver Notes + * - KB/KBe Series Server Hardware Guide + * + * Run: tsx packages/scraper/src/scrapers/haivision-oem.ts + * Cron: daily at 18:45 + */ + +import { pool, ensureVendor } from "../utils/db"; + +interface HaivisionPID { + pid: string; + formFactor: string; + speedGbps: number; + speed: string; + reachMeters: number; + reachLabel: string; + fiberType: string; + connector: string; + wavelengths?: string; + standard?: string; + notes?: string; +} + +const HAIVISION_PIDS: HaivisionPID[] = [ + // ── 1G SFP ────────────────────────────────────────────────────────────── + { pid: "HAI-SFP-1G-SX", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 550, reachLabel: "SX", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "1000BASE-SX", notes: "Haivision 1G SX SFP for Makito X4 encoder primary interface" }, + { pid: "HAI-SFP-1G-LX", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 10000, reachLabel: "LX", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "1000BASE-LX", notes: "Haivision 1G LX SFP for inter-building encoder connectivity" }, + { pid: "HAI-SFP-1G-T", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 100, reachLabel: "T", fiberType: "DAC", connector: "RJ45", standard: "1000BASE-T", notes: "Haivision 1G copper SFP for management and short-reach encoder links" }, + + // ── 10G SFP+ ──────────────────────────────────────────────────────────── + { pid: "HAI-SFP-10G-SR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 300, reachLabel: "SR", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "10GBASE-SR", notes: "Haivision 10G SR SFP+ for SRT Gateway and KB encoder" }, + { pid: "HAI-SFP-10G-LR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 10000, reachLabel: "LR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "10GBASE-LR", notes: "Haivision 10G LR for campus distribution of HEVC streams" }, + { pid: "HAI-SFP-10G-ER", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 40000, reachLabel: "ER", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "10GBASE-ER", notes: "Haivision 10G ER for extended-reach SRT contribution links" }, + + // ── 25G SFP28 ─────────────────────────────────────────────────────────── + { pid: "HAI-SFP28-25G-SR", formFactor: "SFP28", speedGbps: 25, speed: "25G", reachMeters: 100, reachLabel: "SR", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "25GBASE-SR", notes: "Haivision 25G SR SFP28 for high-density Makito X4 server deployments" }, + { pid: "HAI-SFP28-25G-LR", formFactor: "SFP28", speedGbps: 25, speed: "25G", reachMeters: 10000, reachLabel: "LR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "25GBASE-LR", notes: "Haivision 25G LR for long-reach SRT Gateway interconnect" }, + + // ── 40G QSFP+ ─────────────────────────────────────────────────────────── + { pid: "HAI-QSFP-40G-SR4", formFactor: "QSFP+", speedGbps: 40, speed: "40G", reachMeters: 150, reachLabel: "SR4", fiberType: "MMF", connector: "MPO", wavelengths: "850nm", standard: "40GBASE-SR4", notes: "Haivision 40G SR4 for KB server aggregation uplink" }, + { pid: "HAI-QSFP-40G-LR4", formFactor: "QSFP+", speedGbps: 40, speed: "40G", reachMeters: 10000, reachLabel: "LR4", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "40GBASE-LR4" }, + + // ── 100G QSFP28 ───────────────────────────────────────────────────────── + { pid: "HAI-QSFP28-100G-SR4", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 100, reachLabel: "SR4", fiberType: "MMF", connector: "MPO", wavelengths: "850nm", standard: "100GBASE-SR4" }, + { pid: "HAI-QSFP28-100G-LR4", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 10000, reachLabel: "LR4", fiberType: "SMF", connector: "LC", wavelengths: "1295-1310nm", standard: "100GBASE-LR4" }, + + // ── Copper SFP (management) ────────────────────────────────────────────── + { pid: "HAI-SFP-GE-T", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 100, reachLabel: "T", fiberType: "DAC", connector: "RJ45", standard: "1000BASE-T", notes: "Haivision 1G copper SFP for out-of-band management ports" }, + + // ── 400G QSFP-DD ──────────────────────────────────────────────────────── + { pid: "HAI-QSFP-DD-400G-DR4", formFactor: "QSFP-DD", speedGbps: 400, speed: "400G", reachMeters: 500, reachLabel: "DR4", fiberType: "SMF", connector: "MPO", wavelengths: "1310nm", standard: "400GBASE-DR4", notes: "Haivision 400G DR4 for next-gen high-density encoder fabric uplinks" }, +]; + +export async function scrapeHaivisionOem(): Promise { + console.log("=== Haivision OEM Transceiver Seed ===\n"); + + const vendorId = await ensureVendor( + "Haivision", + "oem", + "https://www.haivision.com", + undefined + ); + + let inserted = 0; + let updated = 0; + let errors = 0; + + for (const p of HAIVISION_PIDS) { + const slug = `haivision-${p.pid.toLowerCase().replace(/[^a-z0-9]+/g, "-")}`; + try { + const res = await pool.query( + `INSERT INTO transceivers + (slug, part_number, vendor_id, form_factor, speed, speed_gbps, + reach_meters, reach_label, fiber_type, connector, wavelengths, + dom_support, ieee_reference, market_status, category, notes) + VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,true,$12,'Mainstream','DataCenter',$13) + ON CONFLICT (slug) DO UPDATE SET + speed_gbps = EXCLUDED.speed_gbps, + reach_meters = CASE WHEN EXCLUDED.reach_meters > 0 THEN EXCLUDED.reach_meters ELSE transceivers.reach_meters END, + fiber_type = CASE WHEN EXCLUDED.fiber_type <> '' THEN EXCLUDED.fiber_type ELSE transceivers.fiber_type END, + wavelengths = COALESCE(EXCLUDED.wavelengths, transceivers.wavelengths), + updated_at = NOW() + RETURNING (xmax = 0) as was_inserted`, + [slug, p.pid, vendorId, p.formFactor, p.speed, p.speedGbps, + p.reachMeters, p.reachLabel, p.fiberType, p.connector, + p.wavelengths ?? null, p.standard ?? null, p.notes ?? null] + ); + if (res.rows[0]?.was_inserted) inserted++; else updated++; + } catch (err) { + console.warn(` Skip ${p.pid}: ${(err as Error).message.slice(0, 80)}`); + errors++; + } + } + + console.log(`\n=== Haivision OEM Seed Complete ===`); + console.log(` Inserted: ${inserted}`); + console.log(` Updated: ${updated}`); + console.log(` Errors: ${errors}`); + console.log(` Total PIDs: ${HAIVISION_PIDS.length}\n`); +} + +if (require.main === module) { + scrapeHaivisionOem() + .then(() => pool.end()) + .catch((err) => { + console.error("Fatal:", err); + pool.end(); + process.exit(1); + }); +} diff --git a/packages/scraper/src/scrapers/harmonic-oem.ts b/packages/scraper/src/scrapers/harmonic-oem.ts new file mode 100644 index 0000000..990e363 --- /dev/null +++ b/packages/scraper/src/scrapers/harmonic-oem.ts @@ -0,0 +1,146 @@ +/** + * Harmonic OEM Transceiver Catalog Seed + * + * Seeds Harmonic-branded transceiver PIDs for video streaming and broadcast + * infrastructure: VOS (Video Open Software), NSG (Network Services Gateway), + * Electra X, and Spectrum X platforms. + * + * Sources: + * - Harmonic Product Catalog (harmonicinc.com) + * - Harmonic NSG 9000-6 Hardware Reference Guide + * - VOS/HOS Media Processor Platform Transceiver Compatibility + * + * Run: tsx packages/scraper/src/scrapers/harmonic-oem.ts + * Cron: daily at 21:30 + */ + +import { pool, ensureVendor } from "../utils/db"; + +interface HarmonicPID { + pid: string; + formFactor: string; + speedGbps: number; + speed: string; + reachMeters: number; + reachLabel: string; + fiberType: string; + connector: string; + wavelengths?: string; + standard?: string; + category?: string; + notes?: string; +} + +const HARMONIC_PIDS: HarmonicPID[] = [ + // ── 1G SFP ────────────────────────────────────────────────────────────── + { pid: "HRM-SFP-GE-SX", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 550, reachLabel: "SX", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "1000BASE-SX" }, + { pid: "HRM-SFP-GE-LX", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 10000, reachLabel: "LX", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "1000BASE-LX" }, + + // ── SONET/SDH SFP (broadcast / contribution networks) ─────────────────── + { pid: "HRM-SFP-OC3-SR", formFactor: "SFP", speedGbps: 0.155, speed: "155M", reachMeters: 2000, reachLabel: "SR", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "OC-3/STM-1", category: "Telecom", notes: "Harmonic OC-3 SFP for broadcast SDH ring" }, + { pid: "HRM-SFP-OC3-LR", formFactor: "SFP", speedGbps: 0.155, speed: "155M", reachMeters: 40000, reachLabel: "LR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "OC-3/STM-1", category: "Telecom", notes: "Harmonic OC-3 LR SFP for broadcast SDH" }, + { pid: "HRM-SFP-OC12-SR", formFactor: "SFP", speedGbps: 0.622, speed: "622M", reachMeters: 2000, reachLabel: "SR", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "OC-12/STM-4", category: "Telecom", notes: "Harmonic OC-12 SFP for contribution" }, + { pid: "HRM-SFP-OC12-LR", formFactor: "SFP", speedGbps: 0.622, speed: "622M", reachMeters: 40000, reachLabel: "LR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "OC-12/STM-4", category: "Telecom", notes: "Harmonic OC-12 LR SFP" }, + { pid: "HRM-SFP-OC48-SR", formFactor: "SFP", speedGbps: 2.488, speed: "2.5G", reachMeters: 2000, reachLabel: "SR", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "OC-48/STM-16",category: "Telecom", notes: "Harmonic OC-48 SFP for high-bandwidth contribution" }, + { pid: "HRM-SFP-OC48-LR", formFactor: "SFP", speedGbps: 2.488, speed: "2.5G", reachMeters: 40000, reachLabel: "LR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "OC-48/STM-16",category: "Telecom", notes: "Harmonic OC-48 LR SFP" }, + + // ── 10G SFP+ ──────────────────────────────────────────────────────────── + { pid: "HRM-SFP-10G-SR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 300, reachLabel: "SR", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "10GBASE-SR" }, + { pid: "HRM-SFP-10G-LR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 10000, reachLabel: "LR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "10GBASE-LR" }, + { pid: "HRM-SFP-10G-ER", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 40000, reachLabel: "ER", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "10GBASE-ER" }, + { pid: "HRM-SFP-10G-ZR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 80000, reachLabel: "ZR", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "10GBASE-ZR", notes: "Harmonic 10G ZR for video contribution links" }, + + // ── 10G DWDM SFP+ (broadcast contribution) ────────────────────────────── + { pid: "HRM-DWDM-SFP10G-C", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 80000, reachLabel: "DWDM", fiberType: "SMF", connector: "LC", wavelengths: "C-band", category: "Telecom", notes: "Harmonic 10G DWDM SFP+ for broadcast contribution DWDM ring" }, + + // ── 25G SFP28 ─────────────────────────────────────────────────────────── + { pid: "HRM-SFP-25G-SR", formFactor: "SFP28", speedGbps: 25, speed: "25G", reachMeters: 100, reachLabel: "SR", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "25GBASE-SR" }, + { pid: "HRM-SFP-25G-LR", formFactor: "SFP28", speedGbps: 25, speed: "25G", reachMeters: 10000, reachLabel: "LR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "25GBASE-LR" }, + + // ── 40G QSFP+ ─────────────────────────────────────────────────────────── + { pid: "HRM-QSFP-40G-SR4", formFactor: "QSFP+", speedGbps: 40, speed: "40G", reachMeters: 150, reachLabel: "SR4", fiberType: "MMF", connector: "MPO", wavelengths: "850nm", standard: "40GBASE-SR4" }, + { pid: "HRM-QSFP-40G-LR4", formFactor: "QSFP+", speedGbps: 40, speed: "40G", reachMeters: 10000, reachLabel: "LR4", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "40GBASE-LR4" }, + + // ── 100G QSFP28 ───────────────────────────────────────────────────────── + { pid: "HRM-QSFP-100G-SR4", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 100, reachLabel: "SR4", fiberType: "MMF", connector: "MPO", wavelengths: "850nm", standard: "100GBASE-SR4" }, + { pid: "HRM-QSFP-100G-LR4", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 10000, reachLabel: "LR4", fiberType: "SMF", connector: "LC", wavelengths: "1295-1310nm", standard: "100GBASE-LR4" }, + + // ── 100G CFP (broadcast 100G contribution) ────────────────────────────── + { pid: "HRM-CFP-100G-LR4", formFactor: "CFP", speedGbps: 100, speed: "100G", reachMeters: 10000, reachLabel: "LR4", fiberType: "SMF", connector: "LC", wavelengths: "1295-1310nm", standard: "100GBASE-LR4", category: "Telecom", notes: "Harmonic CFP 100G LR4 for Electra X broadcast platform" }, + + // ── DAC ───────────────────────────────────────────────────────────────── + { pid: "HRM-DAC-10G-1M", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 1, reachLabel: "DAC-1M", fiberType: "DAC", connector: "SFP+", notes: "Harmonic 10G DAC 1m" }, + { pid: "HRM-DAC-10G-3M", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 3, reachLabel: "DAC-3M", fiberType: "DAC", connector: "SFP+", notes: "Harmonic 10G DAC 3m" }, + { pid: "HRM-DAC-100G-1M", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 1, reachLabel: "DAC-1M", fiberType: "DAC", connector: "QSFP28", notes: "Harmonic 100G DAC 1m" }, +]; + +// PIDs that belong to the Telecom category (SONET/SDH, DWDM, CFP coherent) +const TELECOM_PIDS = new Set([ + "HRM-SFP-OC3-SR", + "HRM-SFP-OC3-LR", + "HRM-SFP-OC12-SR", + "HRM-SFP-OC12-LR", + "HRM-SFP-OC48-SR", + "HRM-SFP-OC48-LR", + "HRM-DWDM-SFP10G-C", + "HRM-CFP-100G-LR4", +]); + +export async function scrapeHarmonicOem(): Promise { + console.log("=== Harmonic OEM Transceiver Seed ===\n"); + + const vendorId = await ensureVendor( + "Harmonic", + "oem", + "https://www.harmonicinc.com", + undefined + ); + + let inserted = 0; + let updated = 0; + let errors = 0; + + for (const p of HARMONIC_PIDS) { + const slug = `harmonic-${p.pid.toLowerCase().replace(/[^a-z0-9]+/g, "-")}`; + const category = p.category ?? (TELECOM_PIDS.has(p.pid) ? "Telecom" : "DataCenter"); + try { + const res = await pool.query( + `INSERT INTO transceivers + (slug, part_number, vendor_id, form_factor, speed, speed_gbps, + reach_meters, reach_label, fiber_type, connector, wavelengths, + dom_support, ieee_reference, market_status, category, notes) + VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,true,$12,'Mainstream',$13,$14) + ON CONFLICT (slug) DO UPDATE SET + speed_gbps = EXCLUDED.speed_gbps, + reach_meters = CASE WHEN EXCLUDED.reach_meters > 0 THEN EXCLUDED.reach_meters ELSE transceivers.reach_meters END, + fiber_type = CASE WHEN EXCLUDED.fiber_type <> '' THEN EXCLUDED.fiber_type ELSE transceivers.fiber_type END, + wavelengths = COALESCE(EXCLUDED.wavelengths, transceivers.wavelengths), + updated_at = NOW() + RETURNING (xmax = 0) as was_inserted`, + [slug, p.pid, vendorId, p.formFactor, p.speed, p.speedGbps, + p.reachMeters, p.reachLabel, p.fiberType, p.connector, + p.wavelengths ?? null, p.standard ?? null, category, p.notes ?? null] + ); + if (res.rows[0]?.was_inserted) inserted++; else updated++; + } catch (err) { + console.warn(` Skip ${p.pid}: ${(err as Error).message.slice(0, 80)}`); + errors++; + } + } + + console.log(`\n=== Harmonic OEM Seed Complete ===`); + console.log(` Inserted: ${inserted}`); + console.log(` Updated: ${updated}`); + console.log(` Errors: ${errors}`); + console.log(` Total PIDs: ${HARMONIC_PIDS.length}\n`); +} + +if (require.main === module) { + scrapeHarmonicOem() + .then(() => pool.end()) + .catch((err) => { + console.error("Fatal:", err); + pool.end(); + process.exit(1); + }); +} diff --git a/packages/scraper/src/scrapers/hillstone-oem.ts b/packages/scraper/src/scrapers/hillstone-oem.ts new file mode 100644 index 0000000..e4cf2fb --- /dev/null +++ b/packages/scraper/src/scrapers/hillstone-oem.ts @@ -0,0 +1,120 @@ +/** + * Hillstone Networks OEM Transceiver Catalog Seed + * + * Seeds Hillstone-branded transceiver PIDs for E-Series, T-Series, and + * X-Series next-generation firewalls. + * + * Sources: + * - Hillstone Networks Hardware Compatibility List (hillstonenet.com) + * - E-Series / T-Series / X-Series Appliance Hardware Guide + * + * Run: tsx packages/scraper/src/scrapers/hillstone-oem.ts + * Cron: daily at 19:15 + */ + +import { pool, ensureVendor } from "../utils/db"; + +interface HillstonePID { + pid: string; + formFactor: string; + speedGbps: number; + speed: string; + reachMeters: number; + reachLabel: string; + fiberType: string; + connector: string; + wavelengths?: string; + standard?: string; + notes?: string; +} + +const HILLSTONE_PIDS: HillstonePID[] = [ + // ── 1G SFP ────────────────────────────────────────────────────────────── + { pid: "HS-SFP-1GE-SX", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 550, reachLabel: "SX", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "1000BASE-SX" }, + { pid: "HS-SFP-1GE-LX", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 10000, reachLabel: "LX", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "1000BASE-LX" }, + { pid: "HS-SFP-1GE-ZX", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 80000, reachLabel: "ZX", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "1000BASE-ZX" }, + { pid: "HS-SFP-1GE-T", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 100, reachLabel: "T", fiberType: "DAC", connector: "RJ45", standard: "1000BASE-T" }, + + // ── 10G SFP+ ──────────────────────────────────────────────────────────── + { pid: "HS-SFP-10GE-SR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 300, reachLabel: "SR", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "10GBASE-SR" }, + { pid: "HS-SFP-10GE-LR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 10000, reachLabel: "LR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "10GBASE-LR" }, + { pid: "HS-SFP-10GE-ER", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 40000, reachLabel: "ER", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "10GBASE-ER" }, + { pid: "HS-SFP-10GE-ZR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 80000, reachLabel: "ZR", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "10GBASE-ZR" }, + { pid: "HS-SFP-10GE-T", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 30, reachLabel: "T", fiberType: "DAC", connector: "RJ45", standard: "10GBASE-T" }, + + // ── 25G SFP28 ─────────────────────────────────────────────────────────── + { pid: "HS-SFP28-25GE-SR", formFactor: "SFP28", speedGbps: 25, speed: "25G", reachMeters: 100, reachLabel: "SR", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "25GBASE-SR" }, + { pid: "HS-SFP28-25GE-LR", formFactor: "SFP28", speedGbps: 25, speed: "25G", reachMeters: 10000, reachLabel: "LR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "25GBASE-LR" }, + + // ── 40G QSFP+ ─────────────────────────────────────────────────────────── + { pid: "HS-QSFP-40GE-SR4", formFactor: "QSFP+", speedGbps: 40, speed: "40G", reachMeters: 150, reachLabel: "SR4", fiberType: "MMF", connector: "MPO", wavelengths: "850nm", standard: "40GBASE-SR4" }, + { pid: "HS-QSFP-40GE-LR4", formFactor: "QSFP+", speedGbps: 40, speed: "40G", reachMeters: 10000, reachLabel: "LR4", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "40GBASE-LR4" }, + + // ── 100G QSFP28 ───────────────────────────────────────────────────────── + { pid: "HS-QSFP28-100GE-SR4", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 100, reachLabel: "SR4", fiberType: "MMF", connector: "MPO", wavelengths: "850nm", standard: "100GBASE-SR4" }, + { pid: "HS-QSFP28-100GE-LR4", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 10000, reachLabel: "LR4", fiberType: "SMF", connector: "LC", wavelengths: "1295-1310nm", standard: "100GBASE-LR4" }, + { pid: "HS-QSFP28-100GE-CWDM4",formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 2000, reachLabel: "CWDM4", fiberType: "SMF", connector: "LC", wavelengths: "1271-1331nm", standard: "100GBASE-CWDM4" }, + + // ── DAC ───────────────────────────────────────────────────────────────── + { pid: "HS-DAC-10GE-1M", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 1, reachLabel: "DAC-1M", fiberType: "DAC", connector: "SFP+" }, + { pid: "HS-DAC-10GE-3M", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 3, reachLabel: "DAC-3M", fiberType: "DAC", connector: "SFP+" }, + { pid: "HS-DAC-100GE-1M", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 1, reachLabel: "DAC-1M", fiberType: "DAC", connector: "QSFP28" }, +]; + +export async function scrapeHillstoneOem(): Promise { + console.log("=== Hillstone Networks OEM Transceiver Seed ===\n"); + + const vendorId = await ensureVendor( + "Hillstone Networks", + "oem", + "https://www.hillstonenet.com", + undefined + ); + + let inserted = 0; + let updated = 0; + let errors = 0; + + for (const p of HILLSTONE_PIDS) { + const slug = `hillstone-${p.pid.toLowerCase().replace(/[^a-z0-9]+/g, "-")}`; + try { + const res = await pool.query( + `INSERT INTO transceivers + (slug, part_number, vendor_id, form_factor, speed, speed_gbps, + reach_meters, reach_label, fiber_type, connector, wavelengths, + dom_support, ieee_reference, market_status, category, notes) + VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,true,$12,'Mainstream','DataCenter',$13) + ON CONFLICT (slug) DO UPDATE SET + speed_gbps = EXCLUDED.speed_gbps, + reach_meters = CASE WHEN EXCLUDED.reach_meters > 0 THEN EXCLUDED.reach_meters ELSE transceivers.reach_meters END, + fiber_type = CASE WHEN EXCLUDED.fiber_type <> '' THEN EXCLUDED.fiber_type ELSE transceivers.fiber_type END, + wavelengths = COALESCE(EXCLUDED.wavelengths, transceivers.wavelengths), + updated_at = NOW() + RETURNING (xmax = 0) as was_inserted`, + [slug, p.pid, vendorId, p.formFactor, p.speed, p.speedGbps, + p.reachMeters, p.reachLabel, p.fiberType, p.connector, + p.wavelengths ?? null, p.standard ?? null, p.notes ?? null] + ); + if (res.rows[0]?.was_inserted) inserted++; else updated++; + } catch (err) { + console.warn(` Skip ${p.pid}: ${(err as Error).message.slice(0, 80)}`); + errors++; + } + } + + console.log(`\n=== Hillstone Networks OEM Seed Complete ===`); + console.log(` Inserted: ${inserted}`); + console.log(` Updated: ${updated}`); + console.log(` Errors: ${errors}`); + console.log(` Total PIDs: ${HILLSTONE_PIDS.length}\n`); +} + +if (require.main === module) { + scrapeHillstoneOem() + .then(() => pool.end()) + .catch((err) => { + console.error("Fatal:", err); + pool.end(); + process.exit(1); + }); +} diff --git a/packages/scraper/src/scrapers/hirschmann-oem.ts b/packages/scraper/src/scrapers/hirschmann-oem.ts new file mode 100644 index 0000000..5af19eb --- /dev/null +++ b/packages/scraper/src/scrapers/hirschmann-oem.ts @@ -0,0 +1,130 @@ +/** + * Hirschmann OEM Transceiver Catalog Seed + * + * Seeds transceiver PIDs for Hirschmann (now Belden brand) industrial-grade + * SFP/SFP+/SFP28/QSFP+/QSFP28 modules used in MACH, RSP, OCTOPUS, and + * DRAGON series industrial Ethernet managed switches. + * + * Sources: + * - Hirschmann/Belden SFP module datasheets (belden.com/brands/hirschmann) + * - Hirschmann MACH/RSP series hardware installation guides + * + * Run: tsx packages/scraper/src/scrapers/hirschmann-oem.ts + * Cron: daily at 12:30 + */ + +import { pool, ensureVendor } from "../utils/db"; + +interface HirschmannPID { + pid: string; + formFactor: string; + speedGbps: number; + speed: string; + reachMeters: number; + reachLabel: string; + fiberType: string; + connector: string; + wavelengths?: string; + standard?: string; + notes?: string; +} + +const HIRSCHMANN_PIDS: HirschmannPID[] = [ + // ── 1G SFP (industrial grade) ─────────────────────────────────────────── + { pid: "M-SFP-SX/LC", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 550, reachLabel: "SX", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "1000BASE-SX", notes: "Hirschmann industrial 1G SX" }, + { pid: "M-SFP-LX/LC", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 10000, reachLabel: "LX", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "1000BASE-LX", notes: "Hirschmann industrial 1G LX" }, + { pid: "M-SFP-LH/LC", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 40000, reachLabel: "LH40", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", notes: "Hirschmann industrial 1G 40km" }, + { pid: "M-SFP-ZX/LC", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 80000, reachLabel: "ZX", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "1000BASE-ZX", notes: "Hirschmann industrial 1G ZX" }, + { pid: "M-SFP-T/RJ45", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 100, reachLabel: "T", fiberType: "DAC", connector: "RJ45", standard: "1000BASE-T", notes: "Hirschmann 1G copper SFP" }, + { pid: "M-SFP-BIDI-L/LC", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 20000, reachLabel: "BiDi", fiberType: "SMF", connector: "LC", wavelengths: "1310/1550nm", notes: "Hirschmann 1G BiDi single fiber 20km" }, + + // ── 100M SFP (legacy industrial) ──────────────────────────────────────── + { pid: "M-FAST-SFP-MM/LC", formFactor: "SFP", speedGbps: 0.1, speed: "100M", reachMeters: 2000, reachLabel: "FX", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "100BASE-FX", notes: "Hirschmann legacy industrial 100M FX MMF" }, + { pid: "M-FAST-SFP-SM/LC", formFactor: "SFP", speedGbps: 0.1, speed: "100M", reachMeters: 40000, reachLabel: "LFX", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "100BASE-LFX", notes: "Hirschmann legacy industrial 100M LFX SMF 40km" }, + + // ── 10G SFP+ ──────────────────────────────────────────────────────────── + { pid: "M-SFP-10-SR/LC", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 300, reachLabel: "SR", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "10GBASE-SR", notes: "Hirschmann industrial 10G SR" }, + { pid: "M-SFP-10-LR/LC", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 10000, reachLabel: "LR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "10GBASE-LR", notes: "Hirschmann industrial 10G LR" }, + { pid: "M-SFP-10-ER/LC", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 40000, reachLabel: "ER", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "10GBASE-ER" }, + { pid: "M-SFP-10-ZR/LC", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 80000, reachLabel: "ZR", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "10GBASE-ZR" }, + + // ── 10G SFP+ BiDi ─────────────────────────────────────────────────────── + { pid: "M-SFP-10-BD13/LC", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 10000, reachLabel: "BiDi", fiberType: "SMF", connector: "LC", wavelengths: "TX1270/RX1330nm", notes: "Hirschmann 10G BiDi TX1270/RX1330 single fiber 10km" }, + { pid: "M-SFP-10-BD15/LC", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 10000, reachLabel: "BiDi", fiberType: "SMF", connector: "LC", wavelengths: "TX1330/RX1270nm", notes: "Hirschmann 10G BiDi RX pair for M-SFP-10-BD13" }, + + // ── 25G SFP28 ─────────────────────────────────────────────────────────── + { pid: "M-SFP-25-SR/LC", formFactor: "SFP28", speedGbps: 25, speed: "25G", reachMeters: 100, reachLabel: "SR", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "25GBASE-SR" }, + { pid: "M-SFP-25-LR/LC", formFactor: "SFP28", speedGbps: 25, speed: "25G", reachMeters: 10000, reachLabel: "LR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "25GBASE-LR" }, + + // ── 40G QSFP+ ─────────────────────────────────────────────────────────── + { pid: "M-QSFP-40-SR4/MPO", formFactor: "QSFP+", speedGbps: 40, speed: "40G", reachMeters: 150, reachLabel: "SR4", fiberType: "MMF", connector: "MPO", wavelengths: "850nm", standard: "40GBASE-SR4" }, + { pid: "M-QSFP-40-LR4/LC", formFactor: "QSFP+", speedGbps: 40, speed: "40G", reachMeters: 10000, reachLabel: "LR4", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "40GBASE-LR4" }, + + // ── 100G QSFP28 ───────────────────────────────────────────────────────── + { pid: "M-QSFP-100-SR4/MPO", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 100, reachLabel: "SR4", fiberType: "MMF", connector: "MPO", wavelengths: "850nm", standard: "100GBASE-SR4" }, + { pid: "M-QSFP-100-LR4/LC", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 10000, reachLabel: "LR4", fiberType: "SMF", connector: "LC", wavelengths: "1295-1310nm", standard: "100GBASE-LR4" }, + { pid: "M-QSFP-100-CWDM4/LC", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 2000, reachLabel: "CWDM4", fiberType: "SMF", connector: "LC", wavelengths: "1271-1331nm", standard: "100GBASE-CWDM4" }, + + // ── DAC Cables ────────────────────────────────────────────────────────── + { pid: "M-DAC-SFP-10G-1M", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 1, reachLabel: "DAC1M", fiberType: "DAC", connector: "SFP+", notes: "Hirschmann SFP+ DAC 1m" }, + { pid: "M-DAC-SFP-10G-3M", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 3, reachLabel: "DAC3M", fiberType: "DAC", connector: "SFP+", notes: "Hirschmann SFP+ DAC 3m" }, + { pid: "M-DAC-QSFP-100G-1M", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 1, reachLabel: "DAC1M", fiberType: "DAC", connector: "QSFP28", notes: "Hirschmann QSFP28 DAC 1m" }, +]; + +export async function scrapeHirschmannOem(): Promise { + console.log("=== Hirschmann OEM Transceiver Seed ===\n"); + + const vendorId = await ensureVendor( + "Hirschmann", + "oem", + "https://www.belden.com/brands/hirschmann", + undefined + ); + + let inserted = 0; + let updated = 0; + let errors = 0; + + for (const p of HIRSCHMANN_PIDS) { + const slug = `hirschmann-${p.pid.toLowerCase().replace(/[^a-z0-9]+/g, "-")}`; + try { + const res = await pool.query( + `INSERT INTO transceivers + (slug, part_number, vendor_id, form_factor, speed, speed_gbps, + reach_meters, reach_label, fiber_type, connector, wavelengths, + dom_support, ieee_reference, market_status, category, notes) + VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,true,$12,'Mainstream','Industrial',$13) + ON CONFLICT (slug) DO UPDATE SET + speed_gbps = EXCLUDED.speed_gbps, + reach_meters = CASE WHEN EXCLUDED.reach_meters > 0 THEN EXCLUDED.reach_meters ELSE transceivers.reach_meters END, + fiber_type = CASE WHEN EXCLUDED.fiber_type <> '' THEN EXCLUDED.fiber_type ELSE transceivers.fiber_type END, + wavelengths = COALESCE(EXCLUDED.wavelengths, transceivers.wavelengths), + updated_at = NOW() + RETURNING (xmax = 0) as was_inserted`, + [slug, p.pid, vendorId, p.formFactor, p.speed, p.speedGbps, + p.reachMeters, p.reachLabel, p.fiberType, p.connector, + p.wavelengths ?? null, p.standard ?? null, p.notes ?? null] + ); + if (res.rows[0]?.was_inserted) inserted++; else updated++; + } catch (err) { + console.warn(` Skip ${p.pid}: ${(err as Error).message.slice(0, 80)}`); + errors++; + } + } + + console.log(`\n=== Hirschmann OEM Seed Complete ===`); + console.log(` Inserted: ${inserted}`); + console.log(` Updated: ${updated}`); + console.log(` Errors: ${errors}`); + console.log(` Total PIDs: ${HIRSCHMANN_PIDS.length}\n`); +} + +if (require.main === module) { + scrapeHirschmannOem() + .then(() => pool.end()) + .catch((err) => { + console.error("Fatal:", err); + pool.end(); + process.exit(1); + }); +} diff --git a/packages/scraper/src/scrapers/hisense-broadband-oem.ts b/packages/scraper/src/scrapers/hisense-broadband-oem.ts new file mode 100644 index 0000000..b60a532 --- /dev/null +++ b/packages/scraper/src/scrapers/hisense-broadband-oem.ts @@ -0,0 +1,131 @@ +/** + * Hisense Broadband OEM Transceiver Catalog Seed + * + * Seeds Hisense Broadband-branded transceiver PIDs covering data-center + * switching, 400G high-density, coherent ZR, and CFP2-DCO optics from + * Hisense Broadband Multimedia Technologies Co., Ltd. (Qingdao, China). + * + * Sources: + * - Hisense Broadband Transceiver Product Overview (hisense-broadband.com) + * - Hisense Broadband 400G QSFP-DD ZR Data Sheet + * - Hisense Broadband CFP2-DCO Coherent Module Specification + * + * Run: tsx packages/scraper/src/scrapers/hisense-broadband-oem.ts + * Cron: daily at 20:00 + */ + +import { pool, ensureVendor } from "../utils/db"; + +interface HisenseBBPID { + pid: string; + formFactor: string; + speedGbps: number; + speed: string; + reachMeters: number; + reachLabel: string; + fiberType: string; + connector: string; + wavelengths?: string; + standard?: string; + notes?: string; +} + +// PIDs that belong to TELECOM category (CFP2-DCO, ZR/ZR+) +const TELECOM_PIDS = new Set([ + "HBB-SFP-10G-ZR", + "HBB-CFP2-DCO-100G", + "HBB-QSFP-DD-ZR-400G", +]); + +const HISENSE_BB_PIDS: HisenseBBPID[] = [ + // ── 1G SFP ────────────────────────────────────────────────────────────── + { pid: "HBB-SFP-1G-SX", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 550, reachLabel: "SX", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "1000BASE-SX", notes: "Hisense Broadband 1G SFP SX 550m MMF" }, + { pid: "HBB-SFP-1G-LX", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 10000, reachLabel: "LX", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "1000BASE-LX", notes: "Hisense Broadband 1G SFP LX 10km SMF" }, + + // ── 10G SFP+ ──────────────────────────────────────────────────────────── + { pid: "HBB-SFP-10G-SR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 300, reachLabel: "SR", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "10GBASE-SR", notes: "Hisense Broadband 10G SFP+ SR 300m MMF" }, + { pid: "HBB-SFP-10G-LR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 10000, reachLabel: "LR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "10GBASE-LR", notes: "Hisense Broadband 10G SFP+ LR 10km SMF" }, + { pid: "HBB-SFP-10G-ER", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 40000, reachLabel: "ER", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "10GBASE-ER", notes: "Hisense Broadband 10G SFP+ ER 40km SMF" }, + { pid: "HBB-SFP-10G-ZR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 80000, reachLabel: "ZR", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "10GBASE-ZR", notes: "Hisense Broadband 10G SFP+ ZR 80km SMF" }, + + // ── 25G SFP28 ─────────────────────────────────────────────────────────── + { pid: "HBB-SFP28-25G-SR", formFactor: "SFP28", speedGbps: 25, speed: "25G", reachMeters: 100, reachLabel: "SR", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "25GBASE-SR", notes: "Hisense Broadband 25G SFP28 SR 100m MMF" }, + { pid: "HBB-SFP28-25G-LR", formFactor: "SFP28", speedGbps: 25, speed: "25G", reachMeters: 10000, reachLabel: "LR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "25GBASE-LR", notes: "Hisense Broadband 25G SFP28 LR 10km SMF" }, + + // ── 40G QSFP+ ─────────────────────────────────────────────────────────── + { pid: "HBB-QSFP-40G-SR4", formFactor: "QSFP+", speedGbps: 40, speed: "40G", reachMeters: 150, reachLabel: "SR4", fiberType: "MMF", connector: "MPO", wavelengths: "850nm", standard: "40GBASE-SR4", notes: "Hisense Broadband 40G QSFP+ SR4 150m MMF" }, + { pid: "HBB-QSFP-40G-LR4", formFactor: "QSFP+", speedGbps: 40, speed: "40G", reachMeters: 10000, reachLabel: "LR4", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "40GBASE-LR4", notes: "Hisense Broadband 40G QSFP+ LR4 10km SMF" }, + + // ── 100G QSFP28 ───────────────────────────────────────────────────────── + { pid: "HBB-QSFP28-100G-SR4", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 100, reachLabel: "SR4", fiberType: "MMF", connector: "MPO", wavelengths: "850nm", standard: "100GBASE-SR4", notes: "Hisense Broadband 100G QSFP28 SR4 100m MMF" }, + { pid: "HBB-QSFP28-100G-LR4", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 10000, reachLabel: "LR4", fiberType: "SMF", connector: "LC", wavelengths: "1295-1310nm", standard: "100GBASE-LR4", notes: "Hisense Broadband 100G QSFP28 LR4 10km SMF" }, + + // ── 400G QSFP-DD ──────────────────────────────────────────────────────── + { pid: "HBB-QSFP-DD-400G-DR4", formFactor: "QSFP-DD", speedGbps: 400, speed: "400G", reachMeters: 500, reachLabel: "DR4", fiberType: "SMF", connector: "MPO", wavelengths: "1310nm", standard: "400GBASE-DR4", notes: "Hisense Broadband 400G QSFP-DD DR4 500m SMF" }, + { pid: "HBB-QSFP-DD-400G-SR8", formFactor: "QSFP-DD", speedGbps: 400, speed: "400G", reachMeters: 100, reachLabel: "SR8", fiberType: "MMF", connector: "MPO", wavelengths: "850nm", standard: "400GBASE-SR8", notes: "Hisense Broadband 400G QSFP-DD SR8 100m MMF" }, + + // ── CFP2-DCO (Telecom) ─────────────────────────────────────────────────── + { pid: "HBB-CFP2-DCO-100G", formFactor: "CFP2", speedGbps: 100, speed: "100G", reachMeters: 1000000,reachLabel: "DCO", fiberType: "SMF", connector: "LC", wavelengths: "C-band tunable", standard: "OIF CFP2-DCO", notes: "Hisense Broadband 100G CFP2 DCO coherent C-band, 1000km span" }, + + // ── 400G ZR (Telecom) ──────────────────────────────────────────────────── + { pid: "HBB-QSFP-DD-ZR-400G", formFactor: "QSFP-DD", speedGbps: 400, speed: "400G", reachMeters: 1000000,reachLabel: "ZR", fiberType: "SMF", connector: "LC", wavelengths: "C-band tunable", standard: "OIF 400ZR", notes: "Hisense Broadband 400G QSFP-DD ZR coherent C-band, 1000km span" }, +]; + +export async function scrapeHisenseBroadbandOem(): Promise { + console.log("=== Hisense Broadband OEM Transceiver Seed ===\n"); + + const vendorId = await ensureVendor( + "Hisense Broadband", + "oem", + "https://www.hisense-broadband.com", + undefined + ); + + let inserted = 0; + let updated = 0; + let errors = 0; + + for (const p of HISENSE_BB_PIDS) { + const slug = `hisense-bb-${p.pid.toLowerCase().replace(/[^a-z0-9]+/g, "-")}`; + const category = TELECOM_PIDS.has(p.pid) ? "Telecom" : "DataCenter"; + try { + const res = await pool.query( + `INSERT INTO transceivers + (slug, part_number, vendor_id, form_factor, speed, speed_gbps, + reach_meters, reach_label, fiber_type, connector, wavelengths, + dom_support, ieee_reference, market_status, category, notes) + VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,true,$12,'Mainstream',$13,$14) + ON CONFLICT (slug) DO UPDATE SET + speed_gbps = EXCLUDED.speed_gbps, + reach_meters = CASE WHEN EXCLUDED.reach_meters > 0 THEN EXCLUDED.reach_meters ELSE transceivers.reach_meters END, + fiber_type = CASE WHEN EXCLUDED.fiber_type <> '' THEN EXCLUDED.fiber_type ELSE transceivers.fiber_type END, + wavelengths = COALESCE(EXCLUDED.wavelengths, transceivers.wavelengths), + updated_at = NOW() + RETURNING (xmax = 0) as was_inserted`, + [slug, p.pid, vendorId, p.formFactor, p.speed, p.speedGbps, + p.reachMeters, p.reachLabel, p.fiberType, p.connector, + p.wavelengths ?? null, p.standard ?? null, category, p.notes ?? null] + ); + if (res.rows[0]?.was_inserted) inserted++; else updated++; + } catch (err) { + console.warn(` Skip ${p.pid}: ${(err as Error).message.slice(0, 80)}`); + errors++; + } + } + + console.log(`\n=== Hisense Broadband OEM Seed Complete ===`); + console.log(` Inserted: ${inserted}`); + console.log(` Updated: ${updated}`); + console.log(` Errors: ${errors}`); + console.log(` Total PIDs: ${HISENSE_BB_PIDS.length}\n`); +} + +if (require.main === module) { + scrapeHisenseBroadbandOem() + .then(() => pool.end()) + .catch((err) => { + console.error("Fatal:", err); + pool.end(); + process.exit(1); + }); +} diff --git a/packages/scraper/src/scrapers/hitachi-vantara-oem.ts b/packages/scraper/src/scrapers/hitachi-vantara-oem.ts new file mode 100644 index 0000000..f09a499 --- /dev/null +++ b/packages/scraper/src/scrapers/hitachi-vantara-oem.ts @@ -0,0 +1,315 @@ +/** + * Hitachi Vantara OEM Transceiver Catalog Seed + * + * Seeds Hitachi Vantara-branded transceiver PIDs for VSP (Virtual Storage + * Platform) 5000/G/F series, VSP One, and HUS VM SAN storage controllers. + * Covers FC, iSCSI, and NVMe-oF host/target optical modules. + * + * Sources: + * - Hitachi Vantara Interoperability Matrix (hitachivantara.com/support) + * - VSP Hardware Installation and Configuration Guide + * - Hitachi VSP 5000 Series Optical Connectivity Reference + * + * Run: tsx packages/scraper/src/scrapers/hitachi-vantara-oem.ts + * Cron: daily at 07:00 + */ + +import { pool, ensureVendor } from "../utils/db"; + +interface HitachiVantaraPID { + pid: string; + formFactor: string; + speedGbps: number; + speed: string; + reachMeters: number; + reachLabel: string; + fiberType: string; + connector: string; + wavelengths?: string; + standard?: string; + notes?: string; +} + +// Fibre Channel line-rate speeds (Gbps): +// 8G = 8.5 Gbps (8GFC) +// 16G = 14.025 Gbps (16GFC) +// 32G = 28.05 Gbps (32GFC) +// 64G = 56.1 Gbps (64GFC) +const HITACHI_VANTARA_PIDS: HitachiVantaraPID[] = [ + // ── 8G FC SFP+ ─────────────────────────────────────────────────────────── + { + pid: "HV-SFP-8G-FC-SW", + formFactor: "SFP+", + speedGbps: 8.5, + speed: "8G FC", + reachMeters: 150, + reachLabel: "SW", + fiberType: "MMF", + connector: "LC", + wavelengths: "850nm", + standard: "8GFC", + notes: "8G FC SFP+ SW; Hitachi VSP G200/G400/G600 FC target port; OM3/OM4 MMF up to 150m", + }, + { + pid: "HV-SFP-8G-FC-LW", + formFactor: "SFP+", + speedGbps: 8.5, + speed: "8G FC", + reachMeters: 10000, + reachLabel: "LW", + fiberType: "SMF", + connector: "LC", + wavelengths: "1310nm", + standard: "8GFC", + notes: "8G FC SFP+ LW; Hitachi VSP G200/G400/G600 FC target port long-reach; OS2 SMF up to 10km", + }, + // ── 16G FC SFP+ ────────────────────────────────────────────────────────── + { + pid: "HV-SFP-16G-FC-SW", + formFactor: "SFP+", + speedGbps: 14.025, + speed: "16G FC", + reachMeters: 125, + reachLabel: "SW", + fiberType: "MMF", + connector: "LC", + wavelengths: "850nm", + standard: "16GFC", + notes: "16G FC SFP+ SW; Hitachi VSP G800/G1000/F800 FC target port; OM4 MMF up to 125m", + }, + { + pid: "HV-SFP-16G-FC-LW", + formFactor: "SFP+", + speedGbps: 14.025, + speed: "16G FC", + reachMeters: 10000, + reachLabel: "LW", + fiberType: "SMF", + connector: "LC", + wavelengths: "1310nm", + standard: "16GFC", + notes: "16G FC SFP+ LW; Hitachi VSP G800/G1000/F800 FC target port long-reach; OS2 SMF", + }, + // ── 32G FC SFP28 ───────────────────────────────────────────────────────── + { + pid: "HV-SFP-32G-FC-SW", + formFactor: "SFP28", + speedGbps: 28.05, + speed: "32G FC", + reachMeters: 100, + reachLabel: "SW", + fiberType: "MMF", + connector: "LC", + wavelengths: "850nm", + standard: "32GFC", + notes: "32G FC SFP28 SW; Hitachi VSP 5100/5500/5600 NVMe/FC port; OM4/OM5 MMF up to 100m", + }, + // ── 10GbE SFP+ ─────────────────────────────────────────────────────────── + { + pid: "HV-SFP-10G-SR", + formFactor: "SFP+", + speedGbps: 10, + speed: "10G", + reachMeters: 300, + reachLabel: "SR", + fiberType: "MMF", + connector: "LC", + wavelengths: "850nm", + standard: "10GBASE-SR", + notes: "10GbE SFP+ SR; Hitachi VSP iSCSI/FCoE host port; OM3/OM4 MMF up to 300m", + }, + { + pid: "HV-SFP-10G-LR", + formFactor: "SFP+", + speedGbps: 10, + speed: "10G", + reachMeters: 10000, + reachLabel: "LR", + fiberType: "SMF", + connector: "LC", + wavelengths: "1310nm", + standard: "10GBASE-LR", + notes: "10GbE SFP+ LR; Hitachi VSP iSCSI/FCoE host port long-reach; OS2 SMF up to 10km", + }, + // ── 25GbE SFP28 ────────────────────────────────────────────────────────── + { + pid: "HV-SFP28-25G-SR", + formFactor: "SFP28", + speedGbps: 25, + speed: "25G", + reachMeters: 100, + reachLabel: "SR", + fiberType: "MMF", + connector: "LC", + wavelengths: "850nm", + standard: "25GBASE-SR", + notes: "25GbE SFP28 SR; Hitachi VSP 5000 series NVMe-oF iSCSI port; OM4 MMF", + }, + { + pid: "HV-SFP28-25G-LR", + formFactor: "SFP28", + speedGbps: 25, + speed: "25G", + reachMeters: 10000, + reachLabel: "LR", + fiberType: "SMF", + connector: "LC", + wavelengths: "1310nm", + standard: "25GBASE-LR", + notes: "25GbE SFP28 LR; Hitachi VSP 5000 series NVMe-oF iSCSI long-reach; OS2 SMF", + }, + // ── 100GbE QSFP28 ──────────────────────────────────────────────────────── + { + pid: "HV-QSFP28-100G-SR4", + formFactor: "QSFP28", + speedGbps: 100, + speed: "100G", + reachMeters: 100, + reachLabel: "SR4", + fiberType: "MMF", + connector: "MPO", + wavelengths: "850nm", + standard: "100GBASE-SR4", + notes: "100GbE QSFP28 SR4; Hitachi VSP 5000 series backend replication link; OM4 MPO-12", + }, + { + pid: "HV-QSFP28-100G-LR4", + formFactor: "QSFP28", + speedGbps: 100, + speed: "100G", + reachMeters: 10000, + reachLabel: "LR4", + fiberType: "SMF", + connector: "LC", + wavelengths: "1295-1310nm", + standard: "100GBASE-LR4", + notes: "100GbE QSFP28 LR4; Hitachi VSP 5000 series replication long-reach; OS2 SMF", + }, + // ── 400GbE QSFP-DD ─────────────────────────────────────────────────────── + { + pid: "HV-QSFP-DD-400G-DR4", + formFactor: "QSFP-DD", + speedGbps: 400, + speed: "400G", + reachMeters: 500, + reachLabel: "DR4", + fiberType: "SMF", + connector: "MPO", + wavelengths: "1310nm", + standard: "400GBASE-DR4", + notes: "400GbE QSFP-DD DR4; Hitachi VSP One next-gen NVMe-oF fabric link; OS2 SMF up to 500m", + }, + // ── 1GbE SFP ───────────────────────────────────────────────────────────── + { + pid: "HV-SFP-1G-SX", + formFactor: "SFP", + speedGbps: 1, + speed: "1G", + reachMeters: 550, + reachLabel: "SX", + fiberType: "MMF", + connector: "LC", + wavelengths: "850nm", + standard: "1000BASE-SX", + notes: "1GbE SFP SX; Hitachi storage management and iSCSI port; OM2/OM3 MMF", + }, + { + pid: "HV-SFP-1G-LX", + formFactor: "SFP", + speedGbps: 1, + speed: "1G", + reachMeters: 10000, + reachLabel: "LX", + fiberType: "SMF", + connector: "LC", + wavelengths: "1310nm", + standard: "1000BASE-LX", + notes: "1GbE SFP LX; Hitachi storage management and iSCSI port long-reach; OS2 SMF", + }, + // ── 40GbE QSFP+ ────────────────────────────────────────────────────────── + { + pid: "HV-QSFP-40G-SR4", + formFactor: "QSFP+", + speedGbps: 40, + speed: "40G", + reachMeters: 150, + reachLabel: "SR4", + fiberType: "MMF", + connector: "MPO", + wavelengths: "850nm", + standard: "40GBASE-SR4", + notes: "40GbE QSFP+ SR4; Hitachi storage fabric switch uplink; OM3/OM4 MPO-12", + }, + // ── 64G FC SFP28 ───────────────────────────────────────────────────────── + { + pid: "HV-SFP28-64G-FC-SW", + formFactor: "SFP28", + speedGbps: 56.1, + speed: "64G FC", + reachMeters: 70, + reachLabel: "SW", + fiberType: "MMF", + connector: "LC", + wavelengths: "850nm", + standard: "64GFC", + notes: "64G FC SFP28 SW; Hitachi VSP One next-gen NVMe/FC port; OM5 WBMMF up to 70m", + }, +]; + +export async function scrapeHitachiVantaraOem(): Promise { + console.log("=== Hitachi Vantara OEM Transceiver Seed ===\n"); + + const vendorId = await ensureVendor( + "Hitachi Vantara", + "oem", + "https://www.hitachivantara.com", + undefined + ); + + let inserted = 0; + let updated = 0; + let errors = 0; + + for (const p of HITACHI_VANTARA_PIDS) { + const slug = `hitachi-vantara-${p.pid.toLowerCase().replace(/[^a-z0-9]+/g, "-")}`; + try { + const res = await pool.query( + `INSERT INTO transceivers + (slug, part_number, vendor_id, form_factor, speed, speed_gbps, + reach_meters, reach_label, fiber_type, connector, wavelengths, + dom_support, ieee_reference, market_status, category, notes) + VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,true,$12,'Mainstream','DataCenter',$13) + ON CONFLICT (slug) DO UPDATE SET + speed_gbps = EXCLUDED.speed_gbps, + reach_meters = CASE WHEN EXCLUDED.reach_meters > 0 THEN EXCLUDED.reach_meters ELSE transceivers.reach_meters END, + fiber_type = CASE WHEN EXCLUDED.fiber_type <> '' THEN EXCLUDED.fiber_type ELSE transceivers.fiber_type END, + wavelengths = COALESCE(EXCLUDED.wavelengths, transceivers.wavelengths), + updated_at = NOW() + RETURNING (xmax = 0) as was_inserted`, + [slug, p.pid, vendorId, p.formFactor, p.speed, p.speedGbps, + p.reachMeters, p.reachLabel, p.fiberType, p.connector, + p.wavelengths ?? null, p.standard ?? null, p.notes ?? null] + ); + if (res.rows[0]?.was_inserted) inserted++; else updated++; + } catch (err) { + console.warn(` Skip ${p.pid}: ${(err as Error).message.slice(0, 80)}`); + errors++; + } + } + + console.log(`\n=== Hitachi Vantara OEM Seed Complete ===`); + console.log(` Inserted: ${inserted}`); + console.log(` Updated: ${updated}`); + console.log(` Errors: ${errors}`); + console.log(` Total PIDs: ${HITACHI_VANTARA_PIDS.length}\n`); +} + +if (require.main === module) { + scrapeHitachiVantaraOem() + .then(() => pool.end()) + .catch((err) => { + console.error("Fatal:", err); + pool.end(); + process.exit(1); + }); +} diff --git a/packages/scraper/src/scrapers/hpe-storage-oem.ts b/packages/scraper/src/scrapers/hpe-storage-oem.ts new file mode 100644 index 0000000..abfce01 --- /dev/null +++ b/packages/scraper/src/scrapers/hpe-storage-oem.ts @@ -0,0 +1,365 @@ +/** + * HPE Storage OEM Transceiver Catalog Seed + * + * Seeds HPE Storage-branded transceiver PIDs for 3PAR/Primera/Alletra SAN + * storage controllers, FC host bus adapters, and iSCSI/FCoE host ports. + * Covers the full HPE StoreServ / Nimble / Alletra optical module lineup. + * + * Sources: + * - HPE Storage Compatibility Matrix (support.hpe.com) + * - HPE 3PAR/Primera/Alletra Hardware Installation Guides + * - HPE QuickSpecs for SAN Switch and Storage optical modules + * + * Run: tsx packages/scraper/src/scrapers/hpe-storage-oem.ts + * Cron: daily at 06:15 + */ + +import { pool, ensureVendor } from "../utils/db"; + +interface HpeStoragePID { + pid: string; + formFactor: string; + speedGbps: number; + speed: string; + reachMeters: number; + reachLabel: string; + fiberType: string; + connector: string; + wavelengths?: string; + standard?: string; + notes?: string; +} + +// Fibre Channel line-rate speeds (Gbps): +// 8G = 8.5 Gbps (8GFC) +// 16G = 14.025 Gbps (16GFC) +// 32G = 28.05 Gbps (32GFC) +const HPE_STORAGE_PIDS: HpeStoragePID[] = [ + // ── 8G FC SFP+ ─────────────────────────────────────────────────────────── + { + pid: "AJ716B", + formFactor: "SFP+", + speedGbps: 8.5, + speed: "8G FC", + reachMeters: 150, + reachLabel: "SW", + fiberType: "MMF", + connector: "LC", + wavelengths: "850nm", + standard: "8GFC", + notes: "8G FC SFP+ SW; HPE 3PAR/P9000 FC host/target port; OM3/OM4 MMF up to 150m", + }, + { + pid: "AJ717B", + formFactor: "SFP+", + speedGbps: 8.5, + speed: "8G FC", + reachMeters: 10000, + reachLabel: "LW", + fiberType: "SMF", + connector: "LC", + wavelengths: "1310nm", + standard: "8GFC", + notes: "8G FC SFP+ LW; HPE 3PAR/P9000 FC host/target port long-reach; OS2 SMF up to 10km", + }, + // ── 16G FC SFP+ ────────────────────────────────────────────────────────── + { + pid: "C8R23B", + formFactor: "SFP+", + speedGbps: 14.025, + speed: "16G FC", + reachMeters: 125, + reachLabel: "SW", + fiberType: "MMF", + connector: "LC", + wavelengths: "850nm", + standard: "16GFC", + notes: "16G FC SFP+ SW; HPE 3PAR 7000/8000/Primera FC target port; OM4 MMF up to 125m", + }, + { + pid: "C8R24B", + formFactor: "SFP+", + speedGbps: 14.025, + speed: "16G FC", + reachMeters: 10000, + reachLabel: "LW", + fiberType: "SMF", + connector: "LC", + wavelengths: "1310nm", + standard: "16GFC", + notes: "16G FC SFP+ LW; HPE 3PAR 7000/8000/Primera FC target port long-reach; OS2 SMF up to 10km", + }, + // ── 32G FC SFP28 ───────────────────────────────────────────────────────── + { + pid: "Q2P63A", + formFactor: "SFP28", + speedGbps: 28.05, + speed: "32G FC", + reachMeters: 100, + reachLabel: "SW", + fiberType: "MMF", + connector: "LC", + wavelengths: "850nm", + standard: "32GFC", + notes: "32G FC SFP28 SW; HPE Primera A630/A650/Alletra 9000 FC NVMe/FC port; OM4/OM5 MMF", + }, + { + pid: "Q2P64A", + formFactor: "SFP28", + speedGbps: 28.05, + speed: "32G FC", + reachMeters: 10000, + reachLabel: "LW", + fiberType: "SMF", + connector: "LC", + wavelengths: "1310nm", + standard: "32GFC", + notes: "32G FC SFP28 LW; HPE Primera A630/A650/Alletra 9000 FC NVMe/FC long-reach; OS2 SMF", + }, + // ── 10GbE SFP+ ─────────────────────────────────────────────────────────── + { + pid: "455885-B21", + formFactor: "SFP+", + speedGbps: 10, + speed: "10G", + reachMeters: 300, + reachLabel: "SR", + fiberType: "MMF", + connector: "LC", + wavelengths: "850nm", + standard: "10GBASE-SR", + notes: "10GbE SFP+ SR; HPE storage and server host port; OM3 300m / OM4 400m MMF", + }, + { + pid: "455886-B21", + formFactor: "SFP+", + speedGbps: 10, + speed: "10G", + reachMeters: 10000, + reachLabel: "LR", + fiberType: "SMF", + connector: "LC", + wavelengths: "1310nm", + standard: "10GBASE-LR", + notes: "10GbE SFP+ LR; HPE storage and server host port long-reach; OS2 SMF up to 10km", + }, + // ── 25GbE SFP28 ────────────────────────────────────────────────────────── + { + pid: "813874-B21", + formFactor: "SFP28", + speedGbps: 25, + speed: "25G", + reachMeters: 100, + reachLabel: "SR", + fiberType: "MMF", + connector: "LC", + wavelengths: "850nm", + standard: "25GBASE-SR", + notes: "25GbE SFP28 SR; HPE Alletra 6000/9000 iSCSI/NVMe-oF host port; OM4 MMF", + }, + { + pid: "813875-B21", + formFactor: "SFP28", + speedGbps: 25, + speed: "25G", + reachMeters: 10000, + reachLabel: "LR", + fiberType: "SMF", + connector: "LC", + wavelengths: "1310nm", + standard: "25GBASE-LR", + notes: "25GbE SFP28 LR; HPE Alletra 6000/9000 iSCSI/NVMe-oF host port long-reach; OS2 SMF", + }, + // ── 100GbE QSFP28 ──────────────────────────────────────────────────────── + { + pid: "817753-B21", + formFactor: "QSFP28", + speedGbps: 100, + speed: "100G", + reachMeters: 100, + reachLabel: "SR4", + fiberType: "MMF", + connector: "MPO", + wavelengths: "850nm", + standard: "100GBASE-SR4", + notes: "100GbE QSFP28 SR4; HPE storage backend/replication interconnect; OM4 MPO-12", + }, + { + pid: "817754-B21", + formFactor: "QSFP28", + speedGbps: 100, + speed: "100G", + reachMeters: 10000, + reachLabel: "LR4", + fiberType: "SMF", + connector: "LC", + wavelengths: "1295-1310nm", + standard: "100GBASE-LR4", + notes: "100GbE QSFP28 LR4; HPE storage backend/replication long-reach; OS2 SMF up to 10km", + }, + // ── 400GbE QSFP-DD ─────────────────────────────────────────────────────── + { + pid: "P08748-B21", + formFactor: "QSFP-DD", + speedGbps: 400, + speed: "400G", + reachMeters: 500, + reachLabel: "DR4", + fiberType: "SMF", + connector: "MPO", + wavelengths: "1310nm", + standard: "400GBASE-DR4", + notes: "400GbE QSFP-DD DR4; HPE next-gen storage fabric interconnect; OS2 SMF up to 500m", + }, + // ── 1GbE SFP ───────────────────────────────────────────────────────────── + { + pid: "453154-B21", + formFactor: "SFP", + speedGbps: 1, + speed: "1G", + reachMeters: 550, + reachLabel: "SX", + fiberType: "MMF", + connector: "LC", + wavelengths: "850nm", + standard: "1000BASE-SX", + notes: "1GbE SFP SX; HPE storage management and iSCSI port; OM2/OM3 MMF", + }, + { + pid: "453156-B21", + formFactor: "SFP", + speedGbps: 1, + speed: "1G", + reachMeters: 10000, + reachLabel: "LX", + fiberType: "SMF", + connector: "LC", + wavelengths: "1310nm", + standard: "1000BASE-LX", + notes: "1GbE SFP LX; HPE storage management and iSCSI port long-reach; OS2 SMF", + }, + // ── Copper SFP ─────────────────────────────────────────────────────────── + { + pid: "HPE-SFP-1G-T", + formFactor: "SFP", + speedGbps: 1, + speed: "1G", + reachMeters: 100, + reachLabel: "T", + fiberType: "DAC", + connector: "RJ45", + standard: "1000BASE-T", + notes: "1GbE copper SFP RJ45; HPE storage management port copper option; Cat5e/6", + }, + { + pid: "HPE-SFP-10G-T", + formFactor: "SFP+", + speedGbps: 10, + speed: "10G", + reachMeters: 30, + reachLabel: "T", + fiberType: "DAC", + connector: "RJ45", + standard: "10GBASE-T", + notes: "10GbE copper SFP+ RJ45; HPE iSCSI storage host port; Cat6a up to 30m", + }, + // ── 40GbE QSFP+ ────────────────────────────────────────────────────────── + { + pid: "HPE-QSFP-40G-SR4", + formFactor: "QSFP+", + speedGbps: 40, + speed: "40G", + reachMeters: 150, + reachLabel: "SR4", + fiberType: "MMF", + connector: "MPO", + wavelengths: "850nm", + standard: "40GBASE-SR4", + notes: "40GbE QSFP+ SR4; HPE storage fabric switch uplink; OM3/OM4 MPO-12", + }, + { + pid: "HPE-QSFP-40G-LR4", + formFactor: "QSFP+", + speedGbps: 40, + speed: "40G", + reachMeters: 10000, + reachLabel: "LR4", + fiberType: "SMF", + connector: "LC", + wavelengths: "1310nm", + standard: "40GBASE-LR4", + notes: "40GbE QSFP+ LR4; HPE storage fabric switch uplink long-reach; OS2 SMF", + }, + // ── 16G FC SFP+ Long-Wave (generic HPE part) ───────────────────────────── + { + pid: "HPE-SFP-16G-FC-LW", + formFactor: "SFP+", + speedGbps: 14.025, + speed: "16G FC", + reachMeters: 10000, + reachLabel: "LW", + fiberType: "SMF", + connector: "LC", + wavelengths: "1310nm", + standard: "16GFC", + notes: "16G FC SFP+ LW generic HPE part; 3PAR/Primera cross-compat long-wave; OS2 SMF", + }, +]; + +export async function scrapeHpeStorageOem(): Promise { + console.log("=== HPE Storage OEM Transceiver Seed ===\n"); + + const vendorId = await ensureVendor( + "HPE Storage", + "oem", + "https://www.hpe.com/storage", + undefined + ); + + let inserted = 0; + let updated = 0; + let errors = 0; + + for (const p of HPE_STORAGE_PIDS) { + const slug = `hpe-storage-${p.pid.toLowerCase().replace(/[^a-z0-9]+/g, "-")}`; + try { + const res = await pool.query( + `INSERT INTO transceivers + (slug, part_number, vendor_id, form_factor, speed, speed_gbps, + reach_meters, reach_label, fiber_type, connector, wavelengths, + dom_support, ieee_reference, market_status, category, notes) + VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,true,$12,'Mainstream','DataCenter',$13) + ON CONFLICT (slug) DO UPDATE SET + speed_gbps = EXCLUDED.speed_gbps, + reach_meters = CASE WHEN EXCLUDED.reach_meters > 0 THEN EXCLUDED.reach_meters ELSE transceivers.reach_meters END, + fiber_type = CASE WHEN EXCLUDED.fiber_type <> '' THEN EXCLUDED.fiber_type ELSE transceivers.fiber_type END, + wavelengths = COALESCE(EXCLUDED.wavelengths, transceivers.wavelengths), + updated_at = NOW() + RETURNING (xmax = 0) as was_inserted`, + [slug, p.pid, vendorId, p.formFactor, p.speed, p.speedGbps, + p.reachMeters, p.reachLabel, p.fiberType, p.connector, + p.wavelengths ?? null, p.standard ?? null, p.notes ?? null] + ); + if (res.rows[0]?.was_inserted) inserted++; else updated++; + } catch (err) { + console.warn(` Skip ${p.pid}: ${(err as Error).message.slice(0, 80)}`); + errors++; + } + } + + console.log(`\n=== HPE Storage OEM Seed Complete ===`); + console.log(` Inserted: ${inserted}`); + console.log(` Updated: ${updated}`); + console.log(` Errors: ${errors}`); + console.log(` Total PIDs: ${HPE_STORAGE_PIDS.length}\n`); +} + +if (require.main === module) { + scrapeHpeStorageOem() + .then(() => pool.end()) + .catch((err) => { + console.error("Fatal:", err); + pool.end(); + process.exit(1); + }); +} diff --git a/packages/scraper/src/scrapers/huawei-access-oem.ts b/packages/scraper/src/scrapers/huawei-access-oem.ts new file mode 100644 index 0000000..65619b5 --- /dev/null +++ b/packages/scraper/src/scrapers/huawei-access-oem.ts @@ -0,0 +1,147 @@ +/** + * Huawei Access OEM Transceiver Catalog Seed + * + * Seeds Huawei Access-branded transceiver PIDs for SmartAX OLT platforms + * (MA5800, MA5600T) supporting GPON, XGS-PON, and 25G-PON line cards. + * + * Sources: + * - Huawei Fixed Network Access OLT Product Page (carrier.huawei.com) + * - Huawei SmartAX MA5800 Hardware Description + * - Huawei XGS-PON / 25G-PON Optical Module Data Sheets + * + * Run: tsx packages/scraper/src/scrapers/huawei-access-oem.ts + * Cron: daily at 08:30 + */ + +import { pool, ensureVendor } from "../utils/db"; + +interface HuaweiAccessPID { + pid: string; + formFactor: string; + speedGbps: number; + speed: string; + reachMeters: number; + reachLabel: string; + fiberType: string; + connector: string; + wavelengths?: string; + standard?: string; + notes?: string; + isTelecom?: boolean; +} + +const TELECOM_PIDS: Set = new Set([ + "H3C-GPON-OLT-CLASS-B", + "H3C-GPON-OLT-CLASS-C", + "HW-XGSPON-OLT-1577", + "HW-XGSPON-ONU-1270", + "HW-EPON-OLT", + "HW-10G-EPON-OLT", + "HW-25G-PON-OLT", + "HW-SFP-CWDM-1490", + "HW-SFP-CWDM-1550", + "HW-SFP-BIDI-1310", + "HW-SFP-BIDI-1490", + "HW-SFP-10G-BIDI-1270", +]); + +const HUAWEI_ACCESS_PIDS: HuaweiAccessPID[] = [ + // ── GPON OLT SFP ───────────────────────────────────────────────────────── + { pid: "H3C-GPON-OLT-CLASS-B", formFactor: "SFP", speedGbps: 2.488, speed: "GPON", reachMeters: 20000, reachLabel: "GPON-20K", fiberType: "SMF", connector: "SC", wavelengths: "1490/1310nm", standard: "G.984", notes: "Huawei Access GPON OLT SFP Class B+, SmartAX platform", isTelecom: true }, + { pid: "H3C-GPON-OLT-CLASS-C", formFactor: "SFP", speedGbps: 2.488, speed: "GPON", reachMeters: 20000, reachLabel: "GPON-C+", fiberType: "SMF", connector: "SC", wavelengths: "1490/1310nm", standard: "G.984", notes: "Huawei Access GPON OLT SFP Class C+, extended reach", isTelecom: true }, + + // ── XGS-PON OLT / ONU SFP+ ─────────────────────────────────────────────── + { pid: "HW-XGSPON-OLT-1577", formFactor: "SFP+", speedGbps: 10, speed: "XGS-PON", reachMeters: 20000, reachLabel: "XGS-PON-20K", fiberType: "SMF", connector: "SC", wavelengths: "1577/1270nm", standard: "G.9807.1", notes: "Huawei Access XGS-PON OLT SFP+ for MA5800", isTelecom: true }, + { pid: "HW-XGSPON-ONU-1270", formFactor: "SFP+", speedGbps: 10, speed: "XGS-PON", reachMeters: 20000, reachLabel: "XGS-ONU-20K", fiberType: "SMF", connector: "SC", wavelengths: "1270/1577nm", standard: "G.9807.1", notes: "Huawei Access XGS-PON ONU SFP+ 1270nm TX", isTelecom: true }, + + // ── EPON OLT SFP ───────────────────────────────────────────────────────── + { pid: "HW-EPON-OLT", formFactor: "SFP", speedGbps: 1, speed: "EPON", reachMeters: 20000, reachLabel: "EPON-20K", fiberType: "SMF", connector: "SC", wavelengths: "1490/1310nm", standard: "802.3ah", notes: "Huawei Access EPON OLT SFP 1G/1G", isTelecom: true }, + { pid: "HW-10G-EPON-OLT", formFactor: "SFP+", speedGbps: 10, speed: "10G-EPON", reachMeters: 20000, reachLabel: "10G-EPON-20K",fiberType: "SMF", connector: "SC", wavelengths: "1577/1270nm", standard: "802.3av", notes: "Huawei Access 10G-EPON OLT SFP+", isTelecom: true }, + + // ── 25G-PON OLT SFP28 ──────────────────────────────────────────────────── + { pid: "HW-25G-PON-OLT", formFactor: "SFP28", speedGbps: 25, speed: "25G-PON", reachMeters: 20000, reachLabel: "25G-PON-20K", fiberType: "SMF", connector: "SC", wavelengths: "1577/1270nm", standard: "G.9804.3", notes: "Huawei Access 25G-PON OLT SFP28", isTelecom: true }, + + // ── Standard 1G SFP ────────────────────────────────────────────────────── + { pid: "HW-SFP-GE-SX", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 550, reachLabel: "SX", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "1000BASE-SX" }, + { pid: "HW-SFP-GE-LX", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 10000, reachLabel: "LX", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "1000BASE-LX" }, + + // ── Standard 10G SFP+ ──────────────────────────────────────────────────── + { pid: "HW-SFP-10G-SR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 300, reachLabel: "SR", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "10GBASE-SR" }, + { pid: "HW-SFP-10G-LR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 10000, reachLabel: "LR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "10GBASE-LR" }, + { pid: "HW-SFP-10G-ER", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 40000, reachLabel: "ER", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "10GBASE-ER" }, + + // ── CWDM SFP ───────────────────────────────────────────────────────────── + { pid: "HW-SFP-CWDM-1490", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 40000, reachLabel: "CWDM-1490", fiberType: "SMF", connector: "LC", wavelengths: "1490nm", standard: "CWDM", notes: "Huawei Access CWDM SFP 1490nm", isTelecom: true }, + { pid: "HW-SFP-CWDM-1550", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 40000, reachLabel: "CWDM-1550", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "CWDM", notes: "Huawei Access CWDM SFP 1550nm", isTelecom: true }, + + // ── BiDi SFP ───────────────────────────────────────────────────────────── + { pid: "HW-SFP-BIDI-1310", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 20000, reachLabel: "BiDi-1310", fiberType: "SMF", connector: "SC", wavelengths: "1310/1490nm", notes: "Huawei Access 1G BiDi SFP 1310nm TX / 1490nm RX", isTelecom: true }, + { pid: "HW-SFP-BIDI-1490", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 20000, reachLabel: "BiDi-1490", fiberType: "SMF", connector: "SC", wavelengths: "1490/1310nm", notes: "Huawei Access 1G BiDi SFP 1490nm TX / 1310nm RX", isTelecom: true }, + { pid: "HW-SFP-10G-BIDI-1270", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 20000, reachLabel: "BiDi-1270", fiberType: "SMF", connector: "LC", wavelengths: "1270/1330nm", notes: "Huawei Access 10G BiDi SFP+ 1270nm TX", isTelecom: true }, + + // ── 25G SFP28 ──────────────────────────────────────────────────────────── + { pid: "HW-SFP-25G-LR", formFactor: "SFP28", speedGbps: 25, speed: "25G", reachMeters: 10000, reachLabel: "LR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "25GBASE-LR" }, + + // ── 40G / 100G QSFP ────────────────────────────────────────────────────── + { pid: "HW-QSFP-40G-LR4", formFactor: "QSFP+", speedGbps: 40, speed: "40G", reachMeters: 10000, reachLabel: "LR4", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "40GBASE-LR4" }, + { pid: "HW-QSFP-100G-LR4", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 10000, reachLabel: "LR4", fiberType: "SMF", connector: "LC", wavelengths: "1295-1310nm", standard: "100GBASE-LR4" }, +]; + +export async function scrapeHuaweiAccessOem(): Promise { + console.log("=== Huawei Access OEM Transceiver Seed ===\n"); + + const vendorId = await ensureVendor( + "Huawei Access", + "oem", + "https://carrier.huawei.com/en/products/fixed-network/access/olt", + undefined + ); + + let inserted = 0; + let updated = 0; + let errors = 0; + + for (const p of HUAWEI_ACCESS_PIDS) { + const slug = `huawei-access-${p.pid.toLowerCase().replace(/[^a-z0-9]+/g, "-")}`; + const category = TELECOM_PIDS.has(p.pid) ? "Telecom" : "DataCenter"; + try { + const res = await pool.query( + `INSERT INTO transceivers + (slug, part_number, vendor_id, form_factor, speed, speed_gbps, + reach_meters, reach_label, fiber_type, connector, wavelengths, + dom_support, ieee_reference, market_status, category, notes) + VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,true,$12,'Mainstream',$13,$14) + ON CONFLICT (slug) DO UPDATE SET + speed_gbps = EXCLUDED.speed_gbps, + reach_meters = CASE WHEN EXCLUDED.reach_meters > 0 THEN EXCLUDED.reach_meters ELSE transceivers.reach_meters END, + fiber_type = CASE WHEN EXCLUDED.fiber_type <> '' THEN EXCLUDED.fiber_type ELSE transceivers.fiber_type END, + wavelengths = COALESCE(EXCLUDED.wavelengths, transceivers.wavelengths), + updated_at = NOW() + RETURNING (xmax = 0) as was_inserted`, + [slug, p.pid, vendorId, p.formFactor, p.speed, p.speedGbps, + p.reachMeters, p.reachLabel, p.fiberType, p.connector, + p.wavelengths ?? null, p.standard ?? null, category, p.notes ?? null] + ); + if (res.rows[0]?.was_inserted) inserted++; else updated++; + } catch (err) { + console.warn(` Skip ${p.pid}: ${(err as Error).message.slice(0, 80)}`); + errors++; + } + } + + console.log(`\n=== Huawei Access OEM Seed Complete ===`); + console.log(` Inserted: ${inserted}`); + console.log(` Updated: ${updated}`); + console.log(` Errors: ${errors}`); + console.log(` Total PIDs: ${HUAWEI_ACCESS_PIDS.length}\n`); +} + +if (require.main === module) { + scrapeHuaweiAccessOem() + .then(() => pool.end()) + .catch((err) => { + console.error("Fatal:", err); + pool.end(); + process.exit(1); + }); +} diff --git a/packages/scraper/src/scrapers/ibm-storage-oem.ts b/packages/scraper/src/scrapers/ibm-storage-oem.ts new file mode 100644 index 0000000..b4a68a0 --- /dev/null +++ b/packages/scraper/src/scrapers/ibm-storage-oem.ts @@ -0,0 +1,368 @@ +/** + * IBM Storage OEM Transceiver Catalog Seed + * + * Seeds IBM Storage-branded transceiver PIDs for FlashSystem 5000/7000/9000, + * DS8000, Spectrum Virtualize SAN controllers, and IBM SAN Volume Controller + * (SVC) FC/FCoE/iSCSI host and inter-system link ports. + * + * Sources: + * - IBM System Storage Interoperability Center (SSIC) + * - IBM FlashSystem Hardware Installation and Maintenance Guide + * - IBM DS8000 and SAN Volume Controller optical compatibility matrices + * + * Run: tsx packages/scraper/src/scrapers/ibm-storage-oem.ts + * Cron: daily at 06:30 + */ + +import { pool, ensureVendor } from "../utils/db"; + +interface IbmStoragePID { + pid: string; + formFactor: string; + speedGbps: number; + speed: string; + reachMeters: number; + reachLabel: string; + fiberType: string; + connector: string; + wavelengths?: string; + standard?: string; + notes?: string; +} + +// Fibre Channel line-rate speeds (Gbps): +// 8G = 8.5 Gbps (8GFC) +// 16G = 14.025 Gbps (16GFC) +// 32G = 28.05 Gbps (32GFC) +// 64G = 56.1 Gbps (64GFC) +const IBM_STORAGE_PIDS: IbmStoragePID[] = [ + // ── 8G FC SFP+ ─────────────────────────────────────────────────────────── + { + pid: "45W2408", + formFactor: "SFP+", + speedGbps: 8.5, + speed: "8G FC", + reachMeters: 150, + reachLabel: "SW", + fiberType: "MMF", + connector: "LC", + wavelengths: "850nm", + standard: "8GFC", + notes: "8G FC SFP+ SW; IBM DS8000/SVC/V7000 FC target port; OM3/OM4 MMF up to 150m", + }, + { + pid: "45W2409", + formFactor: "SFP+", + speedGbps: 8.5, + speed: "8G FC", + reachMeters: 10000, + reachLabel: "LW", + fiberType: "SMF", + connector: "LC", + wavelengths: "1310nm", + standard: "8GFC", + notes: "8G FC SFP+ LW; IBM DS8000/SVC/V7000 FC target port long-reach; OS2 SMF up to 10km", + }, + // ── 16G FC SFP+ ────────────────────────────────────────────────────────── + { + pid: "00RY192", + formFactor: "SFP+", + speedGbps: 14.025, + speed: "16G FC", + reachMeters: 125, + reachLabel: "SW", + fiberType: "MMF", + connector: "LC", + wavelengths: "850nm", + standard: "16GFC", + notes: "16G FC SFP+ SW; IBM FlashSystem 7200/9100 FC port; OM4 MMF up to 125m", + }, + { + pid: "00RY193", + formFactor: "SFP+", + speedGbps: 14.025, + speed: "16G FC", + reachMeters: 10000, + reachLabel: "LW", + fiberType: "SMF", + connector: "LC", + wavelengths: "1310nm", + standard: "16GFC", + notes: "16G FC SFP+ LW; IBM FlashSystem 7200/9100 FC port long-reach; OS2 SMF up to 10km", + }, + // ── 32G FC SFP28 ───────────────────────────────────────────────────────── + { + pid: "02JG521", + formFactor: "SFP28", + speedGbps: 28.05, + speed: "32G FC", + reachMeters: 100, + reachLabel: "SW", + fiberType: "MMF", + connector: "LC", + wavelengths: "850nm", + standard: "32GFC", + notes: "32G FC SFP28 SW; IBM FlashSystem 9200/9200R NVMe/FC port; OM4/OM5 MMF", + }, + // ── 10GbE SFP+ ─────────────────────────────────────────────────────────── + { + pid: "00MN503", + formFactor: "SFP+", + speedGbps: 10, + speed: "10G", + reachMeters: 300, + reachLabel: "SR", + fiberType: "MMF", + connector: "LC", + wavelengths: "850nm", + standard: "10GBASE-SR", + notes: "10GbE SFP+ SR; IBM Storwize/FlashSystem iSCSI and FCoE host port; OM3/OM4 MMF", + }, + { + pid: "00MN505", + formFactor: "SFP+", + speedGbps: 10, + speed: "10G", + reachMeters: 10000, + reachLabel: "LR", + fiberType: "SMF", + connector: "LC", + wavelengths: "1310nm", + standard: "10GBASE-LR", + notes: "10GbE SFP+ LR; IBM Storwize/FlashSystem iSCSI and FCoE host port long-reach; OS2 SMF", + }, + // ── 25GbE SFP28 ────────────────────────────────────────────────────────── + { + pid: "00E6419", + formFactor: "SFP28", + speedGbps: 25, + speed: "25G", + reachMeters: 100, + reachLabel: "SR", + fiberType: "MMF", + connector: "LC", + wavelengths: "850nm", + standard: "25GBASE-SR", + notes: "25GbE SFP28 SR; IBM FlashSystem 5035/5045 NVMe-oF host port; OM4 MMF", + }, + { + pid: "00E6420", + formFactor: "SFP28", + speedGbps: 25, + speed: "25G", + reachMeters: 10000, + reachLabel: "LR", + fiberType: "SMF", + connector: "LC", + wavelengths: "1310nm", + standard: "25GBASE-LR", + notes: "25GbE SFP28 LR; IBM FlashSystem 5035/5045 NVMe-oF host port long-reach; OS2 SMF", + }, + // ── 100GbE QSFP28 ──────────────────────────────────────────────────────── + { + pid: "02JG528", + formFactor: "QSFP28", + speedGbps: 100, + speed: "100G", + reachMeters: 100, + reachLabel: "SR4", + fiberType: "MMF", + connector: "MPO", + wavelengths: "850nm", + standard: "100GBASE-SR4", + notes: "100GbE QSFP28 SR4; IBM FlashSystem 9200R/9500R inter-node link; OM4 MPO-12", + }, + { + pid: "02JG529", + formFactor: "QSFP28", + speedGbps: 100, + speed: "100G", + reachMeters: 10000, + reachLabel: "LR4", + fiberType: "SMF", + connector: "LC", + wavelengths: "1295-1310nm", + standard: "100GBASE-LR4", + notes: "100GbE QSFP28 LR4; IBM FlashSystem 9200R/9500R inter-node long-reach link; OS2 SMF", + }, + // ── 1GbE SFP ───────────────────────────────────────────────────────────── + { + pid: "IBM-SFP-1G-SX", + formFactor: "SFP", + speedGbps: 1, + speed: "1G", + reachMeters: 550, + reachLabel: "SX", + fiberType: "MMF", + connector: "LC", + wavelengths: "850nm", + standard: "1000BASE-SX", + notes: "1GbE SFP SX; IBM storage management and iSCSI port; OM2/OM3 MMF", + }, + { + pid: "IBM-SFP-1G-LX", + formFactor: "SFP", + speedGbps: 1, + speed: "1G", + reachMeters: 10000, + reachLabel: "LX", + fiberType: "SMF", + connector: "LC", + wavelengths: "1310nm", + standard: "1000BASE-LX", + notes: "1GbE SFP LX; IBM storage management and iSCSI port long-reach; OS2 SMF", + }, + // ── Copper SFP ─────────────────────────────────────────────────────────── + { + pid: "IBM-SFP-1G-T", + formFactor: "SFP", + speedGbps: 1, + speed: "1G", + reachMeters: 100, + reachLabel: "T", + fiberType: "DAC", + connector: "RJ45", + standard: "1000BASE-T", + notes: "1GbE copper SFP RJ45; IBM storage management copper option; Cat5e/6", + }, + // ── 40GbE QSFP+ ────────────────────────────────────────────────────────── + { + pid: "IBM-QSFP-40G-SR4", + formFactor: "QSFP+", + speedGbps: 40, + speed: "40G", + reachMeters: 150, + reachLabel: "SR4", + fiberType: "MMF", + connector: "MPO", + wavelengths: "850nm", + standard: "40GBASE-SR4", + notes: "40GbE QSFP+ SR4; IBM storage fabric switch uplink; OM3/OM4 MPO-12", + }, + { + pid: "IBM-QSFP-40G-LR4", + formFactor: "QSFP+", + speedGbps: 40, + speed: "40G", + reachMeters: 10000, + reachLabel: "LR4", + fiberType: "SMF", + connector: "LC", + wavelengths: "1310nm", + standard: "40GBASE-LR4", + notes: "40GbE QSFP+ LR4; IBM storage fabric switch uplink long-reach; OS2 SMF", + }, + // ── 400GbE QSFP-DD ─────────────────────────────────────────────────────── + { + pid: "IBM-QSFP-DD-400G-DR4", + formFactor: "QSFP-DD", + speedGbps: 400, + speed: "400G", + reachMeters: 500, + reachLabel: "DR4", + fiberType: "SMF", + connector: "MPO", + wavelengths: "1310nm", + standard: "400GBASE-DR4", + notes: "400GbE QSFP-DD DR4; IBM FlashSystem next-gen NVMe-oF fabric; OS2 SMF up to 500m", + }, + // ── 10GBASE-T SFP+ ─────────────────────────────────────────────────────── + { + pid: "IBM-SFP-10G-T", + formFactor: "SFP+", + speedGbps: 10, + speed: "10G", + reachMeters: 30, + reachLabel: "T", + fiberType: "DAC", + connector: "RJ45", + standard: "10GBASE-T", + notes: "10GbE copper SFP+ RJ45; IBM iSCSI storage host copper option; Cat6a up to 30m", + }, + // ── 4G FC SFP (legacy) ─────────────────────────────────────────────────── + { + pid: "IBM-SFP-FC-4G-SW", + formFactor: "SFP", + speedGbps: 4.25, + speed: "4G FC", + reachMeters: 150, + reachLabel: "SW", + fiberType: "MMF", + connector: "LC", + wavelengths: "850nm", + standard: "4GFC", + notes: "4G FC SFP SW legacy; IBM DS4000/DS8000 legacy FC port; OM2/OM3 MMF", + }, + // ── 64G FC SFP28 ───────────────────────────────────────────────────────── + { + pid: "IBM-SFP28-64G-FC-SW", + formFactor: "SFP28", + speedGbps: 56.1, + speed: "64G FC", + reachMeters: 70, + reachLabel: "SW", + fiberType: "MMF", + connector: "LC", + wavelengths: "850nm", + standard: "64GFC", + notes: "64G FC SFP28 SW; IBM FlashSystem 9500 next-gen NVMe/FC; OM5 WBMMF up to 70m", + }, +]; + +export async function scrapeIbmStorageOem(): Promise { + console.log("=== IBM Storage OEM Transceiver Seed ===\n"); + + const vendorId = await ensureVendor( + "IBM Storage", + "oem", + "https://www.ibm.com/storage", + undefined + ); + + let inserted = 0; + let updated = 0; + let errors = 0; + + for (const p of IBM_STORAGE_PIDS) { + const slug = `ibm-storage-${p.pid.toLowerCase().replace(/[^a-z0-9]+/g, "-")}`; + try { + const res = await pool.query( + `INSERT INTO transceivers + (slug, part_number, vendor_id, form_factor, speed, speed_gbps, + reach_meters, reach_label, fiber_type, connector, wavelengths, + dom_support, ieee_reference, market_status, category, notes) + VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,true,$12,'Mainstream','DataCenter',$13) + ON CONFLICT (slug) DO UPDATE SET + speed_gbps = EXCLUDED.speed_gbps, + reach_meters = CASE WHEN EXCLUDED.reach_meters > 0 THEN EXCLUDED.reach_meters ELSE transceivers.reach_meters END, + fiber_type = CASE WHEN EXCLUDED.fiber_type <> '' THEN EXCLUDED.fiber_type ELSE transceivers.fiber_type END, + wavelengths = COALESCE(EXCLUDED.wavelengths, transceivers.wavelengths), + updated_at = NOW() + RETURNING (xmax = 0) as was_inserted`, + [slug, p.pid, vendorId, p.formFactor, p.speed, p.speedGbps, + p.reachMeters, p.reachLabel, p.fiberType, p.connector, + p.wavelengths ?? null, p.standard ?? null, p.notes ?? null] + ); + if (res.rows[0]?.was_inserted) inserted++; else updated++; + } catch (err) { + console.warn(` Skip ${p.pid}: ${(err as Error).message.slice(0, 80)}`); + errors++; + } + } + + console.log(`\n=== IBM Storage OEM Seed Complete ===`); + console.log(` Inserted: ${inserted}`); + console.log(` Updated: ${updated}`); + console.log(` Errors: ${errors}`); + console.log(` Total PIDs: ${IBM_STORAGE_PIDS.length}\n`); +} + +if (require.main === module) { + scrapeIbmStorageOem() + .then(() => pool.end()) + .catch((err) => { + console.error("Fatal:", err); + pool.end(); + process.exit(1); + }); +} diff --git a/packages/scraper/src/scrapers/ii-vi-oem.ts b/packages/scraper/src/scrapers/ii-vi-oem.ts new file mode 100644 index 0000000..e6b8681 --- /dev/null +++ b/packages/scraper/src/scrapers/ii-vi-oem.ts @@ -0,0 +1,141 @@ +/** + * II-VI / Coherent OEM Transceiver Catalog Seed + * + * Seeds II-VI Incorporated (now Coherent Corp) branded transceiver PIDs. + * II-VI is one of the world's largest vertically integrated optical + * transceiver manufacturers, supplying hyperscalers, telcos, and OEMs. + * Acquired Finisar in 2019 and rebranded to Coherent Corp in 2022. + * + * Sources: + * - Coherent Corp Product Portfolio (coherent.com/networking) + * - II-VI Optical Transceiver Datasheet Archive + * - OIF 400ZR Implementation Agreement + * - IEEE 802.3 Standards (SR4, LR4, ER4, DR4, FR4, LR8) + * + * Run: tsx packages/scraper/src/scrapers/ii-vi-oem.ts + * Cron: daily at 20:30 + */ + +import { pool, ensureVendor } from "../utils/db"; + +interface IiViPID { + pid: string; + formFactor: string; + speedGbps: number; + speed: string; + reachMeters: number; + reachLabel: string; + fiberType: string; + connector: string; + wavelengths?: string; + standard?: string; + category?: string; + notes?: string; +} + +// PIDs that belong to the Telecom category (coherent, DWDM, ZR) +const TELECOM_PIDS = new Set([ + "IIVI-SFP10G-ZR", + "IIVI-DWDM-SFP10G-TUNE", + "IIVI-CFP2-DCO-100G", + "IIVI-QSFPDD-400G-ZR", + "IIVI-OSFP-800G-ZR", +]); + +const IIVI_PIDS: IiViPID[] = [ + // ── 10G SFP+ ──────────────────────────────────────────────────────────── + { pid: "IIVI-SFP10G-SR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 300, reachLabel: "SR", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "10GBASE-SR", notes: "II-VI/Coherent 10G SFP+ SR 300m MMF" }, + { pid: "IIVI-SFP10G-LR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 10000, reachLabel: "LR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "10GBASE-LR", notes: "II-VI/Coherent 10G SFP+ LR 10km SMF" }, + { pid: "IIVI-SFP10G-ER", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 40000, reachLabel: "ER", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "10GBASE-ER", notes: "II-VI/Coherent 10G SFP+ ER 40km SMF" }, + { pid: "IIVI-SFP10G-ZR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 80000, reachLabel: "ZR", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "10GBASE-ZR", notes: "II-VI/Coherent 10G SFP+ ZR 80km SMF" }, + + // ── 10G DWDM SFP+ C-band tunable (Telecom) ────────────────────────────── + { pid: "IIVI-DWDM-SFP10G-TUNE", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 80000, reachLabel: "DWDM", fiberType: "SMF", connector: "LC", wavelengths: "C-band tunable", category: "Telecom", notes: "II-VI/Coherent 10G DWDM SFP+ C-band tunable for metro DWDM" }, + + // ── 25G SFP28 ─────────────────────────────────────────────────────────── + { pid: "IIVI-SFP28-25G-SR", formFactor: "SFP28", speedGbps: 25, speed: "25G", reachMeters: 300, reachLabel: "SR", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "25GBASE-SR", notes: "II-VI/Coherent 25G SFP28 SR 300m MMF" }, + { pid: "IIVI-SFP28-25G-LR", formFactor: "SFP28", speedGbps: 25, speed: "25G", reachMeters: 10000, reachLabel: "LR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "25GBASE-LR", notes: "II-VI/Coherent 25G SFP28 LR 10km SMF" }, + { pid: "IIVI-SFP28-25G-ER", formFactor: "SFP28", speedGbps: 25, speed: "25G", reachMeters: 30000, reachLabel: "ER", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "25GBASE-ER", notes: "II-VI/Coherent 25G SFP28 ER 30km SMF" }, + + // ── 40G QSFP+ ─────────────────────────────────────────────────────────── + { pid: "IIVI-QSFP-40G-SR4", formFactor: "QSFP+", speedGbps: 40, speed: "40G", reachMeters: 150, reachLabel: "SR4", fiberType: "MMF", connector: "MPO", wavelengths: "850nm", standard: "40GBASE-SR4", notes: "II-VI/Coherent 40G QSFP+ SR4 150m MMF" }, + { pid: "IIVI-QSFP-40G-LR4", formFactor: "QSFP+", speedGbps: 40, speed: "40G", reachMeters: 10000, reachLabel: "LR4", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "40GBASE-LR4", notes: "II-VI/Coherent 40G QSFP+ LR4 10km SMF" }, + + // ── 100G QSFP28 ───────────────────────────────────────────────────────── + { pid: "IIVI-QSFP28-100G-SR4", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 100, reachLabel: "SR4", fiberType: "MMF", connector: "MPO", wavelengths: "850nm", standard: "100GBASE-SR4", notes: "II-VI/Coherent 100G QSFP28 SR4 100m MMF" }, + { pid: "IIVI-QSFP28-100G-LR4", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 10000, reachLabel: "LR4", fiberType: "SMF", connector: "LC", wavelengths: "1295-1310nm", standard: "100GBASE-LR4", notes: "II-VI/Coherent 100G QSFP28 LR4 10km SMF" }, + { pid: "IIVI-QSFP28-100G-ER4", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 40000, reachLabel: "ER4", fiberType: "SMF", connector: "LC", wavelengths: "1295-1310nm", standard: "100GBASE-ER4", notes: "II-VI/Coherent 100G QSFP28 ER4 40km SMF" }, + + // ── 100G CFP2-DCO Coherent (Telecom) ──────────────────────────────────── + { pid: "IIVI-CFP2-DCO-100G", formFactor: "CFP2", speedGbps: 100, speed: "100G", reachMeters: 1000000, reachLabel: "DCO", fiberType: "SMF", connector: "LC", wavelengths: "C-band DWDM", category: "Telecom", notes: "II-VI/Coherent 100G CFP2-DCO coherent, up to 1000km" }, + + // ── 400G QSFP-DD ──────────────────────────────────────────────────────── + { pid: "IIVI-QSFPDD-400G-DR4", formFactor: "QSFP-DD", speedGbps: 400, speed: "400G", reachMeters: 500, reachLabel: "DR4", fiberType: "SMF", connector: "MPO", wavelengths: "1310nm", standard: "400GBASE-DR4", notes: "II-VI/Coherent 400G QSFP-DD DR4 500m SMF" }, + { pid: "IIVI-QSFPDD-400G-FR4", formFactor: "QSFP-DD", speedGbps: 400, speed: "400G", reachMeters: 2000, reachLabel: "FR4", fiberType: "SMF", connector: "LC", wavelengths: "1271-1331nm", standard: "400GBASE-FR4", notes: "II-VI/Coherent 400G QSFP-DD FR4 2km SMF" }, + { pid: "IIVI-QSFPDD-400G-LR8", formFactor: "QSFP-DD", speedGbps: 400, speed: "400G", reachMeters: 10000, reachLabel: "LR8", fiberType: "SMF", connector: "LC", wavelengths: "1295-1310nm", standard: "400GBASE-LR8", notes: "II-VI/Coherent 400G QSFP-DD LR8 10km SMF 8-lambda" }, + + // ── 400G ZR QSFP-DD Coherent (Telecom) ────────────────────────────────── + { pid: "IIVI-QSFPDD-400G-ZR", formFactor: "QSFP-DD", speedGbps: 400, speed: "400G", reachMeters: 1000000, reachLabel: "ZR", fiberType: "SMF", connector: "LC", wavelengths: "C-band DWDM", standard: "400ZR", category: "Telecom", notes: "II-VI/Coherent 400G ZR QSFP-DD coherent, up to 1000km" }, + + // ── 800G OSFP Coherent (Telecom) ──────────────────────────────────────── + { pid: "IIVI-OSFP-800G-ZR", formFactor: "OSFP", speedGbps: 800, speed: "800G", reachMeters: 1000000, reachLabel: "ZR", fiberType: "SMF", connector: "LC", wavelengths: "C-band DWDM", category: "Telecom", notes: "II-VI/Coherent 800G OSFP coherent ZR, up to 1000km" }, +]; + +export async function scrapeIiViOem(): Promise { + console.log("=== II-VI / Coherent OEM Transceiver Seed ===\n"); + + const vendorId = await ensureVendor( + "II-VI / Coherent", + "oem", + "https://www.coherent.com", + undefined + ); + + let inserted = 0; + let updated = 0; + let errors = 0; + + for (const p of IIVI_PIDS) { + const slug = `ii-vi-${p.pid.toLowerCase().replace(/[^a-z0-9]+/g, "-")}`; + const category = p.category ?? (TELECOM_PIDS.has(p.pid) ? "Telecom" : "DataCenter"); + try { + const res = await pool.query( + `INSERT INTO transceivers + (slug, part_number, vendor_id, form_factor, speed, speed_gbps, + reach_meters, reach_label, fiber_type, connector, wavelengths, + dom_support, ieee_reference, market_status, category, notes) + VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,true,$12,'Mainstream',$13,$14) + ON CONFLICT (slug) DO UPDATE SET + speed_gbps = EXCLUDED.speed_gbps, + reach_meters = CASE WHEN EXCLUDED.reach_meters > 0 THEN EXCLUDED.reach_meters ELSE transceivers.reach_meters END, + fiber_type = CASE WHEN EXCLUDED.fiber_type <> '' THEN EXCLUDED.fiber_type ELSE transceivers.fiber_type END, + wavelengths = COALESCE(EXCLUDED.wavelengths, transceivers.wavelengths), + updated_at = NOW() + RETURNING (xmax = 0) as was_inserted`, + [slug, p.pid, vendorId, p.formFactor, p.speed, p.speedGbps, + p.reachMeters, p.reachLabel, p.fiberType, p.connector, + p.wavelengths ?? null, p.standard ?? null, category, p.notes ?? null] + ); + if (res.rows[0]?.was_inserted) inserted++; else updated++; + } catch (err) { + console.warn(` Skip ${p.pid}: ${(err as Error).message.slice(0, 80)}`); + errors++; + } + } + + console.log(`\n=== II-VI / Coherent OEM Seed Complete ===`); + console.log(` Inserted: ${inserted}`); + console.log(` Updated: ${updated}`); + console.log(` Errors: ${errors}`); + console.log(` Total PIDs: ${IIVI_PIDS.length}\n`); +} + +if (require.main === module) { + scrapeIiViOem() + .then(() => pool.end()) + .catch((err) => { + console.error("Fatal:", err); + pool.end(); + process.exit(1); + }); +} diff --git a/packages/scraper/src/scrapers/infinera-groove-oem.ts b/packages/scraper/src/scrapers/infinera-groove-oem.ts new file mode 100644 index 0000000..dc2ccf0 --- /dev/null +++ b/packages/scraper/src/scrapers/infinera-groove-oem.ts @@ -0,0 +1,135 @@ +/** + * Infinera Groove/ICE OEM Transceiver Catalog Seed + * + * Seeds Infinera INF-prefixed transceiver PIDs for the Groove G30/G42 + * disaggregated open line system and ICE4/ICE6 coherent engine platforms. + * Covers standard grey optics, OpenZR+, ZR, OTN/OTU, muxponder modules, + * and CFP2-DCO coherent transceivers used across the Infinera portfolio. + * + * Sources: + * - Infinera Groove G30/G42 Hardware Compatibility Guide (infinera.com) + * - Infinera ICE4/ICE6 Coherent Engine Module Reference + * - OIF 400ZR Implementation Agreement + * - ITU-T G.709 OTN specification + * + * Run: tsx packages/scraper/src/scrapers/infinera-groove-oem.ts + * Cron: daily at 23:00 + */ + +import { pool, ensureVendor } from "../utils/db"; + +interface InfineraGroovePID { + pid: string; + formFactor: string; + speedGbps: number; + speed: string; + reachMeters: number; + reachLabel: string; + fiberType: string; + connector: string; + wavelengths?: string; + standard?: string; + notes?: string; + isTelecom?: boolean; +} + +const INFINERA_GROOVE_PIDS: InfineraGroovePID[] = [ + // ── 1G SFP (management / client) ───────────────────────────────────────── + { pid: "INF-SFP-GE-SX", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 550, reachLabel: "SX", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "1000BASE-SX" }, + + // ── 10G SFP+ client optics ──────────────────────────────────────────────── + { pid: "INF-SFP-10G-SR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 300, reachLabel: "SR", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "10GBASE-SR" }, + { pid: "INF-SFP-10G-LR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 10000, reachLabel: "LR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "10GBASE-LR" }, + { pid: "INF-SFP-10G-ER", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 40000, reachLabel: "ER", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "10GBASE-ER" }, + { pid: "INF-SFP-10G-ZR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 80000, reachLabel: "ZR", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "10GBASE-ZR", notes: "10G ZR 80km grey optic for Groove G30 client side" }, + + // ── OTN / OTU client optics (Telecom) ──────────────────────────────────── + { pid: "INF-OTU2-SFP-10G", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 10000, reachLabel: "OTU2", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "ITU-T G.709", notes: "OTU2 10G client SFP+ for Groove G30 OTN muxponder", isTelecom: true }, + { pid: "INF-OTU2E-SFP-10G", formFactor: "SFP+", speedGbps: 11, speed: "11G", reachMeters: 10000, reachLabel: "OTU2e", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "ITU-T G.709", notes: "OTU2e 11.09Gbps client SFP+ for 10GbE over OTN mapping", isTelecom: true }, + + // ── 40G QSFP+ ──────────────────────────────────────────────────────────── + { pid: "INF-QSFP-40G-LR4", formFactor: "QSFP+", speedGbps: 40, speed: "40G", reachMeters: 10000, reachLabel: "LR4", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "40GBASE-LR4" }, + + // ── 100G QSFP28 client optics ───────────────────────────────────────────── + { pid: "INF-QSFP28-100G-SR4", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 100, reachLabel: "SR4", fiberType: "MMF", connector: "MPO", wavelengths: "850nm", standard: "100GBASE-SR4" }, + { pid: "INF-QSFP28-100G-LR4", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 10000, reachLabel: "LR4", fiberType: "SMF", connector: "LC", wavelengths: "1295-1310nm", standard: "100GBASE-LR4" }, + { pid: "INF-QSFP28-100G-ER4", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 40000, reachLabel: "ER4", fiberType: "SMF", connector: "LC", wavelengths: "1295-1310nm", notes: "100G ER4 40km QSFP28 for Groove G42 inter-site client" }, + + // ── GRV2 QSFP28 (Groove G30 integrated coherent) ───────────────────────── + { pid: "INF-GRV2-QSFP28", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 2000000, reachLabel: "GRV2-Coh", fiberType: "SMF", connector: "LC", wavelengths: "C-band", notes: "Groove G30 Gen2 integrated coherent QSFP28 DSP module, up to 2000km", isTelecom: true }, + + // ── CFP2-DCO coherent (Groove G42 line side) ───────────────────────────── + { pid: "INF-CFP2-DCO-100G", formFactor: "CFP2", speedGbps: 100, speed: "100G", reachMeters: 2000000, reachLabel: "DCO-100G", fiberType: "SMF", connector: "LC", wavelengths: "C-band", notes: "CFP2-DCO 100G coherent for Groove G42 open line system, up to 2000km", isTelecom: true }, + { pid: "INF-CFP2-DCO-200G", formFactor: "CFP2", speedGbps: 200, speed: "200G", reachMeters: 1500000, reachLabel: "DCO-200G", fiberType: "SMF", connector: "LC", wavelengths: "C-band", notes: "CFP2-DCO 200G coherent for Groove G42, up to 1500km dual-polarization QPSK", isTelecom: true }, + + // ── OTU4 line optics (Telecom) ──────────────────────────────────────────── + { pid: "INF-CFP-OTU4-100G", formFactor: "CFP", speedGbps: 100, speed: "100G", reachMeters: 2000000, reachLabel: "OTU4", fiberType: "SMF", connector: "LC", wavelengths: "C-band", standard: "ITU-T G.709", notes: "CFP OTU4 100G coherent line module for legacy Infinera DTN-X platform", isTelecom: true }, + + // ── 400G QSFP-DD (ICE4 / Groove G42) ───────────────────────────────────── + { pid: "INF-QSFP-DD-400G-ZR", formFactor: "QSFP-DD", speedGbps: 400, speed: "400G", reachMeters: 120000, reachLabel: "ZR", fiberType: "SMF", connector: "LC", wavelengths: "C-band", standard: "400ZR", notes: "400G OpenZR coherent QSFP-DD for ICE4 engine, up to 120km DWDM", isTelecom: true }, + { pid: "INF-QSFP-DD-400G-ZRP", formFactor: "QSFP-DD", speedGbps: 400, speed: "400G", reachMeters: 2000000, reachLabel: "ZR+", fiberType: "SMF", connector: "LC", wavelengths: "C-band", notes: "400G ZR+ OpenROADM coherent QSFP-DD for ICE4, up to 2000km long-haul", isTelecom: true }, + { pid: "INF-ICE4-QSFP-DD-400G", formFactor: "QSFP-DD", speedGbps: 400, speed: "400G", reachMeters: 4000000, reachLabel: "ICE4-Coh", fiberType: "SMF", connector: "LC", wavelengths: "C-band", notes: "Infinera ICE4 coherent engine QSFP-DD 400G, up to 4000km transoceanic, FlexE", isTelecom: true }, + + // ── Muxponder module (Telecom) ──────────────────────────────────────────── + { pid: "INF-MXPONDER-10x10G", formFactor: "CFP2", speedGbps: 100, speed: "100G", reachMeters: 2000000, reachLabel: "MXP-10x10G",fiberType: "SMF", connector: "LC", wavelengths: "C-band", notes: "Groove G30 10x10G muxponder module; aggregates 10x10G client into 100G coherent line", isTelecom: true }, +]; + +export async function scrapeInfineraGrooveOem(): Promise { + console.log("=== Infinera Groove/ICE OEM Transceiver Seed ===\n"); + + const vendorId = await ensureVendor( + "Infinera", + "oem", + "https://www.infinera.com", + undefined + ); + + let inserted = 0; + let updated = 0; + let errors = 0; + + for (const p of INFINERA_GROOVE_PIDS) { + const slug = `infinera-${p.pid.toLowerCase().replace(/[^a-z0-9]+/g, "-")}`; + const category = p.isTelecom ? "Telecom" : "DataCenter"; + try { + const res = await pool.query( + `INSERT INTO transceivers + (slug, part_number, vendor_id, form_factor, speed, speed_gbps, + reach_meters, reach_label, fiber_type, connector, wavelengths, + dom_support, ieee_reference, market_status, category, notes) + VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,true,$12,'Mainstream',$13,$14) + ON CONFLICT (slug) DO UPDATE SET + speed_gbps = EXCLUDED.speed_gbps, + reach_meters = CASE WHEN EXCLUDED.reach_meters > 0 THEN EXCLUDED.reach_meters ELSE transceivers.reach_meters END, + fiber_type = CASE WHEN EXCLUDED.fiber_type <> '' THEN EXCLUDED.fiber_type ELSE transceivers.fiber_type END, + wavelengths = COALESCE(EXCLUDED.wavelengths, transceivers.wavelengths), + is_oem_seed = true, + updated_at = NOW() + RETURNING (xmax = 0) as was_inserted`, + [slug, p.pid, vendorId, p.formFactor, p.speed, p.speedGbps, + p.reachMeters, p.reachLabel, p.fiberType, p.connector, + p.wavelengths ?? null, p.standard ?? null, category, p.notes ?? null] + ); + if (res.rows[0]?.was_inserted) inserted++; else updated++; + } catch (err) { + console.warn(` Skip ${p.pid}: ${(err as Error).message.slice(0, 80)}`); + errors++; + } + } + + console.log(`\n=== Infinera Groove/ICE OEM Seed Complete ===`); + console.log(` Inserted: ${inserted}`); + console.log(` Updated: ${updated}`); + console.log(` Errors: ${errors}`); + console.log(` Total PIDs: ${INFINERA_GROOVE_PIDS.length}\n`); +} + +if (require.main === module) { + scrapeInfineraGrooveOem() + .then(() => pool.end()) + .catch((err) => { + console.error("Fatal:", err); + pool.end(); + process.exit(1); + }); +} diff --git a/packages/scraper/src/scrapers/infinera-oem.ts b/packages/scraper/src/scrapers/infinera-oem.ts new file mode 100644 index 0000000..d19f4b0 --- /dev/null +++ b/packages/scraper/src/scrapers/infinera-oem.ts @@ -0,0 +1,130 @@ +/** + * Infinera OEM Transceiver Catalog Seed + * + * Seeds Infinera-branded transceiver PIDs for GX Series, XTM-Series, + * and Cloud Xpress platforms. + * + * Sources: Infinera Transceiver Compatibility Guide (infinera.com) + * + * Run: tsx packages/scraper/src/scrapers/infinera-oem.ts + * Cron: daily at 10:30 + */ + +import { pool, ensureVendor } from "../utils/db"; + +interface InfineraPID { + pid: string; + formFactor: string; + speedGbps: number; + speed: string; + reachMeters: number; + reachLabel: string; + fiberType: string; + connector: string; + wavelengths?: string; + standard?: string; + notes?: string; +} + +const INFINERA_PIDS: InfineraPID[] = [ + // ── 1G SFP ────────────────────────────────────────────────────────────── + { pid: "XCVR-1GIG-MM-SX", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 550, reachLabel: "SX", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "1000BASE-SX" }, + { pid: "XCVR-1GIG-SM-LX", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 10000, reachLabel: "LX", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "1000BASE-LX" }, + { pid: "XCVR-1GIG-SM-ZX", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 80000, reachLabel: "ZX", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "1000BASE-ZX" }, + { pid: "XCVR-1GIG-RJ45", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 100, reachLabel: "T", fiberType: "DAC", connector: "RJ45", standard: "1000BASE-T" }, + + // ── 10G SFP+ ──────────────────────────────────────────────────────────── + { pid: "XCVR-10G-SR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 300, reachLabel: "SR", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "10GBASE-SR" }, + { pid: "XCVR-10G-LR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 10000, reachLabel: "LR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "10GBASE-LR" }, + { pid: "XCVR-10G-ER", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 40000, reachLabel: "ER", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "10GBASE-ER" }, + { pid: "XCVR-10G-ZR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 80000, reachLabel: "ZR", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "10GBASE-ZR" }, + { pid: "XCVR-10G-LRM", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 220, reachLabel: "LRM", fiberType: "MMF", connector: "LC", wavelengths: "1310nm", standard: "10GBASE-LRM" }, + { pid: "XCVR-10G-DWDM-T", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 80000, reachLabel: "DWDM", fiberType: "SMF", connector: "LC", wavelengths: "C-band", notes: "10G DWDM tunable" }, + + // ── 25G SFP28 ─────────────────────────────────────────────────────────── + { pid: "XCVR-25G-SR", formFactor: "SFP28", speedGbps: 25, speed: "25G", reachMeters: 100, reachLabel: "SR", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "25GBASE-SR" }, + { pid: "XCVR-25G-LR", formFactor: "SFP28", speedGbps: 25, speed: "25G", reachMeters: 10000, reachLabel: "LR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "25GBASE-LR" }, + { pid: "XCVR-25G-ER", formFactor: "SFP28", speedGbps: 25, speed: "25G", reachMeters: 30000, reachLabel: "ER", fiberType: "SMF", connector: "LC", wavelengths: "1310nm" }, + + // ── 100G QSFP28 ───────────────────────────────────────────────────────── + { pid: "XCVR-100G-SR4", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 100, reachLabel: "SR4", fiberType: "MMF", connector: "MPO", wavelengths: "850nm", standard: "100GBASE-SR4" }, + { pid: "XCVR-100G-LR4", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 10000, reachLabel: "LR4", fiberType: "SMF", connector: "LC", wavelengths: "1295-1310nm", standard: "100GBASE-LR4" }, + { pid: "XCVR-100G-CWDM4", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 2000, reachLabel: "CWDM4", fiberType: "SMF", connector: "LC", wavelengths: "1271-1331nm", standard: "100GBASE-CWDM4" }, + { pid: "XCVR-100G-DR", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 500, reachLabel: "DR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "100GBASE-DR" }, + { pid: "XCVR-100G-FR", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 2000, reachLabel: "FR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "100GBASE-FR" }, + + // ── 400G QSFP-DD coherent (GX Series) ─────────────────────────────────── + { pid: "XCVR-400G-ZR", formFactor: "QSFP-DD", speedGbps: 400, speed: "400G", reachMeters: 120000, reachLabel: "ZR", fiberType: "SMF", connector: "LC", wavelengths: "C-band", standard: "400ZR", notes: "400G coherent QSFP-DD" }, + { pid: "XCVR-400G-ZR-PLUS",formFactor: "QSFP-DD", speedGbps: 400, speed: "400G", reachMeters: 1000000,reachLabel: "ZR+", fiberType: "SMF", connector: "LC", wavelengths: "C-band", notes: "400G ZR+ OpenROADM coherent" }, + { pid: "XCVR-400G-DR4", formFactor: "QSFP-DD", speedGbps: 400, speed: "400G", reachMeters: 500, reachLabel: "DR4", fiberType: "SMF", connector: "MPO", wavelengths: "1310nm", standard: "400GBASE-DR4" }, + { pid: "XCVR-400G-FR4", formFactor: "QSFP-DD", speedGbps: 400, speed: "400G", reachMeters: 2000, reachLabel: "FR4", fiberType: "SMF", connector: "LC", wavelengths: "1271-1331nm", standard: "400GBASE-FR4" }, + { pid: "XCVR-400G-LR4", formFactor: "QSFP-DD", speedGbps: 400, speed: "400G", reachMeters: 10000, reachLabel: "LR4", fiberType: "SMF", connector: "LC", wavelengths: "1295-1310nm", standard: "400GBASE-LR4" }, + + // ── 800G OSFP (GX G42/G48) ────────────────────────────────────────────── + { pid: "XCVR-800G-ZR", formFactor: "OSFP", speedGbps: 800, speed: "800G", reachMeters: 120000, reachLabel: "ZR", fiberType: "SMF", connector: "LC", wavelengths: "C-band", notes: "800G coherent OSFP ZR" }, + { pid: "XCVR-800G-DR8", formFactor: "OSFP", speedGbps: 800, speed: "800G", reachMeters: 500, reachLabel: "DR8", fiberType: "SMF", connector: "MPO", wavelengths: "1310nm", notes: "800G DR8 OSFP" }, + { pid: "XCVR-800G-FR8", formFactor: "OSFP", speedGbps: 800, speed: "800G", reachMeters: 2000, reachLabel: "FR8", fiberType: "SMF", connector: "LC", wavelengths: "1271-1331nm", notes: "800G FR8 OSFP" }, + + // ── DAC ───────────────────────────────────────────────────────────────── + { pid: "DAC-10G-SFP-1M", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 1, reachLabel: "DAC-1M", fiberType: "DAC", connector: "SFP+" }, + { pid: "DAC-100G-QSFP28-1M", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 1, reachLabel: "DAC-1M", fiberType: "DAC", connector: "QSFP28" }, + { pid: "DAC-400G-QSFPDD-1M", formFactor: "QSFP-DD", speedGbps: 400, speed: "400G", reachMeters: 1, reachLabel: "DAC-1M", fiberType: "DAC", connector: "QSFP-DD" }, +]; + +export async function scrapeInfineraOem(): Promise { + console.log("=== Infinera OEM Transceiver Seed ===\n"); + + const vendorId = await ensureVendor( + "Infinera", + "oem", + "https://www.infinera.com", + undefined + ); + + let inserted = 0; + let updated = 0; + let errors = 0; + + for (const p of INFINERA_PIDS) { + const slug = `infinera-${p.pid.toLowerCase().replace(/[^a-z0-9]+/g, "-")}`; + try { + const res = await pool.query( + `INSERT INTO transceivers + (slug, part_number, vendor_id, form_factor, speed, speed_gbps, + reach_meters, reach_label, fiber_type, connector, wavelengths, + dom_support, ieee_reference, market_status, category, notes) + VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,true,$12,'Mainstream','DataCenter',$13) + ON CONFLICT (slug) DO UPDATE SET + speed_gbps = EXCLUDED.speed_gbps, + reach_meters = CASE WHEN EXCLUDED.reach_meters > 0 THEN EXCLUDED.reach_meters ELSE transceivers.reach_meters END, + fiber_type = CASE WHEN EXCLUDED.fiber_type <> '' THEN EXCLUDED.fiber_type ELSE transceivers.fiber_type END, + wavelengths = COALESCE(EXCLUDED.wavelengths, transceivers.wavelengths), + updated_at = NOW() + RETURNING (xmax = 0) as was_inserted`, + [slug, p.pid, vendorId, p.formFactor, p.speed, p.speedGbps, + p.reachMeters, p.reachLabel, p.fiberType, p.connector, + p.wavelengths ?? null, p.standard ?? null, p.notes ?? null] + ); + if (res.rows[0]?.was_inserted) inserted++; else updated++; + } catch (err) { + console.warn(` Skip ${p.pid}: ${(err as Error).message.slice(0, 80)}`); + errors++; + } + } + + console.log(`\n=== Infinera OEM Seed Complete ===`); + console.log(` Inserted: ${inserted}`); + console.log(` Updated: ${updated}`); + console.log(` Errors: ${errors}`); + console.log(` Total PIDs: ${INFINERA_PIDS.length}\n`); +} + +if (require.main === module) { + scrapeInfineraOem() + .then(() => pool.end()) + .catch((err) => { + console.error("Fatal:", err); + pool.end(); + process.exit(1); + }); +} diff --git a/packages/scraper/src/scrapers/innolight-oem.ts b/packages/scraper/src/scrapers/innolight-oem.ts new file mode 100644 index 0000000..75d4c23 --- /dev/null +++ b/packages/scraper/src/scrapers/innolight-oem.ts @@ -0,0 +1,137 @@ +/** + * InnoLight Technology OEM Transceiver Catalog Seed + * + * Seeds InnoLight-branded transceiver PIDs. InnoLight Technology Co., Ltd. + * (Shenzhen, China) is one of the world's largest optical transceiver + * manufacturers, supplying hyperscalers, cloud providers, and major OEMs. + * + * Sources: + * - InnoLight Product Overview (innolight.com) + * - InnoLight 400G/800G Transceiver Specification Sheets + * - InnoLight QSFP-DD and OSFP Product Family Guides + * + * Run: tsx packages/scraper/src/scrapers/innolight-oem.ts + * Cron: daily at 21:15 + */ + +import { pool, ensureVendor } from "../utils/db"; + +interface InnoLightPID { + pid: string; + formFactor: string; + speedGbps: number; + speed: string; + reachMeters: number; + reachLabel: string; + fiberType: string; + connector: string; + wavelengths?: string; + standard?: string; + category?: string; + notes?: string; +} + +const TELECOM_PIDS = new Set([ + "IL-SFP-10G-ZR", + "IL-DWDM-SFP10G-C", + "IL-QSFP28-100G-ZR4", + "IL-CFP2-DCO-100G", + "IL-QSFP-DD-400G-ZR", +]); + +const INNOLIGHT_PIDS: InnoLightPID[] = [ + // ── 10G SFP+ ──────────────────────────────────────────────────────────── + { pid: "IL-SFP-10G-SR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 300, reachLabel: "SR", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "10GBASE-SR", notes: "InnoLight 10G SFP+ SR 300m MMF" }, + { pid: "IL-SFP-10G-LR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 10000, reachLabel: "LR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "10GBASE-LR", notes: "InnoLight 10G SFP+ LR 10km SMF" }, + { pid: "IL-SFP-10G-ER", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 40000, reachLabel: "ER", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "10GBASE-ER", notes: "InnoLight 10G SFP+ ER 40km SMF" }, + { pid: "IL-SFP-10G-ZR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 80000, reachLabel: "ZR", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "10GBASE-ZR", notes: "InnoLight 10G SFP+ ZR 80km SMF" }, + + // ── 25G SFP28 ─────────────────────────────────────────────────────────── + { pid: "IL-SFP28-25G-SR", formFactor: "SFP28", speedGbps: 25, speed: "25G", reachMeters: 100, reachLabel: "SR", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "25GBASE-SR", notes: "InnoLight 25G SFP28 SR 100m MMF" }, + { pid: "IL-SFP28-25G-LR", formFactor: "SFP28", speedGbps: 25, speed: "25G", reachMeters: 10000, reachLabel: "LR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "25GBASE-LR", notes: "InnoLight 25G SFP28 LR 10km SMF" }, + + // ── 40G QSFP+ ─────────────────────────────────────────────────────────── + { pid: "IL-QSFP-40G-SR4", formFactor: "QSFP+", speedGbps: 40, speed: "40G", reachMeters: 150, reachLabel: "SR4", fiberType: "MMF", connector: "MPO", wavelengths: "850nm", standard: "40GBASE-SR4", notes: "InnoLight 40G QSFP+ SR4 150m MMF" }, + { pid: "IL-QSFP-40G-LR4", formFactor: "QSFP+", speedGbps: 40, speed: "40G", reachMeters: 10000, reachLabel: "LR4", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "40GBASE-LR4", notes: "InnoLight 40G QSFP+ LR4 10km SMF" }, + + // ── 100G QSFP28 ───────────────────────────────────────────────────────── + { pid: "IL-QSFP28-100G-SR4", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 100, reachLabel: "SR4", fiberType: "MMF", connector: "MPO", wavelengths: "850nm", standard: "100GBASE-SR4", notes: "InnoLight 100G QSFP28 SR4 100m MMF" }, + { pid: "IL-QSFP28-100G-LR4", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 10000, reachLabel: "LR4", fiberType: "SMF", connector: "LC", wavelengths: "1295-1310nm", standard: "100GBASE-LR4", notes: "InnoLight 100G QSFP28 LR4 10km SMF" }, + { pid: "IL-QSFP28-100G-ER4", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 40000, reachLabel: "ER4", fiberType: "SMF", connector: "LC", wavelengths: "1295-1310nm", standard: "100GBASE-ER4", notes: "InnoLight 100G QSFP28 ER4 40km SMF" }, + { pid: "IL-QSFP28-100G-ZR4", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 80000, reachLabel: "ZR4", fiberType: "SMF", connector: "LC", wavelengths: "C-band", standard: "100GBASE-ZR4", notes: "InnoLight 100G QSFP28 ZR4 80km, coherent" }, + + // ── 100G CFP2-DCO (Telecom coherent) ───────────────────────────────────── + { pid: "IL-CFP2-DCO-100G", formFactor: "CFP2", speedGbps: 100, speed: "100G", reachMeters: 1000000, reachLabel: "DCO", fiberType: "SMF", connector: "LC", wavelengths: "C-band tunable", standard: "OIF CFP2-DCO", notes: "InnoLight 100G CFP2 DCO coherent C-band, 1000km" }, + + // ── 400G QSFP-DD ──────────────────────────────────────────────────────── + { pid: "IL-QSFP-DD-400G-SR8", formFactor: "QSFP-DD", speedGbps: 400, speed: "400G", reachMeters: 100, reachLabel: "SR8", fiberType: "MMF", connector: "MPO", wavelengths: "850nm", standard: "400GBASE-SR8", notes: "InnoLight 400G QSFP-DD SR8 100m MMF" }, + { pid: "IL-QSFP-DD-400G-DR4", formFactor: "QSFP-DD", speedGbps: 400, speed: "400G", reachMeters: 500, reachLabel: "DR4", fiberType: "SMF", connector: "MPO", wavelengths: "1310nm", standard: "400GBASE-DR4", notes: "InnoLight 400G QSFP-DD DR4 500m SMF" }, + { pid: "IL-QSFP-DD-400G-FR4", formFactor: "QSFP-DD", speedGbps: 400, speed: "400G", reachMeters: 2000, reachLabel: "FR4", fiberType: "SMF", connector: "LC", wavelengths: "1271-1331nm", standard: "400GBASE-FR4", notes: "InnoLight 400G QSFP-DD FR4 2km SMF" }, + { pid: "IL-QSFP-DD-400G-LR4", formFactor: "QSFP-DD", speedGbps: 400, speed: "400G", reachMeters: 10000, reachLabel: "LR4", fiberType: "SMF", connector: "LC", wavelengths: "1271-1331nm", standard: "400GBASE-LR4", notes: "InnoLight 400G QSFP-DD LR4 10km SMF" }, + { pid: "IL-QSFP-DD-400G-ZR", formFactor: "QSFP-DD", speedGbps: 400, speed: "400G", reachMeters: 1000000, reachLabel: "ZR", fiberType: "SMF", connector: "LC", wavelengths: "C-band tunable", standard: "OIF 400ZR", notes: "InnoLight 400G QSFP-DD ZR coherent, 1000km, C-band" }, + + // ── DWDM (Telecom) ──────────────────────────────────────────────────────── + { pid: "IL-DWDM-SFP10G-C", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 80000, reachLabel: "DWDM", fiberType: "SMF", connector: "LC", wavelengths: "C-band tunable", standard: "ITU-T G.694.1", notes: "InnoLight 10G DWDM SFP+ C-band tunable 80km" }, + + // ── 800G OSFP ──────────────────────────────────────────────────────────── + { pid: "IL-OSFP-800G-SR8", formFactor: "OSFP", speedGbps: 800, speed: "800G", reachMeters: 100, reachLabel: "SR8", fiberType: "MMF", connector: "MPO", wavelengths: "850nm", standard: "800GBASE-SR8", notes: "InnoLight 800G OSFP SR8 100m MMF — hyperscaler spine" }, +]; + +export async function scrapeInnoLightOem(): Promise { + console.log("=== InnoLight Technology OEM Transceiver Seed ===\n"); + + const vendorId = await ensureVendor( + "InnoLight Technology", + "oem", + "https://www.innolight.com", + undefined + ); + + let inserted = 0; + let updated = 0; + let errors = 0; + + for (const p of INNOLIGHT_PIDS) { + const slug = `innolight-${p.pid.toLowerCase().replace(/[^a-z0-9]+/g, "-")}`; + const category = p.category ?? (TELECOM_PIDS.has(p.pid) ? "Telecom" : "DataCenter"); + try { + const res = await pool.query( + `INSERT INTO transceivers + (slug, part_number, vendor_id, form_factor, speed, speed_gbps, + reach_meters, reach_label, fiber_type, connector, wavelengths, + dom_support, ieee_reference, market_status, category, notes) + VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,true,$12,'Mainstream',$13,$14) + ON CONFLICT (slug) DO UPDATE SET + speed_gbps = EXCLUDED.speed_gbps, + reach_meters = CASE WHEN EXCLUDED.reach_meters > 0 THEN EXCLUDED.reach_meters ELSE transceivers.reach_meters END, + fiber_type = CASE WHEN EXCLUDED.fiber_type <> '' THEN EXCLUDED.fiber_type ELSE transceivers.fiber_type END, + wavelengths = COALESCE(EXCLUDED.wavelengths, transceivers.wavelengths), + updated_at = NOW() + RETURNING (xmax = 0) as was_inserted`, + [slug, p.pid, vendorId, p.formFactor, p.speed, p.speedGbps, + p.reachMeters, p.reachLabel, p.fiberType, p.connector, + p.wavelengths ?? null, p.standard ?? null, category, p.notes ?? null] + ); + if (res.rows[0]?.was_inserted) inserted++; else updated++; + } catch (err) { + console.warn(` Skip ${p.pid}: ${(err as Error).message.slice(0, 80)}`); + errors++; + } + } + + console.log(`\n=== InnoLight Technology OEM Seed Complete ===`); + console.log(` Inserted: ${inserted}`); + console.log(` Updated: ${updated}`); + console.log(` Errors: ${errors}`); + console.log(` Total PIDs: ${INNOLIGHT_PIDS.length}\n`); +} + +if (require.main === module) { + scrapeInnoLightOem() + .then(() => pool.end()) + .catch((err) => { + console.error("Fatal:", err); + pool.end(); + process.exit(1); + }); +} diff --git a/packages/scraper/src/scrapers/intel-oem.ts b/packages/scraper/src/scrapers/intel-oem.ts new file mode 100644 index 0000000..d8c08a2 --- /dev/null +++ b/packages/scraper/src/scrapers/intel-oem.ts @@ -0,0 +1,131 @@ +/** + * Intel OEM Transceiver Catalog Seed + * + * Seeds Intel-branded transceiver PIDs for X710, XXV710, E810, and E830 + * series network adapter optical transceiver options. + * + * Sources: + * - Intel Ethernet Products Compatibility Guide (intel.com) + * - Intel Ethernet Adapter X710/XXV710/E810/E830 Hardware Reference + * - Intel Ethernet Products Optical Module Specifications + * + * Run: tsx packages/scraper/src/scrapers/intel-oem.ts + * Cron: daily at 15:15 + */ + +import { pool, ensureVendor } from "../utils/db"; + +interface IntelPID { + pid: string; + formFactor: string; + speedGbps: number; + speed: string; + reachMeters: number; + reachLabel: string; + fiberType: string; + connector: string; + wavelengths?: string; + standard?: string; + notes?: string; +} + +const INTEL_PIDS: IntelPID[] = [ + // ── 1G SFP ────────────────────────────────────────────────────────────── + { pid: "AFCT-701SMZ", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 550, reachLabel: "SX", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "1000BASE-SX", notes: "Intel OEM 1G SFP SX" }, + { pid: "AFCT-701SDZ", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 10000, reachLabel: "LX", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "1000BASE-LX" }, + { pid: "AFCT-709SMZ", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 80000, reachLabel: "ZX", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "1000BASE-ZX" }, + { pid: "AFCT-701SQPZ", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 100, reachLabel: "T", fiberType: "DAC", connector: "RJ45", standard: "1000BASE-T" }, + + // ── 10G SFP+ ──────────────────────────────────────────────────────────── + { pid: "E10GSFPSR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 300, reachLabel: "SR", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "10GBASE-SR", notes: "Intel E10GSFPSR for X520/X550/X710" }, + { pid: "E10GSFPLR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 10000, reachLabel: "LR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "10GBASE-LR", notes: "Intel E10GSFPLR for X520/X710" }, + { pid: "AFBR-703SDZ", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 40000, reachLabel: "ER", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "10GBASE-ER" }, + { pid: "AFBR-703SDZ-IN2", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 80000, reachLabel: "ZR", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "10GBASE-ZR" }, + { pid: "E10GSFPT", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 30, reachLabel: "T", fiberType: "DAC", connector: "RJ45", standard: "10GBASE-T", notes: "Intel E10GSFPT for X550" }, + + // ── 25G SFP28 ─────────────────────────────────────────────────────────── + { pid: "E25GSFP28SR", formFactor: "SFP28", speedGbps: 25, speed: "25G", reachMeters: 100, reachLabel: "SR", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "25GBASE-SR", notes: "Intel 25G SFP28 SR for XXV710/E810" }, + { pid: "E25GSFP28LR", formFactor: "SFP28", speedGbps: 25, speed: "25G", reachMeters: 10000, reachLabel: "LR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "25GBASE-LR" }, + { pid: "E25GSFP28ER", formFactor: "SFP28", speedGbps: 25, speed: "25G", reachMeters: 30000, reachLabel: "ER", fiberType: "SMF", connector: "LC", wavelengths: "1310nm" }, + + // ── 40G QSFP+ ─────────────────────────────────────────────────────────── + { pid: "E40GQSFPSR4", formFactor: "QSFP+", speedGbps: 40, speed: "40G", reachMeters: 150, reachLabel: "SR4", fiberType: "MMF", connector: "MPO", wavelengths: "850nm", standard: "40GBASE-SR4", notes: "Intel 40G QSFP+ SR4 for XL710" }, + { pid: "E40GQSFPLR4", formFactor: "QSFP+", speedGbps: 40, speed: "40G", reachMeters: 10000, reachLabel: "LR4", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "40GBASE-LR4" }, + + // ── 100G QSFP28 ───────────────────────────────────────────────────────── + { pid: "E100GQSFPSR4", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 100, reachLabel: "SR4", fiberType: "MMF", connector: "MPO", wavelengths: "850nm", standard: "100GBASE-SR4", notes: "Intel 100G QSFP28 SR4 for E810" }, + { pid: "E100GQSFPLR4", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 10000, reachLabel: "LR4", fiberType: "SMF", connector: "LC", wavelengths: "1295-1310nm", standard: "100GBASE-LR4" }, + { pid: "E100GQSFPCWDM4", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 2000, reachLabel: "CWDM4", fiberType: "SMF", connector: "LC", wavelengths: "1271-1331nm", standard: "100GBASE-CWDM4" }, + { pid: "E100GQSFPDR", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 500, reachLabel: "DR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "100GBASE-DR" }, + + // ── 400G QSFP-DD ──────────────────────────────────────────────────────── + { pid: "E400GQSFPDDSR8", formFactor: "QSFP-DD",speedGbps: 400, speed: "400G", reachMeters: 100, reachLabel: "SR8", fiberType: "MMF", connector: "MPO", wavelengths: "850nm", standard: "400GBASE-SR8", notes: "Intel 400G QSFP-DD SR8 for E830" }, + { pid: "E400GQSFPDDDR4", formFactor: "QSFP-DD",speedGbps: 400, speed: "400G", reachMeters: 500, reachLabel: "DR4", fiberType: "SMF", connector: "MPO", wavelengths: "1310nm", standard: "400GBASE-DR4" }, + { pid: "E400GQSFPDDFR4", formFactor: "QSFP-DD",speedGbps: 400, speed: "400G", reachMeters: 2000, reachLabel: "FR4", fiberType: "SMF", connector: "LC", wavelengths: "1271-1331nm", standard: "400GBASE-FR4" }, + { pid: "E400GQSFPDFLR4", formFactor: "QSFP-DD",speedGbps: 400, speed: "400G", reachMeters: 10000, reachLabel: "LR4", fiberType: "SMF", connector: "LC", wavelengths: "1295-1310nm", standard: "400GBASE-LR4" }, + + // ── DAC ───────────────────────────────────────────────────────────────── + { pid: "XDACBL1M", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 1, reachLabel: "DAC-1M", fiberType: "DAC", connector: "SFP+" }, + { pid: "XDACBL3M", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 3, reachLabel: "DAC-3M", fiberType: "DAC", connector: "SFP+" }, + { pid: "QSFP28DACBL1M", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 1, reachLabel: "DAC-1M", fiberType: "DAC", connector: "QSFP28" }, + { pid: "QSFP28DACBL3M", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 3, reachLabel: "DAC-3M", fiberType: "DAC", connector: "QSFP28" }, + { pid: "QSFPDD400GDAC1M", formFactor: "QSFP-DD",speedGbps: 400, speed: "400G", reachMeters: 1, reachLabel: "DAC-1M", fiberType: "DAC", connector: "QSFP-DD" }, +]; + +export async function scrapeIntelOem(): Promise { + console.log("=== Intel OEM Transceiver Seed ===\n"); + + const vendorId = await ensureVendor( + "Intel", + "oem", + "https://www.intel.com/content/www/us/en/products/details/ethernet.html", + undefined + ); + + let inserted = 0; + let updated = 0; + let errors = 0; + + for (const p of INTEL_PIDS) { + const slug = `intel-${p.pid.toLowerCase().replace(/[^a-z0-9]+/g, "-")}`; + try { + const res = await pool.query( + `INSERT INTO transceivers + (slug, part_number, vendor_id, form_factor, speed, speed_gbps, + reach_meters, reach_label, fiber_type, connector, wavelengths, + dom_support, ieee_reference, market_status, category, notes) + VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,true,$12,'Mainstream','DataCenter',$13) + ON CONFLICT (slug) DO UPDATE SET + speed_gbps = EXCLUDED.speed_gbps, + reach_meters = CASE WHEN EXCLUDED.reach_meters > 0 THEN EXCLUDED.reach_meters ELSE transceivers.reach_meters END, + fiber_type = CASE WHEN EXCLUDED.fiber_type <> '' THEN EXCLUDED.fiber_type ELSE transceivers.fiber_type END, + wavelengths = COALESCE(EXCLUDED.wavelengths, transceivers.wavelengths), + updated_at = NOW() + RETURNING (xmax = 0) as was_inserted`, + [slug, p.pid, vendorId, p.formFactor, p.speed, p.speedGbps, + p.reachMeters, p.reachLabel, p.fiberType, p.connector, + p.wavelengths ?? null, p.standard ?? null, p.notes ?? null] + ); + if (res.rows[0]?.was_inserted) inserted++; else updated++; + } catch (err) { + console.warn(` Skip ${p.pid}: ${(err as Error).message.slice(0, 80)}`); + errors++; + } + } + + console.log(`\n=== Intel OEM Seed Complete ===`); + console.log(` Inserted: ${inserted}`); + console.log(` Updated: ${updated}`); + console.log(` Errors: ${errors}`); + console.log(` Total PIDs: ${INTEL_PIDS.length}\n`); +} + +if (require.main === module) { + scrapeIntelOem() + .then(() => pool.end()) + .catch((err) => { + console.error("Fatal:", err); + pool.end(); + process.exit(1); + }); +} diff --git a/packages/scraper/src/scrapers/ipinfusion-oem.ts b/packages/scraper/src/scrapers/ipinfusion-oem.ts new file mode 100644 index 0000000..99b6fdd --- /dev/null +++ b/packages/scraper/src/scrapers/ipinfusion-oem.ts @@ -0,0 +1,129 @@ +/** + * IP Infusion OEM Transceiver Catalog Seed + * + * Seeds IP Infusion-branded transceiver PIDs for OcNOS white-box NOS platforms (ZebOS). + * + * Sources: + * - IP Infusion OcNOS Hardware Compatibility List (ipinfusion.com) + * - IP Infusion ZebOS & OcNOS Transceiver Support Matrix + * + * Run: tsx packages/scraper/src/scrapers/ipinfusion-oem.ts + * Cron: daily at 03:00 + */ + +import { pool, ensureVendor } from "../utils/db"; + +interface IpInfusionPID { + pid: string; + formFactor: string; + speedGbps: number; + speed: string; + reachMeters: number; + reachLabel: string; + fiberType: string; + connector: string; + wavelengths?: string; + standard?: string; + category?: string; + notes?: string; +} + +const IPINFUSION_PIDS: IpInfusionPID[] = [ + // ── 1G SFP ────────────────────────────────────────────────────────────── + { pid: "IPI-SFP-1G-SX", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 550, reachLabel: "SX", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "1000BASE-SX" }, + { pid: "IPI-SFP-1G-LX", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 10000, reachLabel: "LX", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "1000BASE-LX" }, + { pid: "IPI-SFP-GE-T", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 100, reachLabel: "T", fiberType: "Cu", connector: "RJ45", wavelengths: "N/A", standard: "1000BASE-T" }, + + // ── 10G SFP+ ──────────────────────────────────────────────────────────── + { pid: "IPI-SFP-10G-SR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 300, reachLabel: "SR", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "10GBASE-SR" }, + { pid: "IPI-SFP-10G-LR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 10000, reachLabel: "LR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "10GBASE-LR" }, + { pid: "IPI-SFP-10G-ER", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 40000, reachLabel: "ER", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "10GBASE-ER" }, + { pid: "IPI-SFP-10G-ZR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 80000, reachLabel: "ZR", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", category: "Telecom", notes: "IP Infusion 10G ZR SFP+ 80km SMF" }, + { pid: "IPI-SFP-CWDM-1550", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 40000, reachLabel: "CWDM", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", category: "Telecom", notes: "IP Infusion 10G CWDM SFP+ 1550nm channel" }, + { pid: "IPI-DWDM-SFP-C", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 80000, reachLabel: "DWDM", fiberType: "SMF", connector: "LC", wavelengths: "C-band DWDM", category: "Telecom", notes: "IP Infusion 10G DWDM SFP+ C-band fixed channel" }, + { pid: "IPI-SFP-OTU2-10G", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 40000, reachLabel: "OTU2", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", category: "Telecom", notes: "IP Infusion OTU2 10G SFP+ for OTN transport" }, + + // ── 40G QSFP+ ─────────────────────────────────────────────────────────── + { pid: "IPI-QSFP-40G-SR4", formFactor: "QSFP+", speedGbps: 40, speed: "40G", reachMeters: 150, reachLabel: "SR4", fiberType: "MMF", connector: "MPO", wavelengths: "850nm", standard: "40GBASE-SR4" }, + { pid: "IPI-QSFP-40G-LR4", formFactor: "QSFP+", speedGbps: 40, speed: "40G", reachMeters: 10000, reachLabel: "LR4", fiberType: "SMF", connector: "LC", wavelengths: "1295-1310nm", standard: "40GBASE-LR4" }, + + // ── 25G SFP28 ─────────────────────────────────────────────────────────── + { pid: "IPI-SFP28-25G-SR", formFactor: "SFP28", speedGbps: 25, speed: "25G", reachMeters: 300, reachLabel: "SR", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "25GBASE-SR" }, + { pid: "IPI-SFP28-25G-LR", formFactor: "SFP28", speedGbps: 25, speed: "25G", reachMeters: 10000, reachLabel: "LR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "25GBASE-LR" }, + + // ── 100G QSFP28 ───────────────────────────────────────────────────────── + { pid: "IPI-QSFP28-100G-SR4", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 100, reachLabel: "SR4", fiberType: "MMF", connector: "MPO", wavelengths: "850nm", standard: "100GBASE-SR4" }, + { pid: "IPI-QSFP28-100G-LR4", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 10000, reachLabel: "LR4", fiberType: "SMF", connector: "LC", wavelengths: "1295-1310nm", standard: "100GBASE-LR4" }, + { pid: "IPI-QSFP28-100G-ZR4", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 80000, reachLabel: "ZR4", fiberType: "SMF", connector: "LC", wavelengths: "C-band", category: "Telecom", notes: "IP Infusion 100G ZR4 QSFP28 coherent 80km" }, + + // ── 400G QSFP-DD ──────────────────────────────────────────────────────── + { pid: "IPI-QSFP-DD-400G-DR4", formFactor: "QSFP-DD", speedGbps: 400, speed: "400G", reachMeters: 500, reachLabel: "DR4", fiberType: "SMF", connector: "MPO", wavelengths: "1310nm", standard: "400GBASE-DR4" }, +]; + +// PIDs that use 'Telecom' category (CWDM, DWDM, OTU2, ZR variants) +const TELECOM_PIDS = new Set([ + "IPI-SFP-10G-ZR", + "IPI-SFP-CWDM-1550", + "IPI-DWDM-SFP-C", + "IPI-SFP-OTU2-10G", + "IPI-QSFP28-100G-ZR4", +]); + +export async function scrapeIpInfusionOem(): Promise { + console.log("=== IP Infusion OEM Transceiver Seed ===\n"); + + const vendorId = await ensureVendor( + "IP Infusion", + "oem", + "https://www.ipinfusion.com", + undefined + ); + + let inserted = 0; + let updated = 0; + let errors = 0; + + for (const p of IPINFUSION_PIDS) { + const slug = `ipinfusion-${p.pid.toLowerCase().replace(/[^a-z0-9]+/g, "-")}`; + const category = p.category ?? (TELECOM_PIDS.has(p.pid) ? "Telecom" : "DataCenter"); + try { + const res = await pool.query( + `INSERT INTO transceivers + (slug, part_number, vendor_id, form_factor, speed, speed_gbps, + reach_meters, reach_label, fiber_type, connector, wavelengths, + dom_support, ieee_reference, market_status, category, notes) + VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,true,$12,'Mainstream',$13,$14) + ON CONFLICT (slug) DO UPDATE SET + speed_gbps = EXCLUDED.speed_gbps, + reach_meters = CASE WHEN EXCLUDED.reach_meters > 0 THEN EXCLUDED.reach_meters ELSE transceivers.reach_meters END, + fiber_type = CASE WHEN EXCLUDED.fiber_type <> '' THEN EXCLUDED.fiber_type ELSE transceivers.fiber_type END, + wavelengths = COALESCE(EXCLUDED.wavelengths, transceivers.wavelengths), + updated_at = NOW() + RETURNING (xmax = 0) as was_inserted`, + [slug, p.pid, vendorId, p.formFactor, p.speed, p.speedGbps, + p.reachMeters, p.reachLabel, p.fiberType, p.connector, + p.wavelengths ?? null, p.standard ?? null, category, p.notes ?? null] + ); + if (res.rows[0]?.was_inserted) inserted++; else updated++; + } catch (err) { + console.warn(` Skip ${p.pid}: ${(err as Error).message.slice(0, 80)}`); + errors++; + } + } + + console.log(`\n=== IP Infusion OEM Seed Complete ===`); + console.log(` Inserted: ${inserted}`); + console.log(` Updated: ${updated}`); + console.log(` Errors: ${errors}`); + console.log(` Total PIDs: ${IPINFUSION_PIDS.length}\n`); +} + +if (require.main === module) { + scrapeIpInfusionOem() + .then(() => pool.end()) + .catch((err) => { + console.error("Fatal:", err); + pool.end(); + process.exit(1); + }); +} diff --git a/packages/scraper/src/scrapers/isolan-oem.ts b/packages/scraper/src/scrapers/isolan-oem.ts new file mode 100644 index 0000000..5051477 --- /dev/null +++ b/packages/scraper/src/scrapers/isolan-oem.ts @@ -0,0 +1,141 @@ +/** + * iSolan OEM Transceiver Catalog Seed + * + * Seeds iSolan-branded transceiver PIDs for optical components and media + * converters. iSolan is a German manufacturer specializing in fiber optic + * transceivers, CWDM/BiDi SFPs, and media conversion for enterprise and + * carrier access networks. + * + * Sources: + * - iSolan Product Catalog (isolan.com/products/sfp) + * - iSolan SFP/SFP+ Datasheet Series (ISL-SFP-*) + * - iSolan CWDM SFP Specification Sheet (8-channel 1470-1610nm) + * - iSolan QSFP+ / SFP28 Product Range + * + * Run: tsx packages/scraper/src/scrapers/isolan-oem.ts + * Cron: daily at 00:45 + */ + +import { pool, ensureVendor } from "../utils/db"; + +interface IsolanPID { + pid: string; + formFactor: string; + speedGbps: number; + speed: string; + reachMeters: number; + reachLabel: string; + fiberType: string; + connector: string; + wavelengths?: string; + standard?: string; + category?: string; + notes?: string; +} + +const ISOLAN_PIDS: IsolanPID[] = [ + // ── 1G SFP ────────────────────────────────────────────────────────────── + { pid: "ISL-SFP-1G-SX", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 550, reachLabel: "SX", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "1000BASE-SX" }, + { pid: "ISL-SFP-1G-LX", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 10000, reachLabel: "LX", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "1000BASE-LX" }, + { pid: "ISL-SFP-1G-ZX", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 80000, reachLabel: "ZX", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "1000BASE-ZX", notes: "iSolan 80km SMF extended reach SFP" }, + + // ── 10G SFP+ ──────────────────────────────────────────────────────────── + { pid: "ISL-SFP-10G-SR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 300, reachLabel: "SR", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "10GBASE-SR" }, + { pid: "ISL-SFP-10G-LR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 10000, reachLabel: "LR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "10GBASE-LR" }, + { pid: "ISL-SFP-10G-ER", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 40000, reachLabel: "ER", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "10GBASE-ER" }, + { pid: "ISL-SFP-10G-ZR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 80000, reachLabel: "ZR", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "10GBASE-ZR", category: "Telecom", notes: "iSolan 80km ZR SFP+ for long-haul access links" }, + + // ── CWDM SFP (8-channel 1470–1610nm) ──────────────────────────────────── + { pid: "ISL-SFP-CWDM-1470", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 40000, reachLabel: "CWDM-1470", fiberType: "SMF", connector: "LC", wavelengths: "1470nm", standard: "1000BASE-CWDM", category: "Telecom", notes: "iSolan CWDM SFP ch1 1470nm, 40km SMF" }, + { pid: "ISL-SFP-CWDM-1490", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 40000, reachLabel: "CWDM-1490", fiberType: "SMF", connector: "LC", wavelengths: "1490nm", standard: "1000BASE-CWDM", category: "Telecom", notes: "iSolan CWDM SFP ch2 1490nm, 40km SMF" }, + { pid: "ISL-SFP-CWDM-1510", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 40000, reachLabel: "CWDM-1510", fiberType: "SMF", connector: "LC", wavelengths: "1510nm", standard: "1000BASE-CWDM", category: "Telecom", notes: "iSolan CWDM SFP ch3 1510nm, 40km SMF" }, + { pid: "ISL-SFP-CWDM-1530", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 40000, reachLabel: "CWDM-1530", fiberType: "SMF", connector: "LC", wavelengths: "1530nm", standard: "1000BASE-CWDM", category: "Telecom", notes: "iSolan CWDM SFP ch4 1530nm, 40km SMF" }, + { pid: "ISL-SFP-CWDM-1550", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 40000, reachLabel: "CWDM-1550", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "1000BASE-CWDM", category: "Telecom", notes: "iSolan CWDM SFP ch5 1550nm, 40km SMF" }, + { pid: "ISL-SFP-CWDM-1570", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 40000, reachLabel: "CWDM-1570", fiberType: "SMF", connector: "LC", wavelengths: "1570nm", standard: "1000BASE-CWDM", category: "Telecom", notes: "iSolan CWDM SFP ch6 1570nm, 40km SMF" }, + { pid: "ISL-SFP-CWDM-1590", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 40000, reachLabel: "CWDM-1590", fiberType: "SMF", connector: "LC", wavelengths: "1590nm", standard: "1000BASE-CWDM", category: "Telecom", notes: "iSolan CWDM SFP ch7 1590nm, 40km SMF" }, + { pid: "ISL-SFP-CWDM-1610", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 40000, reachLabel: "CWDM-1610", fiberType: "SMF", connector: "LC", wavelengths: "1610nm", standard: "1000BASE-CWDM", category: "Telecom", notes: "iSolan CWDM SFP ch8 1610nm, 40km SMF" }, + + // ── BiDi SFP ───────────────────────────────────────────────────────────── + { pid: "ISL-SFP-BIDI-1310", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 20000, reachLabel: "BiDi-1310", fiberType: "SMF", connector: "LC", wavelengths: "1310nm TX / 1490nm RX", standard: "1000BASE-BX", category: "Telecom", notes: "iSolan BiDi SFP 1310TX/1490RX single-fiber WDM" }, + + // ── 40G QSFP+ ─────────────────────────────────────────────────────────── + { pid: "ISL-QSFP-40G-SR4", formFactor: "QSFP+", speedGbps: 40, speed: "40G", reachMeters: 150, reachLabel: "SR4", fiberType: "MMF", connector: "MPO", wavelengths: "850nm", standard: "40GBASE-SR4" }, + { pid: "ISL-QSFP-40G-LR4", formFactor: "QSFP+", speedGbps: 40, speed: "40G", reachMeters: 10000, reachLabel: "LR4", fiberType: "SMF", connector: "LC", wavelengths: "1270-1330nm", standard: "40GBASE-LR4" }, + + // ── 25G SFP28 ─────────────────────────────────────────────────────────── + { pid: "ISL-SFP28-25G-SR", formFactor: "SFP28", speedGbps: 25, speed: "25G", reachMeters: 100, reachLabel: "SR", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "25GBASE-SR" }, + { pid: "ISL-SFP28-25G-LR", formFactor: "SFP28", speedGbps: 25, speed: "25G", reachMeters: 10000, reachLabel: "LR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "25GBASE-LR" }, +]; + +// PIDs that belong to the Telecom category (CWDM, BiDi, ZR) +const TELECOM_PIDS = new Set([ + "ISL-SFP-10G-ZR", + "ISL-SFP-CWDM-1470", + "ISL-SFP-CWDM-1490", + "ISL-SFP-CWDM-1510", + "ISL-SFP-CWDM-1530", + "ISL-SFP-CWDM-1550", + "ISL-SFP-CWDM-1570", + "ISL-SFP-CWDM-1590", + "ISL-SFP-CWDM-1610", + "ISL-SFP-BIDI-1310", +]); + +export async function scrapeIsolanOem(): Promise { + console.log("=== iSolan OEM Transceiver Seed ===\n"); + + const vendorId = await ensureVendor( + "iSolan", + "oem", + "https://www.isolan.com", + undefined + ); + + let inserted = 0; + let updated = 0; + let errors = 0; + + for (const p of ISOLAN_PIDS) { + const slug = `isolan-${p.pid.toLowerCase().replace(/[^a-z0-9]+/g, "-")}`; + const category = p.category ?? (TELECOM_PIDS.has(p.pid) ? "Telecom" : "DataCenter"); + try { + const res = await pool.query( + `INSERT INTO transceivers + (slug, part_number, vendor_id, form_factor, speed, speed_gbps, + reach_meters, reach_label, fiber_type, connector, wavelengths, + dom_support, ieee_reference, market_status, category, notes) + VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,true,$12,'Mainstream',$13,$14) + ON CONFLICT (slug) DO UPDATE SET + speed_gbps = EXCLUDED.speed_gbps, + reach_meters = CASE WHEN EXCLUDED.reach_meters > 0 THEN EXCLUDED.reach_meters ELSE transceivers.reach_meters END, + fiber_type = CASE WHEN EXCLUDED.fiber_type <> '' THEN EXCLUDED.fiber_type ELSE transceivers.fiber_type END, + wavelengths = COALESCE(EXCLUDED.wavelengths, transceivers.wavelengths), + updated_at = NOW() + RETURNING (xmax = 0) as was_inserted`, + [slug, p.pid, vendorId, p.formFactor, p.speed, p.speedGbps, + p.reachMeters, p.reachLabel, p.fiberType, p.connector, + p.wavelengths ?? null, p.standard ?? null, category, p.notes ?? null] + ); + if (res.rows[0]?.was_inserted) inserted++; else updated++; + } catch (err) { + console.warn(` Skip ${p.pid}: ${(err as Error).message.slice(0, 80)}`); + errors++; + } + } + + console.log(`\n=== iSolan OEM Seed Complete ===`); + console.log(` Inserted: ${inserted}`); + console.log(` Updated: ${updated}`); + console.log(` Errors: ${errors}`); + console.log(` Total PIDs: ${ISOLAN_PIDS.length}\n`); +} + +if (require.main === module) { + scrapeIsolanOem() + .then(() => pool.end()) + .catch((err) => { + console.error("Fatal:", err); + pool.end(); + process.exit(1); + }); +} diff --git a/packages/scraper/src/scrapers/ixia-oem.ts b/packages/scraper/src/scrapers/ixia-oem.ts new file mode 100644 index 0000000..dc129cf --- /dev/null +++ b/packages/scraper/src/scrapers/ixia-oem.ts @@ -0,0 +1,132 @@ +/** + * Ixia / Keysight OEM Transceiver Catalog Seed + * + * Seeds Ixia-branded transceiver PIDs for Keysight (formerly Ixia) + * network test and visibility platform optical port hardware. + * + * Sources: + * - Keysight Network Test Hardware (keysight.com/us/en/products/network-test/network-test-hardware.html) + * - Ixia IxNetwork and IxLoad Platform Hardware Guides + * - Ixia Vision Series Network Packet Broker Data Sheets + * + * Run: tsx packages/scraper/src/scrapers/ixia-oem.ts + * Cron: daily at 10:15 + */ + +import { pool, ensureVendor } from "../utils/db"; + +interface IxiaPID { + pid: string; + formFactor: string; + speedGbps: number; + speed: string; + reachMeters: number; + reachLabel: string; + fiberType: string; + connector: string; + wavelengths?: string; + standard?: string; + category?: string; + notes?: string; +} + +// PIDs requiring TELECOM/ITU-T classification (CFP, CFP2, ZR, ER4 over WDM) +const TELECOM_PIDS = new Set([ + "IXIA-CFP-100G-LR4", + "IXIA-CFP2-100G-LR4", + "IXIA-SFP-10G-ZR", + "IXIA-QSFP28-100G-ER4", +]); + +const IXIA_PIDS: IxiaPID[] = [ + // ── 1G SFP ────────────────────────────────────────────────────────────── + { pid: "IXIA-SFP-1G-SX", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 550, reachLabel: "SX", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "1000BASE-SX" }, + { pid: "IXIA-SFP-1G-LX", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 10000, reachLabel: "LX", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "1000BASE-LX" }, + { pid: "IXIA-SFP-GE-T", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 100, reachLabel: "T", fiberType: "DAC", connector: "RJ45", standard: "1000BASE-T" }, + + // ── 10G SFP+ ──────────────────────────────────────────────────────────── + { pid: "IXIA-SFP-10G-SR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 300, reachLabel: "SR", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "10GBASE-SR" }, + { pid: "IXIA-SFP-10G-LR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 10000, reachLabel: "LR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "10GBASE-LR" }, + { pid: "IXIA-SFP-10G-ER", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 40000, reachLabel: "ER", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "10GBASE-ER" }, + { pid: "IXIA-SFP-10G-ZR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 80000, reachLabel: "ZR", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "10GBASE-ZR", notes: "DWDM extended reach" }, + + // ── 25G SFP28 ─────────────────────────────────────────────────────────── + { pid: "IXIA-SFP28-25G-SR", formFactor: "SFP28", speedGbps: 25, speed: "25G", reachMeters: 100, reachLabel: "SR", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "25GBASE-SR" }, + { pid: "IXIA-SFP28-25G-LR", formFactor: "SFP28", speedGbps: 25, speed: "25G", reachMeters: 10000, reachLabel: "LR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "25GBASE-LR" }, + + // ── 40G QSFP+ ─────────────────────────────────────────────────────────── + { pid: "IXIA-QSFP-40G-SR4", formFactor: "QSFP+", speedGbps: 40, speed: "40G", reachMeters: 150, reachLabel: "SR4", fiberType: "MMF", connector: "MPO", wavelengths: "850nm", standard: "40GBASE-SR4" }, + { pid: "IXIA-QSFP-40G-LR4", formFactor: "QSFP+", speedGbps: 40, speed: "40G", reachMeters: 10000, reachLabel: "LR4", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "40GBASE-LR4" }, + + // ── 100G QSFP28 ───────────────────────────────────────────────────────── + { pid: "IXIA-QSFP28-100G-SR4", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 100, reachLabel: "SR4", fiberType: "MMF", connector: "MPO", wavelengths: "850nm", standard: "100GBASE-SR4" }, + { pid: "IXIA-QSFP28-100G-LR4", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 10000, reachLabel: "LR4", fiberType: "SMF", connector: "LC", wavelengths: "1295-1310nm", standard: "100GBASE-LR4" }, + { pid: "IXIA-QSFP28-100G-ER4", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 40000, reachLabel: "ER4", fiberType: "SMF", connector: "LC", wavelengths: "1295-1310nm", standard: "100GBASE-ER4", notes: "Extended reach, ITU-T G.694 WDM" }, + + // ── 400G QSFP-DD ──────────────────────────────────────────────────────── + { pid: "IXIA-QSFP-DD-400G-DR4", formFactor: "QSFP-DD", speedGbps: 400, speed: "400G", reachMeters: 500, reachLabel: "DR4", fiberType: "SMF", connector: "MPO", wavelengths: "1310nm", standard: "400GBASE-DR4" }, + { pid: "IXIA-QSFP-DD-400G-SR8", formFactor: "QSFP-DD", speedGbps: 400, speed: "400G", reachMeters: 100, reachLabel: "SR8", fiberType: "MMF", connector: "MPO", wavelengths: "850nm", standard: "400GBASE-SR8" }, + + // ── 100G CFP / CFP2 (Telecom) ─────────────────────────────────────────── + { pid: "IXIA-CFP-100G-LR4", formFactor: "CFP", speedGbps: 100, speed: "100G", reachMeters: 10000, reachLabel: "LR4", fiberType: "SMF", connector: "LC", wavelengths: "1295-1310nm", standard: "100GBASE-LR4", notes: "CFP MSA, OTU4 capable" }, + { pid: "IXIA-CFP2-100G-LR4", formFactor: "CFP2", speedGbps: 100, speed: "100G", reachMeters: 10000, reachLabel: "LR4", fiberType: "SMF", connector: "LC", wavelengths: "1295-1310nm", standard: "100GBASE-LR4", notes: "CFP2 MSA, OTU4 capable" }, +]; + +export async function scrapeIxiaOem(): Promise { + console.log("=== Ixia / Keysight OEM Transceiver Seed ===\n"); + + const vendorId = await ensureVendor( + "Ixia", + "oem", + "https://www.keysight.com/us/en/products/network-test/network-test-hardware.html", + undefined + ); + + let inserted = 0; + let updated = 0; + let errors = 0; + + for (const p of IXIA_PIDS) { + const slug = `ixia-${p.pid.toLowerCase().replace(/[^a-z0-9]+/g, "-")}`; + const category = TELECOM_PIDS.has(p.pid) ? "Telecom" : "DataCenter"; + try { + const res = await pool.query( + `INSERT INTO transceivers + (slug, part_number, vendor_id, form_factor, speed, speed_gbps, + reach_meters, reach_label, fiber_type, connector, wavelengths, + dom_support, ieee_reference, market_status, category, notes) + VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,true,$12,'Mainstream',$13,$14) + ON CONFLICT (slug) DO UPDATE SET + speed_gbps = EXCLUDED.speed_gbps, + reach_meters = CASE WHEN EXCLUDED.reach_meters > 0 THEN EXCLUDED.reach_meters ELSE transceivers.reach_meters END, + fiber_type = CASE WHEN EXCLUDED.fiber_type <> '' THEN EXCLUDED.fiber_type ELSE transceivers.fiber_type END, + wavelengths = COALESCE(EXCLUDED.wavelengths, transceivers.wavelengths), + updated_at = NOW() + RETURNING (xmax = 0) as was_inserted`, + [slug, p.pid, vendorId, p.formFactor, p.speed, p.speedGbps, + p.reachMeters, p.reachLabel, p.fiberType, p.connector, + p.wavelengths ?? null, p.standard ?? null, category, p.notes ?? null] + ); + if (res.rows[0]?.was_inserted) inserted++; else updated++; + } catch (err) { + console.warn(` Skip ${p.pid}: ${(err as Error).message.slice(0, 80)}`); + errors++; + } + } + + console.log(`\n=== Ixia OEM Seed Complete ===`); + console.log(` Inserted: ${inserted}`); + console.log(` Updated: ${updated}`); + console.log(` Errors: ${errors}`); + console.log(` Total PIDs: ${IXIA_PIDS.length}\n`); +} + +if (require.main === module) { + scrapeIxiaOem() + .then(() => pool.end()) + .catch((err) => { + console.error("Fatal:", err); + pool.end(); + process.exit(1); + }); +} diff --git a/packages/scraper/src/scrapers/juniper-mx-oem.ts b/packages/scraper/src/scrapers/juniper-mx-oem.ts new file mode 100644 index 0000000..e4c528f --- /dev/null +++ b/packages/scraper/src/scrapers/juniper-mx-oem.ts @@ -0,0 +1,132 @@ +/** + * Juniper MX OEM Transceiver Catalog Seed + * + * Seeds Juniper MX-branded transceiver PIDs for MX480, MX960, MX10003, + * and PTX series service provider routers and packet-optical platforms, + * including OC-n SONET, CFP2-DCO coherent, and 400G ZR modules. + * + * Sources: + * - Juniper MX Series Router Hardware Guide + * - Juniper PTX Series Packet Transport Router Data Sheet + * - Juniper Optics Compatibility Tool (HCT) + * - Juniper Networks Transceiver Module Reference (TN1157) + * + * Run: tsx packages/scraper/src/scrapers/juniper-mx-oem.ts + * Cron: daily at 13:15 + */ + +import { pool, ensureVendor } from "../utils/db"; + +interface JuniperMxPID { + pid: string; + formFactor: string; + speedGbps: number; + speed: string; + reachMeters: number; + reachLabel: string; + fiberType: string; + connector: string; + wavelengths?: string; + standard?: string; + category: "DataCenter" | "Telecom"; + notes?: string; +} + +// TELECOM_PIDS: OC-3/12/48 SONET, CFP2-DCO coherent, ZR variants. +const JUNIPER_MX_PIDS: JuniperMxPID[] = [ + // ── 1G SFP ────────────────────────────────────────────────────────────── + { pid: "SFP-1GE-SX", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 550, reachLabel: "SX", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "1000BASE-SX", category: "DataCenter", notes: "Juniper MX 1G multimode SFP" }, + { pid: "SFP-1GE-LX", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 10000, reachLabel: "LX", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "1000BASE-LX", category: "DataCenter", notes: "Juniper MX 1G single-mode SFP 10km" }, + { pid: "SFP-1GE-T", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 100, reachLabel: "T", fiberType: "DAC", connector: "RJ45", standard: "1000BASE-T", category: "DataCenter", notes: "Juniper MX 1G copper SFP" }, + + // ── 10G SFP+ ──────────────────────────────────────────────────────────── + { pid: "SFP-10GE-SR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 300, reachLabel: "SR", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "10GBASE-SR", category: "DataCenter", notes: "Juniper MX 10G multimode SFP+" }, + { pid: "SFP-10GE-LR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 10000, reachLabel: "LR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "10GBASE-LR", category: "DataCenter", notes: "Juniper MX 10G single-mode SFP+ 10km" }, + { pid: "SFP-10GE-ER", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 40000, reachLabel: "ER", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "10GBASE-ER", category: "DataCenter", notes: "Juniper MX 10G extended-reach SFP+ 40km" }, + { pid: "SFP-10GE-ZR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 80000, reachLabel: "ZR", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "10GBASE-ZR", category: "Telecom", notes: "Juniper MX 10G ZR SFP+ 80km metro/SP" }, + + // ── SONET/SDH OC-n SFP ────────────────────────────────────────────────── + { pid: "SFP-OC3-MM", formFactor: "SFP", speedGbps: 0.155, speed: "OC3", reachMeters: 2000, reachLabel: "SR", fiberType: "MMF", connector: "LC", wavelengths: "1310nm", standard: "OC-3/STM-1", category: "Telecom", notes: "Juniper MX OC-3 multimode short-reach SONET SFP" }, + { pid: "SFP-OC3-SM10", formFactor: "SFP", speedGbps: 0.155, speed: "OC3", reachMeters: 10000, reachLabel: "LR-10km", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "OC-3/STM-1", category: "Telecom", notes: "Juniper MX OC-3 single-mode 10km SONET SFP" }, + { pid: "SFP-OC12-SM10", formFactor: "SFP", speedGbps: 0.622, speed: "OC12", reachMeters: 10000, reachLabel: "LR-10km", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "OC-12/STM-4", category: "Telecom", notes: "Juniper MX OC-12 single-mode 10km SONET SFP" }, + { pid: "SFP-OC48-SM", formFactor: "SFP", speedGbps: 2.488, speed: "OC48", reachMeters: 2000, reachLabel: "SR", fiberType: "MMF", connector: "LC", wavelengths: "1310nm", standard: "OC-48/STM-16", category: "Telecom", notes: "Juniper MX OC-48 short-reach SONET SFP" }, + + // ── 40G QSFP+ ─────────────────────────────────────────────────────────── + { pid: "QSFP-40G-SR4", formFactor: "QSFP+", speedGbps: 40, speed: "40G", reachMeters: 150, reachLabel: "SR4", fiberType: "MMF", connector: "MPO", wavelengths: "850nm", standard: "40GBASE-SR4", category: "DataCenter", notes: "Juniper MX 40G multimode QSFP+" }, + { pid: "QSFP-40G-LR4", formFactor: "QSFP+", speedGbps: 40, speed: "40G", reachMeters: 10000, reachLabel: "LR4", fiberType: "SMF", connector: "LC", wavelengths: "1295-1310nm", standard: "40GBASE-LR4", category: "DataCenter", notes: "Juniper MX 40G single-mode QSFP+ 10km" }, + + // ── 25G SFP28 ─────────────────────────────────────────────────────────── + { pid: "SFP28-25G-SR", formFactor: "SFP28", speedGbps: 25, speed: "25G", reachMeters: 100, reachLabel: "SR", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "25GBASE-SR", category: "DataCenter", notes: "Juniper MX 25G multimode SFP28" }, + { pid: "SFP28-25G-LR", formFactor: "SFP28", speedGbps: 25, speed: "25G", reachMeters: 10000, reachLabel: "LR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "25GBASE-LR", category: "DataCenter", notes: "Juniper MX 25G single-mode SFP28 10km" }, + + // ── 100G QSFP28 ───────────────────────────────────────────────────────── + { pid: "QSFP28-100G-SR4", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 100, reachLabel: "SR4", fiberType: "MMF", connector: "MPO", wavelengths: "850nm", standard: "100GBASE-SR4", category: "DataCenter", notes: "Juniper MX 100G multimode QSFP28" }, + { pid: "QSFP28-100G-LR4", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 10000, reachLabel: "LR4", fiberType: "SMF", connector: "LC", wavelengths: "1295-1310nm", standard: "100GBASE-LR4", category: "DataCenter", notes: "Juniper MX 100G single-mode QSFP28 10km" }, + { pid: "QSFP28-100G-ER4", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 40000, reachLabel: "ER4", fiberType: "SMF", connector: "LC", wavelengths: "1295-1310nm", standard: "100GBASE-ER4", category: "DataCenter", notes: "Juniper MX 100G extended-reach QSFP28 40km" }, + + // ── Coherent / PTX high-speed ──────────────────────────────────────────── + { pid: "CFP2-DCO-200G", formFactor: "CFP2", speedGbps: 200, speed: "200G", reachMeters: 1000000, reachLabel: "DCO-longhaul", fiberType: "SMF", connector: "LC", wavelengths: "C-band DWDM", standard: "OTN/FlexE", category: "Telecom", notes: "Juniper PTX 200G CFP2 digital coherent optics long-haul DWDM" }, + { pid: "QSFP-DD-ZR-400G", formFactor: "QSFP-DD", speedGbps: 400, speed: "400G", reachMeters: 120000, reachLabel: "ZR-120km", fiberType: "SMF", connector: "LC", wavelengths: "C-band DWDM", standard: "400ZR OpenROADM", category: "Telecom", notes: "Juniper PTX 400G QSFP-DD coherent ZR 120km metro DWDM" }, +]; + +export async function scrapeJuniperMxOem(): Promise { + console.log("=== Juniper MX OEM Transceiver Seed ===\n"); + + const vendorId = await ensureVendor( + "Juniper MX", + "oem", + "https://www.juniper.net/us/en/products/routers/mx-series.html", + undefined + ); + + let inserted = 0; + let updated = 0; + let errors = 0; + + for (const p of JUNIPER_MX_PIDS) { + const slug = `juniper-mx-${p.pid.toLowerCase().replace(/[^a-z0-9]+/g, "-")}`; + try { + const res = await pool.query( + `INSERT INTO transceivers + (slug, part_number, vendor_id, form_factor, speed, speed_gbps, + reach_meters, reach_label, fiber_type, connector, wavelengths, + dom_support, ieee_reference, market_status, category, notes) + VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,true,$12,'Mainstream',$13,$14) + ON CONFLICT (slug) DO UPDATE SET + speed_gbps = EXCLUDED.speed_gbps, + reach_meters = CASE WHEN EXCLUDED.reach_meters > 0 THEN EXCLUDED.reach_meters ELSE transceivers.reach_meters END, + fiber_type = CASE WHEN EXCLUDED.fiber_type <> '' THEN EXCLUDED.fiber_type ELSE transceivers.fiber_type END, + wavelengths = COALESCE(EXCLUDED.wavelengths, transceivers.wavelengths), + category = EXCLUDED.category, + updated_at = NOW() + RETURNING (xmax = 0) as was_inserted`, + [slug, p.pid, vendorId, p.formFactor, p.speed, p.speedGbps, + p.reachMeters, p.reachLabel, p.fiberType, p.connector, + p.wavelengths ?? null, p.standard ?? null, p.category, p.notes ?? null] + ); + if (res.rows[0]?.was_inserted) inserted++; else updated++; + } catch (err) { + console.warn(` Skip ${p.pid}: ${(err as Error).message.slice(0, 80)}`); + errors++; + } + } + + const telecomCount = JUNIPER_MX_PIDS.filter(p => p.category === "Telecom").length; + const dcCount = JUNIPER_MX_PIDS.filter(p => p.category === "DataCenter").length; + + console.log(`\n=== Juniper MX OEM Seed Complete ===`); + console.log(` Inserted: ${inserted}`); + console.log(` Updated: ${updated}`); + console.log(` Errors: ${errors}`); + console.log(` Total PIDs: ${JUNIPER_MX_PIDS.length} (Telecom: ${telecomCount}, DataCenter: ${dcCount})\n`); +} + +if (require.main === module) { + scrapeJuniperMxOem() + .then(() => pool.end()) + .catch((err) => { + console.error("Fatal:", err); + pool.end(); + process.exit(1); + }); +} diff --git a/packages/scraper/src/scrapers/juniper-qfx-oem.ts b/packages/scraper/src/scrapers/juniper-qfx-oem.ts new file mode 100644 index 0000000..8d39383 --- /dev/null +++ b/packages/scraper/src/scrapers/juniper-qfx-oem.ts @@ -0,0 +1,123 @@ +/** + * Juniper QFX OEM Transceiver Catalog Seed + * + * Seeds Juniper QFX/EX-branded transceiver PIDs for QFX5100, QFX5200, + * QFX10000, and EX series data center and campus switches. + * + * Sources: + * - Juniper QFX Series Switch Hardware Guide + * - Juniper EX Series Ethernet Switch Data Sheets + * - Juniper Optics Compatibility Tool (HCT) + * - Juniper Networks Transceiver Module Reference (TN1157) + * + * Run: tsx packages/scraper/src/scrapers/juniper-qfx-oem.ts + * Cron: daily at 13:30 + */ + +import { pool, ensureVendor } from "../utils/db"; + +interface JuniperQfxPID { + pid: string; + formFactor: string; + speedGbps: number; + speed: string; + reachMeters: number; + reachLabel: string; + fiberType: string; + connector: string; + wavelengths?: string; + standard?: string; + notes?: string; +} + +const JUNIPER_QFX_PIDS: JuniperQfxPID[] = [ + // ── 1G SFP ────────────────────────────────────────────────────────────── + { pid: "SFP-1GE-SX", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 550, reachLabel: "SX", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "1000BASE-SX", notes: "Juniper QFX/EX 1G multimode SFP" }, + { pid: "SFP-1GE-LX", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 10000, reachLabel: "LX", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "1000BASE-LX", notes: "Juniper QFX/EX 1G single-mode SFP 10km" }, + { pid: "SFP-1GE-T", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 100, reachLabel: "T", fiberType: "DAC", connector: "RJ45", standard: "1000BASE-T", notes: "Juniper QFX/EX 1G copper SFP" }, + + // ── 10G SFP+ ──────────────────────────────────────────────────────────── + { pid: "SFP-10GE-SR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 300, reachLabel: "SR", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "10GBASE-SR", notes: "Juniper QFX 10G multimode SFP+" }, + { pid: "SFP-10GE-LR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 10000, reachLabel: "LR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "10GBASE-LR", notes: "Juniper QFX 10G single-mode SFP+ 10km" }, + { pid: "SFP-10GE-ER", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 40000, reachLabel: "ER", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "10GBASE-ER", notes: "Juniper QFX 10G extended-reach SFP+ 40km" }, + { pid: "SFP-10GE-ZR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 80000, reachLabel: "ZR", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "10GBASE-ZR", notes: "Juniper QFX 10G ZR SFP+ 80km" }, + + // ── 40G QSFP+ ─────────────────────────────────────────────────────────── + { pid: "QSFP-40G-SR4", formFactor: "QSFP+", speedGbps: 40, speed: "40G", reachMeters: 150, reachLabel: "SR4", fiberType: "MMF", connector: "MPO", wavelengths: "850nm", standard: "40GBASE-SR4", notes: "Juniper QFX 40G multimode QSFP+" }, + { pid: "QSFP-40G-LR4", formFactor: "QSFP+", speedGbps: 40, speed: "40G", reachMeters: 10000, reachLabel: "LR4", fiberType: "SMF", connector: "LC", wavelengths: "1295-1310nm", standard: "40GBASE-LR4", notes: "Juniper QFX 40G single-mode QSFP+ 10km" }, + { pid: "QSFP-40G-SR-BD", formFactor: "QSFP+", speedGbps: 40, speed: "40G", reachMeters: 150, reachLabel: "SR-BiDi", fiberType: "MMF", connector: "LC", wavelengths: "832nm/853nm", standard: "40GBASE-BiDi", notes: "Juniper QFX 40G BiDi QSFP+ dual-rate over duplex MMF" }, + + // ── 25G SFP28 ─────────────────────────────────────────────────────────── + { pid: "SFP28-25G-SR", formFactor: "SFP28", speedGbps: 25, speed: "25G", reachMeters: 100, reachLabel: "SR", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "25GBASE-SR", notes: "Juniper QFX 25G multimode SFP28" }, + { pid: "SFP28-25G-LR", formFactor: "SFP28", speedGbps: 25, speed: "25G", reachMeters: 10000, reachLabel: "LR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "25GBASE-LR", notes: "Juniper QFX 25G single-mode SFP28 10km" }, + + // ── 100G QSFP28 ───────────────────────────────────────────────────────── + { pid: "QSFP28-100G-SR4", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 100, reachLabel: "SR4", fiberType: "MMF", connector: "MPO", wavelengths: "850nm", standard: "100GBASE-SR4", notes: "Juniper QFX 100G multimode QSFP28" }, + { pid: "QSFP28-100G-LR4", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 10000, reachLabel: "LR4", fiberType: "SMF", connector: "LC", wavelengths: "1295-1310nm", standard: "100GBASE-LR4", notes: "Juniper QFX 100G single-mode QSFP28 10km" }, + { pid: "QSFP28-100G-ER4", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 40000, reachLabel: "ER4", fiberType: "SMF", connector: "LC", wavelengths: "1295-1310nm", standard: "100GBASE-ER4", notes: "Juniper QFX 100G extended-reach QSFP28 40km" }, + { pid: "QSFP28-100G-CWDM4", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 2000, reachLabel: "CWDM4", fiberType: "SMF", connector: "LC", wavelengths: "1271-1331nm", standard: "100GBASE-CWDM4", notes: "Juniper QFX 100G CWDM4 QSFP28 2km SMF" }, + { pid: "QSFP28-100G-PSM4", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 500, reachLabel: "PSM4", fiberType: "SMF", connector: "MPO", wavelengths: "1310nm", standard: "100GBASE-PSM4", notes: "Juniper QFX 100G PSM4 QSFP28 500m parallel SMF" }, + + // ── 400G QSFP-DD / 800G QSFP-DD ──────────────────────────────────────── + { pid: "QSFP-DD-400G-DR4", formFactor: "QSFP-DD", speedGbps: 400, speed: "400G", reachMeters: 500, reachLabel: "DR4", fiberType: "SMF", connector: "MPO", wavelengths: "1310nm", standard: "400GBASE-DR4", notes: "Juniper QFX 400G QSFP-DD DR4 500m SMF" }, + { pid: "QSFP-DD-400G-SR8", formFactor: "QSFP-DD", speedGbps: 400, speed: "400G", reachMeters: 100, reachLabel: "SR8", fiberType: "MMF", connector: "MPO", wavelengths: "850nm", standard: "400GBASE-SR8", notes: "Juniper QFX 400G QSFP-DD SR8 100m MMF" }, + { pid: "QSFP-DD-800G-DR8", formFactor: "QSFP-DD", speedGbps: 800, speed: "800G", reachMeters: 500, reachLabel: "DR8", fiberType: "SMF", connector: "MPO", wavelengths: "1310nm", standard: "800GBASE-DR8", notes: "Juniper QFX10000 800G QSFP-DD DR8 500m parallel SMF" }, +]; + +export async function scrapeJuniperQfxOem(): Promise { + console.log("=== Juniper QFX OEM Transceiver Seed ===\n"); + + const vendorId = await ensureVendor( + "Juniper QFX", + "oem", + "https://www.juniper.net/us/en/products/switches/qfx-series.html", + undefined + ); + + let inserted = 0; + let updated = 0; + let errors = 0; + + for (const p of JUNIPER_QFX_PIDS) { + const slug = `juniper-qfx-${p.pid.toLowerCase().replace(/[^a-z0-9]+/g, "-")}`; + try { + const res = await pool.query( + `INSERT INTO transceivers + (slug, part_number, vendor_id, form_factor, speed, speed_gbps, + reach_meters, reach_label, fiber_type, connector, wavelengths, + dom_support, ieee_reference, market_status, category, notes) + VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,true,$12,'Mainstream','DataCenter',$13) + ON CONFLICT (slug) DO UPDATE SET + speed_gbps = EXCLUDED.speed_gbps, + reach_meters = CASE WHEN EXCLUDED.reach_meters > 0 THEN EXCLUDED.reach_meters ELSE transceivers.reach_meters END, + fiber_type = CASE WHEN EXCLUDED.fiber_type <> '' THEN EXCLUDED.fiber_type ELSE transceivers.fiber_type END, + wavelengths = COALESCE(EXCLUDED.wavelengths, transceivers.wavelengths), + updated_at = NOW() + RETURNING (xmax = 0) as was_inserted`, + [slug, p.pid, vendorId, p.formFactor, p.speed, p.speedGbps, + p.reachMeters, p.reachLabel, p.fiberType, p.connector, + p.wavelengths ?? null, p.standard ?? null, p.notes ?? null] + ); + if (res.rows[0]?.was_inserted) inserted++; else updated++; + } catch (err) { + console.warn(` Skip ${p.pid}: ${(err as Error).message.slice(0, 80)}`); + errors++; + } + } + + console.log(`\n=== Juniper QFX OEM Seed Complete ===`); + console.log(` Inserted: ${inserted}`); + console.log(` Updated: ${updated}`); + console.log(` Errors: ${errors}`); + console.log(` Total PIDs: ${JUNIPER_QFX_PIDS.length}\n`); +} + +if (require.main === module) { + scrapeJuniperQfxOem() + .then(() => pool.end()) + .catch((err) => { + console.error("Fatal:", err); + pool.end(); + process.exit(1); + }); +} diff --git a/packages/scraper/src/scrapers/keysight-oem.ts b/packages/scraper/src/scrapers/keysight-oem.ts new file mode 100644 index 0000000..3124597 --- /dev/null +++ b/packages/scraper/src/scrapers/keysight-oem.ts @@ -0,0 +1,130 @@ +/** + * Keysight Technologies OEM Transceiver Catalog Seed + * + * Seeds Keysight/Ixia-branded transceiver PIDs for IxNetwork, + * AresONE, and BreakingPoint network test platforms. + * + * Sources: + * - Keysight Network Test Hardware Compatibility Guide + * - IxNetwork Platform Data Sheets + * - AresONE 400G/800G Platform Guide + * - BreakingPoint Appliance Hardware Reference + * + * Run: tsx packages/scraper/src/scrapers/keysight-oem.ts + * Cron: daily at 20:00 + */ + +import { pool, ensureVendor } from "../utils/db"; + +interface KeysightPID { + pid: string; + formFactor: string; + speedGbps: number; + speed: string; + reachMeters: number; + reachLabel: string; + fiberType: string; + connector: string; + wavelengths?: string; + standard?: string; + notes?: string; +} + +const KEYSIGHT_PIDS: KeysightPID[] = [ + // ── 10G SFP+ ──────────────────────────────────────────────────────────── + { pid: "KS-SFP-10G-SR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 300, reachLabel: "SR", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "10GBASE-SR" }, + { pid: "KS-SFP-10G-LR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 10000, reachLabel: "LR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "10GBASE-LR" }, + { pid: "KS-SFP-10G-ER", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 40000, reachLabel: "ER", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "10GBASE-ER" }, + { pid: "KS-SFP-10G-ZR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 80000, reachLabel: "ZR", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "10GBASE-ZR" }, + { pid: "KS-SFP-10G-T", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 30, reachLabel: "T", fiberType: "DAC", connector: "RJ45", standard: "10GBASE-T" }, + + // ── 25G SFP28 ─────────────────────────────────────────────────────────── + { pid: "KS-SFP28-25G-SR", formFactor: "SFP28", speedGbps: 25, speed: "25G", reachMeters: 100, reachLabel: "SR", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "25GBASE-SR" }, + { pid: "KS-SFP28-25G-LR", formFactor: "SFP28", speedGbps: 25, speed: "25G", reachMeters: 10000, reachLabel: "LR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "25GBASE-LR" }, + + // ── 40G QSFP+ ─────────────────────────────────────────────────────────── + { pid: "KS-QSFP-40G-SR4", formFactor: "QSFP+", speedGbps: 40, speed: "40G", reachMeters: 150, reachLabel: "SR4", fiberType: "MMF", connector: "MPO", wavelengths: "850nm", standard: "40GBASE-SR4" }, + { pid: "KS-QSFP-40G-LR4", formFactor: "QSFP+", speedGbps: 40, speed: "40G", reachMeters: 10000, reachLabel: "LR4", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "40GBASE-LR4" }, + + // ── 100G QSFP28 ───────────────────────────────────────────────────────── + { pid: "KS-QSFP28-100G-SR4", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 100, reachLabel: "SR4", fiberType: "MMF", connector: "MPO", wavelengths: "850nm", standard: "100GBASE-SR4" }, + { pid: "KS-QSFP28-100G-LR4", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 10000, reachLabel: "LR4", fiberType: "SMF", connector: "LC", wavelengths: "1295-1310nm", standard: "100GBASE-LR4" }, + { pid: "KS-QSFP28-100G-CWDM4", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 2000, reachLabel: "CWDM4", fiberType: "SMF", connector: "LC", wavelengths: "1271-1331nm", standard: "100GBASE-CWDM4" }, + { pid: "KS-QSFP28-100G-DR", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 500, reachLabel: "DR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "100GBASE-DR" }, + { pid: "KS-QSFP28-100G-FR", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 2000, reachLabel: "FR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "100GBASE-FR" }, + + // ── 400G QSFP-DD ──────────────────────────────────────────────────────── + { pid: "KS-QSFPDD-400G-SR8", formFactor: "QSFP-DD", speedGbps: 400, speed: "400G", reachMeters: 100, reachLabel: "SR8", fiberType: "MMF", connector: "MPO", wavelengths: "850nm", standard: "400GBASE-SR8" }, + { pid: "KS-QSFPDD-400G-DR4", formFactor: "QSFP-DD", speedGbps: 400, speed: "400G", reachMeters: 500, reachLabel: "DR4", fiberType: "SMF", connector: "MPO", wavelengths: "1310nm", standard: "400GBASE-DR4" }, + { pid: "KS-QSFPDD-400G-FR4", formFactor: "QSFP-DD", speedGbps: 400, speed: "400G", reachMeters: 2000, reachLabel: "FR4", fiberType: "SMF", connector: "LC", wavelengths: "1271-1331nm", standard: "400GBASE-FR4" }, + { pid: "KS-QSFPDD-400G-LR4", formFactor: "QSFP-DD", speedGbps: 400, speed: "400G", reachMeters: 10000, reachLabel: "LR4", fiberType: "SMF", connector: "LC", wavelengths: "1295-1310nm", standard: "400GBASE-LR4" }, + + // ── 800G OSFP ─────────────────────────────────────────────────────────── + { pid: "KS-OSFP-800G-SR8", formFactor: "OSFP", speedGbps: 800, speed: "800G", reachMeters: 500, reachLabel: "SR8", fiberType: "MMF", connector: "MPO", wavelengths: "850nm", standard: "800GBASE-SR8" }, + { pid: "KS-OSFP-800G-DR8", formFactor: "OSFP", speedGbps: 800, speed: "800G", reachMeters: 2000, reachLabel: "DR8", fiberType: "SMF", connector: "LC", wavelengths: "1310nm" }, + + // ── DAC ───────────────────────────────────────────────────────────────── + { pid: "KS-DAC-10G-1M", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 1, reachLabel: "DAC-1M", fiberType: "DAC", connector: "SFP+" }, + { pid: "KS-DAC-10G-3M", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 3, reachLabel: "DAC-3M", fiberType: "DAC", connector: "SFP+" }, + { pid: "KS-DAC-100G-1M", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 1, reachLabel: "DAC-1M", fiberType: "DAC", connector: "QSFP28" }, + { pid: "KS-DAC-100G-3M", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 3, reachLabel: "DAC-3M", fiberType: "DAC", connector: "QSFP28" }, + { pid: "KS-DAC-400G-1M", formFactor: "QSFP-DD",speedGbps: 400, speed: "400G", reachMeters: 1, reachLabel: "DAC-1M", fiberType: "DAC", connector: "QSFP-DD" }, +]; + +export async function scrapeKeysightOem(): Promise { + console.log("=== Keysight Technologies OEM Transceiver Seed ===\n"); + + const vendorId = await ensureVendor( + "Keysight Technologies", + "oem", + "https://www.keysight.com/us/en/products/network-test.html", + undefined + ); + + let inserted = 0; + let updated = 0; + let errors = 0; + + for (const p of KEYSIGHT_PIDS) { + const slug = `keysight-${p.pid.toLowerCase().replace(/[^a-z0-9]+/g, "-")}`; + try { + const res = await pool.query( + `INSERT INTO transceivers + (slug, part_number, vendor_id, form_factor, speed, speed_gbps, + reach_meters, reach_label, fiber_type, connector, wavelengths, + dom_support, ieee_reference, market_status, category, notes) + VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,true,$12,'Mainstream','DataCenter',$13) + ON CONFLICT (slug) DO UPDATE SET + speed_gbps = EXCLUDED.speed_gbps, + reach_meters = CASE WHEN EXCLUDED.reach_meters > 0 THEN EXCLUDED.reach_meters ELSE transceivers.reach_meters END, + fiber_type = CASE WHEN EXCLUDED.fiber_type <> '' THEN EXCLUDED.fiber_type ELSE transceivers.fiber_type END, + wavelengths = COALESCE(EXCLUDED.wavelengths, transceivers.wavelengths), + updated_at = NOW() + RETURNING (xmax = 0) as was_inserted`, + [slug, p.pid, vendorId, p.formFactor, p.speed, p.speedGbps, + p.reachMeters, p.reachLabel, p.fiberType, p.connector, + p.wavelengths ?? null, p.standard ?? null, p.notes ?? null] + ); + if (res.rows[0]?.was_inserted) inserted++; else updated++; + } catch (err) { + console.warn(` Skip ${p.pid}: ${(err as Error).message.slice(0, 80)}`); + errors++; + } + } + + console.log(`\n=== Keysight Technologies OEM Seed Complete ===`); + console.log(` Inserted: ${inserted}`); + console.log(` Updated: ${updated}`); + console.log(` Errors: ${errors}`); + console.log(` Total PIDs: ${KEYSIGHT_PIDS.length}\n`); +} + +if (require.main === module) { + scrapeKeysightOem() + .then(() => pool.end()) + .catch((err) => { + console.error("Fatal:", err); + pool.end(); + process.exit(1); + }); +} diff --git a/packages/scraper/src/scrapers/kontron-oem.ts b/packages/scraper/src/scrapers/kontron-oem.ts new file mode 100644 index 0000000..4bdee25 --- /dev/null +++ b/packages/scraper/src/scrapers/kontron-oem.ts @@ -0,0 +1,131 @@ +/** + * Kontron OEM Transceiver Catalog Seed + * + * Seeds Kontron-branded transceiver PIDs for ATCA/telecom platforms (S&T Group). + * + * Sources: + * - Kontron Product Portfolio — Telecom & ATCA Line Cards (kontron.com) + * - Kontron ATCA & CompactPCI Transceiver Compatibility Matrix + * + * Run: tsx packages/scraper/src/scrapers/kontron-oem.ts + * Cron: daily at 02:45 + */ + +import { pool, ensureVendor } from "../utils/db"; + +interface KontronPID { + pid: string; + formFactor: string; + speedGbps: number; + speed: string; + reachMeters: number; + reachLabel: string; + fiberType: string; + connector: string; + wavelengths?: string; + standard?: string; + category?: string; + notes?: string; +} + +const KONTRON_PIDS: KontronPID[] = [ + // ── 1G SFP ────────────────────────────────────────────────────────────── + { pid: "KT-SFP-1G-SX", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 550, reachLabel: "SX", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "1000BASE-SX" }, + { pid: "KT-SFP-1G-LX", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 10000, reachLabel: "LX", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "1000BASE-LX" }, + { pid: "KT-SFP-GE-T", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 100, reachLabel: "T", fiberType: "Cu", connector: "RJ45", wavelengths: "N/A", standard: "1000BASE-T" }, + + // ── OC-3 / OC-12 SONET SFP ────────────────────────────────────────────── + { pid: "KT-SFP-OC3-SR", formFactor: "SFP", speedGbps: 0.155, speed: "OC-3", reachMeters: 2000, reachLabel: "SR", fiberType: "MMF", connector: "LC", wavelengths: "1310nm", category: "Telecom", notes: "Kontron OC-3 / STM-1 SFP short reach" }, + { pid: "KT-SFP-OC12-SR", formFactor: "SFP", speedGbps: 0.622, speed: "OC-12", reachMeters: 2000, reachLabel: "SR", fiberType: "MMF", connector: "LC", wavelengths: "1310nm", category: "Telecom", notes: "Kontron OC-12 / STM-4 SFP short reach" }, + + // ── 10G SFP+ ──────────────────────────────────────────────────────────── + { pid: "KT-SFP-10G-SR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 300, reachLabel: "SR", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "10GBASE-SR" }, + { pid: "KT-SFP-10G-LR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 10000, reachLabel: "LR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "10GBASE-LR" }, + { pid: "KT-SFP-10G-ER", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 40000, reachLabel: "ER", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "10GBASE-ER" }, + { pid: "KT-SFP-10G-ZR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 80000, reachLabel: "ZR", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", category: "Telecom", notes: "Kontron 10G ZR SFP+ 80km SMF" }, + { pid: "KT-SFP-OTU2-10G", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 40000, reachLabel: "OTU2", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", category: "Telecom", notes: "Kontron OTU2 10G SFP+ for OTN transport" }, + { pid: "KT-SFP-CWDM-1550", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 40000, reachLabel: "CWDM", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", category: "Telecom", notes: "Kontron 10G CWDM SFP+ 1550nm channel" }, + + // ── 40G QSFP+ ─────────────────────────────────────────────────────────── + { pid: "KT-QSFP-40G-SR4", formFactor: "QSFP+", speedGbps: 40, speed: "40G", reachMeters: 150, reachLabel: "SR4", fiberType: "MMF", connector: "MPO", wavelengths: "850nm", standard: "40GBASE-SR4" }, + { pid: "KT-QSFP-40G-LR4", formFactor: "QSFP+", speedGbps: 40, speed: "40G", reachMeters: 10000, reachLabel: "LR4", fiberType: "SMF", connector: "LC", wavelengths: "1295-1310nm", standard: "40GBASE-LR4" }, + + // ── 25G SFP28 ─────────────────────────────────────────────────────────── + { pid: "KT-SFP28-25G-SR", formFactor: "SFP28", speedGbps: 25, speed: "25G", reachMeters: 300, reachLabel: "SR", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "25GBASE-SR" }, + { pid: "KT-SFP28-25G-LR", formFactor: "SFP28", speedGbps: 25, speed: "25G", reachMeters: 10000, reachLabel: "LR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "25GBASE-LR" }, + + // ── 100G QSFP28 ───────────────────────────────────────────────────────── + { pid: "KT-QSFP28-100G-SR4", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 100, reachLabel: "SR4", fiberType: "MMF", connector: "MPO", wavelengths: "850nm", standard: "100GBASE-SR4" }, + { pid: "KT-QSFP28-100G-LR4", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 10000, reachLabel: "LR4", fiberType: "SMF", connector: "LC", wavelengths: "1295-1310nm", standard: "100GBASE-LR4" }, + + // ── 400G QSFP-DD ──────────────────────────────────────────────────────── + { pid: "KT-QSFP-DD-400G-DR4", formFactor: "QSFP-DD", speedGbps: 400, speed: "400G", reachMeters: 500, reachLabel: "DR4", fiberType: "SMF", connector: "MPO", wavelengths: "1310nm", standard: "400GBASE-DR4" }, +]; + +// PIDs that use 'Telecom' category (OC-3/12, OTU2, CWDM, ZR) +const TELECOM_PIDS = new Set([ + "KT-SFP-OC3-SR", + "KT-SFP-OC12-SR", + "KT-SFP-10G-ZR", + "KT-SFP-OTU2-10G", + "KT-SFP-CWDM-1550", +]); + +export async function scrapeKontronOem(): Promise { + console.log("=== Kontron OEM Transceiver Seed ===\n"); + + const vendorId = await ensureVendor( + "Kontron", + "oem", + "https://www.kontron.com", + undefined + ); + + let inserted = 0; + let updated = 0; + let errors = 0; + + for (const p of KONTRON_PIDS) { + const slug = `kontron-${p.pid.toLowerCase().replace(/[^a-z0-9]+/g, "-")}`; + const category = p.category ?? (TELECOM_PIDS.has(p.pid) ? "Telecom" : "DataCenter"); + try { + const res = await pool.query( + `INSERT INTO transceivers + (slug, part_number, vendor_id, form_factor, speed, speed_gbps, + reach_meters, reach_label, fiber_type, connector, wavelengths, + dom_support, ieee_reference, market_status, category, notes) + VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,true,$12,'Mainstream',$13,$14) + ON CONFLICT (slug) DO UPDATE SET + speed_gbps = EXCLUDED.speed_gbps, + reach_meters = CASE WHEN EXCLUDED.reach_meters > 0 THEN EXCLUDED.reach_meters ELSE transceivers.reach_meters END, + fiber_type = CASE WHEN EXCLUDED.fiber_type <> '' THEN EXCLUDED.fiber_type ELSE transceivers.fiber_type END, + wavelengths = COALESCE(EXCLUDED.wavelengths, transceivers.wavelengths), + updated_at = NOW() + RETURNING (xmax = 0) as was_inserted`, + [slug, p.pid, vendorId, p.formFactor, p.speed, p.speedGbps, + p.reachMeters, p.reachLabel, p.fiberType, p.connector, + p.wavelengths ?? null, p.standard ?? null, category, p.notes ?? null] + ); + if (res.rows[0]?.was_inserted) inserted++; else updated++; + } catch (err) { + console.warn(` Skip ${p.pid}: ${(err as Error).message.slice(0, 80)}`); + errors++; + } + } + + console.log(`\n=== Kontron OEM Seed Complete ===`); + console.log(` Inserted: ${inserted}`); + console.log(` Updated: ${updated}`); + console.log(` Errors: ${errors}`); + console.log(` Total PIDs: ${KONTRON_PIDS.length}\n`); +} + +if (require.main === module) { + scrapeKontronOem() + .then(() => pool.end()) + .catch((err) => { + console.error("Fatal:", err); + pool.end(); + process.exit(1); + }); +} diff --git a/packages/scraper/src/scrapers/korenix-oem.ts b/packages/scraper/src/scrapers/korenix-oem.ts new file mode 100644 index 0000000..71c68ca --- /dev/null +++ b/packages/scraper/src/scrapers/korenix-oem.ts @@ -0,0 +1,115 @@ +/** + * Korenix Technology OEM Transceiver Catalog Seed + * + * Seeds transceiver PIDs for Korenix industrial-grade SFP/SFP+ modules used in + * railway, power, and manufacturing automation Ethernet switches. + * + * Sources: + * - Korenix KSM series SFP module datasheets (korenix.com) + * - Korenix JetNet/JetNet Plus series hardware guides + * + * Run: tsx packages/scraper/src/scrapers/korenix-oem.ts + * Cron: daily at 17:45 + */ + +import { pool, ensureVendor } from "../utils/db"; + +interface KorenixPID { + pid: string; + formFactor: string; + speedGbps: number; + speed: string; + reachMeters: number; + reachLabel: string; + fiberType: string; + connector: string; + wavelengths?: string; + standard?: string; + notes?: string; +} + +const KORENIX_PIDS: KorenixPID[] = [ + // ── 100M SFP ──────────────────────────────────────────────────────────── + { pid: "KSM-100M-MM2-LC", formFactor: "SFP", speedGbps: 0.1, speed: "100M", reachMeters: 2000, reachLabel: "FX", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "100BASE-FX", notes: undefined }, + { pid: "KSM-100M-SM15-LC", formFactor: "SFP", speedGbps: 0.1, speed: "100M", reachMeters: 15000, reachLabel: "LFX", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "100BASE-LFX", notes: undefined }, + { pid: "KSM-100M-SM40-LC", formFactor: "SFP", speedGbps: 0.1, speed: "100M", reachMeters: 40000, reachLabel: "LFX", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: undefined, notes: "Korenix 100M SM SFP 40km" }, + { pid: "KSM-100M-BX20U-LC", formFactor: "SFP", speedGbps: 0.1, speed: "100M", reachMeters: 20000, reachLabel: "BiDi-20K", fiberType: "SMF", connector: "LC", wavelengths: "TX1310/RX1550", standard: undefined, notes: "Korenix 100M BiDi SFP upstream" }, + + // ── 1G SFP ────────────────────────────────────────────────────────────── + { pid: "KSM-1000M-MM550-LC", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 550, reachLabel: "SX", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "1000BASE-SX", notes: undefined }, + { pid: "KSM-1000M-SM10-LC", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 10000, reachLabel: "LX", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "1000BASE-LX", notes: undefined }, + { pid: "KSM-1000M-SM20-LC", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 20000, reachLabel: "LH", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: undefined, notes: "Korenix 1G SM SFP 20km" }, + { pid: "KSM-1000M-SM40-LC", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 40000, reachLabel: "LH", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: undefined, notes: "Korenix 1G SM SFP 40km" }, + { pid: "KSM-1000M-SM80-LC", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 80000, reachLabel: "ZX", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "1000BASE-ZX", notes: undefined }, + { pid: "KSM-1000M-RJ45", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 100, reachLabel: "T", fiberType: "DAC", connector: "RJ45", wavelengths: undefined, standard: "1000BASE-T", notes: undefined }, + { pid: "KSM-1000M-BX20U-LC", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 20000, reachLabel: "BiDi-20K", fiberType: "SMF", connector: "LC", wavelengths: "TX1310/RX1550", standard: undefined, notes: "Korenix 1G BiDi SFP upstream" }, + { pid: "KSM-1000M-BX20D-LC", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 20000, reachLabel: "BiDi-20K", fiberType: "SMF", connector: "LC", wavelengths: "TX1550/RX1310", standard: undefined, notes: "Korenix 1G BiDi SFP downstream" }, + + // ── 10G SFP+ ──────────────────────────────────────────────────────────── + { pid: "KSM-10G-SR-MM300-LC", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 300, reachLabel: "SR", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "10GBASE-SR", notes: undefined }, + { pid: "KSM-10G-LR-SM10-LC", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 10000, reachLabel: "LR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "10GBASE-LR", notes: undefined }, + { pid: "KSM-10G-ER-SM40-LC", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 40000, reachLabel: "ER", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "10GBASE-ER", notes: undefined }, + { pid: "KSM-10G-ZR-SM80-LC", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 80000, reachLabel: "ZR", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "10GBASE-ZR", notes: undefined }, + + // ── DAC ───────────────────────────────────────────────────────────────── + { pid: "KSM-10G-DAC-1M", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 1, reachLabel: "DAC-1M", fiberType: "DAC", connector: "SFP+", wavelengths: undefined, standard: undefined, notes: undefined }, + { pid: "KSM-10G-DAC-3M", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 3, reachLabel: "DAC-3M", fiberType: "DAC", connector: "SFP+", wavelengths: undefined, standard: undefined, notes: undefined }, +]; + +export async function scrapeKorenixOem(): Promise { + console.log("=== Korenix Technology OEM Transceiver Seed ===\n"); + + const vendorId = await ensureVendor( + "Korenix Technology", + "oem", + "https://www.korenix.com", + undefined + ); + + let inserted = 0; + let updated = 0; + let errors = 0; + + for (const p of KORENIX_PIDS) { + const slug = `korenix-${p.pid.toLowerCase().replace(/[^a-z0-9]+/g, "-")}`; + try { + const res = await pool.query( + `INSERT INTO transceivers + (slug, part_number, vendor_id, form_factor, speed, speed_gbps, + reach_meters, reach_label, fiber_type, connector, wavelengths, + dom_support, ieee_reference, market_status, category, notes) + VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,true,$12,'Mainstream','Industrial',$13) + ON CONFLICT (slug) DO UPDATE SET + speed_gbps = EXCLUDED.speed_gbps, + reach_meters = CASE WHEN EXCLUDED.reach_meters > 0 THEN EXCLUDED.reach_meters ELSE transceivers.reach_meters END, + fiber_type = CASE WHEN EXCLUDED.fiber_type <> '' THEN EXCLUDED.fiber_type ELSE transceivers.fiber_type END, + wavelengths = COALESCE(EXCLUDED.wavelengths, transceivers.wavelengths), + updated_at = NOW() + RETURNING (xmax = 0) as was_inserted`, + [slug, p.pid, vendorId, p.formFactor, p.speed, p.speedGbps, + p.reachMeters, p.reachLabel, p.fiberType, p.connector, + p.wavelengths ?? null, p.standard ?? null, p.notes ?? null] + ); + if (res.rows[0]?.was_inserted) inserted++; else updated++; + } catch (err) { + console.warn(` Skip ${p.pid}: ${(err as Error).message.slice(0, 80)}`); + errors++; + } + } + + console.log(`\n=== Korenix OEM Seed Complete ===`); + console.log(` Inserted: ${inserted}`); + console.log(` Updated: ${updated}`); + console.log(` Errors: ${errors}`); + console.log(` Total PIDs: ${KORENIX_PIDS.length}\n`); +} + +if (require.main === module) { + scrapeKorenixOem() + .then(() => pool.end()) + .catch((err) => { + console.error("Fatal:", err); + pool.end(); + process.exit(1); + }); +} diff --git a/packages/scraper/src/scrapers/lancom-oem.ts b/packages/scraper/src/scrapers/lancom-oem.ts new file mode 100644 index 0000000..22b667b --- /dev/null +++ b/packages/scraper/src/scrapers/lancom-oem.ts @@ -0,0 +1,126 @@ +/** + * LANCOM Systems OEM Transceiver Catalog Seed + * + * Seeds LANCOM-branded transceiver PIDs for GS-2xxx, XS-5xxx, and XS-6xxx + * enterprise/campus switch and router series. + * + * Sources: + * - LANCOM Systems Product Catalog (lancom-systems.com) + * - LANCOM Switch Hardware Compatibility Guide + * - LANCOM XS-6xxx/XS-5xxx Series Data Sheets + * + * Run: tsx packages/scraper/src/scrapers/lancom-oem.ts + * Cron: daily at 13:30 + */ + +import { pool, ensureVendor } from "../utils/db"; + +interface LancomPID { + pid: string; + formFactor: string; + speedGbps: number; + speed: string; + reachMeters: number; + reachLabel: string; + fiberType: string; + connector: string; + wavelengths?: string; + standard?: string; + notes?: string; +} + +const LANCOM_PIDS: LancomPID[] = [ + // ── 1G SFP ────────────────────────────────────────────────────────────── + { pid: "SFP-LX-SM1310", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 10000, reachLabel: "LX", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "1000BASE-LX", notes: "LANCOM 1G SM SFP LX" }, + { pid: "SFP-SX-MM850", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 550, reachLabel: "SX", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "1000BASE-SX", notes: "LANCOM 1G MM SFP SX" }, + { pid: "SFP-ZX-SM1550", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 80000, reachLabel: "ZX", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "1000BASE-ZX" }, + { pid: "SFP-T-RJ45", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 100, reachLabel: "T", fiberType: "DAC", connector: "RJ45", standard: "1000BASE-T" }, + { pid: "SFP-BIDI-U", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 20000, reachLabel: "BiDi-U", fiberType: "SMF", connector: "LC", wavelengths: "TX1310/RX1550", notes: "LANCOM 1G BiDi SFP upstream" }, + { pid: "SFP-BIDI-D", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 20000, reachLabel: "BiDi-D", fiberType: "SMF", connector: "LC", wavelengths: "TX1550/RX1310", notes: "LANCOM 1G BiDi SFP downstream" }, + + // ── 10G SFP+ ──────────────────────────────────────────────────────────── + { pid: "SFP-Plus-SR-MM850", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 300, reachLabel: "SR", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "10GBASE-SR" }, + { pid: "SFP-Plus-LR-SM1310", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 10000, reachLabel: "LR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "10GBASE-LR" }, + { pid: "SFP-Plus-ER-SM1550", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 40000, reachLabel: "ER", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "10GBASE-ER" }, + { pid: "SFP-Plus-ZR-SM1550", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 80000, reachLabel: "ZR", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "10GBASE-ZR" }, + { pid: "SFP-Plus-T-RJ45", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 30, reachLabel: "T", fiberType: "DAC", connector: "RJ45", standard: "10GBASE-T" }, + { pid: "SFP-Plus-BIDI-U", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 10000, reachLabel: "BiDi-U", fiberType: "SMF", connector: "LC", wavelengths: "TX1270/RX1330", notes: "LANCOM 10G BiDi SFP+ upstream" }, + + // ── 25G SFP28 ─────────────────────────────────────────────────────────── + { pid: "SFP28-SR-MM850", formFactor: "SFP28", speedGbps: 25, speed: "25G", reachMeters: 100, reachLabel: "SR", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "25GBASE-SR" }, + { pid: "SFP28-LR-SM1310", formFactor: "SFP28", speedGbps: 25, speed: "25G", reachMeters: 10000, reachLabel: "LR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "25GBASE-LR" }, + + // ── 40G QSFP+ ─────────────────────────────────────────────────────────── + { pid: "QSFP-Plus-SR4-MM850", formFactor: "QSFP+", speedGbps: 40, speed: "40G", reachMeters: 150, reachLabel: "SR4", fiberType: "MMF", connector: "MPO", wavelengths: "850nm", standard: "40GBASE-SR4" }, + { pid: "QSFP-Plus-LR4-SM1310", formFactor: "QSFP+", speedGbps: 40, speed: "40G", reachMeters: 10000, reachLabel: "LR4", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "40GBASE-LR4" }, + + // ── 100G QSFP28 ───────────────────────────────────────────────────────── + { pid: "QSFP28-SR4-MM850", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 100, reachLabel: "SR4", fiberType: "MMF", connector: "MPO", wavelengths: "850nm", standard: "100GBASE-SR4" }, + { pid: "QSFP28-LR4-SM1310", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 10000, reachLabel: "LR4", fiberType: "SMF", connector: "LC", wavelengths: "1295-1310nm", standard: "100GBASE-LR4" }, + { pid: "QSFP28-CWDM4-SM", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 2000, reachLabel: "CWDM4", fiberType: "SMF", connector: "LC", wavelengths: "1271-1331nm", standard: "100GBASE-CWDM4" }, + { pid: "QSFP28-DR-SM1310", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 500, reachLabel: "DR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "100GBASE-DR" }, + + // ── DAC ───────────────────────────────────────────────────────────────── + { pid: "DAC-SFP-Plus-1M", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 1, reachLabel: "DAC-1M", fiberType: "DAC", connector: "SFP+" }, + { pid: "DAC-SFP-Plus-3M", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 3, reachLabel: "DAC-3M", fiberType: "DAC", connector: "SFP+" }, + { pid: "DAC-QSFP28-1M", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 1, reachLabel: "DAC-1M", fiberType: "DAC", connector: "QSFP28" }, + { pid: "DAC-QSFP28-3M", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 3, reachLabel: "DAC-3M", fiberType: "DAC", connector: "QSFP28" }, +]; + +export async function scrapeLancomOem(): Promise { + console.log("=== LANCOM Systems OEM Transceiver Seed ===\n"); + + const vendorId = await ensureVendor( + "LANCOM Systems", + "oem", + "https://www.lancom-systems.com", + undefined + ); + + let inserted = 0; + let updated = 0; + let errors = 0; + + for (const p of LANCOM_PIDS) { + const slug = `lancom-${p.pid.toLowerCase().replace(/[^a-z0-9]+/g, "-")}`; + try { + const res = await pool.query( + `INSERT INTO transceivers + (slug, part_number, vendor_id, form_factor, speed, speed_gbps, + reach_meters, reach_label, fiber_type, connector, wavelengths, + dom_support, ieee_reference, market_status, category, notes) + VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,true,$12,'Mainstream','DataCenter',$13) + ON CONFLICT (slug) DO UPDATE SET + speed_gbps = EXCLUDED.speed_gbps, + reach_meters = CASE WHEN EXCLUDED.reach_meters > 0 THEN EXCLUDED.reach_meters ELSE transceivers.reach_meters END, + fiber_type = CASE WHEN EXCLUDED.fiber_type <> '' THEN EXCLUDED.fiber_type ELSE transceivers.fiber_type END, + wavelengths = COALESCE(EXCLUDED.wavelengths, transceivers.wavelengths), + updated_at = NOW() + RETURNING (xmax = 0) as was_inserted`, + [slug, p.pid, vendorId, p.formFactor, p.speed, p.speedGbps, + p.reachMeters, p.reachLabel, p.fiberType, p.connector, + p.wavelengths ?? null, p.standard ?? null, p.notes ?? null] + ); + if (res.rows[0]?.was_inserted) inserted++; else updated++; + } catch (err) { + console.warn(` Skip ${p.pid}: ${(err as Error).message.slice(0, 80)}`); + errors++; + } + } + + console.log(`\n=== LANCOM Systems OEM Seed Complete ===`); + console.log(` Inserted: ${inserted}`); + console.log(` Updated: ${updated}`); + console.log(` Errors: ${errors}`); + console.log(` Total PIDs: ${LANCOM_PIDS.length}\n`); +} + +if (require.main === module) { + scrapeLancomOem() + .then(() => pool.end()) + .catch((err) => { + console.error("Fatal:", err); + pool.end(); + process.exit(1); + }); +} diff --git a/packages/scraper/src/scrapers/lumentum-oem.ts b/packages/scraper/src/scrapers/lumentum-oem.ts new file mode 100644 index 0000000..c061b5f --- /dev/null +++ b/packages/scraper/src/scrapers/lumentum-oem.ts @@ -0,0 +1,135 @@ +/** + * Lumentum OEM Transceiver Catalog Seed + * + * Seeds Lumentum-branded transceiver PIDs covering DataCenter and Telecom + * portfolios. Lumentum is a leading OEM optical transceiver manufacturer + * supplying modules to major network vendors and hyperscalers. + * + * Sources: + * - Lumentum Product Catalog (lumentum.com/en-us/products/optical-transceivers) + * - Lumentum 400ZR / ZR+ Coherent Module Datasheet + * - IEEE 802.3 / OIF 400ZR / OpenZR+ MSA Standards + * + * Run: tsx packages/scraper/src/scrapers/lumentum-oem.ts + * Cron: daily at 20:15 + */ + +import { pool, ensureVendor } from "../utils/db"; + +interface LumentumPID { + pid: string; + formFactor: string; + speedGbps: number; + speed: string; + reachMeters: number; + reachLabel: string; + fiberType: string; + connector: string; + wavelengths?: string; + standard?: string; + category?: string; + notes?: string; +} + +// PIDs that belong to the Telecom category (coherent, DWDM, ZR) +const TELECOM_PIDS = new Set([ + "LMT-SFP10G-ZR", + "LMT-DWDM-SFP10G-TUNE", + "LMT-QSFP28-100G-ZR4", + "LMT-CFP2-DCO-100G", + "LMT-QSFPDD-400G-ZR", +]); + +const LUMENTUM_PIDS: LumentumPID[] = [ + // ── 10G SFP+ ──────────────────────────────────────────────────────────── + { pid: "LMT-SFP10G-SR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 300, reachLabel: "SR", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "10GBASE-SR", notes: "Lumentum 10G SFP+ SR 300m MMF" }, + { pid: "LMT-SFP10G-LR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 10000, reachLabel: "LR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "10GBASE-LR", notes: "Lumentum 10G SFP+ LR 10km SMF" }, + { pid: "LMT-SFP10G-ER", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 40000, reachLabel: "ER", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "10GBASE-ER", notes: "Lumentum 10G SFP+ ER 40km SMF" }, + { pid: "LMT-SFP10G-ZR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 80000, reachLabel: "ZR", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "10GBASE-ZR", notes: "Lumentum 10G SFP+ ZR 80km SMF" }, + + // ── 10G DWDM SFP+ C-band tunable (Telecom) ────────────────────────────── + { pid: "LMT-DWDM-SFP10G-TUNE", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 80000, reachLabel: "DWDM", fiberType: "SMF", connector: "LC", wavelengths: "C-band tunable", category: "Telecom", notes: "Lumentum 10G DWDM SFP+ C-band tunable for metro/long-haul DWDM rings" }, + + // ── 25G SFP28 ─────────────────────────────────────────────────────────── + { pid: "LMT-SFP28-25G-SR", formFactor: "SFP28", speedGbps: 25, speed: "25G", reachMeters: 300, reachLabel: "SR", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "25GBASE-SR", notes: "Lumentum 25G SFP28 SR 300m MMF" }, + { pid: "LMT-SFP28-25G-LR", formFactor: "SFP28", speedGbps: 25, speed: "25G", reachMeters: 10000, reachLabel: "LR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "25GBASE-LR", notes: "Lumentum 25G SFP28 LR 10km SMF" }, + + // ── 40G QSFP+ ─────────────────────────────────────────────────────────── + { pid: "LMT-QSFP-40G-SR4", formFactor: "QSFP+", speedGbps: 40, speed: "40G", reachMeters: 150, reachLabel: "SR4", fiberType: "MMF", connector: "MPO", wavelengths: "850nm", standard: "40GBASE-SR4", notes: "Lumentum 40G QSFP+ SR4 150m MMF" }, + { pid: "LMT-QSFP-40G-LR4", formFactor: "QSFP+", speedGbps: 40, speed: "40G", reachMeters: 10000, reachLabel: "LR4", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "40GBASE-LR4", notes: "Lumentum 40G QSFP+ LR4 10km SMF" }, + + // ── 100G QSFP28 ───────────────────────────────────────────────────────── + { pid: "LMT-QSFP28-100G-SR4", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 100, reachLabel: "SR4", fiberType: "MMF", connector: "MPO", wavelengths: "850nm", standard: "100GBASE-SR4", notes: "Lumentum 100G QSFP28 SR4 100m MMF" }, + { pid: "LMT-QSFP28-100G-LR4", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 10000, reachLabel: "LR4", fiberType: "SMF", connector: "LC", wavelengths: "1295-1310nm", standard: "100GBASE-LR4", notes: "Lumentum 100G QSFP28 LR4 10km SMF" }, + { pid: "LMT-QSFP28-100G-ER4", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 40000, reachLabel: "ER4", fiberType: "SMF", connector: "LC", wavelengths: "1295-1310nm", standard: "100GBASE-ER4", notes: "Lumentum 100G QSFP28 ER4 40km SMF" }, + { pid: "LMT-QSFP28-100G-ZR4", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 80000, reachLabel: "ZR4", fiberType: "SMF", connector: "LC", wavelengths: "C-band DWDM", category: "Telecom", notes: "Lumentum 100G QSFP28 ZR4 80km coherent" }, + + // ── 100G CFP2-DCO Coherent (Telecom) ──────────────────────────────────── + { pid: "LMT-CFP2-DCO-100G", formFactor: "CFP2", speedGbps: 100, speed: "100G", reachMeters: 1000000, reachLabel: "DCO", fiberType: "SMF", connector: "LC", wavelengths: "C-band DWDM", category: "Telecom", notes: "Lumentum 100G CFP2-DCO coherent, up to 1000km" }, + + // ── 400G QSFP-DD ──────────────────────────────────────────────────────── + { pid: "LMT-QSFPDD-400G-DR4", formFactor: "QSFP-DD", speedGbps: 400, speed: "400G", reachMeters: 500, reachLabel: "DR4", fiberType: "SMF", connector: "MPO", wavelengths: "1310nm", standard: "400GBASE-DR4", notes: "Lumentum 400G QSFP-DD DR4 500m SMF" }, + { pid: "LMT-QSFPDD-400G-FR4", formFactor: "QSFP-DD", speedGbps: 400, speed: "400G", reachMeters: 2000, reachLabel: "FR4", fiberType: "SMF", connector: "LC", wavelengths: "1271-1331nm", standard: "400GBASE-FR4", notes: "Lumentum 400G QSFP-DD FR4 2km SMF" }, + + // ── 400G ZR QSFP-DD Coherent (Telecom) ────────────────────────────────── + { pid: "LMT-QSFPDD-400G-ZR", formFactor: "QSFP-DD", speedGbps: 400, speed: "400G", reachMeters: 1000000, reachLabel: "ZR", fiberType: "SMF", connector: "LC", wavelengths: "C-band DWDM", standard: "400ZR", category: "Telecom", notes: "Lumentum 400G ZR QSFP-DD coherent, up to 1000km" }, +]; + +export async function scrapeLumentumOem(): Promise { + console.log("=== Lumentum OEM Transceiver Seed ===\n"); + + const vendorId = await ensureVendor( + "Lumentum", + "oem", + "https://www.lumentum.com", + undefined + ); + + let inserted = 0; + let updated = 0; + let errors = 0; + + for (const p of LUMENTUM_PIDS) { + const slug = `lumentum-${p.pid.toLowerCase().replace(/[^a-z0-9]+/g, "-")}`; + const category = p.category ?? (TELECOM_PIDS.has(p.pid) ? "Telecom" : "DataCenter"); + try { + const res = await pool.query( + `INSERT INTO transceivers + (slug, part_number, vendor_id, form_factor, speed, speed_gbps, + reach_meters, reach_label, fiber_type, connector, wavelengths, + dom_support, ieee_reference, market_status, category, notes) + VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,true,$12,'Mainstream',$13,$14) + ON CONFLICT (slug) DO UPDATE SET + speed_gbps = EXCLUDED.speed_gbps, + reach_meters = CASE WHEN EXCLUDED.reach_meters > 0 THEN EXCLUDED.reach_meters ELSE transceivers.reach_meters END, + fiber_type = CASE WHEN EXCLUDED.fiber_type <> '' THEN EXCLUDED.fiber_type ELSE transceivers.fiber_type END, + wavelengths = COALESCE(EXCLUDED.wavelengths, transceivers.wavelengths), + updated_at = NOW() + RETURNING (xmax = 0) as was_inserted`, + [slug, p.pid, vendorId, p.formFactor, p.speed, p.speedGbps, + p.reachMeters, p.reachLabel, p.fiberType, p.connector, + p.wavelengths ?? null, p.standard ?? null, category, p.notes ?? null] + ); + if (res.rows[0]?.was_inserted) inserted++; else updated++; + } catch (err) { + console.warn(` Skip ${p.pid}: ${(err as Error).message.slice(0, 80)}`); + errors++; + } + } + + console.log(`\n=== Lumentum OEM Seed Complete ===`); + console.log(` Inserted: ${inserted}`); + console.log(` Updated: ${updated}`); + console.log(` Errors: ${errors}`); + console.log(` Total PIDs: ${LUMENTUM_PIDS.length}\n`); +} + +if (require.main === module) { + scrapeLumentumOem() + .then(() => pool.end()) + .catch((err) => { + console.error("Fatal:", err); + pool.end(); + process.exit(1); + }); +} diff --git a/packages/scraper/src/scrapers/marvell-oem.ts b/packages/scraper/src/scrapers/marvell-oem.ts new file mode 100644 index 0000000..a16c794 --- /dev/null +++ b/packages/scraper/src/scrapers/marvell-oem.ts @@ -0,0 +1,133 @@ +/** + * Marvell OEM Transceiver Catalog Seed + * + * Seeds Marvell-branded transceiver PIDs including QLogic FC HBA SFPs + * (acquired 2021) for Fibre Channel SANs, plus Ethernet modules for + * Prestera, Octeon, and ASIC-attached platforms. + * + * Sources: + * - Marvell Product Catalog (marvell.com) + * - QLogic 2700/2600/2500 Series FC HBA Optical Transceiver Guide + * - Marvell Prestera DX/CX Switch ASIC Hardware Guide + * + * Run: tsx packages/scraper/src/scrapers/marvell-oem.ts + * Cron: daily at 22:00 + */ + +import { pool, ensureVendor } from "../utils/db"; + +interface MarvellPID { + pid: string; + formFactor: string; + speedGbps: number; + speed: string; + reachMeters: number; + reachLabel: string; + fiberType: string; + connector: string; + wavelengths?: string; + standard?: string; + notes?: string; +} + +const MARVELL_PIDS: MarvellPID[] = [ + // ── Fibre Channel SFP (QLogic / Marvell HBA) ──────────────────────────── + { pid: "MRVL-SFP-8G-FC-SW", formFactor: "SFP+", speedGbps: 8, speed: "8G", reachMeters: 500, reachLabel: "SW", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "8GFC", notes: "Marvell/QLogic 8G Fibre Channel SFP+ short-wave, QLE2560/2562" }, + { pid: "MRVL-SFP-8G-FC-LW", formFactor: "SFP+", speedGbps: 8, speed: "8G", reachMeters: 10000, reachLabel: "LW", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "8GFC", notes: "Marvell/QLogic 8G Fibre Channel SFP+ long-wave" }, + { pid: "MRVL-SFP-16G-FC-SW", formFactor: "SFP+", speedGbps: 16, speed: "16G", reachMeters: 300, reachLabel: "SW", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "16GFC", notes: "Marvell/QLogic 16G Fibre Channel SFP+ short-wave, QLE2672" }, + { pid: "MRVL-SFP-16G-FC-LW", formFactor: "SFP+", speedGbps: 16, speed: "16G", reachMeters: 10000, reachLabel: "LW", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "16GFC", notes: "Marvell/QLogic 16G Fibre Channel SFP+ long-wave" }, + { pid: "MRVL-SFP-32G-FC-SW", formFactor: "SFP28", speedGbps: 32, speed: "32G", reachMeters: 100, reachLabel: "SW", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "32GFC", notes: "Marvell/QLogic 32G Fibre Channel SFP28 short-wave, QLE2742" }, + { pid: "MRVL-SFP-32G-FC-LW", formFactor: "SFP28", speedGbps: 32, speed: "32G", reachMeters: 10000, reachLabel: "LW", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "32GFC", notes: "Marvell/QLogic 32G Fibre Channel SFP28 long-wave" }, + + // ── 1G SFP ────────────────────────────────────────────────────────────── + { pid: "MRVL-SFP-1G-SX", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 550, reachLabel: "SX", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "1000BASE-SX" }, + { pid: "MRVL-SFP-1G-LX", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 10000, reachLabel: "LX", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "1000BASE-LX" }, + + // ── 10G SFP+ ──────────────────────────────────────────────────────────── + { pid: "MRVL-SFP+-10G-SR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 300, reachLabel: "SR", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "10GBASE-SR" }, + { pid: "MRVL-SFP+-10G-LR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 10000, reachLabel: "LR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "10GBASE-LR" }, + { pid: "MRVL-SFP+-10G-ER", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 40000, reachLabel: "ER", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "10GBASE-ER" }, + { pid: "MRVL-SFP+-10G-ZR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 80000, reachLabel: "ZR", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "10GBASE-ZR" }, + { pid: "MRVL-SFP+-10G-T", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 30, reachLabel: "T", fiberType: "DAC", connector: "RJ45", standard: "10GBASE-T", notes: "Marvell 10GBASE-T copper SFP+" }, + + // ── 25G SFP28 ─────────────────────────────────────────────────────────── + { pid: "MRVL-SFP28-25G-SR", formFactor: "SFP28", speedGbps: 25, speed: "25G", reachMeters: 100, reachLabel: "SR", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "25GBASE-SR" }, + { pid: "MRVL-SFP28-25G-LR", formFactor: "SFP28", speedGbps: 25, speed: "25G", reachMeters: 10000, reachLabel: "LR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "25GBASE-LR" }, + { pid: "MRVL-SFP-25G-ER", formFactor: "SFP28", speedGbps: 25, speed: "25G", reachMeters: 30000, reachLabel: "ER", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", notes: "Marvell 25G ER for Prestera DX inter-DC link" }, + + // ── 40G QSFP+ ─────────────────────────────────────────────────────────── + { pid: "MRVL-QSFP-40G-SR4", formFactor: "QSFP+", speedGbps: 40, speed: "40G", reachMeters: 150, reachLabel: "SR4", fiberType: "MMF", connector: "MPO", wavelengths: "850nm", standard: "40GBASE-SR4" }, + { pid: "MRVL-QSFP-40G-LR4", formFactor: "QSFP+", speedGbps: 40, speed: "40G", reachMeters: 10000, reachLabel: "LR4", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "40GBASE-LR4" }, + + // ── 100G QSFP28 ───────────────────────────────────────────────────────── + { pid: "MRVL-QSFP28-100G-SR4", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 100, reachLabel: "SR4", fiberType: "MMF", connector: "MPO", wavelengths: "850nm", standard: "100GBASE-SR4" }, + { pid: "MRVL-QSFP28-100G-LR4", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 10000, reachLabel: "LR4", fiberType: "SMF", connector: "LC", wavelengths: "1295-1310nm", standard: "100GBASE-LR4" }, + + // ── 200G QSFP56 ───────────────────────────────────────────────────────── + { pid: "MRVL-QSFP56-200G-SR4", formFactor: "QSFP56", speedGbps: 200, speed: "200G", reachMeters: 100, reachLabel: "SR4", fiberType: "MMF", connector: "MPO", wavelengths: "850nm", notes: "Marvell 200G QSFP56 SR4 for Prestera CX spine" }, + { pid: "MRVL-QSFP56-200G-DR", formFactor: "QSFP56", speedGbps: 200, speed: "200G", reachMeters: 500, reachLabel: "DR", fiberType: "SMF", connector: "MPO", wavelengths: "1310nm", notes: "Marvell 200G QSFP56 DR for campus aggregation" }, + + // ── 400G QSFP-DD ──────────────────────────────────────────────────────── + { pid: "MRVL-QSFPDD-400G-SR8", formFactor: "QSFP-DD",speedGbps: 400, speed: "400G", reachMeters: 100, reachLabel: "SR8", fiberType: "MMF", connector: "MPO", wavelengths: "850nm", standard: "400GBASE-SR8" }, + { pid: "MRVL-QSFPDD-400G-DR4", formFactor: "QSFP-DD",speedGbps: 400, speed: "400G", reachMeters: 500, reachLabel: "DR4", fiberType: "SMF", connector: "MPO", wavelengths: "1310nm", standard: "400GBASE-DR4" }, + { pid: "MRVL-QSFPDD-400G-FR4", formFactor: "QSFP-DD",speedGbps: 400, speed: "400G", reachMeters: 2000, reachLabel: "FR4", fiberType: "SMF", connector: "LC", wavelengths: "1271-1331nm", standard: "400GBASE-FR4" }, + { pid: "MRVL-QSFPDD-400G-LR4", formFactor: "QSFP-DD",speedGbps: 400, speed: "400G", reachMeters: 10000, reachLabel: "LR4", fiberType: "SMF", connector: "LC", wavelengths: "1295-1310nm", standard: "400GBASE-LR4" }, +]; + +export async function scrapeMarvellOem(): Promise { + console.log("=== Marvell OEM Transceiver Seed ===\n"); + + const vendorId = await ensureVendor( + "Marvell", + "oem", + "https://www.marvell.com", + undefined + ); + + let inserted = 0; + let updated = 0; + let errors = 0; + + for (const p of MARVELL_PIDS) { + const slug = `marvell-${p.pid.toLowerCase().replace(/[^a-z0-9]+/g, "-")}`; + try { + const res = await pool.query( + `INSERT INTO transceivers + (slug, part_number, vendor_id, form_factor, speed, speed_gbps, + reach_meters, reach_label, fiber_type, connector, wavelengths, + dom_support, ieee_reference, market_status, category, notes) + VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,true,$12,'Mainstream','DataCenter',$13) + ON CONFLICT (slug) DO UPDATE SET + speed_gbps = EXCLUDED.speed_gbps, + reach_meters = CASE WHEN EXCLUDED.reach_meters > 0 THEN EXCLUDED.reach_meters ELSE transceivers.reach_meters END, + fiber_type = CASE WHEN EXCLUDED.fiber_type <> '' THEN EXCLUDED.fiber_type ELSE transceivers.fiber_type END, + wavelengths = COALESCE(EXCLUDED.wavelengths, transceivers.wavelengths), + updated_at = NOW() + RETURNING (xmax = 0) as was_inserted`, + [slug, p.pid, vendorId, p.formFactor, p.speed, p.speedGbps, + p.reachMeters, p.reachLabel, p.fiberType, p.connector, + p.wavelengths ?? null, p.standard ?? null, p.notes ?? null] + ); + if (res.rows[0]?.was_inserted) inserted++; else updated++; + } catch (err) { + console.warn(` Skip ${p.pid}: ${(err as Error).message.slice(0, 80)}`); + errors++; + } + } + + console.log(`\n=== Marvell OEM Seed Complete ===`); + console.log(` Inserted: ${inserted}`); + console.log(` Updated: ${updated}`); + console.log(` Errors: ${errors}`); + console.log(` Total PIDs: ${MARVELL_PIDS.length}\n`); +} + +if (require.main === module) { + scrapeMarvellOem() + .then(() => pool.end()) + .catch((err) => { + console.error("Fatal:", err); + pool.end(); + process.exit(1); + }); +} diff --git a/packages/scraper/src/scrapers/mavenir-oem.ts b/packages/scraper/src/scrapers/mavenir-oem.ts new file mode 100644 index 0000000..37d006a --- /dev/null +++ b/packages/scraper/src/scrapers/mavenir-oem.ts @@ -0,0 +1,123 @@ +/** + * Mavenir OEM Transceiver Catalog Seed + * + * Seeds Mavenir-branded transceiver PIDs used in Open RAN and cloud-native + * 5G deployments (vBBU / vDU / vCU optical interfaces for Mavenir's + * Open vRAN, MavCore, and MavAIR product lines). + * + * Sources: + * - Mavenir Product Portfolio (mavenir.com) + * - O-RAN Alliance WG4 fronthaul transport specifications + * - Open vRAN hardware compatibility guides + * + * Run: tsx packages/scraper/src/scrapers/mavenir-oem.ts + * Cron: daily at 10:00 + */ + +import { pool, ensureVendor } from "../utils/db"; + +interface MavenirPID { + pid: string; + formFactor: string; + speedGbps: number; + speed: string; + reachMeters: number; + reachLabel: string; + fiberType: string; + connector: string; + wavelengths?: string; + standard?: string; + notes?: string; +} + +const MAVENIR_PIDS: MavenirPID[] = [ + // ── 1G SFP ────────────────────────────────────────────────────────────── + { pid: "MAV-SFP-1G-SX", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 550, reachLabel: "SX", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "1000BASE-SX", notes: "Mavenir 1G SFP SX for Open vRAN management / cell site uplink" }, + { pid: "MAV-SFP-1G-LX", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 10000, reachLabel: "LX", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "1000BASE-LX", notes: "Mavenir 1G SFP LX for cell site uplink" }, + + // ── 10G SFP+ ──────────────────────────────────────────────────────────── + { pid: "MAV-SFP-10G-SR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 300, reachLabel: "SR", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "10GBASE-SR", notes: "Mavenir 10G SFP+ SR for Open vRAN eCPRI fronthaul intra-site" }, + { pid: "MAV-SFP-10G-LR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 10000, reachLabel: "LR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "10GBASE-LR", notes: "Mavenir 10G SFP+ LR for Open vRAN eCPRI fronthaul long-reach" }, + + // ── 10G Copper SFP+ ───────────────────────────────────────────────────── + { pid: "MAV-SFP-10G-T", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 100, reachLabel: "T", fiberType: "DAC", connector: "RJ45", standard: "10GBASE-T", notes: "Mavenir 10G copper SFP+ for vBBU server NIC management" }, + + // ── 25G SFP28 ─────────────────────────────────────────────────────────── + { pid: "MAV-SFP28-25G-SR", formFactor: "SFP28", speedGbps: 25, speed: "25G", reachMeters: 100, reachLabel: "SR", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "25GBASE-SR", notes: "Mavenir 25G SFP28 SR for Open RAN eCPRI fronthaul (O-RAN WG4 split 7-2x)" }, + { pid: "MAV-SFP28-25G-LR", formFactor: "SFP28", speedGbps: 25, speed: "25G", reachMeters: 10000, reachLabel: "LR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "25GBASE-LR", notes: "Mavenir 25G SFP28 LR for long-reach Open RAN fronthaul" }, + + // ── 40G QSFP+ ─────────────────────────────────────────────────────────── + { pid: "MAV-QSFP-40G-SR4", formFactor: "QSFP+", speedGbps: 40, speed: "40G", reachMeters: 150, reachLabel: "SR4", fiberType: "MMF", connector: "MPO", wavelengths: "850nm", standard: "40GBASE-SR4", notes: "Mavenir 40G QSFP+ SR4 for vBBU aggregation fabric" }, + { pid: "MAV-QSFP-40G-LR4", formFactor: "QSFP+", speedGbps: 40, speed: "40G", reachMeters: 10000, reachLabel: "LR4", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "40GBASE-LR4" }, + + // ── 100G QSFP28 ───────────────────────────────────────────────────────── + { pid: "MAV-QSFP28-100G-SR4", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 100, reachLabel: "SR4", fiberType: "MMF", connector: "MPO", wavelengths: "850nm", standard: "100GBASE-SR4", notes: "Mavenir 100G QSFP28 SR4 for cloud-native 5G vDU-to-switch fabric" }, + { pid: "MAV-QSFP28-100G-LR4", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 10000, reachLabel: "LR4", fiberType: "SMF", connector: "LC", wavelengths: "1295-1310nm", standard: "100GBASE-LR4", notes: "Mavenir 100G QSFP28 LR4 for vCU/vDU midhaul interconnect" }, + + // ── 400G QSFP-DD ──────────────────────────────────────────────────────── + { pid: "MAV-QSFP-DD-400G-DR4", formFactor: "QSFP-DD", speedGbps: 400, speed: "400G", reachMeters: 500, reachLabel: "DR4", fiberType: "SMF", connector: "MPO", wavelengths: "1310nm", standard: "400GBASE-DR4", notes: "Mavenir 400G QSFP-DD for cloud-native 5G core (MavCore) data center fabric" }, + + // ── Copper GE SFP ─────────────────────────────────────────────────────── + { pid: "MAV-SFP-GE-T", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 100, reachLabel: "T", fiberType: "DAC", connector: "RJ45", standard: "1000BASE-T", notes: "Mavenir copper GE SFP for OAM management plane" }, + + // ── BiDi SFP+ (single-fiber fronthaul) ────────────────────────────────── + { pid: "MAV-SFP-10G-BIDI-1270", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 20000, reachLabel: "BIDI", fiberType: "SMF", connector: "LC", wavelengths: "1270/1330nm", notes: "Mavenir BiDi SFP+ Tx1270/Rx1330 for Open RAN eCPRI single-fiber fronthaul runs" }, +]; + +export async function scrapeMavenirOem(): Promise { + console.log("=== Mavenir OEM Transceiver Seed ===\n"); + + const vendorId = await ensureVendor( + "Mavenir", + "oem", + "https://mavenir.com", + undefined + ); + + let inserted = 0; + let updated = 0; + let errors = 0; + + for (const p of MAVENIR_PIDS) { + const slug = `mavenir-${p.pid.toLowerCase().replace(/[^a-z0-9]+/g, "-")}`; + try { + const res = await pool.query( + `INSERT INTO transceivers + (slug, part_number, vendor_id, form_factor, speed, speed_gbps, + reach_meters, reach_label, fiber_type, connector, wavelengths, + dom_support, ieee_reference, market_status, category, notes) + VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,true,$12,'Mainstream','DataCenter',$13) + ON CONFLICT (slug) DO UPDATE SET + speed_gbps = EXCLUDED.speed_gbps, + reach_meters = CASE WHEN EXCLUDED.reach_meters > 0 THEN EXCLUDED.reach_meters ELSE transceivers.reach_meters END, + fiber_type = CASE WHEN EXCLUDED.fiber_type <> '' THEN EXCLUDED.fiber_type ELSE transceivers.fiber_type END, + wavelengths = COALESCE(EXCLUDED.wavelengths, transceivers.wavelengths), + updated_at = NOW() + RETURNING (xmax = 0) as was_inserted`, + [slug, p.pid, vendorId, p.formFactor, p.speed, p.speedGbps, + p.reachMeters, p.reachLabel, p.fiberType, p.connector, + p.wavelengths ?? null, p.standard ?? null, p.notes ?? null] + ); + if (res.rows[0]?.was_inserted) inserted++; else updated++; + } catch (err) { + console.warn(` Skip ${p.pid}: ${(err as Error).message.slice(0, 80)}`); + errors++; + } + } + + console.log(`\n=== Mavenir OEM Seed Complete ===`); + console.log(` Inserted: ${inserted}`); + console.log(` Updated: ${updated}`); + console.log(` Errors: ${errors}`); + console.log(` Total PIDs: ${MAVENIR_PIDS.length}\n`); +} + +if (require.main === module) { + scrapeMavenirOem() + .then(() => pool.end()) + .catch((err) => { + console.error("Fatal:", err); + pool.end(); + process.exit(1); + }); +} diff --git a/packages/scraper/src/scrapers/mellanox-oem.ts b/packages/scraper/src/scrapers/mellanox-oem.ts new file mode 100644 index 0000000..832ddf1 --- /dev/null +++ b/packages/scraper/src/scrapers/mellanox-oem.ts @@ -0,0 +1,136 @@ +/** + * Mellanox (NVIDIA Networking) OEM Transceiver Catalog Seed + * + * Seeds Mellanox-branded transceiver PIDs (MFM/MMA prefix) for + * ConnectX NICs and Spectrum/Quantum series switches. + * + * Sources: + * - NVIDIA Networking Product Catalog (nvidia.com/networking) + * - Mellanox Optical Transceiver Compatibility Matrix + * - ConnectX-5/7/8 and Quantum-3 hardware guides + * + * Run: tsx packages/scraper/src/scrapers/mellanox-oem.ts + * Cron: daily at 15:00 + */ + +import { pool, ensureVendor } from "../utils/db"; + +interface MellanoxPID { + pid: string; + formFactor: string; + speedGbps: number; + speed: string; + reachMeters: number; + reachLabel: string; + fiberType: string; + connector: string; + wavelengths?: string; + standard?: string; + notes?: string; +} + +const MELLANOX_PIDS: MellanoxPID[] = [ + // ── 1G SFP ────────────────────────────────────────────────────────────── + { pid: "MFM1T02A-SR", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 550, reachLabel: "SX", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "1000BASE-SX" }, + { pid: "MFM1T02A-LR", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 10000, reachLabel: "LX", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "1000BASE-LX" }, + + // ── 10G SFP+ ──────────────────────────────────────────────────────────── + { pid: "MFM10011A-SR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 300, reachLabel: "SR", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "10GBASE-SR", notes: "Mellanox 10G SFP+ SR for ConnectX" }, + { pid: "MFM10011A-LR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 10000, reachLabel: "LR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "10GBASE-LR" }, + { pid: "MFM10011A-ER", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 40000, reachLabel: "ER", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "10GBASE-ER" }, + { pid: "MFM10011A-ZR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 80000, reachLabel: "ZR", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "10GBASE-ZR" }, + { pid: "MFM10011A-T", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 30, reachLabel: "T", fiberType: "DAC", connector: "RJ45", standard: "10GBASE-T" }, + + // ── 25G SFP28 ─────────────────────────────────────────────────────────── + { pid: "MMA1B00-AS", formFactor: "SFP28", speedGbps: 25, speed: "25G", reachMeters: 100, reachLabel: "SR", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "25GBASE-SR", notes: "Mellanox 25G SFP28 SR for Spectrum/ConnectX" }, + { pid: "MMA1B00-AL", formFactor: "SFP28", speedGbps: 25, speed: "25G", reachMeters: 10000, reachLabel: "LR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "25GBASE-LR" }, + { pid: "MMA1B00-AE", formFactor: "SFP28", speedGbps: 25, speed: "25G", reachMeters: 30000, reachLabel: "ER", fiberType: "SMF", connector: "LC", wavelengths: "1310nm" }, + + // ── 40G QSFP+ ─────────────────────────────────────────────────────────── + { pid: "MFM1532B-04", formFactor: "QSFP+", speedGbps: 40, speed: "40G", reachMeters: 150, reachLabel: "SR4", fiberType: "MMF", connector: "MPO", wavelengths: "850nm", standard: "40GBASE-SR4" }, + { pid: "MFM1532B-LR", formFactor: "QSFP+", speedGbps: 40, speed: "40G", reachMeters: 10000, reachLabel: "LR4", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "40GBASE-LR4" }, + + // ── 100G QSFP28 ───────────────────────────────────────────────────────── + { pid: "MMA1B00-HS", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 100, reachLabel: "SR4", fiberType: "MMF", connector: "MPO", wavelengths: "850nm", standard: "100GBASE-SR4", notes: "Mellanox 100G QSFP28 SR4 for ConnectX-5" }, + { pid: "MMA1B00-HL", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 10000, reachLabel: "LR4", fiberType: "SMF", connector: "LC", wavelengths: "1295-1310nm", standard: "100GBASE-LR4" }, + { pid: "MMA1B00-HC", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 2000, reachLabel: "CWDM4", fiberType: "SMF", connector: "LC", wavelengths: "1271-1331nm", standard: "100GBASE-CWDM4" }, + { pid: "MMA1B00-HD", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 500, reachLabel: "DR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "100GBASE-DR" }, + + // ── 200G QSFP56 ───────────────────────────────────────────────────────── + { pid: "MMA1B00-VS", formFactor: "QSFP56", speedGbps: 200, speed: "200G", reachMeters: 100, reachLabel: "SR4", fiberType: "MMF", connector: "MPO", wavelengths: "850nm", standard: "200GBASE-SR4", notes: "Mellanox 200G QSFP56 SR4" }, + { pid: "MMA1B00-VL", formFactor: "QSFP56", speedGbps: 200, speed: "200G", reachMeters: 10000, reachLabel: "LR4", fiberType: "SMF", connector: "LC", wavelengths: "1295-1310nm", standard: "200GBASE-LR4" }, + + // ── 400G QSFP-DD ──────────────────────────────────────────────────────── + { pid: "MMA1B00-AS400", formFactor: "QSFP-DD", speedGbps: 400, speed: "400G", reachMeters: 100, reachLabel: "SR8", fiberType: "MMF", connector: "MPO", wavelengths: "850nm", standard: "400GBASE-SR8", notes: "Mellanox 400G QSFP-DD SR8 for ConnectX-7" }, + { pid: "MMA1B00-AR400", formFactor: "QSFP-DD", speedGbps: 400, speed: "400G", reachMeters: 500, reachLabel: "DR4", fiberType: "SMF", connector: "MPO", wavelengths: "1310nm", standard: "400GBASE-DR4" }, + { pid: "MMA1B00-AF400", formFactor: "QSFP-DD", speedGbps: 400, speed: "400G", reachMeters: 2000, reachLabel: "FR4", fiberType: "SMF", connector: "LC", wavelengths: "1271-1331nm", standard: "400GBASE-FR4" }, + + // ── 800G OSFP (ConnectX-8 / Quantum-3) ────────────────────────────────── + { pid: "MMA4Z00-NS", formFactor: "OSFP", speedGbps: 800, speed: "800G", reachMeters: 500, reachLabel: "SR8", fiberType: "MMF", connector: "MPO", wavelengths: "850nm", standard: "800GBASE-SR8", notes: "Mellanox 800G OSFP SR8 for ConnectX-8/Quantum-3" }, + { pid: "MMA4Z00-NL", formFactor: "OSFP", speedGbps: 800, speed: "800G", reachMeters: 2000, reachLabel: "LR8", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "800GBASE-LR8" }, + + // ── DAC (LinkX) ───────────────────────────────────────────────────────── + { pid: "MCP2100-X001A", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 1, reachLabel: "DAC-1M", fiberType: "DAC", connector: "SFP+", notes: "SFP+ 10G DAC 1m" }, + { pid: "MCP2100-X003A", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 3, reachLabel: "DAC-3M", fiberType: "DAC", connector: "SFP+", notes: "SFP+ 10G DAC 3m" }, + { pid: "MCP1650-H001E26", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 1, reachLabel: "DAC-1M", fiberType: "DAC", connector: "QSFP28", notes: "QSFP28 100G DAC 1m" }, + { pid: "MCP1650-H003E26", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 3, reachLabel: "DAC-3M", fiberType: "DAC", connector: "QSFP28", notes: "QSFP28 100G DAC 3m" }, + { pid: "MCP1660-W001E26", formFactor: "QSFP-DD", speedGbps: 400, speed: "400G", reachMeters: 1, reachLabel: "DAC-1M", fiberType: "DAC", connector: "QSFP-DD", notes: "QSFP-DD 400G DAC 1m" }, +]; + +export async function scrapeMellanoxOem(): Promise { + console.log("=== Mellanox (NVIDIA Networking) OEM Transceiver Seed ===\n"); + + const vendorId = await ensureVendor( + "NVIDIA Mellanox", + "oem", + "https://www.nvidia.com/networking", + undefined + ); + + let inserted = 0; + let updated = 0; + let errors = 0; + + for (const p of MELLANOX_PIDS) { + const slug = `mellanox-${p.pid.toLowerCase().replace(/[^a-z0-9]+/g, "-")}`; + try { + const res = await pool.query( + `INSERT INTO transceivers + (slug, part_number, vendor_id, form_factor, speed, speed_gbps, + reach_meters, reach_label, fiber_type, connector, wavelengths, + dom_support, ieee_reference, market_status, category, notes) + VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,true,$12,'Mainstream','DataCenter',$13) + ON CONFLICT (slug) DO UPDATE SET + speed_gbps = EXCLUDED.speed_gbps, + reach_meters = CASE WHEN EXCLUDED.reach_meters > 0 THEN EXCLUDED.reach_meters ELSE transceivers.reach_meters END, + fiber_type = CASE WHEN EXCLUDED.fiber_type <> '' THEN EXCLUDED.fiber_type ELSE transceivers.fiber_type END, + wavelengths = COALESCE(EXCLUDED.wavelengths, transceivers.wavelengths), + updated_at = NOW() + RETURNING (xmax = 0) as was_inserted`, + [slug, p.pid, vendorId, p.formFactor, p.speed, p.speedGbps, + p.reachMeters, p.reachLabel, p.fiberType, p.connector, + p.wavelengths ?? null, p.standard ?? null, p.notes ?? null] + ); + if (res.rows[0]?.was_inserted) inserted++; else updated++; + } catch (err) { + console.warn(` Skip ${p.pid}: ${(err as Error).message.slice(0, 80)}`); + errors++; + } + } + + console.log(`\n=== Mellanox OEM Seed Complete ===`); + console.log(` Inserted: ${inserted}`); + console.log(` Updated: ${updated}`); + console.log(` Errors: ${errors}`); + console.log(` Total PIDs: ${MELLANOX_PIDS.length}\n`); +} + +if (require.main === module) { + scrapeMellanoxOem() + .then(() => pool.end()) + .catch((err) => { + console.error("Fatal:", err); + pool.end(); + process.exit(1); + }); +} diff --git a/packages/scraper/src/scrapers/meta-oem.ts b/packages/scraper/src/scrapers/meta-oem.ts new file mode 100644 index 0000000..cfe222a --- /dev/null +++ b/packages/scraper/src/scrapers/meta-oem.ts @@ -0,0 +1,314 @@ +/** + * Meta OEM Transceiver Catalog Seed + * + * Seeds Meta (Facebook)-branded transceiver PIDs used across Meta's global + * datacenter fleet on the Open Compute Project (OCP) FBOSS switching platform. + * Meta contributes hardware designs to OCP and uses a META- prefix for optics + * validated on its internally developed Wedge/Wedge100/Minipack/Montara switch + * ASICs running FBOSS (Facebook Open Switching System). + * + * Notable entries: + * - META-QSFP-DD-800G-SR8 / META-OSFP-800G-DR8: Meta's 800G OCP next-gen + * fabric ports targeting the Wedge400/Minipack2 upgrade cycle. + * + * Sources: + * - Meta Engineering networking blog (engineering.fb.com/category/networking-traffic/) + * - Open Compute Project networking specifications (opencompute.org) + * - OIF 400G-ZR / 800G-FR8 MSA implementation agreements + * + * Run: tsx packages/scraper/src/scrapers/meta-oem.ts + * Cron: daily at 08:00 + */ + +import { pool, ensureVendor } from "../utils/db"; + +interface MetaPID { + pid: string; + formFactor: string; + speedGbps: number; + speed: string; + reachMeters: number; + reachLabel: string; + fiberType: string; + connector: string; + wavelengths?: string; + standard?: string; + notes?: string; +} + +const META_PIDS: MetaPID[] = [ + // ── 1G SFP ─────────────────────────────────────────────────────────────── + { + pid: "META-SFP-1G-SX", + formFactor: "SFP", + speedGbps: 1, + speed: "1G", + reachMeters: 550, + reachLabel: "SX", + fiberType: "MMF", + connector: "LC", + wavelengths: "850nm", + standard: "1000BASE-SX", + notes: "1GbE SFP SX; Meta OCP server management port; OM2/OM3 MMF up to 550m", + }, + { + pid: "META-SFP-1G-LX", + formFactor: "SFP", + speedGbps: 1, + speed: "1G", + reachMeters: 10000, + reachLabel: "LX", + fiberType: "SMF", + connector: "LC", + wavelengths: "1310nm", + standard: "1000BASE-LX", + notes: "1GbE SFP LX; Meta OCP server management port; OS2 SMF up to 10km", + }, + // ── 1G Copper SFP ──────────────────────────────────────────────────────── + { + pid: "META-SFP-GE-T", + formFactor: "SFP", + speedGbps: 1, + speed: "1G", + reachMeters: 100, + reachLabel: "T", + fiberType: "DAC", + connector: "RJ45", + standard: "1000BASE-T", + notes: "1GbE copper SFP RJ45; Meta OCP server management copper option; Cat5e/6", + }, + // ── 10G SFP+ ───────────────────────────────────────────────────────────── + { + pid: "META-SFP-10G-SR", + formFactor: "SFP+", + speedGbps: 10, + speed: "10G", + reachMeters: 300, + reachLabel: "SR", + fiberType: "MMF", + connector: "LC", + wavelengths: "850nm", + standard: "10GBASE-SR", + notes: "10GbE SFP+ SR; Meta FBOSS Wedge100 server downlink; OM3/OM4 MMF up to 300m", + }, + { + pid: "META-SFP-10G-LR", + formFactor: "SFP+", + speedGbps: 10, + speed: "10G", + reachMeters: 10000, + reachLabel: "LR", + fiberType: "SMF", + connector: "LC", + wavelengths: "1310nm", + standard: "10GBASE-LR", + notes: "10GbE SFP+ LR; Meta FBOSS Wedge100 inter-pod link; OS2 SMF up to 10km", + }, + { + pid: "META-SFP-10G-ER", + formFactor: "SFP+", + speedGbps: 10, + speed: "10G", + reachMeters: 40000, + reachLabel: "ER", + fiberType: "SMF", + connector: "LC", + wavelengths: "1550nm", + standard: "10GBASE-ER", + notes: "10GbE SFP+ ER; Meta datacenter campus interconnect; OS2 SMF up to 40km", + }, + // ── 25G SFP28 ──────────────────────────────────────────────────────────── + { + pid: "META-SFP28-25G-SR", + formFactor: "SFP28", + speedGbps: 25, + speed: "25G", + reachMeters: 100, + reachLabel: "SR", + fiberType: "MMF", + connector: "LC", + wavelengths: "850nm", + standard: "25GBASE-SR", + notes: "25GbE SFP28 SR; Meta OCP server ToR downlink port; OM4 MMF up to 100m", + }, + { + pid: "META-SFP28-25G-LR", + formFactor: "SFP28", + speedGbps: 25, + speed: "25G", + reachMeters: 10000, + reachLabel: "LR", + fiberType: "SMF", + connector: "LC", + wavelengths: "1310nm", + standard: "25GBASE-LR", + notes: "25GbE SFP28 LR; Meta OCP server ToR downlink port; OS2 SMF up to 10km", + }, + // ── 40G QSFP+ ──────────────────────────────────────────────────────────── + { + pid: "META-QSFP-40G-SR4", + formFactor: "QSFP+", + speedGbps: 40, + speed: "40G", + reachMeters: 150, + reachLabel: "SR4", + fiberType: "MMF", + connector: "MPO", + wavelengths: "850nm", + standard: "40GBASE-SR4", + notes: "40GbE QSFP+ SR4; Meta FBOSS Wedge100 aggregation uplink; OM3/OM4 MPO-12 up to 150m", + }, + { + pid: "META-QSFP-40G-LR4", + formFactor: "QSFP+", + speedGbps: 40, + speed: "40G", + reachMeters: 10000, + reachLabel: "LR4", + fiberType: "SMF", + connector: "LC", + wavelengths: "1270-1330nm", + standard: "40GBASE-LR4", + notes: "40GbE QSFP+ LR4; Meta FBOSS Wedge100 inter-fabric link; OS2 SMF up to 10km", + }, + // ── 100G QSFP28 ────────────────────────────────────────────────────────── + { + pid: "META-QSFP28-100G-SR4", + formFactor: "QSFP28", + speedGbps: 100, + speed: "100G", + reachMeters: 100, + reachLabel: "SR4", + fiberType: "MMF", + connector: "MPO", + wavelengths: "850nm", + standard: "100GBASE-SR4", + notes: "100GbE QSFP28 SR4; Meta FBOSS Minipack fabric spine uplink; OM4 MPO-12 up to 100m", + }, + { + pid: "META-QSFP28-100G-LR4", + formFactor: "QSFP28", + speedGbps: 100, + speed: "100G", + reachMeters: 10000, + reachLabel: "LR4", + fiberType: "SMF", + connector: "LC", + wavelengths: "1295-1310nm", + standard: "100GBASE-LR4", + notes: "100GbE QSFP28 LR4; Meta FBOSS Minipack inter-pod DCI link; OS2 SMF up to 10km", + }, + // ── 400G QSFP-DD ───────────────────────────────────────────────────────── + { + pid: "META-QSFP-DD-400G-DR4", + formFactor: "QSFP-DD", + speedGbps: 400, + speed: "400G", + reachMeters: 500, + reachLabel: "DR4", + fiberType: "SMF", + connector: "MPO", + wavelengths: "1310nm", + standard: "400GBASE-DR4", + notes: "400GbE QSFP-DD DR4; Meta Minipack2/Montara OCP 400G spine interconnect; OS2 SMF up to 500m", + }, + { + pid: "META-QSFP-DD-400G-SR8", + formFactor: "QSFP-DD", + speedGbps: 400, + speed: "400G", + reachMeters: 100, + reachLabel: "SR8", + fiberType: "MMF", + connector: "MPO", + wavelengths: "850nm", + standard: "400GBASE-SR8", + notes: "400GbE QSFP-DD SR8; Meta Minipack2/Montara OCP 400G fabric; OM4/OM5 MPO-16 up to 100m", + }, + // ── 800G QSFP-DD (OCP FBOSS next-gen) ──────────────────────────────────── + { + pid: "META-QSFP-DD-800G-SR8", + formFactor: "QSFP-DD", + speedGbps: 800, + speed: "800G", + reachMeters: 100, + reachLabel: "SR8", + fiberType: "MMF", + connector: "MPO", + wavelengths: "850nm", + standard: "800GBASE-SR8", + notes: "800GbE QSFP-DD SR8; Meta OCP FBOSS next-gen 800G fabric (Wedge400 upgrade cycle); OM5 MPO-16 up to 100m", + }, + // ── 800G OSFP (OCP FBOSS next-gen) ─────────────────────────────────────── + { + pid: "META-OSFP-800G-DR8", + formFactor: "OSFP", + speedGbps: 800, + speed: "800G", + reachMeters: 500, + reachLabel: "DR8", + fiberType: "SMF", + connector: "MPO", + wavelengths: "1310nm", + standard: "800GBASE-DR8", + notes: "800G OSFP DR8; Meta OCP 800G OSFP for Minipack3 datacenter spine; OS2 SMF MPO-16 up to 500m; OCP FBOSS platform", + }, +]; + +export async function scrapeMetaOem(): Promise { + console.log("=== Meta OEM Transceiver Seed ===\n"); + + const vendorId = await ensureVendor( + "Meta", + "oem", + "https://engineering.fb.com/category/networking-traffic/", + undefined + ); + + let inserted = 0; + let updated = 0; + let errors = 0; + + for (const p of META_PIDS) { + const slug = `meta-${p.pid.toLowerCase().replace(/[^a-z0-9]+/g, "-")}`; + try { + const res = await pool.query( + `INSERT INTO transceivers + (slug, part_number, vendor_id, form_factor, speed, speed_gbps, + reach_meters, reach_label, fiber_type, connector, wavelengths, + dom_support, ieee_reference, market_status, category, notes) + VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,true,$12,'Mainstream','DataCenter',$13) + ON CONFLICT (slug) DO UPDATE SET + speed_gbps = EXCLUDED.speed_gbps, + reach_meters = CASE WHEN EXCLUDED.reach_meters > 0 THEN EXCLUDED.reach_meters ELSE transceivers.reach_meters END, + fiber_type = CASE WHEN EXCLUDED.fiber_type <> '' THEN EXCLUDED.fiber_type ELSE transceivers.fiber_type END, + wavelengths = COALESCE(EXCLUDED.wavelengths, transceivers.wavelengths), + updated_at = NOW() + RETURNING (xmax = 0) as was_inserted`, + [slug, p.pid, vendorId, p.formFactor, p.speed, p.speedGbps, + p.reachMeters, p.reachLabel, p.fiberType, p.connector, + p.wavelengths ?? null, p.standard ?? null, p.notes ?? null] + ); + if (res.rows[0]?.was_inserted) inserted++; else updated++; + } catch (err) { + console.warn(` Skip ${p.pid}: ${(err as Error).message.slice(0, 80)}`); + errors++; + } + } + + console.log(`\n=== Meta OEM Seed Complete ===`); + console.log(` Inserted: ${inserted}`); + console.log(` Updated: ${updated}`); + console.log(` Errors: ${errors}`); + console.log(` Total PIDs: ${META_PIDS.length}\n`); +} + +if (require.main === module) { + scrapeMetaOem() + .then(() => pool.end()) + .catch((err) => { + console.error("Fatal:", err); + pool.end(); + process.exit(1); + }); +} diff --git a/packages/scraper/src/scrapers/mikrotik-oem.ts b/packages/scraper/src/scrapers/mikrotik-oem.ts new file mode 100644 index 0000000..c117b0d --- /dev/null +++ b/packages/scraper/src/scrapers/mikrotik-oem.ts @@ -0,0 +1,127 @@ +/** + * MikroTik OEM Transceiver Catalog Seed + * + * Seeds MikroTik-branded transceiver PIDs for RouterBoard CRS, + * CCR, and CRS3xx/CRS5xx series switches. + * + * Sources: + * - MikroTik Product Catalog (mikrotik.com) + * - MikroTik RouterOS Transceiver Compatibility Table + * + * Run: tsx packages/scraper/src/scrapers/mikrotik-oem.ts + * Cron: daily at 08:00 + */ + +import { pool, ensureVendor } from "../utils/db"; + +interface MikrotikPID { + pid: string; + formFactor: string; + speedGbps: number; + speed: string; + reachMeters: number; + reachLabel: string; + fiberType: string; + connector: string; + wavelengths?: string; + standard?: string; + notes?: string; +} + +const MIKROTIK_PIDS: MikrotikPID[] = [ + // ── 1G SFP ────────────────────────────────────────────────────────────── + { pid: "S-85DLC05D", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 550, reachLabel: "SX", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "1000BASE-SX", notes: "MikroTik 1G SFP MM" }, + { pid: "S-31DLC20D", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 20000, reachLabel: "LX20", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", notes: "MikroTik 1G SFP SM 20km" }, + { pid: "S-3553LC20D", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 20000, reachLabel: "LX20", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", notes: "MikroTik 1G SFP SM 20km 1550nm" }, + { pid: "S-35LC20D", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 20000, reachLabel: "LX20", fiberType: "SMF", connector: "LC", wavelengths: "1310nm" }, + { pid: "S-55LC80D", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 80000, reachLabel: "ZX", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "1000BASE-ZX" }, + { pid: "S-RJ01", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 100, reachLabel: "T", fiberType: "DAC", connector: "RJ45", standard: "1000BASE-T", notes: "MikroTik SFP RJ45 copper" }, + + // ── 1G SFP BiDi ───────────────────────────────────────────────────────── + { pid: "S-31DLC20D-LH", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 20000, reachLabel: "BiDi", fiberType: "SMF", connector: "LC", wavelengths: "1310/1550nm", notes: "1G BiDi single fiber 20km" }, + + // ── 10G SFP+ ──────────────────────────────────────────────────────────── + { pid: "S+85DLC03D", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 300, reachLabel: "SR", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "10GBASE-SR", notes: "MikroTik 10G SFP+ MM" }, + { pid: "S+31DLC10D", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 10000, reachLabel: "LR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "10GBASE-LR", notes: "MikroTik 10G SFP+ SM 10km" }, + { pid: "S+23LC10D", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 10000, reachLabel: "BiDi", fiberType: "SMF", connector: "LC", wavelengths: "1270/1330nm", notes: "MikroTik 10G BiDi SFP+ single fiber" }, + { pid: "S+RJ10", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 30, reachLabel: "T", fiberType: "DAC", connector: "RJ45", standard: "10GBASE-T", notes: "MikroTik SFP+ RJ45 copper" }, + + // ── 25G SFP28 ─────────────────────────────────────────────────────────── + { pid: "S+85DLC03D-25", formFactor: "SFP28", speedGbps: 25, speed: "25G", reachMeters: 100, reachLabel: "SR", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "25GBASE-SR" }, + { pid: "S+31DLC10D-25", formFactor: "SFP28", speedGbps: 25, speed: "25G", reachMeters: 10000, reachLabel: "LR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "25GBASE-LR" }, + + // ── 40G QSFP+ ─────────────────────────────────────────────────────────── + { pid: "Q+85MP01D", formFactor: "QSFP+", speedGbps: 40, speed: "40G", reachMeters: 150, reachLabel: "SR4", fiberType: "MMF", connector: "MPO", wavelengths: "850nm", standard: "40GBASE-SR4", notes: "MikroTik 40G QSFP+ SR4" }, + { pid: "Q+31DLC10D", formFactor: "QSFP+", speedGbps: 40, speed: "40G", reachMeters: 10000, reachLabel: "LR4", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "40GBASE-LR4", notes: "MikroTik 40G QSFP+ LR4" }, + + // ── 100G QSFP28 ───────────────────────────────────────────────────────── + { pid: "Q+85MP01D-100", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 100, reachLabel: "SR4", fiberType: "MMF", connector: "MPO", wavelengths: "850nm", standard: "100GBASE-SR4" }, + { pid: "Q+31DLC10D-100",formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 10000, reachLabel: "LR4", fiberType: "SMF", connector: "LC", wavelengths: "1295-1310nm", standard: "100GBASE-LR4" }, + { pid: "XQ+85MP01D", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 100, reachLabel: "SR4", fiberType: "MMF", connector: "MPO", wavelengths: "850nm", notes: "MikroTik 100G QSFP28 SR4 (CRS504)" }, + + // ── DAC ───────────────────────────────────────────────────────────────── + { pid: "S+DA0001", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 1, reachLabel: "DAC-1M",fiberType: "DAC", connector: "SFP+", notes: "MikroTik SFP+ DAC 1m" }, + { pid: "S+DA0003", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 3, reachLabel: "DAC-3M",fiberType: "DAC", connector: "SFP+", notes: "MikroTik SFP+ DAC 3m" }, + { pid: "Q+DA0001", formFactor: "QSFP+", speedGbps: 40, speed: "40G", reachMeters: 1, reachLabel: "DAC-1M",fiberType: "DAC", connector: "QSFP+", notes: "MikroTik QSFP+ DAC 1m" }, + { pid: "Q+DA0003", formFactor: "QSFP+", speedGbps: 40, speed: "40G", reachMeters: 3, reachLabel: "DAC-3M",fiberType: "DAC", connector: "QSFP+", notes: "MikroTik QSFP+ DAC 3m" }, + { pid: "XQ+DA0001", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 1, reachLabel: "DAC-1M",fiberType: "DAC", connector: "QSFP28", notes: "MikroTik QSFP28 DAC 1m" }, + { pid: "XQ+DA0003", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 3, reachLabel: "DAC-3M",fiberType: "DAC", connector: "QSFP28", notes: "MikroTik QSFP28 DAC 3m" }, +]; + +export async function scrapeMikrotikOem(): Promise { + console.log("=== MikroTik OEM Transceiver Seed ===\n"); + + const vendorId = await ensureVendor( + "MikroTik", + "oem", + "https://mikrotik.com", + undefined + ); + + let inserted = 0; + let updated = 0; + let errors = 0; + + for (const p of MIKROTIK_PIDS) { + const slug = `mikrotik-${p.pid.toLowerCase().replace(/[^a-z0-9]+/g, "-")}`; + try { + const res = await pool.query( + `INSERT INTO transceivers + (slug, part_number, vendor_id, form_factor, speed, speed_gbps, + reach_meters, reach_label, fiber_type, connector, wavelengths, + dom_support, ieee_reference, market_status, category, notes) + VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,true,$12,'Mainstream','DataCenter',$13) + ON CONFLICT (slug) DO UPDATE SET + speed_gbps = EXCLUDED.speed_gbps, + reach_meters = CASE WHEN EXCLUDED.reach_meters > 0 THEN EXCLUDED.reach_meters ELSE transceivers.reach_meters END, + fiber_type = CASE WHEN EXCLUDED.fiber_type <> '' THEN EXCLUDED.fiber_type ELSE transceivers.fiber_type END, + wavelengths = COALESCE(EXCLUDED.wavelengths, transceivers.wavelengths), + updated_at = NOW() + RETURNING (xmax = 0) as was_inserted`, + [slug, p.pid, vendorId, p.formFactor, p.speed, p.speedGbps, + p.reachMeters, p.reachLabel, p.fiberType, p.connector, + p.wavelengths ?? null, p.standard ?? null, p.notes ?? null] + ); + if (res.rows[0]?.was_inserted) inserted++; else updated++; + } catch (err) { + console.warn(` Skip ${p.pid}: ${(err as Error).message.slice(0, 80)}`); + errors++; + } + } + + console.log(`\n=== MikroTik OEM Seed Complete ===`); + console.log(` Inserted: ${inserted}`); + console.log(` Updated: ${updated}`); + console.log(` Errors: ${errors}`); + console.log(` Total PIDs: ${MIKROTIK_PIDS.length}\n`); +} + +if (require.main === module) { + scrapeMikrotikOem() + .then(() => pool.end()) + .catch((err) => { + console.error("Fatal:", err); + pool.end(); + process.exit(1); + }); +} diff --git a/packages/scraper/src/scrapers/moxa-industrial-oem.ts b/packages/scraper/src/scrapers/moxa-industrial-oem.ts new file mode 100644 index 0000000..51f02a3 --- /dev/null +++ b/packages/scraper/src/scrapers/moxa-industrial-oem.ts @@ -0,0 +1,123 @@ +/** + * Moxa Industrial OEM Transceiver Catalog Seed (EDS/AWK Series) + * + * Seeds transceiver PIDs for Moxa Industrial SFP/SFP+/SFP28/QSFP+ modules + * used in the newer EDS (Ethernet Device Server) and AWK (wireless) managed + * switch series for industrial automation, factory networking, and IIoT + * infrastructure. + * + * Note: The base moxa-oem.ts covers the core 16 legacy Moxa SFPs. + * This file adds newer EDS/AWK-series optics under the moxa-ind- prefix. + * + * Sources: + * - Moxa Industrial Networking product catalog + * (moxa.com/en/products/industrial-networking/ethernet-switches) + * - Moxa EDS-G4000 / AWK-4131A series datasheets + * + * Run: tsx packages/scraper/src/scrapers/moxa-industrial-oem.ts + * Cron: daily at 17:45 + */ + +import { pool, ensureVendor } from "../utils/db"; + +interface MoxaIndPID { + pid: string; + formFactor: string; + speedGbps: number; + speed: string; + reachMeters: number; + reachLabel: string; + fiberType: string; + connector: string; + wavelengths?: string; + standard?: string; + notes?: string; +} + +const MOXA_IND_PIDS: MoxaIndPID[] = [ + // ── 1G SFP ────────────────────────────────────────────────────────────── + { pid: "MOXA-IND-SFP-1G-SX", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 550, reachLabel: "SX", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "1000BASE-SX", notes: "Moxa Industrial SFP 1G SX EDS/AWK series" }, + { pid: "MOXA-IND-SFP-1G-LX", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 10000, reachLabel: "LX", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "1000BASE-LX", notes: "Moxa Industrial SFP 1G LX EDS/AWK series" }, + { pid: "MOXA-IND-SFP-1G-ZX", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 80000, reachLabel: "ZX", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "1000BASE-ZX", notes: "Moxa Industrial SFP 1G ZX 80km EDS series" }, + { pid: "MOXA-IND-SFP-1G-T", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 100, reachLabel: "T", fiberType: "DAC", connector: "RJ45", standard: "1000BASE-T", notes: "Moxa Industrial SFP 1G copper RJ45 EDS series" }, + { pid: "MOXA-IND-SFP-GE-T", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 100, reachLabel: "T", fiberType: "DAC", connector: "RJ45", standard: "1000BASE-T", notes: "Moxa Industrial SFP GE copper AWK/EDS series" }, + + // ── 1G SFP BiDi ───────────────────────────────────────────────────────── + { pid: "MOXA-IND-SFP-1G-BIDI-1310", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 20000, reachLabel: "BiDi-TX1310", fiberType: "SMF", connector: "LC", wavelengths: "TX1310/RX1550nm", notes: "Moxa Industrial SFP 1G BiDi TX1310 single fiber" }, + { pid: "MOXA-IND-SFP-1G-BIDI-1550", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 20000, reachLabel: "BiDi-TX1550", fiberType: "SMF", connector: "LC", wavelengths: "TX1550/RX1310nm", notes: "Moxa Industrial SFP 1G BiDi TX1550 single fiber" }, + + // ── 10G SFP+ ──────────────────────────────────────────────────────────── + { pid: "MOXA-IND-SFP-10G-SR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 300, reachLabel: "SR", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "10GBASE-SR", notes: "Moxa Industrial SFP+ 10G SR EDS-G4000 series" }, + { pid: "MOXA-IND-SFP-10G-LR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 10000, reachLabel: "LR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "10GBASE-LR", notes: "Moxa Industrial SFP+ 10G LR EDS-G4000 series" }, + { pid: "MOXA-IND-SFP-10G-ER", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 40000, reachLabel: "ER", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "10GBASE-ER", notes: "Moxa Industrial SFP+ 10G ER EDS-G4000 series" }, + + // ── 1G CWDM SFP (factory/plant rings) ─────────────────────────────────── + { pid: "MOXA-IND-SFP-CWDM-1470", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 40000, reachLabel: "CWDM-1470", fiberType: "SMF", connector: "LC", wavelengths: "1470nm", notes: "Moxa Industrial SFP CWDM 1470nm 40km factory ring" }, + { pid: "MOXA-IND-SFP-CWDM-1510", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 40000, reachLabel: "CWDM-1510", fiberType: "SMF", connector: "LC", wavelengths: "1510nm", notes: "Moxa Industrial SFP CWDM 1510nm 40km factory ring" }, + { pid: "MOXA-IND-SFP-CWDM-1530", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 40000, reachLabel: "CWDM-1530", fiberType: "SMF", connector: "LC", wavelengths: "1530nm", notes: "Moxa Industrial SFP CWDM 1530nm 40km factory ring" }, + { pid: "MOXA-IND-SFP-CWDM-1550", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 40000, reachLabel: "CWDM-1550", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", notes: "Moxa Industrial SFP CWDM 1550nm 40km factory ring" }, + + // ── 40G QSFP+ ─────────────────────────────────────────────────────────── + { pid: "MOXA-IND-QSFP-40G-LR4", formFactor: "QSFP+", speedGbps: 40, speed: "40G", reachMeters: 10000, reachLabel: "LR4", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "40GBASE-LR4", notes: "Moxa Industrial QSFP+ 40G LR4 EDS-G4000 core uplink" }, + + // ── 25G SFP28 ─────────────────────────────────────────────────────────── + { pid: "MOXA-IND-SFP28-25G-LR", formFactor: "SFP28", speedGbps: 25, speed: "25G", reachMeters: 10000, reachLabel: "LR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "25GBASE-LR", notes: "Moxa Industrial SFP28 25G LR EDS next-gen uplink" }, +]; + +export async function scrapeIndustrialMoxaOem(): Promise { + console.log("=== Moxa Industrial OEM Transceiver Seed (EDS/AWK Series) ===\n"); + + const vendorId = await ensureVendor( + "Moxa Industrial", + "oem", + "https://www.moxa.com/en/products/industrial-networking/ethernet-switches", + undefined + ); + + let inserted = 0; + let updated = 0; + let errors = 0; + + for (const p of MOXA_IND_PIDS) { + const slug = `moxa-ind-${p.pid.toLowerCase().replace(/[^a-z0-9]+/g, "-")}`; + try { + const res = await pool.query( + `INSERT INTO transceivers + (slug, part_number, vendor_id, form_factor, speed, speed_gbps, + reach_meters, reach_label, fiber_type, connector, wavelengths, + dom_support, ieee_reference, market_status, category, notes) + VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,true,$12,'Mainstream','Industrial',$13) + ON CONFLICT (slug) DO UPDATE SET + speed_gbps = EXCLUDED.speed_gbps, + reach_meters = CASE WHEN EXCLUDED.reach_meters > 0 THEN EXCLUDED.reach_meters ELSE transceivers.reach_meters END, + fiber_type = CASE WHEN EXCLUDED.fiber_type <> '' THEN EXCLUDED.fiber_type ELSE transceivers.fiber_type END, + wavelengths = COALESCE(EXCLUDED.wavelengths, transceivers.wavelengths), + updated_at = NOW() + RETURNING (xmax = 0) as was_inserted`, + [slug, p.pid, vendorId, p.formFactor, p.speed, p.speedGbps, + p.reachMeters, p.reachLabel, p.fiberType, p.connector, + p.wavelengths ?? null, p.standard ?? null, p.notes ?? null] + ); + if (res.rows[0]?.was_inserted) inserted++; else updated++; + } catch (err) { + console.warn(` Skip ${p.pid}: ${(err as Error).message.slice(0, 80)}`); + errors++; + } + } + + console.log(`\n=== Moxa Industrial OEM Seed Complete ===`); + console.log(` Inserted: ${inserted}`); + console.log(` Updated: ${updated}`); + console.log(` Errors: ${errors}`); + console.log(` Total PIDs: ${MOXA_IND_PIDS.length}\n`); +} + +if (require.main === module) { + scrapeIndustrialMoxaOem() + .then(() => pool.end()) + .catch((err) => { + console.error("Fatal:", err); + pool.end(); + process.exit(1); + }); +} diff --git a/packages/scraper/src/scrapers/moxa-oem.ts b/packages/scraper/src/scrapers/moxa-oem.ts new file mode 100644 index 0000000..20b53c6 --- /dev/null +++ b/packages/scraper/src/scrapers/moxa-oem.ts @@ -0,0 +1,111 @@ +/** + * Moxa OEM Transceiver Catalog Seed + * + * Seeds transceiver PIDs for Moxa industrial-grade SFP modules used in + * EDS, PT, and ICS series industrial Ethernet managed switches. + * + * Sources: + * - Moxa SFP/SFP+ module datasheet (moxa.com) + * - Moxa EDS-G series hardware installation guides + * + * Run: tsx packages/scraper/src/scrapers/moxa-oem.ts + * Cron: daily at 11:15 + */ + +import { pool, ensureVendor } from "../utils/db"; + +interface MoxaPID { + pid: string; + formFactor: string; + speedGbps: number; + speed: string; + reachMeters: number; + reachLabel: string; + fiberType: string; + connector: string; + wavelengths?: string; + standard?: string; + notes?: string; +} + +const MOXA_PIDS: MoxaPID[] = [ + // ── 1G SFP (industrial grade) ─────────────────────────────────────────── + { pid: "SFP-1GSXLC", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 550, reachLabel: "SX", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "1000BASE-SX", notes: "Moxa industrial 1G SX" }, + { pid: "SFP-1GLXLC", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 10000, reachLabel: "LX", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "1000BASE-LX", notes: "Moxa industrial 1G LX" }, + { pid: "SFP-1GLHLC", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 40000, reachLabel: "LH40", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", notes: "Moxa industrial 1G 40km" }, + { pid: "SFP-1GZXLC", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 80000, reachLabel: "ZX", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "1000BASE-ZX", notes: "Moxa industrial 1G ZX" }, + { pid: "SFP-1G-T", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 100, reachLabel: "T", fiberType: "DAC", connector: "RJ45", standard: "1000BASE-T", notes: "Moxa 1G copper SFP" }, + { pid: "SFP-1GSXLC-T", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 550, reachLabel: "SX", fiberType: "MMF", connector: "LC", wavelengths: "850nm", notes: "Moxa 1G SX IND temp -40~85°C" }, + { pid: "SFP-1GLXLC-T", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 10000, reachLabel: "LX", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", notes: "Moxa 1G LX IND temp -40~85°C" }, + { pid: "SFP-1GZXLC-T", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 80000, reachLabel: "ZX", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", notes: "Moxa 1G ZX IND temp -40~85°C" }, + + // ── 10G SFP+ ──────────────────────────────────────────────────────────── + { pid: "SFP-10GSRLC", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 300, reachLabel: "SR", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "10GBASE-SR", notes: "Moxa industrial 10G SR" }, + { pid: "SFP-10GLRLC", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 10000, reachLabel: "LR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "10GBASE-LR", notes: "Moxa industrial 10G LR" }, + { pid: "SFP-10GERLC", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 40000, reachLabel: "ER", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "10GBASE-ER" }, + { pid: "SFP-10GZRLC", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 80000, reachLabel: "ZR", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "10GBASE-ZR" }, + { pid: "SFP-10GSRLC-T", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 300, reachLabel: "SR", fiberType: "MMF", connector: "LC", wavelengths: "850nm", notes: "Moxa 10G SR IND temp" }, + { pid: "SFP-10GLRLC-T", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 10000, reachLabel: "LR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", notes: "Moxa 10G LR IND temp" }, + + // ── 25G SFP28 ─────────────────────────────────────────────────────────── + { pid: "SFP-25GSRLC", formFactor: "SFP28", speedGbps: 25, speed: "25G", reachMeters: 100, reachLabel: "SR", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "25GBASE-SR" }, + { pid: "SFP-25GLRLC", formFactor: "SFP28", speedGbps: 25, speed: "25G", reachMeters: 10000, reachLabel: "LR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "25GBASE-LR" }, +]; + +export async function scrapeMoxaOem(): Promise { + console.log("=== Moxa OEM Transceiver Seed ===\n"); + + const vendorId = await ensureVendor( + "Moxa", + "oem", + "https://www.moxa.com", + undefined + ); + + let inserted = 0; + let updated = 0; + let errors = 0; + + for (const p of MOXA_PIDS) { + const slug = `moxa-${p.pid.toLowerCase().replace(/[^a-z0-9]+/g, "-")}`; + try { + const res = await pool.query( + `INSERT INTO transceivers + (slug, part_number, vendor_id, form_factor, speed, speed_gbps, + reach_meters, reach_label, fiber_type, connector, wavelengths, + dom_support, ieee_reference, market_status, category, notes) + VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,true,$12,'Mainstream','Industrial',$13) + ON CONFLICT (slug) DO UPDATE SET + speed_gbps = EXCLUDED.speed_gbps, + reach_meters = CASE WHEN EXCLUDED.reach_meters > 0 THEN EXCLUDED.reach_meters ELSE transceivers.reach_meters END, + fiber_type = CASE WHEN EXCLUDED.fiber_type <> '' THEN EXCLUDED.fiber_type ELSE transceivers.fiber_type END, + wavelengths = COALESCE(EXCLUDED.wavelengths, transceivers.wavelengths), + updated_at = NOW() + RETURNING (xmax = 0) as was_inserted`, + [slug, p.pid, vendorId, p.formFactor, p.speed, p.speedGbps, + p.reachMeters, p.reachLabel, p.fiberType, p.connector, + p.wavelengths ?? null, p.standard ?? null, p.notes ?? null] + ); + if (res.rows[0]?.was_inserted) inserted++; else updated++; + } catch (err) { + console.warn(` Skip ${p.pid}: ${(err as Error).message.slice(0, 80)}`); + errors++; + } + } + + console.log(`\n=== Moxa OEM Seed Complete ===`); + console.log(` Inserted: ${inserted}`); + console.log(` Updated: ${updated}`); + console.log(` Errors: ${errors}`); + console.log(` Total PIDs: ${MOXA_PIDS.length}\n`); +} + +if (require.main === module) { + scrapeMoxaOem() + .then(() => pool.end()) + .catch((err) => { + console.error("Fatal:", err); + pool.end(); + process.exit(1); + }); +} diff --git a/packages/scraper/src/scrapers/nec-oem.ts b/packages/scraper/src/scrapers/nec-oem.ts new file mode 100644 index 0000000..0fb21e5 --- /dev/null +++ b/packages/scraper/src/scrapers/nec-oem.ts @@ -0,0 +1,122 @@ +/** + * NEC Corporation OEM Transceiver Catalog Seed + * + * Seeds NEC-branded transceiver PIDs for UNIVERGE series enterprise + * switches and IP telephony infrastructure. + * + * Sources: + * - NEC UNIVERGE Series Switch Compatibility Guide + * - NEC Enterprise Solutions Optical Transceiver Reference + * - https://www.nec.com/en/global/solutions/nec-univerge/ + * + * Run: tsx packages/scraper/src/scrapers/nec-oem.ts + * Cron: daily at 18:45 + */ + +import { pool, ensureVendor } from "../utils/db"; + +interface NecPID { + pid: string; + formFactor: string; + speedGbps: number; + speed: string; + reachMeters: number; + reachLabel: string; + fiberType: string; + connector: string; + wavelengths?: string; + standard?: string; + notes?: string; +} + +const NEC_PIDS: NecPID[] = [ + // ── 1G SFP ────────────────────────────────────────────────────────────── + { pid: "SFP-NEC-1G-SX", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 550, reachLabel: "SX", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "1000BASE-SX" }, + { pid: "SFP-NEC-1G-LX", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 10000, reachLabel: "LX", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "1000BASE-LX" }, + { pid: "SFP-NEC-1G-ZX", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 80000, reachLabel: "ZX", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "1000BASE-ZX" }, + { pid: "SFP-NEC-1G-T", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 100, reachLabel: "T", fiberType: "DAC", connector: "RJ45", standard: "1000BASE-T" }, + { pid: "SFP-NEC-1G-BXU", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 20000, reachLabel: "BXU", fiberType: "SMF", connector: "LC", wavelengths: "TX1310/RX1550nm", standard: "1000BASE-BX", notes: "NEC 1G BiDi SFP upstream" }, + + // ── 10G SFP+ ──────────────────────────────────────────────────────────── + { pid: "SFP-NEC-10G-SR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 300, reachLabel: "SR", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "10GBASE-SR" }, + { pid: "SFP-NEC-10G-LR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 10000, reachLabel: "LR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "10GBASE-LR" }, + { pid: "SFP-NEC-10G-ER", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 40000, reachLabel: "ER", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "10GBASE-ER" }, + { pid: "SFP-NEC-10G-ZR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 80000, reachLabel: "ZR", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "10GBASE-ZR" }, + { pid: "SFP-NEC-10G-T", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 30, reachLabel: "T", fiberType: "DAC", connector: "RJ45", standard: "10GBASE-T" }, + + // ── 25G SFP28 ─────────────────────────────────────────────────────────── + { pid: "SFP-NEC-25G-SR", formFactor: "SFP28", speedGbps: 25, speed: "25G", reachMeters: 100, reachLabel: "SR", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "25GBASE-SR" }, + { pid: "SFP-NEC-25G-LR", formFactor: "SFP28", speedGbps: 25, speed: "25G", reachMeters: 10000, reachLabel: "LR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "25GBASE-LR" }, + + // ── 40G QSFP+ ─────────────────────────────────────────────────────────── + { pid: "QSFP-NEC-40G-SR4", formFactor: "QSFP+", speedGbps: 40, speed: "40G", reachMeters: 150, reachLabel: "SR4", fiberType: "MMF", connector: "MPO", wavelengths: "850nm", standard: "40GBASE-SR4" }, + { pid: "QSFP-NEC-40G-LR4", formFactor: "QSFP+", speedGbps: 40, speed: "40G", reachMeters: 10000, reachLabel: "LR4", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "40GBASE-LR4" }, + + // ── 100G QSFP28 ───────────────────────────────────────────────────────── + { pid: "QSFP-NEC-100G-SR4", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 100, reachLabel: "SR4", fiberType: "MMF", connector: "MPO", wavelengths: "850nm", standard: "100GBASE-SR4" }, + { pid: "QSFP-NEC-100G-LR4", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 10000, reachLabel: "LR4", fiberType: "SMF", connector: "LC", wavelengths: "1295-1310nm", standard: "100GBASE-LR4" }, + { pid: "QSFP-NEC-100G-CWDM4", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 2000, reachLabel: "CWDM4", fiberType: "SMF", connector: "LC", wavelengths: "1271-1331nm", standard: "100GBASE-CWDM4" }, + + // ── DAC ───────────────────────────────────────────────────────────────── + { pid: "DAC-NEC-10G-1M", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 1, reachLabel: "DAC-1M", fiberType: "DAC", connector: "SFP+" }, + { pid: "DAC-NEC-10G-3M", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 3, reachLabel: "DAC-3M", fiberType: "DAC", connector: "SFP+" }, + { pid: "DAC-NEC-100G-1M", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 1, reachLabel: "DAC-1M", fiberType: "DAC", connector: "QSFP28" }, +]; + +export async function scrapeNecOem(): Promise { + console.log("=== NEC Corporation OEM Transceiver Seed ===\n"); + + const vendorId = await ensureVendor( + "NEC Corporation", + "oem", + "https://www.nec.com/en/global/solutions/nec-univerge/", + undefined + ); + + let inserted = 0; + let updated = 0; + let errors = 0; + + for (const p of NEC_PIDS) { + const slug = `nec-${p.pid.toLowerCase().replace(/[^a-z0-9]+/g, "-")}`; + try { + const res = await pool.query( + `INSERT INTO transceivers + (slug, part_number, vendor_id, form_factor, speed, speed_gbps, + reach_meters, reach_label, fiber_type, connector, wavelengths, + dom_support, ieee_reference, market_status, category, notes) + VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,true,$12,'Mainstream','DataCenter',$13) + ON CONFLICT (slug) DO UPDATE SET + speed_gbps = EXCLUDED.speed_gbps, + reach_meters = CASE WHEN EXCLUDED.reach_meters > 0 THEN EXCLUDED.reach_meters ELSE transceivers.reach_meters END, + fiber_type = CASE WHEN EXCLUDED.fiber_type <> '' THEN EXCLUDED.fiber_type ELSE transceivers.fiber_type END, + wavelengths = COALESCE(EXCLUDED.wavelengths, transceivers.wavelengths), + updated_at = NOW() + RETURNING (xmax = 0) as was_inserted`, + [slug, p.pid, vendorId, p.formFactor, p.speed, p.speedGbps, + p.reachMeters, p.reachLabel, p.fiberType, p.connector, + p.wavelengths ?? null, p.standard ?? null, p.notes ?? null] + ); + if (res.rows[0]?.was_inserted) inserted++; else updated++; + } catch (err) { + console.warn(` Skip ${p.pid}: ${(err as Error).message.slice(0, 80)}`); + errors++; + } + } + + console.log(`\n=== NEC Corporation OEM Seed Complete ===`); + console.log(` Inserted: ${inserted}`); + console.log(` Updated: ${updated}`); + console.log(` Errors: ${errors}`); + console.log(` Total PIDs: ${NEC_PIDS.length}\n`); +} + +if (require.main === module) { + scrapeNecOem() + .then(() => pool.end()) + .catch((err) => { + console.error("Fatal:", err); + pool.end(); + process.exit(1); + }); +} diff --git a/packages/scraper/src/scrapers/neophotonics-oem.ts b/packages/scraper/src/scrapers/neophotonics-oem.ts new file mode 100644 index 0000000..e5bc6f4 --- /dev/null +++ b/packages/scraper/src/scrapers/neophotonics-oem.ts @@ -0,0 +1,140 @@ +/** + * NeoPhotonics OEM Transceiver Catalog Seed + * + * Seeds NeoPhotonics-branded transceiver PIDs. NeoPhotonics Corporation + * (San Jose, CA) was a leading developer of ultra-narrow linewidth lasers + * and photonic integrated circuits (PICs) for coherent 100G/400G/800G + * optical networking. Acquired by Lumentum in 2022. + * + * Sources: + * - NeoPhotonics Product Catalog (neophotonics.com — archived) + * - NeoPhotonics 100G/400G Coherent Transceiver Data Sheets + * - NeoPhotonics CFP2-ACO / CFP2-DCO Application Notes + * + * Run: tsx packages/scraper/src/scrapers/neophotonics-oem.ts + * Cron: daily at 22:00 + */ + +import { pool, ensureVendor } from "../utils/db"; + +interface NeoPID { + pid: string; + formFactor: string; + speedGbps: number; + speed: string; + reachMeters: number; + reachLabel: string; + fiberType: string; + connector: string; + wavelengths?: string; + standard?: string; + category?: string; + notes?: string; +} + +// NeoPhotonics specializes in coherent — most high-speed PIDs are Telecom +const TELECOM_PIDS = new Set([ + "NPH-SFP-10G-ZR", + "NPH-DWDM-SFP10G-C", + "NPH-CFP2-ACO-100G", + "NPH-CFP2-DCO-100G", + "NPH-QSFP28-100G-ZR4", + "NPH-QSFP-DD-400G-ZR", + "NPH-OSFP-800G-ZR", +]); + +const NEOPHOTONICS_PIDS: NeoPID[] = [ + // ── 10G SFP+ ──────────────────────────────────────────────────────────── + { pid: "NPH-SFP-10G-SR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 300, reachLabel: "SR", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "10GBASE-SR", notes: "NeoPhotonics 10G SFP+ SR 300m MMF" }, + { pid: "NPH-SFP-10G-LR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 10000, reachLabel: "LR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "10GBASE-LR", notes: "NeoPhotonics 10G SFP+ LR 10km SMF" }, + { pid: "NPH-SFP-10G-ZR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 80000, reachLabel: "ZR", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "10GBASE-ZR", notes: "NeoPhotonics 10G SFP+ ZR 80km SMF" }, + + // ── 25G SFP28 ─────────────────────────────────────────────────────────── + { pid: "NPH-SFP28-25G-SR", formFactor: "SFP28", speedGbps: 25, speed: "25G", reachMeters: 100, reachLabel: "SR", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "25GBASE-SR", notes: "NeoPhotonics 25G SFP28 SR 100m MMF" }, + { pid: "NPH-SFP28-25G-LR", formFactor: "SFP28", speedGbps: 25, speed: "25G", reachMeters: 10000, reachLabel: "LR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "25GBASE-LR", notes: "NeoPhotonics 25G SFP28 LR 10km SMF" }, + + // ── 100G QSFP28 standard ───────────────────────────────────────────────── + { pid: "NPH-QSFP28-100G-SR4", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 100, reachLabel: "SR4", fiberType: "MMF", connector: "MPO", wavelengths: "850nm", standard: "100GBASE-SR4", notes: "NeoPhotonics 100G QSFP28 SR4 100m MMF" }, + { pid: "NPH-QSFP28-100G-LR4", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 10000, reachLabel: "LR4", fiberType: "SMF", connector: "LC", wavelengths: "1295-1310nm", standard: "100GBASE-LR4", notes: "NeoPhotonics 100G QSFP28 LR4 10km SMF" }, + + // ── 100G QSFP28 coherent ZR4 (Telecom) ─────────────────────────────────── + { pid: "NPH-QSFP28-100G-ZR4", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 80000, reachLabel: "ZR4", fiberType: "SMF", connector: "LC", wavelengths: "C-band", standard: "100G ZR4", notes: "NeoPhotonics 100G QSFP28 ZR4 coherent, 80km, C-band" }, + + // ── 100G CFP2-ACO (Telecom coherent analog) ────────────────────────────── + { pid: "NPH-CFP2-ACO-100G", formFactor: "CFP2", speedGbps: 100, speed: "100G", reachMeters: 1000000, reachLabel: "ACO", fiberType: "SMF", connector: "LC", wavelengths: "C-band tunable", standard: "OIF CFP2-ACO", notes: "NeoPhotonics 100G CFP2 ACO coherent C-band, 1000km" }, + + // ── 100G CFP2-DCO (Telecom coherent digital) ───────────────────────────── + { pid: "NPH-CFP2-DCO-100G", formFactor: "CFP2", speedGbps: 100, speed: "100G", reachMeters: 1000000, reachLabel: "DCO", fiberType: "SMF", connector: "LC", wavelengths: "C-band tunable", standard: "OIF CFP2-DCO", notes: "NeoPhotonics 100G CFP2 DCO coherent C-band, 1000km" }, + + // ── 400G QSFP-DD ──────────────────────────────────────────────────────── + { pid: "NPH-QSFP-DD-400G-DR4", formFactor: "QSFP-DD", speedGbps: 400, speed: "400G", reachMeters: 500, reachLabel: "DR4", fiberType: "SMF", connector: "MPO", wavelengths: "1310nm", standard: "400GBASE-DR4", notes: "NeoPhotonics 400G QSFP-DD DR4 500m SMF" }, + { pid: "NPH-QSFP-DD-400G-FR4", formFactor: "QSFP-DD", speedGbps: 400, speed: "400G", reachMeters: 2000, reachLabel: "FR4", fiberType: "SMF", connector: "LC", wavelengths: "1271-1331nm", standard: "400GBASE-FR4", notes: "NeoPhotonics 400G QSFP-DD FR4 2km SMF" }, + + // ── 400G ZR QSFP-DD coherent (Telecom) ────────────────────────────────── + { pid: "NPH-QSFP-DD-400G-ZR", formFactor: "QSFP-DD", speedGbps: 400, speed: "400G", reachMeters: 1000000, reachLabel: "ZR", fiberType: "SMF", connector: "LC", wavelengths: "C-band tunable", standard: "OIF 400ZR", notes: "NeoPhotonics 400G QSFP-DD ZR coherent C-band, 1000km" }, + + // ── DWDM SFP+ (Telecom) ────────────────────────────────────────────────── + { pid: "NPH-DWDM-SFP10G-C", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 80000, reachLabel: "DWDM", fiberType: "SMF", connector: "LC", wavelengths: "C-band tunable", standard: "ITU-T G.694.1", notes: "NeoPhotonics 10G DWDM SFP+ C-band tunable 80km" }, + + // ── 800G OSFP coherent (Telecom) ───────────────────────────────────────── + { pid: "NPH-OSFP-800G-ZR", formFactor: "OSFP", speedGbps: 800, speed: "800G", reachMeters: 1000000, reachLabel: "ZR", fiberType: "SMF", connector: "LC", wavelengths: "C-band tunable", standard: "OIF 800ZR", notes: "NeoPhotonics 800G OSFP ZR coherent C-band, 1000km — flagship coherent PIC" }, +]; + +export async function scrapeNeoPhotonicsOem(): Promise { + console.log("=== NeoPhotonics OEM Transceiver Seed ===\n"); + + const vendorId = await ensureVendor( + "NeoPhotonics", + "oem", + "https://www.neophotonics.com", + undefined + ); + + let inserted = 0; + let updated = 0; + let errors = 0; + + for (const p of NEOPHOTONICS_PIDS) { + const slug = `neophotonics-${p.pid.toLowerCase().replace(/[^a-z0-9]+/g, "-")}`; + const category = p.category ?? (TELECOM_PIDS.has(p.pid) ? "Telecom" : "DataCenter"); + try { + const res = await pool.query( + `INSERT INTO transceivers + (slug, part_number, vendor_id, form_factor, speed, speed_gbps, + reach_meters, reach_label, fiber_type, connector, wavelengths, + dom_support, ieee_reference, market_status, category, notes) + VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,true,$12,'Mainstream',$13,$14) + ON CONFLICT (slug) DO UPDATE SET + speed_gbps = EXCLUDED.speed_gbps, + reach_meters = CASE WHEN EXCLUDED.reach_meters > 0 THEN EXCLUDED.reach_meters ELSE transceivers.reach_meters END, + fiber_type = CASE WHEN EXCLUDED.fiber_type <> '' THEN EXCLUDED.fiber_type ELSE transceivers.fiber_type END, + wavelengths = COALESCE(EXCLUDED.wavelengths, transceivers.wavelengths), + updated_at = NOW() + RETURNING (xmax = 0) as was_inserted`, + [slug, p.pid, vendorId, p.formFactor, p.speed, p.speedGbps, + p.reachMeters, p.reachLabel, p.fiberType, p.connector, + p.wavelengths ?? null, p.standard ?? null, category, p.notes ?? null] + ); + if (res.rows[0]?.was_inserted) inserted++; else updated++; + } catch (err) { + console.warn(` Skip ${p.pid}: ${(err as Error).message.slice(0, 80)}`); + errors++; + } + } + + console.log(`\n=== NeoPhotonics OEM Seed Complete ===`); + console.log(` Inserted: ${inserted}`); + console.log(` Updated: ${updated}`); + console.log(` Errors: ${errors}`); + console.log(` Total PIDs: ${NEOPHOTONICS_PIDS.length}\n`); +} + +if (require.main === module) { + scrapeNeoPhotonicsOem() + .then(() => pool.end()) + .catch((err) => { + console.error("Fatal:", err); + pool.end(); + process.exit(1); + }); +} diff --git a/packages/scraper/src/scrapers/netapp-oem.ts b/packages/scraper/src/scrapers/netapp-oem.ts new file mode 100644 index 0000000..8758279 --- /dev/null +++ b/packages/scraper/src/scrapers/netapp-oem.ts @@ -0,0 +1,358 @@ +/** + * NetApp OEM Transceiver Catalog Seed + * + * Seeds NetApp-branded transceiver PIDs for ONTAP cluster interconnect, + * FAS/AFF storage controllers, and SAN host ports. NetApp uses an X-prefix + * naming scheme (X6xxx / X66xxx series) for optical modules. + * + * Sources: + * - NetApp Hardware Universe (hwu.netapp.com) + * - NetApp ONTAP Storage Hardware Guide + * - NetApp FAS/AFF system-level optical compatibility matrices + * + * Run: tsx packages/scraper/src/scrapers/netapp-oem.ts + * Cron: daily at 05:45 + */ + +import { pool, ensureVendor } from "../utils/db"; + +interface NetappPID { + pid: string; + formFactor: string; + speedGbps: number; + speed: string; + reachMeters: number; + reachLabel: string; + fiberType: string; + connector: string; + wavelengths?: string; + standard?: string; + notes?: string; +} + +// Fibre Channel line-rate speeds (Gbps): +// 8G = 8.5 Gbps (4x FC) +// 16G = 14.025 Gbps (8x FC) +// 32G = 28.05 Gbps (16x FC) +const NETAPP_PIDS: NetappPID[] = [ + // ── 1G SFP ─────────────────────────────────────────────────────────────── + { + pid: "X6565-R6", + formFactor: "SFP", + speedGbps: 1, + speed: "1G", + reachMeters: 550, + reachLabel: "SX", + fiberType: "MMF", + connector: "LC", + wavelengths: "850nm", + standard: "1000BASE-SX", + notes: "1GbE SFP SX; NetApp FAS/AFF management and data ports; OM2/OM3 MMF", + }, + { + pid: "X6566-R6", + formFactor: "SFP", + speedGbps: 1, + speed: "1G", + reachMeters: 10000, + reachLabel: "LX", + fiberType: "SMF", + connector: "LC", + wavelengths: "1310nm", + standard: "1000BASE-LX", + notes: "1GbE SFP LX; NetApp FAS/AFF management and data ports; OS2 SMF", + }, + // ── 10G SFP+ ───────────────────────────────────────────────────────────── + { + pid: "X6567-R6", + formFactor: "SFP+", + speedGbps: 10, + speed: "10G", + reachMeters: 300, + reachLabel: "SR", + fiberType: "MMF", + connector: "LC", + wavelengths: "850nm", + standard: "10GBASE-SR", + notes: "10GbE SFP+ SR; NetApp cluster interconnect and host ports; OM3/OM4 MMF", + }, + { + pid: "X6568-R6", + formFactor: "SFP+", + speedGbps: 10, + speed: "10G", + reachMeters: 10000, + reachLabel: "LR", + fiberType: "SMF", + connector: "LC", + wavelengths: "1310nm", + standard: "10GBASE-LR", + notes: "10GbE SFP+ LR; NetApp cluster interconnect and host ports; OS2 SMF", + }, + { + pid: "X6569-R6", + formFactor: "SFP+", + speedGbps: 10, + speed: "10G", + reachMeters: 40000, + reachLabel: "ER", + fiberType: "SMF", + connector: "LC", + wavelengths: "1550nm", + standard: "10GBASE-ER", + notes: "10GbE SFP+ ER; extended-reach NetApp data-fabric links; OS2 SMF up to 40km", + }, + // ── 8G FC SFP ──────────────────────────────────────────────────────────── + { + pid: "X6596-R6", + formFactor: "SFP", + speedGbps: 8.5, + speed: "8G FC", + reachMeters: 150, + reachLabel: "SW", + fiberType: "MMF", + connector: "LC", + wavelengths: "850nm", + standard: "8GFC", + notes: "8G FC short-wave; NetApp FAS/AFF FC target port; OM3/OM4 MMF", + }, + // ── 16G FC SFP ─────────────────────────────────────────────────────────── + { + pid: "X6597-R6", + formFactor: "SFP", + speedGbps: 14.025, + speed: "16G FC", + reachMeters: 125, + reachLabel: "SW", + fiberType: "MMF", + connector: "LC", + wavelengths: "850nm", + standard: "16GFC", + notes: "16G FC short-wave; NetApp FAS/AFF FC target port; OM4 MMF", + }, + { + pid: "X6598-R6", + formFactor: "SFP", + speedGbps: 14.025, + speed: "16G FC", + reachMeters: 10000, + reachLabel: "LW", + fiberType: "SMF", + connector: "LC", + wavelengths: "1310nm", + standard: "16GFC", + notes: "16G FC long-wave; NetApp FAS/AFF FC target port; OS2 SMF up to 10km", + }, + // ── 32G FC SFP+ ────────────────────────────────────────────────────────── + { + pid: "X6599-R6", + formFactor: "SFP+", + speedGbps: 28.05, + speed: "32G FC", + reachMeters: 100, + reachLabel: "SW", + fiberType: "MMF", + connector: "LC", + wavelengths: "850nm", + standard: "32GFC", + notes: "32G FC short-wave; NetApp AFF FC NVMe/FC host port; OM4/OM5 MMF", + }, + // ── 25G SFP28 ──────────────────────────────────────────────────────────── + { + pid: "X66030A", + formFactor: "SFP28", + speedGbps: 25, + speed: "25G", + reachMeters: 100, + reachLabel: "SR", + fiberType: "MMF", + connector: "LC", + wavelengths: "850nm", + standard: "25GBASE-SR", + notes: "25GbE SFP28 SR; NetApp AFF A-series cluster interconnect; OM4 MMF", + }, + { + pid: "X66031A", + formFactor: "SFP28", + speedGbps: 25, + speed: "25G", + reachMeters: 10000, + reachLabel: "LR", + fiberType: "SMF", + connector: "LC", + wavelengths: "1310nm", + standard: "25GBASE-LR", + notes: "25GbE SFP28 LR; NetApp AFF A-series cluster interconnect; OS2 SMF", + }, + // ── 40G QSFP+ ──────────────────────────────────────────────────────────── + { + pid: "X66240A", + formFactor: "QSFP+", + speedGbps: 40, + speed: "40G", + reachMeters: 150, + reachLabel: "SR4", + fiberType: "MMF", + connector: "MPO", + wavelengths: "850nm", + standard: "40GBASE-SR4", + notes: "40GbE QSFP+ SR4; NetApp cluster interconnect switch uplinks; OM3/OM4 MMF", + }, + { + pid: "X66100A", + formFactor: "QSFP+", + speedGbps: 40, + speed: "40G", + reachMeters: 10000, + reachLabel: "LR4", + fiberType: "SMF", + connector: "LC", + wavelengths: "1310nm", + standard: "40GBASE-LR4", + notes: "40GbE QSFP+ LR4; NetApp cluster interconnect long-reach; OS2 SMF", + }, + // ── 100G QSFP28 ────────────────────────────────────────────────────────── + { + pid: "X66250A", + formFactor: "QSFP28", + speedGbps: 100, + speed: "100G", + reachMeters: 100, + reachLabel: "SR4", + fiberType: "MMF", + connector: "MPO", + wavelengths: "850nm", + standard: "100GBASE-SR4", + notes: "100GbE QSFP28 SR4; NetApp AFF A800/C800 cluster interconnect; OM4 MMF", + }, + { + pid: "X66260A", + formFactor: "QSFP28", + speedGbps: 100, + speed: "100G", + reachMeters: 10000, + reachLabel: "LR4", + fiberType: "SMF", + connector: "LC", + wavelengths: "1295-1310nm", + standard: "100GBASE-LR4", + notes: "100GbE QSFP28 LR4; NetApp AFF A800/C800 cluster interconnect; OS2 SMF", + }, + // ── Copper SFP ─────────────────────────────────────────────────────────── + { + pid: "NETAPP-SFP-1G-T", + formFactor: "SFP", + speedGbps: 1, + speed: "1G", + reachMeters: 100, + reachLabel: "T", + fiberType: "DAC", + connector: "RJ45", + standard: "1000BASE-T", + notes: "1GbE copper SFP RJ45; NetApp management port copper option; Cat5e/6", + }, + { + pid: "NETAPP-SFP-10G-T", + formFactor: "SFP+", + speedGbps: 10, + speed: "10G", + reachMeters: 30, + reachLabel: "T", + fiberType: "DAC", + connector: "RJ45", + standard: "10GBASE-T", + notes: "10GbE copper SFP+ RJ45; NetApp data port copper option; Cat6a", + }, + // ── AOC / DAC ──────────────────────────────────────────────────────────── + { + pid: "X66210A", + formFactor: "QSFP28", + speedGbps: 100, + speed: "100G", + reachMeters: 30, + reachLabel: "AOC", + fiberType: "AOC", + connector: "QSFP28", + notes: "100G Active Optical Cable (AOC); NetApp cluster interconnect short-reach; 30m", + }, + { + pid: "X66220A", + formFactor: "SFP28", + speedGbps: 25, + speed: "25G", + reachMeters: 1, + reachLabel: "DAC-1m", + fiberType: "DAC", + connector: "SFP28", + notes: "25G Direct Attach Copper 1m; NetApp cluster interconnect; passive twinax", + }, + { + pid: "X66230A", + formFactor: "QSFP28", + speedGbps: 100, + speed: "100G", + reachMeters: 3, + reachLabel: "DAC-3m", + fiberType: "DAC", + connector: "QSFP28", + notes: "100G Direct Attach Copper 3m; NetApp cluster interconnect; passive twinax", + }, +]; + +export async function scrapeNetappOem(): Promise { + console.log("=== NetApp OEM Transceiver Seed ===\n"); + + const vendorId = await ensureVendor( + "NetApp", + "oem", + "https://www.netapp.com", + undefined + ); + + let inserted = 0; + let updated = 0; + let errors = 0; + + for (const p of NETAPP_PIDS) { + const slug = `netapp-${p.pid.toLowerCase().replace(/[^a-z0-9]+/g, "-")}`; + try { + const res = await pool.query( + `INSERT INTO transceivers + (slug, part_number, vendor_id, form_factor, speed, speed_gbps, + reach_meters, reach_label, fiber_type, connector, wavelengths, + dom_support, ieee_reference, market_status, category, notes) + VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,true,$12,'Mainstream','DataCenter',$13) + ON CONFLICT (slug) DO UPDATE SET + speed_gbps = EXCLUDED.speed_gbps, + reach_meters = CASE WHEN EXCLUDED.reach_meters > 0 THEN EXCLUDED.reach_meters ELSE transceivers.reach_meters END, + fiber_type = CASE WHEN EXCLUDED.fiber_type <> '' THEN EXCLUDED.fiber_type ELSE transceivers.fiber_type END, + wavelengths = COALESCE(EXCLUDED.wavelengths, transceivers.wavelengths), + updated_at = NOW() + RETURNING (xmax = 0) as was_inserted`, + [slug, p.pid, vendorId, p.formFactor, p.speed, p.speedGbps, + p.reachMeters, p.reachLabel, p.fiberType, p.connector, + p.wavelengths ?? null, p.standard ?? null, p.notes ?? null] + ); + if (res.rows[0]?.was_inserted) inserted++; else updated++; + } catch (err) { + console.warn(` Skip ${p.pid}: ${(err as Error).message.slice(0, 80)}`); + errors++; + } + } + + console.log(`\n=== NetApp OEM Seed Complete ===`); + console.log(` Inserted: ${inserted}`); + console.log(` Updated: ${updated}`); + console.log(` Errors: ${errors}`); + console.log(` Total PIDs: ${NETAPP_PIDS.length}\n`); +} + +if (require.main === module) { + scrapeNetappOem() + .then(() => pool.end()) + .catch((err) => { + console.error("Fatal:", err); + pool.end(); + process.exit(1); + }); +} diff --git a/packages/scraper/src/scrapers/netgear-oem.ts b/packages/scraper/src/scrapers/netgear-oem.ts new file mode 100644 index 0000000..244a4f0 --- /dev/null +++ b/packages/scraper/src/scrapers/netgear-oem.ts @@ -0,0 +1,124 @@ +/** + * Netgear OEM Transceiver Catalog Seed + * + * Seeds Netgear-branded transceiver PIDs for M4300, M4500, + * M6100, and AV Line managed switches. + * + * Sources: + * - Netgear Transceiver Modules (netgear.com/business/wired/switches) + * - Netgear M4300/M4500 Hardware Reference + * + * Run: tsx packages/scraper/src/scrapers/netgear-oem.ts + * Cron: daily at 08:15 + */ + +import { pool, ensureVendor } from "../utils/db"; + +interface NetgearPID { + pid: string; + formFactor: string; + speedGbps: number; + speed: string; + reachMeters: number; + reachLabel: string; + fiberType: string; + connector: string; + wavelengths?: string; + standard?: string; + notes?: string; +} + +const NETGEAR_PIDS: NetgearPID[] = [ + // ── 1G SFP ────────────────────────────────────────────────────────────── + { pid: "AGM731F", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 550, reachLabel: "SX", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "1000BASE-SX", notes: "Netgear 1G SFP MM 550m" }, + { pid: "AGM732F", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 10000, reachLabel: "LX", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "1000BASE-LX", notes: "Netgear 1G SFP SM 10km" }, + { pid: "AGM733F", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 40000, reachLabel: "LH40", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", notes: "Netgear 1G SFP SM 40km" }, + { pid: "AGM734F", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 70000, reachLabel: "ZX", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "1000BASE-ZX", notes: "Netgear 1G SFP SM 70km" }, + { pid: "AGM734", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 100, reachLabel: "T", fiberType: "DAC", connector: "RJ45", standard: "1000BASE-T", notes: "Netgear SFP 1G copper" }, + + // ── 10G SFP+ ──────────────────────────────────────────────────────────── + { pid: "AXM761", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 300, reachLabel: "SR", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "10GBASE-SR", notes: "Netgear 10G SFP+ SR" }, + { pid: "AXM762", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 10000, reachLabel: "LR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "10GBASE-LR", notes: "Netgear 10G SFP+ LR" }, + { pid: "AXM763", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 40000, reachLabel: "ER", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "10GBASE-ER" }, + { pid: "AXM764", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 80000, reachLabel: "ZR", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "10GBASE-ZR" }, + { pid: "AXM765", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 30, reachLabel: "T", fiberType: "DAC", connector: "RJ45", standard: "10GBASE-T" }, + { pid: "AXM766", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 10000, reachLabel: "BiDi", fiberType: "SMF", connector: "LC", wavelengths: "1270/1330nm", notes: "Netgear 10G BiDi single fiber" }, + + // ── 25G SFP28 ─────────────────────────────────────────────────────────── + { pid: "AXM785", formFactor: "SFP28", speedGbps: 25, speed: "25G", reachMeters: 100, reachLabel: "SR", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "25GBASE-SR" }, + { pid: "AXM786", formFactor: "SFP28", speedGbps: 25, speed: "25G", reachMeters: 10000, reachLabel: "LR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "25GBASE-LR" }, + + // ── 40G QSFP+ ─────────────────────────────────────────────────────────── + { pid: "AXM771", formFactor: "QSFP+", speedGbps: 40, speed: "40G", reachMeters: 150, reachLabel: "SR4", fiberType: "MMF", connector: "MPO", wavelengths: "850nm", standard: "40GBASE-SR4" }, + { pid: "AXM772", formFactor: "QSFP+", speedGbps: 40, speed: "40G", reachMeters: 10000, reachLabel: "LR4", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "40GBASE-LR4" }, + + // ── 100G QSFP28 ───────────────────────────────────────────────────────── + { pid: "AXM781", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 100, reachLabel: "SR4", fiberType: "MMF", connector: "MPO", wavelengths: "850nm", standard: "100GBASE-SR4" }, + { pid: "AXM782", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 10000, reachLabel: "LR4", fiberType: "SMF", connector: "LC", wavelengths: "1295-1310nm", standard: "100GBASE-LR4" }, + { pid: "AXM783", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 2000, reachLabel: "CWDM4", fiberType: "SMF", connector: "LC", wavelengths: "1271-1331nm", standard: "100GBASE-CWDM4" }, + + // ── DAC ───────────────────────────────────────────────────────────────── + { pid: "AXC761", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 1, reachLabel: "DAC-1M",fiberType: "DAC", connector: "SFP+", notes: "Netgear 10G SFP+ DAC 1m" }, + { pid: "AXC763", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 3, reachLabel: "DAC-3M",fiberType: "DAC", connector: "SFP+", notes: "Netgear 10G SFP+ DAC 3m" }, + { pid: "AXC771", formFactor: "QSFP+", speedGbps: 40, speed: "40G", reachMeters: 1, reachLabel: "DAC-1M",fiberType: "DAC", connector: "QSFP+", notes: "Netgear 40G QSFP+ DAC 1m" }, + { pid: "AXC781", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 1, reachLabel: "DAC-1M",fiberType: "DAC", connector: "QSFP28", notes: "Netgear 100G QSFP28 DAC 1m" }, + { pid: "AXC783", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 3, reachLabel: "DAC-3M",fiberType: "DAC", connector: "QSFP28", notes: "Netgear 100G QSFP28 DAC 3m" }, +]; + +export async function scrapeNetgearOem(): Promise { + console.log("=== Netgear OEM Transceiver Seed ===\n"); + + const vendorId = await ensureVendor( + "Netgear", + "oem", + "https://www.netgear.com", + undefined + ); + + let inserted = 0; + let updated = 0; + let errors = 0; + + for (const p of NETGEAR_PIDS) { + const slug = `netgear-${p.pid.toLowerCase().replace(/[^a-z0-9]+/g, "-")}`; + try { + const res = await pool.query( + `INSERT INTO transceivers + (slug, part_number, vendor_id, form_factor, speed, speed_gbps, + reach_meters, reach_label, fiber_type, connector, wavelengths, + dom_support, ieee_reference, market_status, category, notes) + VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,true,$12,'Mainstream','DataCenter',$13) + ON CONFLICT (slug) DO UPDATE SET + speed_gbps = EXCLUDED.speed_gbps, + reach_meters = CASE WHEN EXCLUDED.reach_meters > 0 THEN EXCLUDED.reach_meters ELSE transceivers.reach_meters END, + fiber_type = CASE WHEN EXCLUDED.fiber_type <> '' THEN EXCLUDED.fiber_type ELSE transceivers.fiber_type END, + wavelengths = COALESCE(EXCLUDED.wavelengths, transceivers.wavelengths), + updated_at = NOW() + RETURNING (xmax = 0) as was_inserted`, + [slug, p.pid, vendorId, p.formFactor, p.speed, p.speedGbps, + p.reachMeters, p.reachLabel, p.fiberType, p.connector, + p.wavelengths ?? null, p.standard ?? null, p.notes ?? null] + ); + if (res.rows[0]?.was_inserted) inserted++; else updated++; + } catch (err) { + console.warn(` Skip ${p.pid}: ${(err as Error).message.slice(0, 80)}`); + errors++; + } + } + + console.log(`\n=== Netgear OEM Seed Complete ===`); + console.log(` Inserted: ${inserted}`); + console.log(` Updated: ${updated}`); + console.log(` Errors: ${errors}`); + console.log(` Total PIDs: ${NETGEAR_PIDS.length}\n`); +} + +if (require.main === module) { + scrapeNetgearOem() + .then(() => pool.end()) + .catch((err) => { + console.error("Fatal:", err); + pool.end(); + process.exit(1); + }); +} diff --git a/packages/scraper/src/scrapers/nokia-access-oem.ts b/packages/scraper/src/scrapers/nokia-access-oem.ts new file mode 100644 index 0000000..a27a1c4 --- /dev/null +++ b/packages/scraper/src/scrapers/nokia-access-oem.ts @@ -0,0 +1,148 @@ +/** + * Nokia Access OEM Transceiver Catalog Seed + * + * Seeds Nokia Access-branded transceiver PIDs for ISAM / Lightspan GPON, + * XGS-PON, and 25GS-PON OLT platforms (7360 ISAM FX, 7368 ISAM ONT). + * + * Sources: + * - Nokia Access Networks Product Catalog (nokia.com/networks/access-networks) + * - Nokia 7360 ISAM FX Hardware Documentation + * - Nokia XGS-PON / 25GS-PON Line Card Data Sheets + * + * Run: tsx packages/scraper/src/scrapers/nokia-access-oem.ts + * Cron: daily at 08:15 + */ + +import { pool, ensureVendor } from "../utils/db"; + +interface NokiaAccessPID { + pid: string; + formFactor: string; + speedGbps: number; + speed: string; + reachMeters: number; + reachLabel: string; + fiberType: string; + connector: string; + wavelengths?: string; + standard?: string; + notes?: string; + isTelecom?: boolean; +} + +const TELECOM_PIDS: Set = new Set([ + "NOKA-SFP-GPON-OLT-1490", + "NOKA-SFP-GPON-OLT-1490-PLUS", + "NOKA-SFP-XGSPON-OLT-1577", + "NOKA-SFP-XGS-ONU-1270", + "NOKA-SFP-EPON-OLT", + "NOKA-SFP-10G-EPON-OLT", + "NOKA-SFP-25G-PON-OLT", + "NOKA-SFP-1G-BIDI-1310", + "NOKA-SFP-1G-BIDI-1490", + "NOKA-SFP-10G-BIDI-1270", + "NOKA-SFP-10G-BIDI-1577", + "NOKA-SFP-CWDM-1490", + "NOKA-SFP-CWDM-1550", +]); + +const NOKIA_ACCESS_PIDS: NokiaAccessPID[] = [ + // ── GPON OLT SFP ───────────────────────────────────────────────────────── + { pid: "NOKA-SFP-GPON-OLT-1490", formFactor: "SFP", speedGbps: 2.488, speed: "GPON", reachMeters: 20000, reachLabel: "GPON-20K", fiberType: "SMF", connector: "SC", wavelengths: "1490/1310nm", standard: "G.984", notes: "Nokia Access GPON OLT SFP Class B+, ISAM platform", isTelecom: true }, + { pid: "NOKA-SFP-GPON-OLT-1490-PLUS", formFactor: "SFP", speedGbps: 2.488, speed: "GPON", reachMeters: 20000, reachLabel: "GPON-C+", fiberType: "SMF", connector: "SC", wavelengths: "1490/1310nm", standard: "G.984", notes: "Nokia Access GPON OLT SFP Class C+, extended reach", isTelecom: true }, + + // ── XGS-PON OLT SFP+ ───────────────────────────────────────────────────── + { pid: "NOKA-SFP-XGSPON-OLT-1577", formFactor: "SFP+", speedGbps: 10, speed: "XGS-PON", reachMeters: 20000, reachLabel: "XGS-PON-20K", fiberType: "SMF", connector: "SC", wavelengths: "1577/1270nm", standard: "G.9807.1", notes: "Nokia Access XGS-PON OLT SFP+ for 7360 ISAM FX", isTelecom: true }, + { pid: "NOKA-SFP-XGS-ONU-1270", formFactor: "SFP+", speedGbps: 10, speed: "XGS-PON", reachMeters: 20000, reachLabel: "XGS-ONU-20K", fiberType: "SMF", connector: "SC", wavelengths: "1270/1577nm", standard: "G.9807.1", notes: "Nokia Access XGS-PON ONU SFP+ 1270nm TX", isTelecom: true }, + + // ── EPON OLT SFP ───────────────────────────────────────────────────────── + { pid: "NOKA-SFP-EPON-OLT", formFactor: "SFP", speedGbps: 1, speed: "EPON", reachMeters: 20000, reachLabel: "EPON-20K", fiberType: "SMF", connector: "SC", wavelengths: "1490/1310nm", standard: "802.3ah", notes: "Nokia Access EPON OLT SFP 1G/1G", isTelecom: true }, + { pid: "NOKA-SFP-10G-EPON-OLT", formFactor: "SFP+", speedGbps: 10, speed: "10G-EPON", reachMeters: 20000, reachLabel: "10G-EPON-20K",fiberType: "SMF", connector: "SC", wavelengths: "1577/1270nm", standard: "802.3av", notes: "Nokia Access 10G-EPON OLT SFP+", isTelecom: true }, + + // ── 25GS-PON OLT SFP28 ─────────────────────────────────────────────────── + { pid: "NOKA-SFP-25G-PON-OLT", formFactor: "SFP28", speedGbps: 25, speed: "25GS-PON", reachMeters: 20000, reachLabel: "25G-PON-20K", fiberType: "SMF", connector: "SC", wavelengths: "1577/1270nm", standard: "G.9804.3", notes: "Nokia Access 25GS-PON OLT SFP28", isTelecom: true }, + + // ── BiDi SFP 1G ────────────────────────────────────────────────────────── + { pid: "NOKA-SFP-1G-BIDI-1310", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 20000, reachLabel: "BiDi-1310", fiberType: "SMF", connector: "SC", wavelengths: "1310/1490nm", notes: "Nokia Access 1G BiDi SFP 1310nm TX / 1490nm RX", isTelecom: true }, + { pid: "NOKA-SFP-1G-BIDI-1490", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 20000, reachLabel: "BiDi-1490", fiberType: "SMF", connector: "SC", wavelengths: "1490/1310nm", notes: "Nokia Access 1G BiDi SFP 1490nm TX / 1310nm RX", isTelecom: true }, + + // ── BiDi SFP+ 10G ──────────────────────────────────────────────────────── + { pid: "NOKA-SFP-10G-BIDI-1270", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 20000, reachLabel: "BiDi-1270", fiberType: "SMF", connector: "LC", wavelengths: "1270/1330nm", notes: "Nokia Access 10G BiDi SFP+ 1270nm TX", isTelecom: true }, + { pid: "NOKA-SFP-10G-BIDI-1577", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 20000, reachLabel: "BiDi-1577", fiberType: "SMF", connector: "LC", wavelengths: "1577/1270nm", notes: "Nokia Access 10G BiDi SFP+ 1577nm TX", isTelecom: true }, + + // ── Standard 1G SFP ────────────────────────────────────────────────────── + { pid: "NOKA-SFP-GE-SX", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 550, reachLabel: "SX", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "1000BASE-SX" }, + { pid: "NOKA-SFP-GE-LX", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 10000, reachLabel: "LX", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "1000BASE-LX" }, + + // ── Standard 10G SFP+ ──────────────────────────────────────────────────── + { pid: "NOKA-SFP-10G-SR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 300, reachLabel: "SR", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "10GBASE-SR" }, + { pid: "NOKA-SFP-10G-LR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 10000, reachLabel: "LR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "10GBASE-LR" }, + { pid: "NOKA-SFP-10G-ER", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 40000, reachLabel: "ER", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "10GBASE-ER" }, + + // ── CWDM SFP ───────────────────────────────────────────────────────────── + { pid: "NOKA-SFP-CWDM-1490", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 40000, reachLabel: "CWDM-1490", fiberType: "SMF", connector: "LC", wavelengths: "1490nm", standard: "CWDM", notes: "Nokia Access CWDM SFP 1490nm", isTelecom: true }, + { pid: "NOKA-SFP-CWDM-1550", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 40000, reachLabel: "CWDM-1550", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "CWDM", notes: "Nokia Access CWDM SFP 1550nm", isTelecom: true }, + + // ── 40G / 100G QSFP ────────────────────────────────────────────────────── + { pid: "NOKA-QSFP-40G-LR4", formFactor: "QSFP+", speedGbps: 40, speed: "40G", reachMeters: 10000, reachLabel: "LR4", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "40GBASE-LR4" }, + { pid: "NOKA-QSFP-100G-LR4", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 10000, reachLabel: "LR4", fiberType: "SMF", connector: "LC", wavelengths: "1295-1310nm", standard: "100GBASE-LR4" }, +]; + +export async function scrapeNokiaAccessOem(): Promise { + console.log("=== Nokia Access OEM Transceiver Seed ===\n"); + + const vendorId = await ensureVendor( + "Nokia Access", + "oem", + "https://www.nokia.com/networks/access-networks/", + undefined + ); + + let inserted = 0; + let updated = 0; + let errors = 0; + + for (const p of NOKIA_ACCESS_PIDS) { + const slug = `nokia-access-${p.pid.toLowerCase().replace(/[^a-z0-9]+/g, "-")}`; + const category = TELECOM_PIDS.has(p.pid) ? "Telecom" : "DataCenter"; + try { + const res = await pool.query( + `INSERT INTO transceivers + (slug, part_number, vendor_id, form_factor, speed, speed_gbps, + reach_meters, reach_label, fiber_type, connector, wavelengths, + dom_support, ieee_reference, market_status, category, notes) + VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,true,$12,'Mainstream',$13,$14) + ON CONFLICT (slug) DO UPDATE SET + speed_gbps = EXCLUDED.speed_gbps, + reach_meters = CASE WHEN EXCLUDED.reach_meters > 0 THEN EXCLUDED.reach_meters ELSE transceivers.reach_meters END, + fiber_type = CASE WHEN EXCLUDED.fiber_type <> '' THEN EXCLUDED.fiber_type ELSE transceivers.fiber_type END, + wavelengths = COALESCE(EXCLUDED.wavelengths, transceivers.wavelengths), + updated_at = NOW() + RETURNING (xmax = 0) as was_inserted`, + [slug, p.pid, vendorId, p.formFactor, p.speed, p.speedGbps, + p.reachMeters, p.reachLabel, p.fiberType, p.connector, + p.wavelengths ?? null, p.standard ?? null, category, p.notes ?? null] + ); + if (res.rows[0]?.was_inserted) inserted++; else updated++; + } catch (err) { + console.warn(` Skip ${p.pid}: ${(err as Error).message.slice(0, 80)}`); + errors++; + } + } + + console.log(`\n=== Nokia Access OEM Seed Complete ===`); + console.log(` Inserted: ${inserted}`); + console.log(` Updated: ${updated}`); + console.log(` Errors: ${errors}`); + console.log(` Total PIDs: ${NOKIA_ACCESS_PIDS.length}\n`); +} + +if (require.main === module) { + scrapeNokiaAccessOem() + .then(() => pool.end()) + .catch((err) => { + console.error("Fatal:", err); + pool.end(); + process.exit(1); + }); +} diff --git a/packages/scraper/src/scrapers/nokia-airscale-oem.ts b/packages/scraper/src/scrapers/nokia-airscale-oem.ts new file mode 100644 index 0000000..0a02904 --- /dev/null +++ b/packages/scraper/src/scrapers/nokia-airscale-oem.ts @@ -0,0 +1,133 @@ +/** + * Nokia AirScale OEM Transceiver Catalog Seed + * + * Seeds Nokia AirScale-branded transceiver PIDs used in 5G/LTE baseband + * and radio unit fronthaul deployments (CPRI and eCPRI optical interfaces + * for AirScale Radio Access products: AirScale Base Station, ABIA/ABIA-R, + * ASBA, ASIK baseband units and AEHF/AEQF/AEFZ remote radio heads). + * + * CPRI option mapping: + * Option 1: 614.4 Mbps | Option 2: 1228.8 Mbps + * Option 3: 2457.6 Mbps | Option 4: 4915.2 Mbps + * Option 5: 9830.4 Mbps | Option 7: 10137.6 Mbps (CPRI opt 7 / eCPRI) + * + * Sources: + * - Nokia AirScale Radio Access product portfolio (nokia.com) + * - CPRI Specification v7.0 + * - eCPRI Specification v2.0 + * + * Run: tsx packages/scraper/src/scrapers/nokia-airscale-oem.ts + * Cron: daily at 09:30 + */ + +import { pool, ensureVendor } from "../utils/db"; + +interface NokiaAirscalePID { + pid: string; + formFactor: string; + speedGbps: number; + speed: string; + reachMeters: number; + reachLabel: string; + fiberType: string; + connector: string; + wavelengths?: string; + standard?: string; + notes?: string; +} + +const NOKIA_AIRSCALE_PIDS: NokiaAirscalePID[] = [ + // ── CPRI Option 1/2 — 1G SFP ──────────────────────────────────────────── + { pid: "NAS-SFP-CPRI-1G-SX", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 300, reachLabel: "SX", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "1000BASE-SX", notes: "Nokia AirScale CPRI option 1 (614.4 Mbps) / option 2 (1228.8 Mbps) SFP SX fronthaul" }, + { pid: "NAS-SFP-CPRI-2G-LX", formFactor: "SFP", speedGbps: 1.2288, speed: "1.2G", reachMeters: 10000, reachLabel: "LX", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "1000BASE-LX", notes: "Nokia AirScale CPRI option 2 (1228.8 Mbps) SFP LX fronthaul" }, + + // ── CPRI Option 7 — 10G SFP+ ──────────────────────────────────────────── + { pid: "NAS-SFP-CPRI-10G-SR", formFactor: "SFP+", speedGbps: 10.137, speed: "10G", reachMeters: 300, reachLabel: "SR", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "10GBASE-SR", notes: "Nokia AirScale CPRI option 7 (10137.6 Mbps) SFP+ SR — standard LTE/5G fronthaul" }, + { pid: "NAS-SFP-CPRI-10G-LR", formFactor: "SFP+", speedGbps: 10.137, speed: "10G", reachMeters: 10000, reachLabel: "LR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "10GBASE-LR", notes: "Nokia AirScale CPRI option 7 SFP+ LR for long-reach fronthaul (up to 10 km)" }, + + // ── CPRI Option 7 — 40G QSFP+ ─────────────────────────────────────────── + { pid: "NAS-QSFP-CPRI-40G-SR4", formFactor: "QSFP+", speedGbps: 40, speed: "40G", reachMeters: 150, reachLabel: "SR4", fiberType: "MMF", connector: "MPO", wavelengths: "850nm", standard: "40GBASE-SR4", notes: "Nokia AirScale aggregated CPRI 40G QSFP+ SR4 (4x CPRI opt 7 lanes)" }, + + // ── eCPRI — 25G SFP28 ─────────────────────────────────────────────────── + { pid: "NAS-SFP28-ECPRI-25G-SR", formFactor: "SFP28", speedGbps: 25, speed: "25G", reachMeters: 100, reachLabel: "SR", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "25GBASE-SR", notes: "Nokia AirScale eCPRI 25G SFP28 SR for 5G NR O-RAN fronthaul (Option 7-2x split)" }, + { pid: "NAS-SFP28-ECPRI-25G-LR", formFactor: "SFP28", speedGbps: 25, speed: "25G", reachMeters: 10000, reachLabel: "LR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "25GBASE-LR", notes: "Nokia AirScale eCPRI 25G SFP28 LR for long-reach 5G NR fronthaul" }, + + // ── eCPRI — 100G QSFP28 ───────────────────────────────────────────────── + { pid: "NAS-QSFP28-ECPRI-100G-SR4", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 100, reachLabel: "SR4", fiberType: "MMF", connector: "MPO", wavelengths: "850nm", standard: "100GBASE-SR4", notes: "Nokia AirScale eCPRI 100G QSFP28 SR4 for massive MIMO aggregated fronthaul" }, + + // ── Standard data-plane SFP+ ──────────────────────────────────────────── + { pid: "NAS-SFP-10G-SR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 300, reachLabel: "SR", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "10GBASE-SR", notes: "Nokia AirScale standard 10G SFP+ SR for BBU uplink / transport" }, + { pid: "NAS-SFP-10G-LR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 10000, reachLabel: "LR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "10GBASE-LR" }, + + // ── 40G QSFP+ data-plane ──────────────────────────────────────────────── + { pid: "NAS-QSFP-40G-LR4", formFactor: "QSFP+", speedGbps: 40, speed: "40G", reachMeters: 10000, reachLabel: "LR4", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "40GBASE-LR4" }, + + // ── 100G QSFP28 data-plane ────────────────────────────────────────────── + { pid: "NAS-QSFP-100G-LR4", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 10000, reachLabel: "LR4", fiberType: "SMF", connector: "LC", wavelengths: "1295-1310nm", standard: "100GBASE-LR4", notes: "Nokia AirScale 100G QSFP28 LR4 for midhaul / backhaul" }, + + // ── 1G SFP management ─────────────────────────────────────────────────── + { pid: "NAS-SFP-GE-SX", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 550, reachLabel: "SX", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "1000BASE-SX" }, + { pid: "NAS-SFP-GE-LX", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 10000, reachLabel: "LX", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "1000BASE-LX" }, + + // ── BiDi SFP+ (single-fiber fronthaul) ────────────────────────────────── + { pid: "NAS-SFP-10G-BIDI-1270", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 20000, reachLabel: "BIDI", fiberType: "SMF", connector: "LC", wavelengths: "1270/1330nm", notes: "Nokia AirScale BiDi SFP+ Tx1270/Rx1330 for CPRI opt 7 single-fiber fronthaul" }, + { pid: "NAS-SFP-10G-BIDI-1330", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 20000, reachLabel: "BIDI", fiberType: "SMF", connector: "LC", wavelengths: "1330/1270nm", notes: "Nokia AirScale BiDi SFP+ Tx1330/Rx1270 (paired with NAS-SFP-10G-BIDI-1270)" }, +]; + +export async function scrapeNokiaAirscaleOem(): Promise { + console.log("=== Nokia AirScale OEM Transceiver Seed ===\n"); + + const vendorId = await ensureVendor( + "Nokia AirScale", + "oem", + "https://www.nokia.com/networks/mobile-networks/airscale-radio-access/", + undefined + ); + + let inserted = 0; + let updated = 0; + let errors = 0; + + for (const p of NOKIA_AIRSCALE_PIDS) { + const slug = `nokia-as-${p.pid.toLowerCase().replace(/[^a-z0-9]+/g, "-")}`; + try { + const res = await pool.query( + `INSERT INTO transceivers + (slug, part_number, vendor_id, form_factor, speed, speed_gbps, + reach_meters, reach_label, fiber_type, connector, wavelengths, + dom_support, ieee_reference, market_status, category, notes) + VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,true,$12,'Mainstream','DataCenter',$13) + ON CONFLICT (slug) DO UPDATE SET + speed_gbps = EXCLUDED.speed_gbps, + reach_meters = CASE WHEN EXCLUDED.reach_meters > 0 THEN EXCLUDED.reach_meters ELSE transceivers.reach_meters END, + fiber_type = CASE WHEN EXCLUDED.fiber_type <> '' THEN EXCLUDED.fiber_type ELSE transceivers.fiber_type END, + wavelengths = COALESCE(EXCLUDED.wavelengths, transceivers.wavelengths), + updated_at = NOW() + RETURNING (xmax = 0) as was_inserted`, + [slug, p.pid, vendorId, p.formFactor, p.speed, p.speedGbps, + p.reachMeters, p.reachLabel, p.fiberType, p.connector, + p.wavelengths ?? null, p.standard ?? null, p.notes ?? null] + ); + if (res.rows[0]?.was_inserted) inserted++; else updated++; + } catch (err) { + console.warn(` Skip ${p.pid}: ${(err as Error).message.slice(0, 80)}`); + errors++; + } + } + + console.log(`\n=== Nokia AirScale OEM Seed Complete ===`); + console.log(` Inserted: ${inserted}`); + console.log(` Updated: ${updated}`); + console.log(` Errors: ${errors}`); + console.log(` Total PIDs: ${NOKIA_AIRSCALE_PIDS.length}\n`); +} + +if (require.main === module) { + scrapeNokiaAirscaleOem() + .then(() => pool.end()) + .catch((err) => { + console.error("Fatal:", err); + pool.end(); + process.exit(1); + }); +} diff --git a/packages/scraper/src/scrapers/nokia-oem.ts b/packages/scraper/src/scrapers/nokia-oem.ts index abf115d..d994298 100644 --- a/packages/scraper/src/scrapers/nokia-oem.ts +++ b/packages/scraper/src/scrapers/nokia-oem.ts @@ -1,24 +1,23 @@ /** - * Nokia / Alcatel-Lucent OEM Transceiver Catalog Seed + * Nokia OEM Transceiver Catalog Seed * - * Seeds Nokia-branded transceiver PIDs into the transceivers table. - * Nokia uses both a legacy Alcatel-Lucent naming scheme (SFP-1G-SX-C) - * and 3HExxxxxx part numbers. This seed covers the common public PIDs. + * Seeds Nokia-branded transceiver PIDs for IP/Optical division platforms: + * 7750 SR, 7210 SAS, 7705 SAR, and 7450 ESS series. * * Sources: - * - Nokia Transceiver Compatibility Guide (public, nokia.com) - * - Nokia 7750 SR / 7210 SAS / FP5 platform hardware guides - * - Alcatel-Lucent legacy SFP catalog + * - Nokia 7750 SR Transceiver Module Guide + * - Nokia 7210 SAS-Mxp/Sx/T Hardware Installation Guide + * - Nokia 7705 SAR Hardware Installation Guide + * - Nokia Optical Networks Product Portfolio (nokia.com) * * Run: tsx packages/scraper/src/scrapers/nokia-oem.ts - * Cron: daily at 04:45 + * Cron: daily at 12:45 */ import { pool, ensureVendor } from "../utils/db"; interface NokiaPID { pid: string; - alias?: string; // alternate part number (3HExxxxxxxx) formFactor: string; speedGbps: number; speed: string; @@ -28,77 +27,80 @@ interface NokiaPID { connector: string; wavelengths?: string; standard?: string; + category?: string; notes?: string; } const NOKIA_PIDS: NokiaPID[] = [ // ── 1G SFP ────────────────────────────────────────────────────────────── - { pid: "SFP-1G-SX-C", alias: "3HE00027BA", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 550, reachLabel: "SX", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "1000BASE-SX" }, - { pid: "SFP-1G-LX-C", alias: "3HE00028BA", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 10000, reachLabel: "LX", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "1000BASE-LX" }, - { pid: "SFP-1G-LH-C", alias: "3HE00036BA", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 70000, reachLabel: "LH", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "1000BASE-LH" }, - { pid: "SFP-1G-ZX-C", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 80000, reachLabel: "ZX", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "1000BASE-ZX" }, - { pid: "SFP-1G-T-C", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 100, reachLabel: "T", fiberType: "DAC", connector: "RJ45", standard: "1000BASE-T" }, + { pid: "3HE00027AA", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 550, reachLabel: "SX", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "1000BASE-SX" }, + { pid: "3HE00028AA", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 10000, reachLabel: "LX", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "1000BASE-LX" }, + { pid: "3HE02916AA", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 80000, reachLabel: "ZX", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "1000BASE-ZX" }, + { pid: "3HE00062AA", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 100, reachLabel: "T", fiberType: "DAC", connector: "RJ45", standard: "1000BASE-T" }, // ── 10G SFP+ ──────────────────────────────────────────────────────────── - { pid: "SFP-10G-SR-C", alias: "3HE04823AA", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 300, reachLabel: "SR", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "10GBASE-SR" }, - { pid: "SFP-10G-LR-C", alias: "3HE04824AA", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 10000, reachLabel: "LR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "10GBASE-LR" }, - { pid: "SFP-10G-ER-C", alias: "3HE04826AA", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 40000, reachLabel: "ER", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "10GBASE-ER" }, - { pid: "SFP-10G-ZR-C", alias: "3HE04827AA", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 80000, reachLabel: "ZR", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "10GBASE-ZR" }, - { pid: "SFP-10G-LRM-C", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 220, reachLabel: "LRM", fiberType: "MMF", connector: "LC", wavelengths: "1310nm", standard: "10GBASE-LRM" }, - { pid: "SFP-10G-T-C", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 30, reachLabel: "T", fiberType: "DAC", connector: "RJ45", standard: "10GBASE-T" }, + { pid: "3HE04823AA", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 300, reachLabel: "SR", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "10GBASE-SR" }, + { pid: "3HE04821AA", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 10000, reachLabel: "LR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "10GBASE-LR" }, + { pid: "3HE04822AA", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 40000, reachLabel: "ER", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "10GBASE-ER" }, + { pid: "3HE04824AA", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 80000, reachLabel: "ZR", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "10GBASE-ZR" }, + { pid: "3HE07169AA", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 220, reachLabel: "LRM", fiberType: "MMF", connector: "LC", wavelengths: "1310nm", standard: "10GBASE-LRM" }, - // ── 10G DWDM SFP+ (common in 7750 SR) ─────────────────────────────────── - { pid: "SFP-10G-DWDM-ZR-C", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 80000, reachLabel: "DWDM-ZR",fiberType:"SMF",connector: "LC", wavelengths: "C-band", notes: "DWDM tunable ZR" }, - { pid: "SFP-10G-DWDM-ER-C", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 40000, reachLabel: "DWDM-ER",fiberType:"SMF",connector: "LC", wavelengths: "C-band", notes: "DWDM fixed-channel ER" }, + // ── 10G DWDM SFP+ (IP/Optical) ───────────────────────────────────────── + { pid: "3HE05036AA", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 80000, reachLabel: "DWDM", fiberType: "SMF", connector: "LC", wavelengths: "C-band DWDM", category: "Telecom", notes: "Nokia 10G DWDM SFP+ tunable for 7750 SR" }, + { pid: "3HE05037AA", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 80000, reachLabel: "DWDM", fiberType: "SMF", connector: "LC", wavelengths: "1529.55nm C1", category: "Telecom", notes: "Nokia 10G DWDM SFP+ fixed channel C1" }, // ── 25G SFP28 ─────────────────────────────────────────────────────────── - { pid: "SFP-25G-SR-C", alias: "3HE12170AA", formFactor: "SFP28", speedGbps: 25, speed: "25G", reachMeters: 100, reachLabel: "SR", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "25GBASE-SR" }, - { pid: "SFP-25G-LR-C", alias: "3HE12171AA", formFactor: "SFP28", speedGbps: 25, speed: "25G", reachMeters: 10000, reachLabel: "LR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "25GBASE-LR" }, - { pid: "SFP-25G-ER-C", formFactor: "SFP28", speedGbps: 25, speed: "25G", reachMeters: 30000, reachLabel: "ER", fiberType: "SMF", connector: "LC", wavelengths: "1310nm" }, + { pid: "3HE11999AA", formFactor: "SFP28", speedGbps: 25, speed: "25G", reachMeters: 100, reachLabel: "SR", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "25GBASE-SR" }, + { pid: "3HE12000AA", formFactor: "SFP28", speedGbps: 25, speed: "25G", reachMeters: 10000, reachLabel: "LR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "25GBASE-LR" }, + { pid: "3HE12001AA", formFactor: "SFP28", speedGbps: 25, speed: "25G", reachMeters: 30000, reachLabel: "ER", fiberType: "SMF", connector: "LC", wavelengths: "1310nm" }, // ── 40G QSFP+ ─────────────────────────────────────────────────────────── - { pid: "QSFP+-40G-SR4-C", alias: "3HE07690AA", formFactor: "QSFP+", speedGbps: 40, speed: "40G", reachMeters: 150, reachLabel: "SR4", fiberType: "MMF", connector: "MPO", wavelengths: "850nm", standard: "40GBASE-SR4" }, - { pid: "QSFP+-40G-LR4-C", alias: "3HE07692AA", formFactor: "QSFP+", speedGbps: 40, speed: "40G", reachMeters: 10000, reachLabel: "LR4", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "40GBASE-LR4" }, - { pid: "QSFP+-40G-ER4-C", formFactor: "QSFP+", speedGbps: 40, speed: "40G", reachMeters: 40000, reachLabel: "ER4", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "40GBASE-ER4" }, - { pid: "QSFP+-40G-UNIV-C", formFactor: "QSFP+", speedGbps: 40, speed: "40G", reachMeters: 150, reachLabel: "UNIV", fiberType: "MMF", connector: "LC", wavelengths: "850nm", notes: "Universal SR4 2-fiber" }, + { pid: "3HE09828AA", formFactor: "QSFP+", speedGbps: 40, speed: "40G", reachMeters: 150, reachLabel: "SR4", fiberType: "MMF", connector: "MPO", wavelengths: "850nm", standard: "40GBASE-SR4" }, + { pid: "3HE09829AA", formFactor: "QSFP+", speedGbps: 40, speed: "40G", reachMeters: 10000, reachLabel: "LR4", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "40GBASE-LR4" }, + { pid: "3HE07753AA", formFactor: "QSFP+", speedGbps: 40, speed: "40G", reachMeters: 40000, reachLabel: "ER4", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "40GBASE-ER4" }, // ── 100G QSFP28 ───────────────────────────────────────────────────────── - { pid: "QSFP28-100G-SR4-C", alias: "3HE12138AA", formFactor: "QSFP28",speedGbps: 100, speed: "100G", reachMeters: 100, reachLabel: "SR4", fiberType: "MMF", connector: "MPO", wavelengths: "850nm", standard: "100GBASE-SR4" }, - { pid: "QSFP28-100G-LR4-C", alias: "3HE12139AA", formFactor: "QSFP28",speedGbps: 100, speed: "100G", reachMeters: 10000, reachLabel: "LR4", fiberType: "SMF", connector: "LC", wavelengths: "1295-1310nm", standard: "100GBASE-LR4" }, - { pid: "QSFP28-100G-ER4-C", formFactor: "QSFP28",speedGbps: 100, speed: "100G", reachMeters: 30000, reachLabel: "ER4", fiberType: "SMF", connector: "LC", wavelengths: "1295-1310nm" }, - { pid: "QSFP28-100G-CWDM4-C", formFactor: "QSFP28",speedGbps: 100, speed: "100G", reachMeters: 2000, reachLabel: "CWDM4",fiberType: "SMF", connector: "LC", wavelengths: "1271-1331nm", standard: "100GBASE-CWDM4" }, - { pid: "QSFP28-100G-DR-C", formFactor: "QSFP28",speedGbps: 100, speed: "100G", reachMeters: 500, reachLabel: "DR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "100GBASE-DR" }, - { pid: "QSFP28-100G-FR-C", formFactor: "QSFP28",speedGbps: 100, speed: "100G", reachMeters: 2000, reachLabel: "FR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "100GBASE-FR" }, - { pid: "QSFP28-100G-ZR4-C", formFactor: "QSFP28",speedGbps: 100, speed: "100G", reachMeters: 80000, reachLabel: "ZR4", fiberType: "SMF", connector: "LC", wavelengths: "C-band", notes: "Coherent 100G ZR4 DWDM" }, - { pid: "QSFP28-100G-LR4L-C", formFactor: "QSFP28",speedGbps: 100, speed: "100G", reachMeters: 2000, reachLabel: "LR4L", fiberType: "SMF", connector: "LC", wavelengths: "1295-1310nm", notes: "100G LR4 Lite (Nokia)" }, + { pid: "3HE11941AA", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 100, reachLabel: "SR4", fiberType: "MMF", connector: "MPO", wavelengths: "850nm", standard: "100GBASE-SR4" }, + { pid: "3HE11942AA", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 10000, reachLabel: "LR4", fiberType: "SMF", connector: "LC", wavelengths: "1295-1310nm", standard: "100GBASE-LR4" }, + { pid: "3HE11943AA", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 2000, reachLabel: "CWDM4", fiberType: "SMF", connector: "LC", wavelengths: "1271-1331nm", standard: "100GBASE-CWDM4" }, + { pid: "3HE11944AA", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 500, reachLabel: "DR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "100GBASE-DR" }, + { pid: "3HE11945AA", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 40000, reachLabel: "ER4", fiberType: "SMF", connector: "LC", wavelengths: "1295-1310nm", standard: "100GBASE-ER4" }, - // ── 200G QSFP-DD ──────────────────────────────────────────────────────── - { pid: "QSFPDD-200G-SR4-C", formFactor: "QSFP-DD",speedGbps: 200,speed: "200G", reachMeters: 100, reachLabel: "SR4", fiberType: "MMF", connector: "MPO", wavelengths: "850nm" }, - { pid: "QSFPDD-200G-FR4-C", formFactor: "QSFP-DD",speedGbps: 200,speed: "200G", reachMeters: 2000, reachLabel: "FR4", fiberType: "SMF", connector: "LC", wavelengths: "1271-1331nm" }, + // ── 100G CFP2 Coherent ─────────────────────────────────────────────────── + { pid: "3HE10987AA", formFactor: "CFP2", speedGbps: 100, speed: "100G", reachMeters: 1500000, reachLabel: "DCO", fiberType: "SMF", connector: "LC", wavelengths: "C-band", category: "Telecom", notes: "Nokia 100G CFP2 DCO coherent" }, // ── 400G QSFP-DD ──────────────────────────────────────────────────────── - { pid: "QSFPDD-400G-SR8-C", alias: "3HE15771AA", formFactor: "QSFP-DD",speedGbps: 400,speed: "400G", reachMeters: 100, reachLabel: "SR8", fiberType: "MMF", connector: "MPO", wavelengths: "850nm", standard: "400GBASE-SR8" }, - { pid: "QSFPDD-400G-DR4-C", alias: "3HE15772AA", formFactor: "QSFP-DD",speedGbps: 400,speed: "400G", reachMeters: 500, reachLabel: "DR4", fiberType: "SMF", connector: "MPO", wavelengths: "1310nm", standard: "400GBASE-DR4" }, - { pid: "QSFPDD-400G-FR4-C", formFactor: "QSFP-DD",speedGbps: 400,speed: "400G", reachMeters: 2000, reachLabel: "FR4", fiberType: "SMF", connector: "LC", wavelengths: "1271-1331nm", standard: "400GBASE-FR4" }, - { pid: "QSFPDD-400G-LR4-C", formFactor: "QSFP-DD",speedGbps: 400,speed: "400G", reachMeters: 10000, reachLabel: "LR4", fiberType: "SMF", connector: "LC", wavelengths: "1295-1310nm", standard: "400GBASE-LR4" }, - { pid: "QSFPDD-400G-ZR-C", formFactor: "QSFP-DD",speedGbps: 400,speed: "400G", reachMeters: 80000, reachLabel: "ZR", fiberType: "SMF", connector: "LC", wavelengths: "C-band", standard: "400ZR" }, - { pid: "QSFPDD-400G-ZRP-C", formFactor: "QSFP-DD",speedGbps: 400,speed: "400G", reachMeters: 120000,reachLabel: "ZR+", fiberType: "SMF", connector: "LC", wavelengths: "C-band", standard: "OpenZR+" }, + { pid: "3HE16028AA", formFactor: "QSFP-DD", speedGbps: 400, speed: "400G", reachMeters: 100, reachLabel: "SR8", fiberType: "MMF", connector: "MPO", wavelengths: "850nm", standard: "400GBASE-SR8" }, + { pid: "3HE16029AA", formFactor: "QSFP-DD", speedGbps: 400, speed: "400G", reachMeters: 500, reachLabel: "DR4", fiberType: "SMF", connector: "MPO", wavelengths: "1310nm", standard: "400GBASE-DR4" }, + { pid: "3HE16030AA", formFactor: "QSFP-DD", speedGbps: 400, speed: "400G", reachMeters: 2000, reachLabel: "FR4", fiberType: "SMF", connector: "LC", wavelengths: "1271-1331nm", standard: "400GBASE-FR4" }, + { pid: "3HE16031AA", formFactor: "QSFP-DD", speedGbps: 400, speed: "400G", reachMeters: 10000, reachLabel: "LR4", fiberType: "SMF", connector: "LC", wavelengths: "1295-1310nm", standard: "400GBASE-LR4" }, + + // ── 400G ZR QSFP-DD Coherent ──────────────────────────────────────────── + { pid: "3HE16032AA", formFactor: "QSFP-DD", speedGbps: 400, speed: "400G", reachMeters: 120000, reachLabel: "ZR", fiberType: "SMF", connector: "LC", wavelengths: "C-band", standard: "400ZR", category: "Telecom", notes: "Nokia 400G ZR coherent QSFP-DD" }, // ── DAC ───────────────────────────────────────────────────────────────── - { pid: "SFP-10G-DAC-1M-C", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 1, reachLabel: "DAC-1M",fiberType:"DAC", connector: "SFP+" }, - { pid: "SFP-10G-DAC-3M-C", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 3, reachLabel: "DAC-3M",fiberType:"DAC", connector: "SFP+" }, - { pid: "QSFP+-40G-DAC-3M-C", formFactor: "QSFP+", speedGbps: 40, speed: "40G", reachMeters: 3, reachLabel: "DAC-3M",fiberType:"DAC", connector: "QSFP+" }, - { pid: "QSFP28-100G-DAC-1M-C", formFactor: "QSFP28",speedGbps: 100, speed: "100G", reachMeters: 1, reachLabel: "DAC-1M",fiberType:"DAC", connector: "QSFP28" }, - { pid: "QSFP28-100G-DAC-3M-C", formFactor: "QSFP28",speedGbps: 100, speed: "100G", reachMeters: 3, reachLabel: "DAC-3M",fiberType:"DAC", connector: "QSFP28" }, + { pid: "3HE04930AA", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 1, reachLabel: "DAC-1M", fiberType: "DAC", connector: "SFP+" }, + { pid: "3HE04931AA", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 3, reachLabel: "DAC-3M", fiberType: "DAC", connector: "SFP+" }, + { pid: "3HE11995AA", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 1, reachLabel: "DAC-1M", fiberType: "DAC", connector: "QSFP28" }, + { pid: "3HE11996AA", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 3, reachLabel: "DAC-3M", fiberType: "DAC", connector: "QSFP28" }, + { pid: "3HE16033AA", formFactor: "QSFP-DD", speedGbps: 400, speed: "400G", reachMeters: 1, reachLabel: "DAC-1M", fiberType: "DAC", connector: "QSFP-DD" }, ]; +// PIDs that use 'Telecom' category (coherent/DWDM) +const TELECOM_PIDS = new Set([ + "3HE05036AA", + "3HE05037AA", + "3HE10987AA", + "3HE16032AA", +]); + export async function scrapeNokiaOem(): Promise { - console.log("=== Nokia / Alcatel-Lucent OEM Transceiver Seed ===\n"); + console.log("=== Nokia OEM Transceiver Seed ===\n"); const vendorId = await ensureVendor( "Nokia", "oem", - "https://www.nokia.com", + "https://www.nokia.com/networks/optical-networks/", undefined ); @@ -107,16 +109,15 @@ export async function scrapeNokiaOem(): Promise { let errors = 0; for (const p of NOKIA_PIDS) { - const slug = `nokia-${p.pid.toLowerCase().replace(/[^a-z0-9]+/g, "-")}`; - // Store alias in notes if present - const notes = [p.notes, p.alias ? `Alt PN: ${p.alias}` : null].filter(Boolean).join(" | ") || null; + const slug = `nokia-${p.pid.toLowerCase().replace(/[^a-z0-9]+/g, "-")}`; + const category = p.category ?? (TELECOM_PIDS.has(p.pid) ? "Telecom" : "DataCenter"); try { const res = await pool.query( `INSERT INTO transceivers (slug, part_number, vendor_id, form_factor, speed, speed_gbps, reach_meters, reach_label, fiber_type, connector, wavelengths, dom_support, ieee_reference, market_status, category, notes) - VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,true,$12,'Mainstream','DataCenter',$13) + VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,true,$12,'Mainstream',$13,$14) ON CONFLICT (slug) DO UPDATE SET speed_gbps = EXCLUDED.speed_gbps, reach_meters = CASE WHEN EXCLUDED.reach_meters > 0 THEN EXCLUDED.reach_meters ELSE transceivers.reach_meters END, @@ -126,7 +127,7 @@ export async function scrapeNokiaOem(): Promise { RETURNING (xmax = 0) as was_inserted`, [slug, p.pid, vendorId, p.formFactor, p.speed, p.speedGbps, p.reachMeters, p.reachLabel, p.fiberType, p.connector, - p.wavelengths ?? null, p.standard ?? null, notes] + p.wavelengths ?? null, p.standard ?? null, category, p.notes ?? null] ); if (res.rows[0]?.was_inserted) inserted++; else updated++; } catch (err) { diff --git a/packages/scraper/src/scrapers/o-net-oem.ts b/packages/scraper/src/scrapers/o-net-oem.ts new file mode 100644 index 0000000..794b2b2 --- /dev/null +++ b/packages/scraper/src/scrapers/o-net-oem.ts @@ -0,0 +1,145 @@ +/** + * O-Net Technologies OEM Transceiver Catalog Seed + * + * Seeds O-Net Technologies-branded transceiver PIDs. O-Net Technologies + * (Group) Limited (HKEX: 877) is a Shenzhen-based vertically integrated + * optical transceiver manufacturer covering DataCenter, Telecom, and + * Access network applications. Known for high-volume OEM supply to + * major network equipment vendors. + * + * Sources: + * - O-Net Technologies Product Catalog (o-nettech.com/products) + * - O-Net DataCenter & Telecom Transceiver Portfolio + * - IEEE 802.3 / OIF 400ZR / ITU-T G.694 Standards + * + * Run: tsx packages/scraper/src/scrapers/o-net-oem.ts + * Cron: daily at 21:00 + */ + +import { pool, ensureVendor } from "../utils/db"; + +interface ONetPID { + pid: string; + formFactor: string; + speedGbps: number; + speed: string; + reachMeters: number; + reachLabel: string; + fiberType: string; + connector: string; + wavelengths?: string; + standard?: string; + category?: string; + notes?: string; +} + +// PIDs that belong to the Telecom category (ZR, coherent, DWDM, CWDM) +const TELECOM_PIDS = new Set([ + "ON-SFP10G-ZR", + "ON-CFP2-DCO-100G", + "ON-DWDM-SFP10G-TUNE", + "ON-CWDM-SFP10G-1470", + "ON-CWDM-SFP10G-1490", + "ON-CWDM-SFP10G-1510", + "ON-CWDM-SFP10G-1530", + "ON-QSFPDD-400G-ZR", +]); + +const ONET_PIDS: ONetPID[] = [ + // ── 10G SFP+ ──────────────────────────────────────────────────────────── + { pid: "ON-SFP10G-SR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 300, reachLabel: "SR", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "10GBASE-SR", notes: "O-Net 10G SFP+ SR 300m MMF" }, + { pid: "ON-SFP10G-LR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 10000, reachLabel: "LR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "10GBASE-LR", notes: "O-Net 10G SFP+ LR 10km SMF" }, + { pid: "ON-SFP10G-ER", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 40000, reachLabel: "ER", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "10GBASE-ER", notes: "O-Net 10G SFP+ ER 40km SMF" }, + { pid: "ON-SFP10G-ZR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 80000, reachLabel: "ZR", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "10GBASE-ZR", notes: "O-Net 10G SFP+ ZR 80km SMF" }, + + // ── 10G DWDM SFP+ C-band tunable (Telecom) ────────────────────────────── + { pid: "ON-DWDM-SFP10G-TUNE", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 80000, reachLabel: "DWDM", fiberType: "SMF", connector: "LC", wavelengths: "C-band tunable", category: "Telecom", notes: "O-Net 10G DWDM SFP+ C-band tunable for metro DWDM" }, + + // ── 10G CWDM SFP+ (Telecom) ───────────────────────────────────────────── + { pid: "ON-CWDM-SFP10G-1470", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 40000, reachLabel: "CWDM", fiberType: "SMF", connector: "LC", wavelengths: "1470nm", standard: "ITU-T G.694.2", category: "Telecom", notes: "O-Net 10G CWDM SFP+ 1470nm 40km" }, + { pid: "ON-CWDM-SFP10G-1490", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 40000, reachLabel: "CWDM", fiberType: "SMF", connector: "LC", wavelengths: "1490nm", standard: "ITU-T G.694.2", category: "Telecom", notes: "O-Net 10G CWDM SFP+ 1490nm 40km" }, + { pid: "ON-CWDM-SFP10G-1510", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 40000, reachLabel: "CWDM", fiberType: "SMF", connector: "LC", wavelengths: "1510nm", standard: "ITU-T G.694.2", category: "Telecom", notes: "O-Net 10G CWDM SFP+ 1510nm 40km" }, + { pid: "ON-CWDM-SFP10G-1530", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 40000, reachLabel: "CWDM", fiberType: "SMF", connector: "LC", wavelengths: "1530nm", standard: "ITU-T G.694.2", category: "Telecom", notes: "O-Net 10G CWDM SFP+ 1530nm 40km" }, + + // ── 25G SFP28 ─────────────────────────────────────────────────────────── + { pid: "ON-SFP28-25G-SR", formFactor: "SFP28", speedGbps: 25, speed: "25G", reachMeters: 300, reachLabel: "SR", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "25GBASE-SR", notes: "O-Net 25G SFP28 SR 300m MMF" }, + { pid: "ON-SFP28-25G-LR", formFactor: "SFP28", speedGbps: 25, speed: "25G", reachMeters: 10000, reachLabel: "LR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "25GBASE-LR", notes: "O-Net 25G SFP28 LR 10km SMF" }, + + // ── 40G QSFP+ ─────────────────────────────────────────────────────────── + { pid: "ON-QSFP-40G-SR4", formFactor: "QSFP+", speedGbps: 40, speed: "40G", reachMeters: 150, reachLabel: "SR4", fiberType: "MMF", connector: "MPO", wavelengths: "850nm", standard: "40GBASE-SR4", notes: "O-Net 40G QSFP+ SR4 150m MMF" }, + { pid: "ON-QSFP-40G-LR4", formFactor: "QSFP+", speedGbps: 40, speed: "40G", reachMeters: 10000, reachLabel: "LR4", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "40GBASE-LR4", notes: "O-Net 40G QSFP+ LR4 10km SMF" }, + + // ── 100G QSFP28 ───────────────────────────────────────────────────────── + { pid: "ON-QSFP28-100G-SR4", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 100, reachLabel: "SR4", fiberType: "MMF", connector: "MPO", wavelengths: "850nm", standard: "100GBASE-SR4", notes: "O-Net 100G QSFP28 SR4 100m MMF" }, + { pid: "ON-QSFP28-100G-LR4", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 10000, reachLabel: "LR4", fiberType: "SMF", connector: "LC", wavelengths: "1295-1310nm", standard: "100GBASE-LR4", notes: "O-Net 100G QSFP28 LR4 10km SMF" }, + { pid: "ON-QSFP28-100G-ER4", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 40000, reachLabel: "ER4", fiberType: "SMF", connector: "LC", wavelengths: "1295-1310nm", standard: "100GBASE-ER4", notes: "O-Net 100G QSFP28 ER4 40km SMF" }, + + // ── 100G CFP2-DCO Coherent (Telecom) ──────────────────────────────────── + { pid: "ON-CFP2-DCO-100G", formFactor: "CFP2", speedGbps: 100, speed: "100G", reachMeters: 1000000, reachLabel: "DCO", fiberType: "SMF", connector: "LC", wavelengths: "C-band DWDM", category: "Telecom", notes: "O-Net 100G CFP2-DCO coherent, up to 1000km" }, + + // ── 400G QSFP-DD ──────────────────────────────────────────────────────── + { pid: "ON-QSFPDD-400G-DR4", formFactor: "QSFP-DD", speedGbps: 400, speed: "400G", reachMeters: 500, reachLabel: "DR4", fiberType: "SMF", connector: "MPO", wavelengths: "1310nm", standard: "400GBASE-DR4", notes: "O-Net 400G QSFP-DD DR4 500m SMF" }, + { pid: "ON-QSFPDD-400G-FR4", formFactor: "QSFP-DD", speedGbps: 400, speed: "400G", reachMeters: 2000, reachLabel: "FR4", fiberType: "SMF", connector: "LC", wavelengths: "1271-1331nm", standard: "400GBASE-FR4", notes: "O-Net 400G QSFP-DD FR4 2km SMF" }, + + // ── 400G ZR QSFP-DD Coherent (Telecom) ────────────────────────────────── + { pid: "ON-QSFPDD-400G-ZR", formFactor: "QSFP-DD", speedGbps: 400, speed: "400G", reachMeters: 1000000, reachLabel: "ZR", fiberType: "SMF", connector: "LC", wavelengths: "C-band DWDM", standard: "400ZR", category: "Telecom", notes: "O-Net 400G ZR QSFP-DD coherent, up to 1000km" }, +]; + +export async function scrapeONetOem(): Promise { + console.log("=== O-Net Technologies OEM Transceiver Seed ===\n"); + + const vendorId = await ensureVendor( + "O-Net Technologies", + "oem", + "https://www.o-nettech.com", + undefined + ); + + let inserted = 0; + let updated = 0; + let errors = 0; + + for (const p of ONET_PIDS) { + const slug = `o-net-${p.pid.toLowerCase().replace(/[^a-z0-9]+/g, "-")}`; + const category = p.category ?? (TELECOM_PIDS.has(p.pid) ? "Telecom" : "DataCenter"); + try { + const res = await pool.query( + `INSERT INTO transceivers + (slug, part_number, vendor_id, form_factor, speed, speed_gbps, + reach_meters, reach_label, fiber_type, connector, wavelengths, + dom_support, ieee_reference, market_status, category, notes) + VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,true,$12,'Mainstream',$13,$14) + ON CONFLICT (slug) DO UPDATE SET + speed_gbps = EXCLUDED.speed_gbps, + reach_meters = CASE WHEN EXCLUDED.reach_meters > 0 THEN EXCLUDED.reach_meters ELSE transceivers.reach_meters END, + fiber_type = CASE WHEN EXCLUDED.fiber_type <> '' THEN EXCLUDED.fiber_type ELSE transceivers.fiber_type END, + wavelengths = COALESCE(EXCLUDED.wavelengths, transceivers.wavelengths), + updated_at = NOW() + RETURNING (xmax = 0) as was_inserted`, + [slug, p.pid, vendorId, p.formFactor, p.speed, p.speedGbps, + p.reachMeters, p.reachLabel, p.fiberType, p.connector, + p.wavelengths ?? null, p.standard ?? null, category, p.notes ?? null] + ); + if (res.rows[0]?.was_inserted) inserted++; else updated++; + } catch (err) { + console.warn(` Skip ${p.pid}: ${(err as Error).message.slice(0, 80)}`); + errors++; + } + } + + console.log(`\n=== O-Net Technologies OEM Seed Complete ===`); + console.log(` Inserted: ${inserted}`); + console.log(` Updated: ${updated}`); + console.log(` Errors: ${errors}`); + console.log(` Total PIDs: ${ONET_PIDS.length}\n`); +} + +if (require.main === module) { + scrapeONetOem() + .then(() => pool.end()) + .catch((err) => { + console.error("Fatal:", err); + pool.end(); + process.exit(1); + }); +} diff --git a/packages/scraper/src/scrapers/ofs-oem.ts b/packages/scraper/src/scrapers/ofs-oem.ts new file mode 100644 index 0000000..8086a1f --- /dev/null +++ b/packages/scraper/src/scrapers/ofs-oem.ts @@ -0,0 +1,127 @@ +/** + * OFS OEM Transceiver Catalog Seed + * + * Seeds OFS-branded transceiver PIDs (OFS — a Furukawa company). + * + * Sources: + * - OFS Optics Product Portfolio (ofsoptics.com) + * - OFS Transceiver & Active Components Catalog + * + * Run: tsx packages/scraper/src/scrapers/ofs-oem.ts + * Cron: daily at 02:30 + */ + +import { pool, ensureVendor } from "../utils/db"; + +interface OfsPID { + pid: string; + formFactor: string; + speedGbps: number; + speed: string; + reachMeters: number; + reachLabel: string; + fiberType: string; + connector: string; + wavelengths?: string; + standard?: string; + category?: string; + notes?: string; +} + +const OFS_PIDS: OfsPID[] = [ + // ── 1G SFP ────────────────────────────────────────────────────────────── + { pid: "OFS-SFP-1G-SX", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 550, reachLabel: "SX", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "1000BASE-SX" }, + { pid: "OFS-SFP-1G-LX", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 10000, reachLabel: "LX", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "1000BASE-LX" }, + { pid: "OFS-SFP-1G-BIDI", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 10000, reachLabel: "BiDi", fiberType: "SMF", connector: "LC", wavelengths: "1310/1490nm", category: "Telecom", notes: "OFS 1G BiDi SFP, single-fiber duplex" }, + { pid: "OFS-SFP-GE-T", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 100, reachLabel: "T", fiberType: "Cu", connector: "RJ45", wavelengths: "N/A", standard: "1000BASE-T" }, + + // ── 10G SFP+ ──────────────────────────────────────────────────────────── + { pid: "OFS-SFP-10G-SR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 300, reachLabel: "SR", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "10GBASE-SR" }, + { pid: "OFS-SFP-10G-LR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 10000, reachLabel: "LR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "10GBASE-LR" }, + { pid: "OFS-SFP-10G-ER", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 40000, reachLabel: "ER", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "10GBASE-ER" }, + { pid: "OFS-SFP-10G-ZR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 80000, reachLabel: "ZR", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "10GBASE-ZR" }, + { pid: "OFS-SFP-CWDM-1550", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 40000, reachLabel: "CWDM", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", category: "Telecom", notes: "OFS 10G CWDM SFP+ 1550nm channel" }, + { pid: "OFS-DWDM-SFP10G-C", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 80000, reachLabel: "DWDM", fiberType: "SMF", connector: "LC", wavelengths: "C-band DWDM", category: "Telecom", notes: "OFS 10G DWDM SFP+ C-band fixed channel" }, + + // ── 40G QSFP+ ─────────────────────────────────────────────────────────── + { pid: "OFS-QSFP-40G-SR4", formFactor: "QSFP+", speedGbps: 40, speed: "40G", reachMeters: 150, reachLabel: "SR4", fiberType: "MMF", connector: "MPO", wavelengths: "850nm", standard: "40GBASE-SR4" }, + { pid: "OFS-QSFP-40G-LR4", formFactor: "QSFP+", speedGbps: 40, speed: "40G", reachMeters: 10000, reachLabel: "LR4", fiberType: "SMF", connector: "LC", wavelengths: "1295-1310nm", standard: "40GBASE-LR4" }, + + // ── 25G SFP28 ─────────────────────────────────────────────────────────── + { pid: "OFS-SFP28-25G-SR", formFactor: "SFP28", speedGbps: 25, speed: "25G", reachMeters: 300, reachLabel: "SR", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "25GBASE-SR" }, + { pid: "OFS-SFP28-25G-LR", formFactor: "SFP28", speedGbps: 25, speed: "25G", reachMeters: 10000, reachLabel: "LR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "25GBASE-LR" }, + + // ── 100G QSFP28 ───────────────────────────────────────────────────────── + { pid: "OFS-QSFP28-100G-SR4", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 100, reachLabel: "SR4", fiberType: "MMF", connector: "MPO", wavelengths: "850nm", standard: "100GBASE-SR4" }, + { pid: "OFS-QSFP28-100G-LR4", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 10000, reachLabel: "LR4", fiberType: "SMF", connector: "LC", wavelengths: "1295-1310nm", standard: "100GBASE-LR4" }, + { pid: "OFS-QSFP28-100G-CWDM4", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 2000, reachLabel: "CWDM4", fiberType: "SMF", connector: "LC", wavelengths: "1271-1331nm", standard: "100GBASE-CWDM4" }, + + // ── 400G QSFP-DD ──────────────────────────────────────────────────────── + { pid: "OFS-QSFP-DD-400G-DR4", formFactor: "QSFP-DD", speedGbps: 400, speed: "400G", reachMeters: 500, reachLabel: "DR4", fiberType: "SMF", connector: "MPO", wavelengths: "1310nm", standard: "400GBASE-DR4" }, +]; + +// PIDs that use 'Telecom' category (CWDM, DWDM, BiDi) +const TELECOM_PIDS = new Set([ + "OFS-SFP-1G-BIDI", + "OFS-SFP-CWDM-1550", + "OFS-DWDM-SFP10G-C", +]); + +export async function scrapeOfsOem(): Promise { + console.log("=== OFS OEM Transceiver Seed ===\n"); + + const vendorId = await ensureVendor( + "OFS", + "oem", + "https://www.ofsoptics.com", + undefined + ); + + let inserted = 0; + let updated = 0; + let errors = 0; + + for (const p of OFS_PIDS) { + const slug = `ofs-${p.pid.toLowerCase().replace(/[^a-z0-9]+/g, "-")}`; + const category = p.category ?? (TELECOM_PIDS.has(p.pid) ? "Telecom" : "DataCenter"); + try { + const res = await pool.query( + `INSERT INTO transceivers + (slug, part_number, vendor_id, form_factor, speed, speed_gbps, + reach_meters, reach_label, fiber_type, connector, wavelengths, + dom_support, ieee_reference, market_status, category, notes) + VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,true,$12,'Mainstream',$13,$14) + ON CONFLICT (slug) DO UPDATE SET + speed_gbps = EXCLUDED.speed_gbps, + reach_meters = CASE WHEN EXCLUDED.reach_meters > 0 THEN EXCLUDED.reach_meters ELSE transceivers.reach_meters END, + fiber_type = CASE WHEN EXCLUDED.fiber_type <> '' THEN EXCLUDED.fiber_type ELSE transceivers.fiber_type END, + wavelengths = COALESCE(EXCLUDED.wavelengths, transceivers.wavelengths), + updated_at = NOW() + RETURNING (xmax = 0) as was_inserted`, + [slug, p.pid, vendorId, p.formFactor, p.speed, p.speedGbps, + p.reachMeters, p.reachLabel, p.fiberType, p.connector, + p.wavelengths ?? null, p.standard ?? null, category, p.notes ?? null] + ); + if (res.rows[0]?.was_inserted) inserted++; else updated++; + } catch (err) { + console.warn(` Skip ${p.pid}: ${(err as Error).message.slice(0, 80)}`); + errors++; + } + } + + console.log(`\n=== OFS OEM Seed Complete ===`); + console.log(` Inserted: ${inserted}`); + console.log(` Updated: ${updated}`); + console.log(` Errors: ${errors}`); + console.log(` Total PIDs: ${OFS_PIDS.length}\n`); +} + +if (require.main === module) { + scrapeOfsOem() + .then(() => pool.end()) + .catch((err) => { + console.error("Fatal:", err); + pool.end(); + process.exit(1); + }); +} diff --git a/packages/scraper/src/scrapers/omron-oem.ts b/packages/scraper/src/scrapers/omron-oem.ts new file mode 100644 index 0000000..cf6609e --- /dev/null +++ b/packages/scraper/src/scrapers/omron-oem.ts @@ -0,0 +1,116 @@ +/** + * Omron Industrial OEM Transceiver Catalog Seed + * + * Seeds transceiver PIDs for Omron SFP/SFP+/QSFP+ industrial modules + * used in Omron PLC, FA (Factory Automation) networking hardware including + * the CS, CJ, NX, NJ, and NS series industrial controllers. + * + * Sources: + * - Omron Industrial Automation SFP datasheets (ia.omron.com) + * - Omron FA product catalog and hardware manuals + * + * Run: tsx packages/scraper/src/scrapers/omron-oem.ts + * Cron: daily at 15:45 + */ + +import { pool, ensureVendor } from "../utils/db"; + +interface OmronPID { + pid: string; + formFactor: string; + speedGbps: number; + speed: string; + reachMeters: number; + reachLabel: string; + fiberType: string; + connector: string; + wavelengths?: string; + standard?: string; + notes?: string; +} + +const OMRON_PIDS: OmronPID[] = [ + // ── 1G SFP ────────────────────────────────────────────────────────────── + { pid: "OMR-SFP-1G-SX", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 550, reachLabel: "SX", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "1000BASE-SX", notes: "Omron industrial SFP 1G SX FA networking" }, + { pid: "OMR-SFP-1G-LX", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 10000, reachLabel: "LX", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "1000BASE-LX", notes: "Omron industrial SFP 1G LX FA networking" }, + { pid: "OMR-SFP-1G-ZX", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 80000, reachLabel: "ZX", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "1000BASE-ZX", notes: "Omron industrial SFP 1G ZX 80km" }, + { pid: "OMR-SFP-1G-T", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 100, reachLabel: "T", fiberType: "DAC", connector: "RJ45", standard: "1000BASE-T", notes: "Omron industrial SFP 1G copper RJ45" }, + { pid: "OMR-SFP-GE-T", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 100, reachLabel: "T", fiberType: "DAC", connector: "RJ45", standard: "1000BASE-T", notes: "Omron SFP GE-T copper industrial variant" }, + + // ── 1G SFP BiDi ───────────────────────────────────────────────────────── + { pid: "OMR-SFP-1G-BIDI-1310", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 20000, reachLabel: "BiDi-TX1310", fiberType: "SMF", connector: "LC", wavelengths: "TX1310/RX1550nm", notes: "Omron SFP 1G BiDi TX1310 single fiber" }, + { pid: "OMR-SFP-1G-BIDI-1550", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 20000, reachLabel: "BiDi-TX1550", fiberType: "SMF", connector: "LC", wavelengths: "TX1550/RX1310nm", notes: "Omron SFP 1G BiDi TX1550 single fiber" }, + + // ── 10G SFP+ ──────────────────────────────────────────────────────────── + { pid: "OMR-SFP-10G-SR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 300, reachLabel: "SR", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "10GBASE-SR", notes: "Omron industrial SFP+ 10G SR" }, + { pid: "OMR-SFP-10G-LR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 10000, reachLabel: "LR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "10GBASE-LR", notes: "Omron industrial SFP+ 10G LR" }, + { pid: "OMR-SFP-10G-ER", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 40000, reachLabel: "ER", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "10GBASE-ER", notes: "Omron industrial SFP+ 10G ER" }, + + // ── 1G CWDM SFP (factory/substation rings) ────────────────────────────── + { pid: "OMR-SFP-CWDM-1470", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 40000, reachLabel: "CWDM-1470", fiberType: "SMF", connector: "LC", wavelengths: "1470nm", notes: "Omron SFP CWDM 1470nm 40km" }, + { pid: "OMR-SFP-CWDM-1510", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 40000, reachLabel: "CWDM-1510", fiberType: "SMF", connector: "LC", wavelengths: "1510nm", notes: "Omron SFP CWDM 1510nm 40km" }, + { pid: "OMR-SFP-CWDM-1550", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 40000, reachLabel: "CWDM-1550", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", notes: "Omron SFP CWDM 1550nm 40km" }, + { pid: "OMR-SFP-CWDM-1590", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 40000, reachLabel: "CWDM-1590", fiberType: "SMF", connector: "LC", wavelengths: "1590nm", notes: "Omron SFP CWDM 1590nm 40km" }, + { pid: "OMR-SFP-CWDM-1610", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 40000, reachLabel: "CWDM-1610", fiberType: "SMF", connector: "LC", wavelengths: "1610nm", notes: "Omron SFP CWDM 1610nm 40km" }, + + // ── 40G QSFP+ ─────────────────────────────────────────────────────────── + { pid: "OMR-QSFP-40G-SR4", formFactor: "QSFP+", speedGbps: 40, speed: "40G", reachMeters: 150, reachLabel: "SR4", fiberType: "MMF", connector: "MPO", wavelengths: "850nm", standard: "40GBASE-SR4", notes: "Omron QSFP+ 40G SR4 industrial" }, +]; + +export async function scrapeOmronOem(): Promise { + console.log("=== Omron Industrial OEM Transceiver Seed ===\n"); + + const vendorId = await ensureVendor( + "Omron", + "oem", + "https://www.ia.omron.com", + undefined + ); + + let inserted = 0; + let updated = 0; + let errors = 0; + + for (const p of OMRON_PIDS) { + const slug = `omron-${p.pid.toLowerCase().replace(/[^a-z0-9]+/g, "-")}`; + try { + const res = await pool.query( + `INSERT INTO transceivers + (slug, part_number, vendor_id, form_factor, speed, speed_gbps, + reach_meters, reach_label, fiber_type, connector, wavelengths, + dom_support, ieee_reference, market_status, category, notes) + VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,true,$12,'Mainstream','Industrial',$13) + ON CONFLICT (slug) DO UPDATE SET + speed_gbps = EXCLUDED.speed_gbps, + reach_meters = CASE WHEN EXCLUDED.reach_meters > 0 THEN EXCLUDED.reach_meters ELSE transceivers.reach_meters END, + fiber_type = CASE WHEN EXCLUDED.fiber_type <> '' THEN EXCLUDED.fiber_type ELSE transceivers.fiber_type END, + wavelengths = COALESCE(EXCLUDED.wavelengths, transceivers.wavelengths), + updated_at = NOW() + RETURNING (xmax = 0) as was_inserted`, + [slug, p.pid, vendorId, p.formFactor, p.speed, p.speedGbps, + p.reachMeters, p.reachLabel, p.fiberType, p.connector, + p.wavelengths ?? null, p.standard ?? null, p.notes ?? null] + ); + if (res.rows[0]?.was_inserted) inserted++; else updated++; + } catch (err) { + console.warn(` Skip ${p.pid}: ${(err as Error).message.slice(0, 80)}`); + errors++; + } + } + + console.log(`\n=== Omron Industrial OEM Seed Complete ===`); + console.log(` Inserted: ${inserted}`); + console.log(` Updated: ${updated}`); + console.log(` Errors: ${errors}`); + console.log(` Total PIDs: ${OMRON_PIDS.length}\n`); +} + +if (require.main === module) { + scrapeOmronOem() + .then(() => pool.end()) + .catch((err) => { + console.error("Fatal:", err); + pool.end(); + process.exit(1); + }); +} diff --git a/packages/scraper/src/scrapers/oplink-oem.ts b/packages/scraper/src/scrapers/oplink-oem.ts new file mode 100644 index 0000000..1bb2269 --- /dev/null +++ b/packages/scraper/src/scrapers/oplink-oem.ts @@ -0,0 +1,134 @@ +/** + * Oplink Communications OEM Transceiver Catalog Seed + * + * Seeds Oplink-branded transceiver PIDs covering data-center, metro, + * CWDM, DWDM, and coherent CFP2-DCO optics from Oplink Communications + * (a Molex / Koch Industries subsidiary, San Jose, CA). + * + * Sources: + * - Oplink Transceiver Module Product Catalog (oplink.com) + * - Oplink DWDM & CWDM Module Specification Sheets + * - Oplink CFP2-DCO Coherent Transceiver Data Sheet + * + * Run: tsx packages/scraper/src/scrapers/oplink-oem.ts + * Cron: daily at 19:30 + */ + +import { pool, ensureVendor } from "../utils/db"; + +interface OplinkPID { + pid: string; + formFactor: string; + speedGbps: number; + speed: string; + reachMeters: number; + reachLabel: string; + fiberType: string; + connector: string; + wavelengths?: string; + standard?: string; + notes?: string; +} + +// PIDs that belong to TELECOM category (CWDM, DWDM, CFP2-DCO, ZR) +const TELECOM_PIDS = new Set([ + "OPL-SFP-10G-ZR", + "OPL-SFP-CWDM-1550", + "OPL-DWDM-SFP10G-C", + "OPL-CFP2-DCO-100G", +]); + +const OPLINK_PIDS: OplinkPID[] = [ + // ── 1G SFP ────────────────────────────────────────────────────────────── + { pid: "OPL-SFP-1G-SX", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 550, reachLabel: "SX", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "1000BASE-SX", notes: "Oplink 1G SFP SX 550m MMF" }, + { pid: "OPL-SFP-1G-LX", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 10000, reachLabel: "LX", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "1000BASE-LX", notes: "Oplink 1G SFP LX 10km SMF" }, + + // ── 10G SFP+ ──────────────────────────────────────────────────────────── + { pid: "OPL-SFP-10G-SR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 300, reachLabel: "SR", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "10GBASE-SR", notes: "Oplink 10G SFP+ SR 300m MMF" }, + { pid: "OPL-SFP-10G-LR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 10000, reachLabel: "LR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "10GBASE-LR", notes: "Oplink 10G SFP+ LR 10km SMF" }, + { pid: "OPL-SFP-10G-ER", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 40000, reachLabel: "ER", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "10GBASE-ER", notes: "Oplink 10G SFP+ ER 40km SMF" }, + { pid: "OPL-SFP-10G-ZR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 80000, reachLabel: "ZR", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "10GBASE-ZR", notes: "Oplink 10G SFP+ ZR 80km SMF" }, + + // ── 25G SFP28 ─────────────────────────────────────────────────────────── + { pid: "OPL-SFP28-25G-SR", formFactor: "SFP28", speedGbps: 25, speed: "25G", reachMeters: 100, reachLabel: "SR", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "25GBASE-SR", notes: "Oplink 25G SFP28 SR 100m MMF" }, + { pid: "OPL-SFP28-25G-LR", formFactor: "SFP28", speedGbps: 25, speed: "25G", reachMeters: 10000, reachLabel: "LR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "25GBASE-LR", notes: "Oplink 25G SFP28 LR 10km SMF" }, + + // ── 40G QSFP+ ─────────────────────────────────────────────────────────── + { pid: "OPL-QSFP-40G-SR4", formFactor: "QSFP+", speedGbps: 40, speed: "40G", reachMeters: 150, reachLabel: "SR4", fiberType: "MMF", connector: "MPO", wavelengths: "850nm", standard: "40GBASE-SR4", notes: "Oplink 40G QSFP+ SR4 150m MMF" }, + { pid: "OPL-QSFP-40G-LR4", formFactor: "QSFP+", speedGbps: 40, speed: "40G", reachMeters: 10000, reachLabel: "LR4", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "40GBASE-LR4", notes: "Oplink 40G QSFP+ LR4 10km SMF" }, + + // ── 100G QSFP28 ───────────────────────────────────────────────────────── + { pid: "OPL-QSFP28-100G-SR4", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 100, reachLabel: "SR4", fiberType: "MMF", connector: "MPO", wavelengths: "850nm", standard: "100GBASE-SR4", notes: "Oplink 100G QSFP28 SR4 100m MMF" }, + { pid: "OPL-QSFP28-100G-LR4", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 10000, reachLabel: "LR4", fiberType: "SMF", connector: "LC", wavelengths: "1295-1310nm", standard: "100GBASE-LR4", notes: "Oplink 100G QSFP28 LR4 10km SMF" }, + + // ── 400G QSFP-DD ──────────────────────────────────────────────────────── + { pid: "OPL-QSFP-DD-400G-DR4", formFactor: "QSFP-DD", speedGbps: 400, speed: "400G", reachMeters: 500, reachLabel: "DR4", fiberType: "SMF", connector: "MPO", wavelengths: "1310nm", standard: "400GBASE-DR4", notes: "Oplink 400G QSFP-DD DR4 500m SMF" }, + + // ── CWDM (Telecom) ─────────────────────────────────────────────────────── + { pid: "OPL-SFP-CWDM-1550", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 80000, reachLabel: "CWDM", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "ITU-T G.694.2", notes: "Oplink 10G CWDM SFP+ 1550nm 80km SMF" }, + + // ── DWDM (Telecom) ─────────────────────────────────────────────────────── + { pid: "OPL-DWDM-SFP10G-C", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 80000, reachLabel: "DWDM", fiberType: "SMF", connector: "LC", wavelengths: "C-band tunable", standard: "ITU-T G.694.1", notes: "Oplink 10G DWDM SFP+ C-band tunable 80km" }, + + // ── CFP2-DCO (Telecom) ─────────────────────────────────────────────────── + { pid: "OPL-CFP2-DCO-100G", formFactor: "CFP2", speedGbps: 100, speed: "100G", reachMeters: 1000000,reachLabel: "DCO", fiberType: "SMF", connector: "LC", wavelengths: "C-band tunable", standard: "OIF CFP2-DCO", notes: "Oplink 100G CFP2 DCO coherent C-band, 1000km span" }, +]; + +export async function scrapeOplinkOem(): Promise { + console.log("=== Oplink Communications OEM Transceiver Seed ===\n"); + + const vendorId = await ensureVendor( + "Oplink Communications", + "oem", + "https://www.oplink.com", + undefined + ); + + let inserted = 0; + let updated = 0; + let errors = 0; + + for (const p of OPLINK_PIDS) { + const slug = `oplink-${p.pid.toLowerCase().replace(/[^a-z0-9]+/g, "-")}`; + const category = TELECOM_PIDS.has(p.pid) ? "Telecom" : "DataCenter"; + try { + const res = await pool.query( + `INSERT INTO transceivers + (slug, part_number, vendor_id, form_factor, speed, speed_gbps, + reach_meters, reach_label, fiber_type, connector, wavelengths, + dom_support, ieee_reference, market_status, category, notes) + VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,true,$12,'Mainstream',$13,$14) + ON CONFLICT (slug) DO UPDATE SET + speed_gbps = EXCLUDED.speed_gbps, + reach_meters = CASE WHEN EXCLUDED.reach_meters > 0 THEN EXCLUDED.reach_meters ELSE transceivers.reach_meters END, + fiber_type = CASE WHEN EXCLUDED.fiber_type <> '' THEN EXCLUDED.fiber_type ELSE transceivers.fiber_type END, + wavelengths = COALESCE(EXCLUDED.wavelengths, transceivers.wavelengths), + updated_at = NOW() + RETURNING (xmax = 0) as was_inserted`, + [slug, p.pid, vendorId, p.formFactor, p.speed, p.speedGbps, + p.reachMeters, p.reachLabel, p.fiberType, p.connector, + p.wavelengths ?? null, p.standard ?? null, category, p.notes ?? null] + ); + if (res.rows[0]?.was_inserted) inserted++; else updated++; + } catch (err) { + console.warn(` Skip ${p.pid}: ${(err as Error).message.slice(0, 80)}`); + errors++; + } + } + + console.log(`\n=== Oplink Communications OEM Seed Complete ===`); + console.log(` Inserted: ${inserted}`); + console.log(` Updated: ${updated}`); + console.log(` Errors: ${errors}`); + console.log(` Total PIDs: ${OPLINK_PIDS.length}\n`); +} + +if (require.main === module) { + scrapeOplinkOem() + .then(() => pool.end()) + .catch((err) => { + console.error("Fatal:", err); + pool.end(); + process.exit(1); + }); +} diff --git a/packages/scraper/src/scrapers/packetfront-oem.ts b/packages/scraper/src/scrapers/packetfront-oem.ts new file mode 100644 index 0000000..4addac0 --- /dev/null +++ b/packages/scraper/src/scrapers/packetfront-oem.ts @@ -0,0 +1,138 @@ +/** + * PacketFront OEM Transceiver Catalog Seed + * + * Seeds PacketFront-branded transceiver PIDs for the DRG.OS router/switch + * platform and SP-grade Ethernet access devices. + * PacketFront (Sweden) builds white-label SP Ethernet access gear (DRG + * series) used by European ISPs and municipalities for FTTH/FTTB rollouts. + * + * Sources: + * - PacketFront DRG.OS Pluggable Optics Compatibility List + * - PacketFront SFP/QSFP Module Hardware Datasheets + * - packetfront.com product catalogue + * + * Run: tsx packages/scraper/src/scrapers/packetfront-oem.ts + * Cron: daily at 01:45 + */ + +import { pool, ensureVendor } from "../utils/db"; + +interface PacketfrontPID { + pid: string; + formFactor: string; + speedGbps: number; + speed: string; + reachMeters: number; + reachLabel: string; + fiberType: string; + connector: string; + wavelengths?: string; + standard?: string; + category?: string; + notes?: string; +} + +const PACKETFRONT_PIDS: PacketfrontPID[] = [ + // ── 1G SFP ────────────────────────────────────────────────────────────── + { pid: "PF-SFP-1G-SX", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 550, reachLabel: "SX", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "1000BASE-SX" }, + { pid: "PF-SFP-1G-LX", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 10000, reachLabel: "LX", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "1000BASE-LX" }, + { pid: "PF-SFP-1G-ZX", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 80000, reachLabel: "ZX", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "1000BASE-ZX", category: "Telecom", notes: "PacketFront GE ZX for long-distance DRG uplinks" }, + { pid: "PF-SFP-GE-T", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 100, reachLabel: "T", fiberType: "Cu", connector: "RJ45", standard: "1000BASE-T" }, + + // ── 10G SFP+ ──────────────────────────────────────────────────────────── + { pid: "PF-SFP-10G-SR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 300, reachLabel: "SR", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "10GBASE-SR" }, + { pid: "PF-SFP-10G-LR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 10000, reachLabel: "LR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "10GBASE-LR" }, + { pid: "PF-SFP-10G-ER", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 40000, reachLabel: "ER", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "10GBASE-ER" }, + { pid: "PF-SFP-10G-ZR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 80000, reachLabel: "ZR", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "10GBASE-ZR", category: "Telecom", notes: "PacketFront 10G ZR for extended metro uplinks" }, + + // ── 25G SFP28 ──────────────────────────────────────────────────────────── + { pid: "PF-SFP28-25G-SR", formFactor: "SFP28", speedGbps: 25, speed: "25G", reachMeters: 100, reachLabel: "SR", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "25GBASE-SR" }, + { pid: "PF-SFP28-25G-LR", formFactor: "SFP28", speedGbps: 25, speed: "25G", reachMeters: 10000, reachLabel: "LR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "25GBASE-LR" }, + + // ── 40G QSFP+ ──────────────────────────────────────────────────────────── + { pid: "PF-QSFP-40G-SR4", formFactor: "QSFP+", speedGbps: 40, speed: "40G", reachMeters: 150, reachLabel: "SR4", fiberType: "MMF", connector: "MPO", wavelengths: "850nm", standard: "40GBASE-SR4" }, + { pid: "PF-QSFP-40G-LR4", formFactor: "QSFP+", speedGbps: 40, speed: "40G", reachMeters: 10000, reachLabel: "LR4", fiberType: "SMF", connector: "LC", wavelengths: "1270-1330nm", standard: "40GBASE-LR4" }, + + // ── 100G QSFP28 ────────────────────────────────────────────────────────── + { pid: "PF-QSFP28-100G-SR4", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 100, reachLabel: "SR4", fiberType: "MMF", connector: "MPO", wavelengths: "850nm", standard: "100GBASE-SR4" }, + { pid: "PF-QSFP28-100G-LR4", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 10000, reachLabel: "LR4", fiberType: "SMF", connector: "LC", wavelengths: "1295-1310nm", standard: "100GBASE-LR4" }, + + // ── CWDM SFP ───────────────────────────────────────────────────────────── + { pid: "PF-SFP-CWDM-1550", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 40000, reachLabel: "CWDM", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "CWDM", category: "Telecom", notes: "PacketFront CWDM 1550nm SFP for FTTH WDM aggregation" }, + + // ── DWDM SFP+ ──────────────────────────────────────────────────────────── + { pid: "PF-DWDM-SFP10G-C", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 80000, reachLabel: "DWDM", fiberType: "SMF", connector: "LC", wavelengths: "C-band DWDM", category: "Telecom", notes: "PacketFront 10G DWDM C-band SFP+ for metro rings" }, + + // ── BiDi SFP ───────────────────────────────────────────────────────────── + { pid: "PF-SFP-1G-BIDI", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 20000, reachLabel: "BiDi", fiberType: "SMF", connector: "LC", wavelengths: "1310/1490nm", category: "Telecom", notes: "PacketFront BiDi GE SFP single-fibre for FTTH drop" }, + { pid: "PF-SFP-10G-BIDI", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 10000, reachLabel: "BiDi", fiberType: "SMF", connector: "LC", wavelengths: "1270/1330nm", category: "Telecom", notes: "PacketFront 10G BiDi SFP+ single-fibre aggregation" }, +]; + +// PIDs that use 'Telecom' category (ZX, CWDM, DWDM, BiDi) +const TELECOM_PIDS = new Set([ + "PF-SFP-1G-ZX", + "PF-SFP-10G-ZR", + "PF-SFP-CWDM-1550", + "PF-DWDM-SFP10G-C", + "PF-SFP-1G-BIDI", + "PF-SFP-10G-BIDI", +]); + +export async function scrapePacketfrontOem(): Promise { + console.log("=== PacketFront OEM Transceiver Seed ===\n"); + + const vendorId = await ensureVendor( + "PacketFront", + "oem", + "https://www.packetfront.com", + undefined + ); + + let inserted = 0; + let updated = 0; + let errors = 0; + + for (const p of PACKETFRONT_PIDS) { + const slug = `packetfront-${p.pid.toLowerCase().replace(/[^a-z0-9]+/g, "-")}`; + const category = p.category ?? (TELECOM_PIDS.has(p.pid) ? "Telecom" : "DataCenter"); + try { + const res = await pool.query( + `INSERT INTO transceivers + (slug, part_number, vendor_id, form_factor, speed, speed_gbps, + reach_meters, reach_label, fiber_type, connector, wavelengths, + dom_support, ieee_reference, market_status, category, notes) + VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,true,$12,'Mainstream',$13,$14) + ON CONFLICT (slug) DO UPDATE SET + speed_gbps = EXCLUDED.speed_gbps, + reach_meters = CASE WHEN EXCLUDED.reach_meters > 0 THEN EXCLUDED.reach_meters ELSE transceivers.reach_meters END, + fiber_type = CASE WHEN EXCLUDED.fiber_type <> '' THEN EXCLUDED.fiber_type ELSE transceivers.fiber_type END, + wavelengths = COALESCE(EXCLUDED.wavelengths, transceivers.wavelengths), + updated_at = NOW() + RETURNING (xmax = 0) as was_inserted`, + [slug, p.pid, vendorId, p.formFactor, p.speed, p.speedGbps, + p.reachMeters, p.reachLabel, p.fiberType, p.connector, + p.wavelengths ?? null, p.standard ?? null, category, p.notes ?? null] + ); + if (res.rows[0]?.was_inserted) inserted++; else updated++; + } catch (err) { + console.warn(` Skip ${p.pid}: ${(err as Error).message.slice(0, 80)}`); + errors++; + } + } + + console.log(`\n=== PacketFront OEM Seed Complete ===`); + console.log(` Inserted: ${inserted}`); + console.log(` Updated: ${updated}`); + console.log(` Errors: ${errors}`); + console.log(` Total PIDs: ${PACKETFRONT_PIDS.length}\n`); +} + +if (require.main === module) { + scrapePacketfrontOem() + .then(() => pool.end()) + .catch((err) => { + console.error("Fatal:", err); + pool.end(); + process.exit(1); + }); +} diff --git a/packages/scraper/src/scrapers/packetlight-oem.ts b/packages/scraper/src/scrapers/packetlight-oem.ts new file mode 100644 index 0000000..c24bb6e --- /dev/null +++ b/packages/scraper/src/scrapers/packetlight-oem.ts @@ -0,0 +1,130 @@ +/** + * PacketLight Networks OEM Transceiver Catalog Seed + * + * Seeds PacketLight-branded transceiver PIDs for WDM/DWDM optical transport + * equipment deployed by service providers: PL-1000TN (mux/demux), PL-1000RO + * (ROADM), PL-1000EX (Ethernet over WDM), and PL-2000 (400G coherent). + * + * Sources: + * - PacketLight Networks Product Portfolio (packetlight.com) + * - PacketLight PL-1000TN / PL-1000RO / PL-1000EX hardware guides + * - PacketLight 100G/400G coherent transceiver datasheets + * - PacketLight DWDM SFP+ / CFP2-DCO application notes + * + * Run: tsx packages/scraper/src/scrapers/packetlight-oem.ts + * Cron: daily at 22:30 + */ + +import { pool, ensureVendor } from "../utils/db"; + +interface PacketLightPID { + pid: string; + formFactor: string; + speedGbps: number; + speed: string; + reachMeters: number; + reachLabel: string; + fiberType: string; + connector: string; + wavelengths?: string; + standard?: string; + category?: string; + notes?: string; +} + +// PIDs that belong to the Telecom category (coherent/DWDM/ZR) +const TELECOM_PIDS = new Set([ + "PL-SFP-10G-ZR", + "PL-SFP-10G-DW-TUNE", + "PL-SFP-10G-CWDM-80", + "PL-QSFP28-100G-ZR4", + "PL-CFP2-100G-DCO", + "PL-QSFPDD-400G-ZR", +]); + +const PACKETLIGHT_PIDS: PacketLightPID[] = [ + // ── 10G SFP+ DataCenter ───────────────────────────────────────────────── + { pid: "PL-SFP-10G-SR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 300, reachLabel: "SR", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "10GBASE-SR" }, + { pid: "PL-SFP-10G-LR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 10000, reachLabel: "LR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "10GBASE-LR" }, + { pid: "PL-SFP-10G-ER", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 40000, reachLabel: "ER", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "10GBASE-ER" }, + + // ── 10G SFP+ Telecom ──────────────────────────────────────────────────── + { pid: "PL-SFP-10G-ZR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 80000, reachLabel: "ZR", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "10GBASE-ZR", category: "Telecom", notes: "PacketLight 10G ZR extended-reach SFP+" }, + { pid: "PL-SFP-10G-DW-TUNE", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 80000, reachLabel: "DWDM", fiberType: "SMF", connector: "LC", wavelengths: "C-band DWDM tunable", category: "Telecom", notes: "PacketLight 10G DWDM tunable SFP+ C-band for PL-1000TN/RO" }, + { pid: "PL-SFP-10G-CWDM-80", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 80000, reachLabel: "CWDM", fiberType: "SMF", connector: "LC", wavelengths: "1530-1610nm CWDM", category: "Telecom", notes: "PacketLight 10G CWDM SFP+ 1530-1610nm 80km" }, + + // ── 100G QSFP28 DataCenter ────────────────────────────────────────────── + { pid: "PL-QSFP28-100G-SR4", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 100, reachLabel: "SR4", fiberType: "MMF", connector: "MPO", wavelengths: "850nm", standard: "100GBASE-SR4" }, + { pid: "PL-QSFP28-100G-LR4", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 10000, reachLabel: "LR4", fiberType: "SMF", connector: "LC", wavelengths: "1295-1310nm", standard: "100GBASE-LR4" }, + + // ── 100G QSFP28 Telecom (ZR4 coherent) ───────────────────────────────── + { pid: "PL-QSFP28-100G-ZR4", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 80000, reachLabel: "ZR4", fiberType: "SMF", connector: "LC", wavelengths: "C-band DWDM", category: "Telecom", notes: "PacketLight 100G QSFP28 ZR4 coherent for PL-1000TN" }, + + // ── 100G CFP2-DCO Telecom ─────────────────────────────────────────────── + { pid: "PL-CFP2-100G-DCO", formFactor: "CFP2", speedGbps: 100, speed: "100G", reachMeters: 1000000, reachLabel: "DCO", fiberType: "SMF", connector: "LC", wavelengths: "C-band", category: "Telecom", notes: "PacketLight 100G CFP2-DCO coherent for PL-1000EX long-haul" }, + + // ── 400G QSFP-DD DataCenter ───────────────────────────────────────────── + { pid: "PL-QSFPDD-400G-DR4", formFactor: "QSFP-DD", speedGbps: 400, speed: "400G", reachMeters: 500, reachLabel: "DR4", fiberType: "SMF", connector: "MPO", wavelengths: "1310nm", standard: "400GBASE-DR4" }, + + // ── 400G QSFP-DD Telecom (ZR coherent) ───────────────────────────────── + { pid: "PL-QSFPDD-400G-ZR", formFactor: "QSFP-DD", speedGbps: 400, speed: "400G", reachMeters: 120000, reachLabel: "ZR", fiberType: "SMF", connector: "LC", wavelengths: "C-band", standard: "400ZR", category: "Telecom", notes: "PacketLight 400G QSFP-DD ZR coherent for PL-2000 platform" }, +]; + +export async function scrapePacketLightOem(): Promise { + console.log("=== PacketLight Networks OEM Transceiver Seed ===\n"); + + const vendorId = await ensureVendor( + "PacketLight Networks", + "oem", + "https://www.packetlight.com", + undefined + ); + + let inserted = 0; + let updated = 0; + let errors = 0; + + for (const p of PACKETLIGHT_PIDS) { + const slug = `packetlight-${p.pid.toLowerCase().replace(/[^a-z0-9]+/g, "-")}`; + const category = p.category ?? (TELECOM_PIDS.has(p.pid) ? "Telecom" : "DataCenter"); + try { + const res = await pool.query( + `INSERT INTO transceivers + (slug, part_number, vendor_id, form_factor, speed, speed_gbps, + reach_meters, reach_label, fiber_type, connector, wavelengths, + dom_support, ieee_reference, market_status, category, notes) + VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,true,$12,'Mainstream',$13,$14) + ON CONFLICT (slug) DO UPDATE SET + speed_gbps = EXCLUDED.speed_gbps, + reach_meters = CASE WHEN EXCLUDED.reach_meters > 0 THEN EXCLUDED.reach_meters ELSE transceivers.reach_meters END, + fiber_type = CASE WHEN EXCLUDED.fiber_type <> '' THEN EXCLUDED.fiber_type ELSE transceivers.fiber_type END, + wavelengths = COALESCE(EXCLUDED.wavelengths, transceivers.wavelengths), + updated_at = NOW() + RETURNING (xmax = 0) as was_inserted`, + [slug, p.pid, vendorId, p.formFactor, p.speed, p.speedGbps, + p.reachMeters, p.reachLabel, p.fiberType, p.connector, + p.wavelengths ?? null, p.standard ?? null, category, p.notes ?? null] + ); + if (res.rows[0]?.was_inserted) inserted++; else updated++; + } catch (err) { + console.warn(` Skip ${p.pid}: ${(err as Error).message.slice(0, 80)}`); + errors++; + } + } + + console.log(`\n=== PacketLight Networks OEM Seed Complete ===`); + console.log(` Inserted: ${inserted}`); + console.log(` Updated: ${updated}`); + console.log(` Errors: ${errors}`); + console.log(` Total: ${PACKETLIGHT_PIDS.length}\n`); +} + +if (require.main === module) { + scrapePacketLightOem() + .then(() => pool.end()) + .catch((err) => { + console.error("Fatal:", err); + pool.end(); + process.exit(1); + }); +} diff --git a/packages/scraper/src/scrapers/palo-alto-oem.ts b/packages/scraper/src/scrapers/palo-alto-oem.ts new file mode 100644 index 0000000..b8e32aa --- /dev/null +++ b/packages/scraper/src/scrapers/palo-alto-oem.ts @@ -0,0 +1,129 @@ +/** + * Palo Alto Networks OEM Transceiver Catalog Seed + * + * Seeds Palo Alto Networks-branded transceiver PIDs for PA-7000, + * PA-5400, PA-3400, and PA-400 series firewalls. + * + * Sources: + * - Palo Alto Networks Transceiver Compatibility Guide (paloaltonetworks.com) + * - PA-7000 / PA-5400 Series Hardware Reference + * + * Run: tsx packages/scraper/src/scrapers/palo-alto-oem.ts + * Cron: daily at 23:00 + */ + +import { pool, ensureVendor } from "../utils/db"; + +interface PaloPID { + pid: string; + formFactor: string; + speedGbps: number; + speed: string; + reachMeters: number; + reachLabel: string; + fiberType: string; + connector: string; + wavelengths?: string; + standard?: string; + notes?: string; +} + +const PALO_PIDS: PaloPID[] = [ + // ── 1G SFP ────────────────────────────────────────────────────────────── + { pid: "PAN-SFP-1G-SX", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 550, reachLabel: "SX", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "1000BASE-SX" }, + { pid: "PAN-SFP-1G-LX", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 10000, reachLabel: "LX", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "1000BASE-LX" }, + { pid: "PAN-SFP-1G-ZX", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 70000, reachLabel: "ZX", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "1000BASE-ZX" }, + { pid: "PAN-SFP-1G-T", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 100, reachLabel: "T", fiberType: "DAC", connector: "RJ45", standard: "1000BASE-T" }, + + // ── 10G SFP+ ──────────────────────────────────────────────────────────── + { pid: "PAN-SFP-PLUS-SR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 300, reachLabel: "SR", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "10GBASE-SR" }, + { pid: "PAN-SFP-PLUS-LR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 10000, reachLabel: "LR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "10GBASE-LR" }, + { pid: "PAN-SFP-PLUS-ER", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 40000, reachLabel: "ER", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "10GBASE-ER" }, + { pid: "PAN-SFP-PLUS-ZR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 80000, reachLabel: "ZR", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "10GBASE-ZR" }, + { pid: "PAN-SFP-PLUS-T", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 30, reachLabel: "T", fiberType: "DAC", connector: "RJ45", standard: "10GBASE-T" }, + + // ── 25G SFP28 ─────────────────────────────────────────────────────────── + { pid: "PAN-SFP28-SR", formFactor: "SFP28", speedGbps: 25, speed: "25G", reachMeters: 100, reachLabel: "SR", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "25GBASE-SR" }, + { pid: "PAN-SFP28-LR", formFactor: "SFP28", speedGbps: 25, speed: "25G", reachMeters: 10000, reachLabel: "LR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "25GBASE-LR" }, + { pid: "PAN-SFP28-ER", formFactor: "SFP28", speedGbps: 25, speed: "25G", reachMeters: 30000, reachLabel: "ER", fiberType: "SMF", connector: "LC", wavelengths: "1310nm" }, + + // ── 40G QSFP+ ─────────────────────────────────────────────────────────── + { pid: "PAN-QSFP-PLUS-SR4", formFactor: "QSFP+", speedGbps: 40, speed: "40G", reachMeters: 150, reachLabel: "SR4", fiberType: "MMF", connector: "MPO", wavelengths: "850nm", standard: "40GBASE-SR4" }, + { pid: "PAN-QSFP-PLUS-LR4", formFactor: "QSFP+", speedGbps: 40, speed: "40G", reachMeters: 10000, reachLabel: "LR4", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "40GBASE-LR4" }, + + // ── 100G QSFP28 ───────────────────────────────────────────────────────── + { pid: "PAN-QSFP28-SR4", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 100, reachLabel: "SR4", fiberType: "MMF", connector: "MPO", wavelengths: "850nm", standard: "100GBASE-SR4" }, + { pid: "PAN-QSFP28-LR4", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 10000, reachLabel: "LR4", fiberType: "SMF", connector: "LC", wavelengths: "1295-1310nm", standard: "100GBASE-LR4" }, + { pid: "PAN-QSFP28-CWDM4", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 2000, reachLabel: "CWDM4", fiberType: "SMF", connector: "LC", wavelengths: "1271-1331nm", standard: "100GBASE-CWDM4" }, + { pid: "PAN-QSFP28-DR", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 500, reachLabel: "DR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "100GBASE-DR" }, + + // ── 400G QSFP-DD (PA-7080 / PA-5450) ─────────────────────────────────── + { pid: "PAN-QSFPDD-SR8", formFactor: "QSFP-DD",speedGbps: 400, speed: "400G", reachMeters: 100, reachLabel: "SR8", fiberType: "MMF", connector: "MPO", wavelengths: "850nm", standard: "400GBASE-SR8" }, + { pid: "PAN-QSFPDD-DR4", formFactor: "QSFP-DD",speedGbps: 400, speed: "400G", reachMeters: 500, reachLabel: "DR4", fiberType: "SMF", connector: "MPO", wavelengths: "1310nm", standard: "400GBASE-DR4" }, + { pid: "PAN-QSFPDD-FR4", formFactor: "QSFP-DD",speedGbps: 400, speed: "400G", reachMeters: 2000, reachLabel: "FR4", fiberType: "SMF", connector: "LC", wavelengths: "1271-1331nm", standard: "400GBASE-FR4" }, + { pid: "PAN-QSFPDD-LR4", formFactor: "QSFP-DD",speedGbps: 400, speed: "400G", reachMeters: 10000, reachLabel: "LR4", fiberType: "SMF", connector: "LC", wavelengths: "1295-1310nm", standard: "400GBASE-LR4" }, + + // ── DAC ───────────────────────────────────────────────────────────────── + { pid: "PAN-CABLE-DAC-10G-1M", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 1, reachLabel: "DAC-1M", fiberType: "DAC", connector: "SFP+" }, + { pid: "PAN-CABLE-DAC-10G-3M", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 3, reachLabel: "DAC-3M", fiberType: "DAC", connector: "SFP+" }, + { pid: "PAN-CABLE-DAC-100G-1M", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 1, reachLabel: "DAC-1M", fiberType: "DAC", connector: "QSFP28" }, + { pid: "PAN-CABLE-DAC-100G-3M", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 3, reachLabel: "DAC-3M", fiberType: "DAC", connector: "QSFP28" }, +]; + +export async function scrapePaloAltoOem(): Promise { + console.log("=== Palo Alto Networks OEM Transceiver Seed ===\n"); + + const vendorId = await ensureVendor( + "Palo Alto Networks", + "oem", + "https://www.paloaltonetworks.com", + undefined + ); + + let inserted = 0; + let updated = 0; + let errors = 0; + + for (const p of PALO_PIDS) { + const slug = `paloalto-${p.pid.toLowerCase().replace(/[^a-z0-9]+/g, "-")}`; + try { + const res = await pool.query( + `INSERT INTO transceivers + (slug, part_number, vendor_id, form_factor, speed, speed_gbps, + reach_meters, reach_label, fiber_type, connector, wavelengths, + dom_support, ieee_reference, market_status, category, notes) + VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,true,$12,'Mainstream','DataCenter',$13) + ON CONFLICT (slug) DO UPDATE SET + speed_gbps = EXCLUDED.speed_gbps, + reach_meters = CASE WHEN EXCLUDED.reach_meters > 0 THEN EXCLUDED.reach_meters ELSE transceivers.reach_meters END, + fiber_type = CASE WHEN EXCLUDED.fiber_type <> '' THEN EXCLUDED.fiber_type ELSE transceivers.fiber_type END, + wavelengths = COALESCE(EXCLUDED.wavelengths, transceivers.wavelengths), + updated_at = NOW() + RETURNING (xmax = 0) as was_inserted`, + [slug, p.pid, vendorId, p.formFactor, p.speed, p.speedGbps, + p.reachMeters, p.reachLabel, p.fiberType, p.connector, + p.wavelengths ?? null, p.standard ?? null, p.notes ?? null] + ); + if (res.rows[0]?.was_inserted) inserted++; else updated++; + } catch (err) { + console.warn(` Skip ${p.pid}: ${(err as Error).message.slice(0, 80)}`); + errors++; + } + } + + console.log(`\n=== Palo Alto Networks OEM Seed Complete ===`); + console.log(` Inserted: ${inserted}`); + console.log(` Updated: ${updated}`); + console.log(` Errors: ${errors}`); + console.log(` Total PIDs: ${PALO_PIDS.length}\n`); +} + +if (require.main === module) { + scrapePaloAltoOem() + .then(() => pool.end()) + .catch((err) => { + console.error("Fatal:", err); + pool.end(); + process.exit(1); + }); +} diff --git a/packages/scraper/src/scrapers/perle-oem.ts b/packages/scraper/src/scrapers/perle-oem.ts new file mode 100644 index 0000000..3261bf4 --- /dev/null +++ b/packages/scraper/src/scrapers/perle-oem.ts @@ -0,0 +1,116 @@ +/** + * Perle Systems OEM Transceiver Catalog Seed + * + * Seeds transceiver PIDs for Perle Systems industrial-grade SFP modules used in + * IDS and IOLAN series industrial serial and fiber networking devices. + * + * Sources: + * - Perle Systems SFP module product pages (perle.com) + * - Perle IDS/IOLAN hardware installation guides + * + * Run: tsx packages/scraper/src/scrapers/perle-oem.ts + * Cron: daily at 16:00 + */ + +import { pool, ensureVendor } from "../utils/db"; + +interface PerlePID { + pid: string; + formFactor: string; + speedGbps: number; + speed: string; + reachMeters: number; + reachLabel: string; + fiberType: string; + connector: string; + wavelengths?: string; + standard?: string; + notes?: string; +} + +const PERLE_PIDS: PerlePID[] = [ + // ── 100M SFP ──────────────────────────────────────────────────────────── + { pid: "PSFP-100D-M1LC2", formFactor: "SFP", speedGbps: 0.1, speed: "100M", reachMeters: 2000, reachLabel: "FX", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "100BASE-FX" }, + { pid: "PSFP-100D-S10LC1", formFactor: "SFP", speedGbps: 0.1, speed: "100M", reachMeters: 10000, reachLabel: "LFX", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "100BASE-LFX" }, + { pid: "PSFP-100D-S40LC1", formFactor: "SFP", speedGbps: 0.1, speed: "100M", reachMeters: 40000, reachLabel: "LFX", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", notes: "Perle 100M SM SFP 40km" }, + { pid: "PSFP-100D-S80LC1", formFactor: "SFP", speedGbps: 0.1, speed: "100M", reachMeters: 80000, reachLabel: "LFX", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", notes: "Perle 100M SM SFP 80km" }, + + // ── 1G SFP ────────────────────────────────────────────────────────────── + { pid: "PSFP-1000D-M1LC550", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 550, reachLabel: "SX", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "1000BASE-SX" }, + { pid: "PSFP-1000D-S10LC1", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 10000, reachLabel: "LX", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "1000BASE-LX" }, + { pid: "PSFP-1000D-S20LC1", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 20000, reachLabel: "LH", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", notes: "Perle 1G SM SFP 20km" }, + { pid: "PSFP-1000D-S40LC1", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 40000, reachLabel: "LH", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", notes: "Perle 1G SM SFP 40km" }, + { pid: "PSFP-1000D-S80LC1", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 80000, reachLabel: "ZX", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "1000BASE-ZX" }, + { pid: "PSFP-1000D-RJ45", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 100, reachLabel: "T", fiberType: "DAC", connector: "RJ45", standard: "1000BASE-T" }, + { pid: "PSFP-1000D-BX10U", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 10000, reachLabel: "BX", fiberType: "SMF", connector: "LC", wavelengths: "TX1310/RX1490", notes: "Perle 1G BiDi SFP BX10 upstream" }, + { pid: "PSFP-1000D-BX10D", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 10000, reachLabel: "BX", fiberType: "SMF", connector: "LC", wavelengths: "TX1490/RX1310", notes: "Perle 1G BiDi SFP BX10 downstream" }, + { pid: "PSFP-1000D-BX20U", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 20000, reachLabel: "BX", fiberType: "SMF", connector: "LC", wavelengths: "TX1310/RX1550", notes: "Perle 1G BiDi SFP BX20 upstream" }, + + // ── 10G SFP+ ──────────────────────────────────────────────────────────── + { pid: "PSFP-10000D-M1LC300", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 300, reachLabel: "SR", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "10GBASE-SR" }, + { pid: "PSFP-10000D-S10LC1", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 10000, reachLabel: "LR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "10GBASE-LR" }, + { pid: "PSFP-10000D-S40LC1", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 40000, reachLabel: "ER", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "10GBASE-ER" }, + { pid: "PSFP-10000D-S80LC1", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 80000, reachLabel: "ZR", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "10GBASE-ZR" }, + + // ── DAC ───────────────────────────────────────────────────────────────── + { pid: "PSFP-DAC-10G-1M", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 1, reachLabel: "DAC", fiberType: "DAC", connector: "SFP+", notes: "SFP+ 10G 1m" }, + { pid: "PSFP-DAC-10G-3M", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 3, reachLabel: "DAC", fiberType: "DAC", connector: "SFP+", notes: "SFP+ 10G 3m" }, +]; + +export async function scrapePerleOem(): Promise { + console.log("=== Perle Systems OEM Transceiver Seed ===\n"); + + const vendorId = await ensureVendor( + "Perle Systems", + "oem", + "https://www.perle.com", + undefined + ); + + let inserted = 0; + let updated = 0; + let errors = 0; + + for (const p of PERLE_PIDS) { + const slug = `perle-${p.pid.toLowerCase().replace(/[^a-z0-9]+/g, "-")}`; + try { + const res = await pool.query( + `INSERT INTO transceivers + (slug, part_number, vendor_id, form_factor, speed, speed_gbps, + reach_meters, reach_label, fiber_type, connector, wavelengths, + dom_support, ieee_reference, market_status, category, notes) + VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,true,$12,'Mainstream','Industrial',$13) + ON CONFLICT (slug) DO UPDATE SET + speed_gbps = EXCLUDED.speed_gbps, + reach_meters = CASE WHEN EXCLUDED.reach_meters > 0 THEN EXCLUDED.reach_meters ELSE transceivers.reach_meters END, + fiber_type = CASE WHEN EXCLUDED.fiber_type <> '' THEN EXCLUDED.fiber_type ELSE transceivers.fiber_type END, + wavelengths = COALESCE(EXCLUDED.wavelengths, transceivers.wavelengths), + updated_at = NOW() + RETURNING (xmax = 0) as was_inserted`, + [slug, p.pid, vendorId, p.formFactor, p.speed, p.speedGbps, + p.reachMeters, p.reachLabel, p.fiberType, p.connector, + p.wavelengths ?? null, p.standard ?? null, p.notes ?? null] + ); + if (res.rows[0]?.was_inserted) inserted++; else updated++; + } catch (err) { + console.warn(` Skip ${p.pid}: ${(err as Error).message.slice(0, 80)}`); + errors++; + } + } + + console.log(`\n=== Perle Systems OEM Seed Complete ===`); + console.log(` Inserted: ${inserted}`); + console.log(` Updated: ${updated}`); + console.log(` Errors: ${errors}`); + console.log(` Total PIDs: ${PERLE_PIDS.length}\n`); +} + +if (require.main === module) { + scrapePerleOem() + .then(() => pool.end()) + .catch((err) => { + console.error("Fatal:", err); + pool.end(); + process.exit(1); + }); +} diff --git a/packages/scraper/src/scrapers/phoenix-contact-oem.ts b/packages/scraper/src/scrapers/phoenix-contact-oem.ts new file mode 100644 index 0000000..4034a8d --- /dev/null +++ b/packages/scraper/src/scrapers/phoenix-contact-oem.ts @@ -0,0 +1,113 @@ +/** + * Phoenix Contact OEM Transceiver Catalog Seed + * + * Seeds transceiver PIDs for Phoenix Contact FL SFP/SFP+ industrial modules + * used in FL SWITCH, FL COMSERVER, and Axioline industrial automation devices. + * + * Sources: + * - Phoenix Contact FL SFP product datasheets (phoenixcontact.com) + * - Phoenix Contact Industrial Ethernet catalog + * + * Run: tsx packages/scraper/src/scrapers/phoenix-contact-oem.ts + * Cron: daily at 15:15 + */ + +import { pool, ensureVendor } from "../utils/db"; + +interface PhoenixContactPID { + pid: string; + formFactor: string; + speedGbps: number; + speed: string; + reachMeters: number; + reachLabel: string; + fiberType: string; + connector: string; + wavelengths?: string; + standard?: string; + notes?: string; +} + +const PHOENIX_CONTACT_PIDS: PhoenixContactPID[] = [ + // ── 1G SFP ────────────────────────────────────────────────────────────── + { pid: "FL SFP 1G SX", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 550, reachLabel: "SX", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "1000BASE-SX", notes: "Phoenix Contact FL SFP 1G SX industrial" }, + { pid: "FL SFP 1G LX", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 10000, reachLabel: "LX", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "1000BASE-LX", notes: "Phoenix Contact FL SFP 1G LX industrial" }, + { pid: "FL SFP 1G LH", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 80000, reachLabel: "LH", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "1000BASE-ZX", notes: "Phoenix Contact FL SFP 1G LH 80km" }, + { pid: "FL SFP 1G BIDI TX1310", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 20000, reachLabel: "BiDi-TX1310", fiberType: "SMF", connector: "LC", wavelengths: "TX1310/RX1550nm", notes: "Phoenix Contact FL SFP 1G BiDi TX1310 single fiber" }, + { pid: "FL SFP 1G BIDI TX1550", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 20000, reachLabel: "BiDi-TX1550", fiberType: "SMF", connector: "LC", wavelengths: "TX1550/RX1310nm", notes: "Phoenix Contact FL SFP 1G BiDi TX1550 single fiber" }, + { pid: "FL SFP 1G BIDI TX1490", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 40000, reachLabel: "BiDi-TX1490", fiberType: "SMF", connector: "LC", wavelengths: "TX1490/RX1310nm", notes: "Phoenix Contact FL SFP 1G BiDi TX1490 40km" }, + + // ── 10G SFP+ ──────────────────────────────────────────────────────────── + { pid: "FL SFP PLUS 10G SR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 300, reachLabel: "SR", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "10GBASE-SR", notes: "Phoenix Contact FL SFP+ 10G SR industrial" }, + { pid: "FL SFP PLUS 10G LR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 10000, reachLabel: "LR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "10GBASE-LR", notes: "Phoenix Contact FL SFP+ 10G LR industrial" }, + { pid: "FL SFP PLUS 10G ER", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 40000, reachLabel: "ER", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "10GBASE-ER", notes: "Phoenix Contact FL SFP+ 10G ER industrial" }, + { pid: "FL SFP PLUS 10G ZR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 80000, reachLabel: "ZR", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "10GBASE-ZR", notes: "Phoenix Contact FL SFP+ 10G ZR 80km industrial" }, + + // ── 1G CWDM SFP (factory/substation rings) ────────────────────────────── + { pid: "FL SFP CWDM 1470", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 40000, reachLabel: "CWDM-1470", fiberType: "SMF", connector: "LC", wavelengths: "1470nm", notes: "Phoenix Contact FL SFP CWDM 1470nm 40km" }, + { pid: "FL SFP CWDM 1490", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 40000, reachLabel: "CWDM-1490", fiberType: "SMF", connector: "LC", wavelengths: "1490nm", notes: "Phoenix Contact FL SFP CWDM 1490nm 40km" }, + { pid: "FL SFP CWDM 1510", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 40000, reachLabel: "CWDM-1510", fiberType: "SMF", connector: "LC", wavelengths: "1510nm", notes: "Phoenix Contact FL SFP CWDM 1510nm 40km" }, + { pid: "FL SFP CWDM 1530", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 40000, reachLabel: "CWDM-1530", fiberType: "SMF", connector: "LC", wavelengths: "1530nm", notes: "Phoenix Contact FL SFP CWDM 1530nm 40km" }, + { pid: "FL SFP CWDM 1550", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 40000, reachLabel: "CWDM-1550", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", notes: "Phoenix Contact FL SFP CWDM 1550nm 40km" }, + { pid: "FL SFP CWDM 1570", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 40000, reachLabel: "CWDM-1570", fiberType: "SMF", connector: "LC", wavelengths: "1570nm", notes: "Phoenix Contact FL SFP CWDM 1570nm 40km" }, + { pid: "FL SFP CWDM 1590", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 40000, reachLabel: "CWDM-1590", fiberType: "SMF", connector: "LC", wavelengths: "1590nm", notes: "Phoenix Contact FL SFP CWDM 1590nm 40km" }, + { pid: "FL SFP CWDM 1610", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 40000, reachLabel: "CWDM-1610", fiberType: "SMF", connector: "LC", wavelengths: "1610nm", notes: "Phoenix Contact FL SFP CWDM 1610nm 40km" }, +]; + +export async function scrapePhoenixContactOem(): Promise { + console.log("=== Phoenix Contact OEM Transceiver Seed ===\n"); + + const vendorId = await ensureVendor( + "Phoenix Contact", + "oem", + "https://www.phoenixcontact.com", + undefined + ); + + let inserted = 0; + let updated = 0; + let errors = 0; + + for (const p of PHOENIX_CONTACT_PIDS) { + const slug = `phoenix-contact-${p.pid.toLowerCase().replace(/[^a-z0-9]+/g, "-")}`; + try { + const res = await pool.query( + `INSERT INTO transceivers + (slug, part_number, vendor_id, form_factor, speed, speed_gbps, + reach_meters, reach_label, fiber_type, connector, wavelengths, + dom_support, ieee_reference, market_status, category, notes) + VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,true,$12,'Mainstream','Industrial',$13) + ON CONFLICT (slug) DO UPDATE SET + speed_gbps = EXCLUDED.speed_gbps, + reach_meters = CASE WHEN EXCLUDED.reach_meters > 0 THEN EXCLUDED.reach_meters ELSE transceivers.reach_meters END, + fiber_type = CASE WHEN EXCLUDED.fiber_type <> '' THEN EXCLUDED.fiber_type ELSE transceivers.fiber_type END, + wavelengths = COALESCE(EXCLUDED.wavelengths, transceivers.wavelengths), + updated_at = NOW() + RETURNING (xmax = 0) as was_inserted`, + [slug, p.pid, vendorId, p.formFactor, p.speed, p.speedGbps, + p.reachMeters, p.reachLabel, p.fiberType, p.connector, + p.wavelengths ?? null, p.standard ?? null, p.notes ?? null] + ); + if (res.rows[0]?.was_inserted) inserted++; else updated++; + } catch (err) { + console.warn(` Skip ${p.pid}: ${(err as Error).message.slice(0, 80)}`); + errors++; + } + } + + console.log(`\n=== Phoenix Contact OEM Seed Complete ===`); + console.log(` Inserted: ${inserted}`); + console.log(` Updated: ${updated}`); + console.log(` Errors: ${errors}`); + console.log(` Total PIDs: ${PHOENIX_CONTACT_PIDS.length}\n`); +} + +if (require.main === module) { + scrapePhoenixContactOem() + .then(() => pool.end()) + .catch((err) => { + console.error("Fatal:", err); + pool.end(); + process.exit(1); + }); +} diff --git a/packages/scraper/src/scrapers/pica8-oem.ts b/packages/scraper/src/scrapers/pica8-oem.ts new file mode 100644 index 0000000..c0bd4f2 --- /dev/null +++ b/packages/scraper/src/scrapers/pica8-oem.ts @@ -0,0 +1,120 @@ +/** + * Pica8 OEM Transceiver Catalog Seed + * + * Seeds Pica8-branded transceiver PIDs for PICOS (white-box NOS) running on + * Edgecore, Celestica, and other bare-metal switching hardware. + * + * Sources: + * - Pica8 PICOS Hardware Compatibility List (pica8.com) + * - Pica8 P8-C600/P8-C6X0 Hardware Installation Guide + * - Pica8 Deployment Guide for Edgecore AS9516-32D / AS7726-32X + * + * Run: tsx packages/scraper/src/scrapers/pica8-oem.ts + * Cron: daily at 14:30 + */ + +import { pool, ensureVendor } from "../utils/db"; + +interface Pica8PID { + pid: string; + formFactor: string; + speedGbps: number; + speed: string; + reachMeters: number; + reachLabel: string; + fiberType: string; + connector: string; + wavelengths?: string; + standard?: string; + notes?: string; +} + +// ── Pica8 OEM transceiver catalog ─────────────────────────────────────────── +// Source: Pica8 PICOS HCL and hardware guides +const PICA8_PIDS: Pica8PID[] = [ + // ── 1G SFP ────────────────────────────────────────────────────────────── + { pid: "P8-SFP-1G-SX", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 550, reachLabel: "SX", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "1000BASE-SX", notes: "Pica8 1G multimode SFP for PICOS white-box management" }, + { pid: "P8-SFP-1G-LX", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 10000, reachLabel: "LX", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "1000BASE-LX", notes: "Pica8 1G single-mode SFP 10km for PICOS campus white-box" }, + { pid: "P8-SFP-1G-T", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 100, reachLabel: "T", fiberType: "DAC", connector: "RJ45", standard: "1000BASE-T", notes: "Pica8 1G copper SFP for PICOS Edgecore AS5835 management" }, + { pid: "P8-SFP-GE-T", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 100, reachLabel: "GE-T", fiberType: "DAC", connector: "RJ45", standard: "1000BASE-T", notes: "Pica8 GE copper SFP variant for white-box PICOS leaf" }, + + // ── 10G SFP+ ──────────────────────────────────────────────────────────── + { pid: "P8-SFP-10G-SR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 300, reachLabel: "SR", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "10GBASE-SR", notes: "Pica8 10G SR SFP+ for PICOS server access layer on Edgecore" }, + { pid: "P8-SFP-10G-LR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 10000, reachLabel: "LR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "10GBASE-LR", notes: "Pica8 10G LR SFP+ 10km for PICOS inter-switch SMF links" }, + { pid: "P8-SFP-10G-ER", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 40000, reachLabel: "ER", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "10GBASE-ER", notes: "Pica8 10G ER SFP+ 40km for PICOS white-box DCI" }, + { pid: "P8-SFP-10G-ZR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 80000, reachLabel: "ZR", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "10GBASE-ZR", notes: "Pica8 10G ZR 80km for PICOS open-line dark-fiber WAN" }, + + // ── 25G SFP28 ─────────────────────────────────────────────────────────── + { pid: "P8-SFP28-25G-SR", formFactor: "SFP28", speedGbps: 25, speed: "25G", reachMeters: 100, reachLabel: "SR", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "25GBASE-SR", notes: "Pica8 25G SR SFP28 for PICOS Edgecore AS7726 server leaf" }, + { pid: "P8-SFP28-25G-LR", formFactor: "SFP28", speedGbps: 25, speed: "25G", reachMeters: 10000, reachLabel: "LR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "25GBASE-LR", notes: "Pica8 25G LR SFP28 for PICOS white-box spine uplinks" }, + + // ── 40G QSFP+ ─────────────────────────────────────────────────────────── + { pid: "P8-QSFP-40G-SR4", formFactor: "QSFP+", speedGbps: 40, speed: "40G", reachMeters: 150, reachLabel: "SR4", fiberType: "MMF", connector: "MPO", wavelengths: "850nm", standard: "40GBASE-SR4", notes: "Pica8 40G SR4 QSFP+ for PICOS 40G white-box fabric uplinks" }, + { pid: "P8-QSFP-40G-LR4", formFactor: "QSFP+", speedGbps: 40, speed: "40G", reachMeters: 10000, reachLabel: "LR4", fiberType: "SMF", connector: "LC", wavelengths: "1295-1310nm", standard: "40GBASE-LR4", notes: "Pica8 40G LR4 QSFP+ 10km for PICOS Celestica DCS-7060 spine" }, + + // ── 100G QSFP28 ───────────────────────────────────────────────────────── + { pid: "P8-QSFP28-100G-SR4", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 100, reachLabel: "SR4", fiberType: "MMF", connector: "MPO", wavelengths: "850nm", standard: "100GBASE-SR4", notes: "Pica8 100G SR4 QSFP28 for PICOS AS9516-32D fabric" }, + { pid: "P8-QSFP28-100G-LR4", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 10000, reachLabel: "LR4", fiberType: "SMF", connector: "LC", wavelengths: "1295-1310nm", standard: "100GBASE-LR4", notes: "Pica8 100G LR4 QSFP28 10km for PICOS white-box DCI" }, + + // ── 400G QSFP-DD ──────────────────────────────────────────────────────── + { pid: "P8-QSFP-DD-400G-DR4", formFactor: "QSFP-DD", speedGbps: 400, speed: "400G", reachMeters: 500, reachLabel: "DR4", fiberType: "SMF", connector: "MPO", wavelengths: "1310nm", standard: "400GBASE-DR4", notes: "Pica8 400G DR4 QSFP-DD for next-gen PICOS white-box spine" }, + { pid: "P8-QSFP-DD-400G-SR8", formFactor: "QSFP-DD", speedGbps: 400, speed: "400G", reachMeters: 100, reachLabel: "SR8", fiberType: "MMF", connector: "MPO", wavelengths: "850nm", standard: "400GBASE-SR8", notes: "Pica8 400G SR8 QSFP-DD for PICOS OM4 within-pod fabric" }, +]; + +export async function scrapePica8Oem(): Promise { + console.log("=== Pica8 OEM Transceiver Seed ===\n"); + + const vendorId = await ensureVendor( + "Pica8", + "oem", + "https://www.pica8.com", + undefined + ); + + let inserted = 0; + let updated = 0; + let errors = 0; + + for (const p of PICA8_PIDS) { + const slug = `pica8-${p.pid.toLowerCase().replace(/[^a-z0-9]+/g, "-")}`; + try { + const res = await pool.query( + `INSERT INTO transceivers + (slug, part_number, vendor_id, form_factor, speed, speed_gbps, + reach_meters, reach_label, fiber_type, connector, wavelengths, + dom_support, ieee_reference, market_status, category, notes) + VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,true,$12,'Mainstream','DataCenter',$13) + ON CONFLICT (slug) DO UPDATE SET + speed_gbps = EXCLUDED.speed_gbps, + reach_meters = CASE WHEN EXCLUDED.reach_meters > 0 THEN EXCLUDED.reach_meters ELSE transceivers.reach_meters END, + fiber_type = CASE WHEN EXCLUDED.fiber_type <> '' THEN EXCLUDED.fiber_type ELSE transceivers.fiber_type END, + wavelengths = COALESCE(EXCLUDED.wavelengths, transceivers.wavelengths), + updated_at = NOW() + RETURNING (xmax = 0) as was_inserted`, + [slug, p.pid, vendorId, p.formFactor, p.speed, p.speedGbps, + p.reachMeters, p.reachLabel, p.fiberType, p.connector, + p.wavelengths ?? null, p.standard ?? null, p.notes ?? null] + ); + if (res.rows[0]?.was_inserted) inserted++; else updated++; + } catch (err) { + console.warn(` Skip ${p.pid}: ${(err as Error).message.slice(0, 80)}`); + errors++; + } + } + + console.log(`\n=== Pica8 OEM Seed Complete ===`); + console.log(` Inserted: ${inserted}`); + console.log(` Updated: ${updated}`); + console.log(` Errors: ${errors}`); + console.log(` Total PIDs: ${PICA8_PIDS.length}\n`); +} + +if (require.main === module) { + scrapePica8Oem() + .then(() => pool.end()) + .catch((err) => { + console.error("Fatal:", err); + pool.end(); + process.exit(1); + }); +} diff --git a/packages/scraper/src/scrapers/pluribus-oem.ts b/packages/scraper/src/scrapers/pluribus-oem.ts new file mode 100644 index 0000000..1530442 --- /dev/null +++ b/packages/scraper/src/scrapers/pluribus-oem.ts @@ -0,0 +1,118 @@ +/** + * Pluribus Networks OEM Transceiver Catalog Seed + * + * Seeds Pluribus-branded transceiver PIDs for Netvisor ONE white-box NOS + * running on Edgecore, Accton, and Quanta bare-metal switching hardware. + * + * Sources: + * - Pluribus Networks Netvisor ONE Hardware Compatibility Guide + * - Pluribus Adaptive Cloud Fabric (ACF) Platform Datasheet + * - Pluribus UNUM Management Platform optics compatibility notes + * + * Run: tsx packages/scraper/src/scrapers/pluribus-oem.ts + * Cron: daily at 14:45 + */ + +import { pool, ensureVendor } from "../utils/db"; + +interface PluribusPID { + pid: string; + formFactor: string; + speedGbps: number; + speed: string; + reachMeters: number; + reachLabel: string; + fiberType: string; + connector: string; + wavelengths?: string; + standard?: string; + notes?: string; +} + +// ── Pluribus Networks transceiver catalog ──────────────────────────────────── +// Source: Pluribus Netvisor ONE HCL and ACF Platform Guide +const PLURIBUS_PIDS: PluribusPID[] = [ + // ── 1G SFP ────────────────────────────────────────────────────────────── + { pid: "PLU-SFP-1G-SX", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 550, reachLabel: "SX", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "1000BASE-SX", notes: "Pluribus 1G MM SFP for Netvisor ONE management ports" }, + { pid: "PLU-SFP-1G-LX", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 10000, reachLabel: "LX", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "1000BASE-LX", notes: "Pluribus 1G SM SFP 10km for Netvisor ONE OOB management" }, + { pid: "PLU-SFP-GE-T", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 100, reachLabel: "GE-T", fiberType: "DAC", connector: "RJ45", standard: "1000BASE-T", notes: "Pluribus GE copper SFP for white-box ACF leaf edge ports" }, + + // ── 10G SFP+ ──────────────────────────────────────────────────────────── + { pid: "PLU-SFP-10G-SR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 300, reachLabel: "SR", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "10GBASE-SR", notes: "Pluribus 10G SR SFP+ for Netvisor ONE server access" }, + { pid: "PLU-SFP-10G-LR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 10000, reachLabel: "LR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "10GBASE-LR", notes: "Pluribus 10G LR SFP+ 10km for Netvisor inter-switch SMF" }, + { pid: "PLU-SFP-10G-ER", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 40000, reachLabel: "ER", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "10GBASE-ER", notes: "Pluribus 10G ER 40km for Netvisor ACF metro DCI" }, + { pid: "PLU-SFP-10G-ZR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 80000, reachLabel: "ZR", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "10GBASE-ZR", notes: "Pluribus 10G ZR 80km dark-fiber for Netvisor fabric WAN" }, + + // ── 25G SFP28 ─────────────────────────────────────────────────────────── + { pid: "PLU-SFP28-25G-SR", formFactor: "SFP28", speedGbps: 25, speed: "25G", reachMeters: 100, reachLabel: "SR", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "25GBASE-SR", notes: "Pluribus 25G SR SFP28 for Netvisor ONE ACF 25G leaf" }, + { pid: "PLU-SFP28-25G-LR", formFactor: "SFP28", speedGbps: 25, speed: "25G", reachMeters: 10000, reachLabel: "LR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "25GBASE-LR", notes: "Pluribus 25G LR SFP28 for Netvisor ACF spine uplinks" }, + + // ── 40G QSFP+ ─────────────────────────────────────────────────────────── + { pid: "PLU-QSFP-40G-SR4", formFactor: "QSFP+", speedGbps: 40, speed: "40G", reachMeters: 150, reachLabel: "SR4", fiberType: "MMF", connector: "MPO", wavelengths: "850nm", standard: "40GBASE-SR4", notes: "Pluribus 40G SR4 QSFP+ for Netvisor ACF 40G fabric" }, + { pid: "PLU-QSFP-40G-LR4", formFactor: "QSFP+", speedGbps: 40, speed: "40G", reachMeters: 10000, reachLabel: "LR4", fiberType: "SMF", connector: "LC", wavelengths: "1295-1310nm", standard: "40GBASE-LR4", notes: "Pluribus 40G LR4 QSFP+ 10km for Netvisor inter-cluster" }, + + // ── 100G QSFP28 ───────────────────────────────────────────────────────── + { pid: "PLU-QSFP28-100G-SR4", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 100, reachLabel: "SR4", fiberType: "MMF", connector: "MPO", wavelengths: "850nm", standard: "100GBASE-SR4", notes: "Pluribus 100G SR4 QSFP28 for Netvisor ONE 100G spine" }, + { pid: "PLU-QSFP28-100G-LR4", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 10000, reachLabel: "LR4", fiberType: "SMF", connector: "LC", wavelengths: "1295-1310nm", standard: "100GBASE-LR4", notes: "Pluribus 100G LR4 QSFP28 for Netvisor ACF DCI uplinks" }, + + // ── 400G QSFP-DD ──────────────────────────────────────────────────────── + { pid: "PLU-QSFP-DD-400G-DR4", formFactor: "QSFP-DD", speedGbps: 400, speed: "400G", reachMeters: 500, reachLabel: "DR4", fiberType: "SMF", connector: "MPO", wavelengths: "1310nm", standard: "400GBASE-DR4", notes: "Pluribus 400G DR4 QSFP-DD for next-gen Netvisor ACF spine" }, +]; + +export async function scrapePluribusOem(): Promise { + console.log("=== Pluribus Networks OEM Transceiver Seed ===\n"); + + const vendorId = await ensureVendor( + "Pluribus Networks", + "oem", + "https://www.pluribusnetworks.com", + undefined + ); + + let inserted = 0; + let updated = 0; + let errors = 0; + + for (const p of PLURIBUS_PIDS) { + const slug = `pluribus-${p.pid.toLowerCase().replace(/[^a-z0-9]+/g, "-")}`; + try { + const res = await pool.query( + `INSERT INTO transceivers + (slug, part_number, vendor_id, form_factor, speed, speed_gbps, + reach_meters, reach_label, fiber_type, connector, wavelengths, + dom_support, ieee_reference, market_status, category, notes) + VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,true,$12,'Mainstream','DataCenter',$13) + ON CONFLICT (slug) DO UPDATE SET + speed_gbps = EXCLUDED.speed_gbps, + reach_meters = CASE WHEN EXCLUDED.reach_meters > 0 THEN EXCLUDED.reach_meters ELSE transceivers.reach_meters END, + fiber_type = CASE WHEN EXCLUDED.fiber_type <> '' THEN EXCLUDED.fiber_type ELSE transceivers.fiber_type END, + wavelengths = COALESCE(EXCLUDED.wavelengths, transceivers.wavelengths), + updated_at = NOW() + RETURNING (xmax = 0) as was_inserted`, + [slug, p.pid, vendorId, p.formFactor, p.speed, p.speedGbps, + p.reachMeters, p.reachLabel, p.fiberType, p.connector, + p.wavelengths ?? null, p.standard ?? null, p.notes ?? null] + ); + if (res.rows[0]?.was_inserted) inserted++; else updated++; + } catch (err) { + console.warn(` Skip ${p.pid}: ${(err as Error).message.slice(0, 80)}`); + errors++; + } + } + + console.log(`\n=== Pluribus Networks OEM Seed Complete ===`); + console.log(` Inserted: ${inserted}`); + console.log(` Updated: ${updated}`); + console.log(` Errors: ${errors}`); + console.log(` Total PIDs: ${PLURIBUS_PIDS.length}\n`); +} + +if (require.main === module) { + scrapePluribusOem() + .then(() => pool.end()) + .catch((err) => { + console.error("Fatal:", err); + pool.end(); + process.exit(1); + }); +} diff --git a/packages/scraper/src/scrapers/pure-storage-oem.ts b/packages/scraper/src/scrapers/pure-storage-oem.ts new file mode 100644 index 0000000..19387e9 --- /dev/null +++ b/packages/scraper/src/scrapers/pure-storage-oem.ts @@ -0,0 +1,312 @@ +/** + * Pure Storage OEM Transceiver Catalog Seed + * + * Seeds Pure Storage-branded transceiver PIDs for FlashArray //X, //C, //E + * and FlashBlade platforms. Pure Storage uses a PS- prefix for its optical + * SFP/QSFP accessories across all NVMe-oF, FC, iSCSI, and Ethernet ports. + * + * Sources: + * - Pure Storage FlashArray hardware compatibility guide (purestorage.com) + * - Pure Storage Pure1 hardware universe + * - SFF-8024 Fibre Channel speed codes + * + * Run: tsx packages/scraper/src/scrapers/pure-storage-oem.ts + * Cron: daily at 06:00 + */ + +import { pool, ensureVendor } from "../utils/db"; + +interface PureStoragePID { + pid: string; + formFactor: string; + speedGbps: number; + speed: string; + reachMeters: number; + reachLabel: string; + fiberType: string; + connector: string; + wavelengths?: string; + standard?: string; + notes?: string; +} + +// Fibre Channel line-rate speeds (Gbps): +// 8G = 8.5 Gbps (4x FC) +// 16G = 14.025 Gbps (8x FC) +// 32G = 28.05 Gbps (16x FC) +const PURE_STORAGE_PIDS: PureStoragePID[] = [ + // ── 1G SFP ─────────────────────────────────────────────────────────────── + { + pid: "PS-SFP-1G-SX", + formFactor: "SFP", + speedGbps: 1, + speed: "1G", + reachMeters: 550, + reachLabel: "SX", + fiberType: "MMF", + connector: "LC", + wavelengths: "850nm", + standard: "1000BASE-SX", + notes: "1GbE SFP SX; Pure Storage FlashArray management port; OM2/OM3 MMF", + }, + { + pid: "PS-SFP-1G-LX", + formFactor: "SFP", + speedGbps: 1, + speed: "1G", + reachMeters: 10000, + reachLabel: "LX", + fiberType: "SMF", + connector: "LC", + wavelengths: "1310nm", + standard: "1000BASE-LX", + notes: "1GbE SFP LX; Pure Storage FlashArray management port; OS2 SMF up to 10km", + }, + // ── 1G Copper SFP ──────────────────────────────────────────────────────── + { + pid: "PS-SFP-1G-T", + formFactor: "SFP", + speedGbps: 1, + speed: "1G", + reachMeters: 100, + reachLabel: "T", + fiberType: "DAC", + connector: "RJ45", + standard: "1000BASE-T", + notes: "1GbE copper SFP RJ45; Pure Storage management port copper option; Cat5e/6", + }, + // ── 10G SFP+ ───────────────────────────────────────────────────────────── + { + pid: "PS-SFP-10G-SR", + formFactor: "SFP+", + speedGbps: 10, + speed: "10G", + reachMeters: 300, + reachLabel: "SR", + fiberType: "MMF", + connector: "LC", + wavelengths: "850nm", + standard: "10GBASE-SR", + notes: "10GbE SFP+ SR; FlashArray //X10R3/X20R3 iSCSI host port; OM3/OM4 MMF", + }, + { + pid: "PS-SFP-10G-LR", + formFactor: "SFP+", + speedGbps: 10, + speed: "10G", + reachMeters: 10000, + reachLabel: "LR", + fiberType: "SMF", + connector: "LC", + wavelengths: "1310nm", + standard: "10GBASE-LR", + notes: "10GbE SFP+ LR; FlashArray //X10R3/X20R3 iSCSI host port; OS2 SMF", + }, + // ── 10G Copper SFP+ ────────────────────────────────────────────────────── + { + pid: "PS-SFP-10G-T", + formFactor: "SFP+", + speedGbps: 10, + speed: "10G", + reachMeters: 30, + reachLabel: "T", + fiberType: "DAC", + connector: "RJ45", + standard: "10GBASE-T", + notes: "10GbE copper SFP+ RJ45; Pure Storage host port copper option; Cat6a", + }, + // ── 8G FC SFP ──────────────────────────────────────────────────────────── + { + pid: "PS-SFP-16G-FC-SW", + formFactor: "SFP", + speedGbps: 14.025, + speed: "16G FC", + reachMeters: 125, + reachLabel: "SW", + fiberType: "MMF", + connector: "LC", + wavelengths: "850nm", + standard: "16GFC", + notes: "16G FC short-wave; FlashArray //X FC host port; OM4 MMF; SAN connectivity", + }, + // ── 32G FC SFP+ ────────────────────────────────────────────────────────── + { + pid: "PS-SFP-32G-FC-SW", + formFactor: "SFP+", + speedGbps: 28.05, + speed: "32G FC", + reachMeters: 100, + reachLabel: "SW", + fiberType: "MMF", + connector: "LC", + wavelengths: "850nm", + standard: "32GFC", + notes: "32G FC short-wave; FlashArray //X NVMe/FC and SCSI FC host port; OM4/OM5 MMF", + }, + // ── 8G FC SFP long-wave ─────────────────────────────────────────────────── + { + pid: "PS-SFP-FC-8G-LW", + formFactor: "SFP", + speedGbps: 8.5, + speed: "8G FC", + reachMeters: 10000, + reachLabel: "LW", + fiberType: "SMF", + connector: "LC", + wavelengths: "1310nm", + standard: "8GFC", + notes: "8G FC long-wave; Pure Storage FlashArray FC host port; OS2 SMF up to 10km", + }, + // ── 25G SFP28 ──────────────────────────────────────────────────────────── + { + pid: "PS-SFP28-25G-SR", + formFactor: "SFP28", + speedGbps: 25, + speed: "25G", + reachMeters: 100, + reachLabel: "SR", + fiberType: "MMF", + connector: "LC", + wavelengths: "850nm", + standard: "25GBASE-SR", + notes: "25GbE SFP28 SR; FlashArray //X70R4/X90R4 iSCSI/NVMe-TCP host port; OM4 MMF", + }, + { + pid: "PS-SFP28-25G-LR", + formFactor: "SFP28", + speedGbps: 25, + speed: "25G", + reachMeters: 10000, + reachLabel: "LR", + fiberType: "SMF", + connector: "LC", + wavelengths: "1310nm", + standard: "25GBASE-LR", + notes: "25GbE SFP28 LR; FlashArray //X70R4/X90R4 iSCSI/NVMe-TCP host port; OS2 SMF", + }, + // ── 100G QSFP28 ────────────────────────────────────────────────────────── + { + pid: "PS-QSFP28-100G-SR4", + formFactor: "QSFP28", + speedGbps: 100, + speed: "100G", + reachMeters: 100, + reachLabel: "SR4", + fiberType: "MMF", + connector: "MPO", + wavelengths: "850nm", + standard: "100GBASE-SR4", + notes: "100GbE QSFP28 SR4; FlashBlade //S NVMe-oF host port; OM4 MPO-12", + }, + { + pid: "PS-QSFP28-100G-LR4", + formFactor: "QSFP28", + speedGbps: 100, + speed: "100G", + reachMeters: 10000, + reachLabel: "LR4", + fiberType: "SMF", + connector: "LC", + wavelengths: "1295-1310nm", + standard: "100GBASE-LR4", + notes: "100GbE QSFP28 LR4; FlashBlade //S NVMe-oF host port; OS2 SMF up to 10km", + }, + { + pid: "PS-QSFP28-100G-ER4", + formFactor: "QSFP28", + speedGbps: 100, + speed: "100G", + reachMeters: 40000, + reachLabel: "ER4", + fiberType: "SMF", + connector: "LC", + wavelengths: "1295-1310nm", + standard: "100GBASE-ER4", + notes: "100GbE QSFP28 ER4; FlashBlade extended-reach replication links; OS2 SMF up to 40km", + }, + // ── 400G QSFP-DD ───────────────────────────────────────────────────────── + { + pid: "PS-QSFP-DD-400G-DR4", + formFactor: "QSFP-DD", + speedGbps: 400, + speed: "400G", + reachMeters: 500, + reachLabel: "DR4", + fiberType: "SMF", + connector: "MPO", + wavelengths: "1310nm", + standard: "400GBASE-DR4", + notes: "400GbE QSFP-DD DR4; FlashBlade //S500 NVMe-oF high-density host port; OS2 SMF up to 500m", + }, + { + pid: "PS-QSFP-DD-400G-SR8", + formFactor: "QSFP-DD", + speedGbps: 400, + speed: "400G", + reachMeters: 100, + reachLabel: "SR8", + fiberType: "MMF", + connector: "MPO", + wavelengths: "850nm", + standard: "400GBASE-SR8", + notes: "400GbE QSFP-DD SR8; FlashBlade //S500 NVMe-oF high-density host port; OM4/OM5 MPO-16", + }, +]; + +export async function scrapePureStorageOem(): Promise { + console.log("=== Pure Storage OEM Transceiver Seed ===\n"); + + const vendorId = await ensureVendor( + "Pure Storage", + "oem", + "https://www.purestorage.com", + undefined + ); + + let inserted = 0; + let updated = 0; + let errors = 0; + + for (const p of PURE_STORAGE_PIDS) { + const slug = `pure-storage-${p.pid.toLowerCase().replace(/[^a-z0-9]+/g, "-")}`; + try { + const res = await pool.query( + `INSERT INTO transceivers + (slug, part_number, vendor_id, form_factor, speed, speed_gbps, + reach_meters, reach_label, fiber_type, connector, wavelengths, + dom_support, ieee_reference, market_status, category, notes) + VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,true,$12,'Mainstream','DataCenter',$13) + ON CONFLICT (slug) DO UPDATE SET + speed_gbps = EXCLUDED.speed_gbps, + reach_meters = CASE WHEN EXCLUDED.reach_meters > 0 THEN EXCLUDED.reach_meters ELSE transceivers.reach_meters END, + fiber_type = CASE WHEN EXCLUDED.fiber_type <> '' THEN EXCLUDED.fiber_type ELSE transceivers.fiber_type END, + wavelengths = COALESCE(EXCLUDED.wavelengths, transceivers.wavelengths), + updated_at = NOW() + RETURNING (xmax = 0) as was_inserted`, + [slug, p.pid, vendorId, p.formFactor, p.speed, p.speedGbps, + p.reachMeters, p.reachLabel, p.fiberType, p.connector, + p.wavelengths ?? null, p.standard ?? null, p.notes ?? null] + ); + if (res.rows[0]?.was_inserted) inserted++; else updated++; + } catch (err) { + console.warn(` Skip ${p.pid}: ${(err as Error).message.slice(0, 80)}`); + errors++; + } + } + + console.log(`\n=== Pure Storage OEM Seed Complete ===`); + console.log(` Inserted: ${inserted}`); + console.log(` Updated: ${updated}`); + console.log(` Errors: ${errors}`); + console.log(` Total PIDs: ${PURE_STORAGE_PIDS.length}\n`); +} + +if (require.main === module) { + scrapePureStorageOem() + .then(() => pool.end()) + .catch((err) => { + console.error("Fatal:", err); + pool.end(); + process.exit(1); + }); +} diff --git a/packages/scraper/src/scrapers/qlogic-oem.ts b/packages/scraper/src/scrapers/qlogic-oem.ts new file mode 100644 index 0000000..6ba0706 --- /dev/null +++ b/packages/scraper/src/scrapers/qlogic-oem.ts @@ -0,0 +1,369 @@ +/** + * QLogic / Marvell OEM Transceiver Catalog Seed + * + * Seeds QLogic-branded transceiver PIDs for Fibre Channel HBAs and + * iSCSI/FCoE adapters. QLogic is now owned by Marvell but continues + * shipping under the QLogic brand for FC/storage markets. + * + * Sources: + * - Marvell FC HBA product page (marvell.com/products/fibre-channel-host-bus-adapters) + * - QLogic HBA optical transceiver compatibility guides + * - SFF-8024 Fibre Channel speed codes + * + * Run: tsx packages/scraper/src/scrapers/qlogic-oem.ts + * Cron: daily at 05:15 + */ + +import { pool, ensureVendor } from "../utils/db"; + +interface QlogicPID { + pid: string; + formFactor: string; + speedGbps: number; + speed: string; + reachMeters: number; + reachLabel: string; + fiberType: string; + connector: string; + wavelengths?: string; + standard?: string; + notes?: string; +} + +// Fibre Channel line-rate speeds (Gbps): +// 2G = 2.125 Gbps (1x FC) +// 4G = 4.25 Gbps (2x FC) +// 8G = 8.5 Gbps (4x FC) +// 16G = 14.025 Gbps (8x FC) +// 32G = 28.05 Gbps (16x FC) +// 64G = 56.1 Gbps (32x FC) +const QLOGIC_PIDS: QlogicPID[] = [ + // ── 2G FC SFP ──────────────────────────────────────────────────────────── + { + pid: "QL-SFP-2G-FC-SW", + formFactor: "SFP", + speedGbps: 2.125, + speed: "2G FC", + reachMeters: 300, + reachLabel: "SW", + fiberType: "MMF", + connector: "LC", + wavelengths: "850nm", + standard: "2GFC", + notes: "2G Fibre Channel short-wave; OM2/OM3 MMF; QLogic HBA 2G port", + }, + // ── 4G FC SFP ──────────────────────────────────────────────────────────── + { + pid: "QL-SFP-4G-FC-SW", + formFactor: "SFP", + speedGbps: 4.25, + speed: "4G FC", + reachMeters: 380, + reachLabel: "SW", + fiberType: "MMF", + connector: "LC", + wavelengths: "850nm", + standard: "4GFC", + notes: "4G Fibre Channel short-wave; OM3 MMF preferred", + }, + // ── 8G FC SFP ──────────────────────────────────────────────────────────── + { + pid: "QL-SFP-8G-FC-SW", + formFactor: "SFP", + speedGbps: 8.5, + speed: "8G FC", + reachMeters: 150, + reachLabel: "SW", + fiberType: "MMF", + connector: "LC", + wavelengths: "850nm", + standard: "8GFC", + notes: "8G Fibre Channel short-wave; OM3/OM4 MMF; QLogic QLE2560/2562 HBAs", + }, + { + pid: "QL-SFP-8G-FC-LW", + formFactor: "SFP", + speedGbps: 8.5, + speed: "8G FC", + reachMeters: 10000, + reachLabel: "LW", + fiberType: "SMF", + connector: "LC", + wavelengths: "1310nm", + standard: "8GFC", + notes: "8G Fibre Channel long-wave; OS2 SMF; up to 10km", + }, + // ── 16G FC SFP ─────────────────────────────────────────────────────────── + { + pid: "QL-SFP-16G-FC-SW", + formFactor: "SFP", + speedGbps: 14.025, + speed: "16G FC", + reachMeters: 125, + reachLabel: "SW", + fiberType: "MMF", + connector: "LC", + wavelengths: "850nm", + standard: "16GFC", + notes: "16G FC short-wave; OM4 MMF recommended; QLogic QLE2670/2672 HBAs", + }, + { + pid: "QL-SFP-16G-FC-LW", + formFactor: "SFP", + speedGbps: 14.025, + speed: "16G FC", + reachMeters: 10000, + reachLabel: "LW", + fiberType: "SMF", + connector: "LC", + wavelengths: "1310nm", + standard: "16GFC", + notes: "16G FC long-wave; OS2 SMF; campus/inter-building SANs", + }, + // ── 32G FC SFP+ ────────────────────────────────────────────────────────── + { + pid: "QL-SFP-32G-FC-SW", + formFactor: "SFP+", + speedGbps: 28.05, + speed: "32G FC", + reachMeters: 100, + reachLabel: "SW", + fiberType: "MMF", + connector: "LC", + wavelengths: "850nm", + standard: "32GFC", + notes: "32G FC short-wave; OM4/OM5 MMF; QLogic QLE2740/2742 HBAs", + }, + { + pid: "QL-SFP-32G-FC-LW", + formFactor: "SFP+", + speedGbps: 28.05, + speed: "32G FC", + reachMeters: 10000, + reachLabel: "LW", + fiberType: "SMF", + connector: "LC", + wavelengths: "1310nm", + standard: "32GFC", + notes: "32G FC long-wave; OS2 SMF; extended-distance SAN links", + }, + // ── 64G FC SFP28 ───────────────────────────────────────────────────────── + { + pid: "QL-SFP28-64G-FC-SW", + formFactor: "SFP28", + speedGbps: 56.1, + speed: "64G FC", + reachMeters: 100, + reachLabel: "SW", + fiberType: "MMF", + connector: "LC", + wavelengths: "850nm", + standard: "64GFC", + notes: "64G FC short-wave; OM4/OM5 MMF; QLogic QLE2870 NVMe/FC HBAs", + }, + // ── 32G FC QSFP28 (4x8G breakout) ──────────────────────────────────────── + { + pid: "QL-QSFP28-32G-FC-4X", + formFactor: "QSFP28", + speedGbps: 32, + speed: "32G FC", + reachMeters: 100, + reachLabel: "SR4", + fiberType: "MMF", + connector: "MPO", + wavelengths: "850nm", + standard: "32GFC", + notes: "QSFP28 to 4x SFP28 32G FC breakout; OM4 MPO; director-class switches", + }, + // ── iSCSI SFP ──────────────────────────────────────────────────────────── + { + pid: "QL-SFP-iSCSI-1G-SX", + formFactor: "SFP", + speedGbps: 1, + speed: "1G", + reachMeters: 550, + reachLabel: "SX", + fiberType: "MMF", + connector: "LC", + wavelengths: "850nm", + standard: "1000BASE-SX", + notes: "1GbE SFP SX for QLogic iSCSI HBA optical port", + }, + { + pid: "QL-SFP-iSCSI-1G-LX", + formFactor: "SFP", + speedGbps: 1, + speed: "1G", + reachMeters: 10000, + reachLabel: "LX", + fiberType: "SMF", + connector: "LC", + wavelengths: "1310nm", + standard: "1000BASE-LX", + notes: "1GbE SFP LX for QLogic iSCSI HBA optical port", + }, + { + pid: "QL-SFP-iSCSI-10G-SR", + formFactor: "SFP+", + speedGbps: 10, + speed: "10G", + reachMeters: 300, + reachLabel: "SR", + fiberType: "MMF", + connector: "LC", + wavelengths: "850nm", + standard: "10GBASE-SR", + notes: "10GbE SFP+ SR for QLogic 10GbE iSCSI CNA", + }, + { + pid: "QL-SFP-iSCSI-10G-LR", + formFactor: "SFP+", + speedGbps: 10, + speed: "10G", + reachMeters: 10000, + reachLabel: "LR", + fiberType: "SMF", + connector: "LC", + wavelengths: "1310nm", + standard: "10GBASE-LR", + notes: "10GbE SFP+ LR for QLogic 10GbE iSCSI CNA", + }, + // ── FCoE SFP+ ──────────────────────────────────────────────────────────── + { + pid: "QL-SFP-FCoE-10G-SR", + formFactor: "SFP+", + speedGbps: 10, + speed: "10G", + reachMeters: 300, + reachLabel: "SR", + fiberType: "MMF", + connector: "LC", + wavelengths: "850nm", + standard: "10GBASE-SR", + notes: "10GbE SFP+ SR for QLogic FCoE CNA (FibreChannel over Ethernet)", + }, + { + pid: "QL-SFP-FCoE-10G-LR", + formFactor: "SFP+", + speedGbps: 10, + speed: "10G", + reachMeters: 10000, + reachLabel: "LR", + fiberType: "SMF", + connector: "LC", + wavelengths: "1310nm", + standard: "10GBASE-LR", + notes: "10GbE SFP+ LR for QLogic FCoE CNA", + }, + // ── 25G / 100G Ethernet (Marvell FastLinQ CNAs) ─────────────────────────── + { + pid: "QL-SFP-25G-SR", + formFactor: "SFP28", + speedGbps: 25, + speed: "25G", + reachMeters: 100, + reachLabel: "SR", + fiberType: "MMF", + connector: "LC", + wavelengths: "850nm", + standard: "25GBASE-SR", + notes: "25GbE SFP28 SR for Marvell FastLinQ QL41000 CNA", + }, + { + pid: "QL-SFP-25G-LR", + formFactor: "SFP28", + speedGbps: 25, + speed: "25G", + reachMeters: 10000, + reachLabel: "LR", + fiberType: "SMF", + connector: "LC", + wavelengths: "1310nm", + standard: "25GBASE-LR", + notes: "25GbE SFP28 LR for Marvell FastLinQ QL41000 CNA", + }, + { + pid: "QL-QSFP28-100G-SR4", + formFactor: "QSFP28", + speedGbps: 100, + speed: "100G", + reachMeters: 100, + reachLabel: "SR4", + fiberType: "MMF", + connector: "MPO", + wavelengths: "850nm", + standard: "100GBASE-SR4", + notes: "100GbE QSFP28 SR4; Marvell FastLinQ QL45000 series CNA", + }, + { + pid: "QL-QSFP28-100G-LR4", + formFactor: "QSFP28", + speedGbps: 100, + speed: "100G", + reachMeters: 10000, + reachLabel: "LR4", + fiberType: "SMF", + connector: "LC", + wavelengths: "1295-1310nm", + standard: "100GBASE-LR4", + notes: "100GbE QSFP28 LR4; Marvell FastLinQ QL45000 series CNA", + }, +]; + +export async function scrapeQlogicOem(): Promise { + console.log("=== QLogic / Marvell OEM Transceiver Seed ===\n"); + + const vendorId = await ensureVendor( + "QLogic", + "oem", + "https://www.marvell.com/products/fibre-channel-host-bus-adapters.html", + undefined + ); + + let inserted = 0; + let updated = 0; + let errors = 0; + + for (const p of QLOGIC_PIDS) { + const slug = `qlogic-${p.pid.toLowerCase().replace(/[^a-z0-9]+/g, "-")}`; + try { + const res = await pool.query( + `INSERT INTO transceivers + (slug, part_number, vendor_id, form_factor, speed, speed_gbps, + reach_meters, reach_label, fiber_type, connector, wavelengths, + dom_support, ieee_reference, market_status, category, notes) + VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,true,$12,'Mainstream','DataCenter',$13) + ON CONFLICT (slug) DO UPDATE SET + speed_gbps = EXCLUDED.speed_gbps, + reach_meters = CASE WHEN EXCLUDED.reach_meters > 0 THEN EXCLUDED.reach_meters ELSE transceivers.reach_meters END, + fiber_type = CASE WHEN EXCLUDED.fiber_type <> '' THEN EXCLUDED.fiber_type ELSE transceivers.fiber_type END, + wavelengths = COALESCE(EXCLUDED.wavelengths, transceivers.wavelengths), + updated_at = NOW() + RETURNING (xmax = 0) as was_inserted`, + [slug, p.pid, vendorId, p.formFactor, p.speed, p.speedGbps, + p.reachMeters, p.reachLabel, p.fiberType, p.connector, + p.wavelengths ?? null, p.standard ?? null, p.notes ?? null] + ); + if (res.rows[0]?.was_inserted) inserted++; else updated++; + } catch (err) { + console.warn(` Skip ${p.pid}: ${(err as Error).message.slice(0, 80)}`); + errors++; + } + } + + console.log(`\n=== QLogic OEM Seed Complete ===`); + console.log(` Inserted: ${inserted}`); + console.log(` Updated: ${updated}`); + console.log(` Errors: ${errors}`); + console.log(` Total PIDs: ${QLOGIC_PIDS.length}\n`); +} + +if (require.main === module) { + scrapeQlogicOem() + .then(() => pool.end()) + .catch((err) => { + console.error("Fatal:", err); + pool.end(); + process.exit(1); + }); +} diff --git a/packages/scraper/src/scrapers/rad-oem.ts b/packages/scraper/src/scrapers/rad-oem.ts new file mode 100644 index 0000000..3a571c0 --- /dev/null +++ b/packages/scraper/src/scrapers/rad-oem.ts @@ -0,0 +1,156 @@ +/** + * RAD Data Communications OEM Transceiver Catalog Seed + * + * Seeds RAD-branded transceiver PIDs for carrier Ethernet/MEF platforms, + * ETX, RAD-ETX, AINOS, and Megaplex access devices. + * RAD Data Communications is an Israeli vendor specialising in MEF CE 2.0, + * synchronisation, OTN, and SONET/SDH access transport. + * + * Sources: + * - RAD ETX-203AX / ETX-205A Pluggable Module Data Sheets + * - RAD Megaplex-4100 Optical Interface Cards + * - RAD DWDM and CWDM SFP Module Spec Sheets + * - rad.com product catalogue + * + * Run: tsx packages/scraper/src/scrapers/rad-oem.ts + * Cron: daily at 01:15 + */ + +import { pool, ensureVendor } from "../utils/db"; + +interface RadPID { + pid: string; + formFactor: string; + speedGbps: number; + speed: string; + reachMeters: number; + reachLabel: string; + fiberType: string; + connector: string; + wavelengths?: string; + standard?: string; + category?: string; + notes?: string; +} + +const RAD_PIDS: RadPID[] = [ + // ── 1G SFP ────────────────────────────────────────────────────────────── + { pid: "RAD-SFP-1G-SX", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 550, reachLabel: "SX", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "1000BASE-SX" }, + { pid: "RAD-SFP-1G-LX", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 10000, reachLabel: "LX", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "1000BASE-LX" }, + { pid: "RAD-SFP-1G-ZX", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 80000, reachLabel: "ZX", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "1000BASE-ZX" }, + + // ── 10G SFP+ ──────────────────────────────────────────────────────────── + { pid: "RAD-SFP-10G-SR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 300, reachLabel: "SR", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "10GBASE-SR" }, + { pid: "RAD-SFP-10G-LR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 10000, reachLabel: "LR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "10GBASE-LR" }, + { pid: "RAD-SFP-10G-ER", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 40000, reachLabel: "ER", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "10GBASE-ER" }, + { pid: "RAD-SFP-10G-ZR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 80000, reachLabel: "ZR", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "10GBASE-ZR", category: "Telecom", notes: "RAD 10G ZR for ETX extended reach" }, + + // ── SONET/SDH SFP (OC-3 / STM-1) ──────────────────────────────────────── + { pid: "RAD-SFP-OC3-SR", formFactor: "SFP", speedGbps: 0.155, speed: "OC3", reachMeters: 2000, reachLabel: "SR", fiberType: "MMF", connector: "LC", wavelengths: "1310nm", standard: "OC-3/STM-1", category: "Telecom", notes: "RAD OC-3 short-reach SFP for Megaplex" }, + { pid: "RAD-SFP-OC3-LR", formFactor: "SFP", speedGbps: 0.155, speed: "OC3", reachMeters: 15000, reachLabel: "LR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "OC-3/STM-1", category: "Telecom", notes: "RAD OC-3 long-reach SFP for Megaplex" }, + + // ── SONET/SDH SFP (OC-12 / STM-4) ─────────────────────────────────────── + { pid: "RAD-SFP-OC12-SR", formFactor: "SFP", speedGbps: 0.622, speed: "OC12", reachMeters: 2000, reachLabel: "SR", fiberType: "MMF", connector: "LC", wavelengths: "1310nm", standard: "OC-12/STM-4", category: "Telecom", notes: "RAD OC-12 short-reach SFP" }, + { pid: "RAD-SFP-OC12-LR", formFactor: "SFP", speedGbps: 0.622, speed: "OC12", reachMeters: 15000, reachLabel: "LR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "OC-12/STM-4", category: "Telecom", notes: "RAD OC-12 long-reach SFP" }, + + // ── SONET SFP (OC-48 / STM-16) ─────────────────────────────────────────── + { pid: "RAD-SFP-OC48-LR", formFactor: "SFP", speedGbps: 2.488, speed: "OC48", reachMeters: 40000, reachLabel: "LR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "OC-48/STM-16", category: "Telecom", notes: "RAD OC-48 long-reach SFP" }, + + // ── STM-1 SFP ──────────────────────────────────────────────────────────── + { pid: "RAD-SFP-STM1-LR", formFactor: "SFP", speedGbps: 0.155, speed: "STM1", reachMeters: 15000, reachLabel: "LR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "STM-1", category: "Telecom", notes: "RAD STM-1 long-reach for ETX SDH mux" }, + + // ── CWDM SFP ───────────────────────────────────────────────────────────── + { pid: "RAD-SFP-CWDM-1550", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 40000, reachLabel: "CWDM", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "CWDM", category: "Telecom", notes: "RAD CWDM 1550nm SFP for metro WDM access" }, + + // ── DWDM SFP ───────────────────────────────────────────────────────────── + { pid: "RAD-DWDM-SFP-C", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 80000, reachLabel: "DWDM", fiberType: "SMF", connector: "LC", wavelengths: "C-band DWDM", category: "Telecom", notes: "RAD ITU-T G.694.1 DWDM C-band SFP" }, + + // ── BiDi SFP ───────────────────────────────────────────────────────────── + { pid: "RAD-SFP-GE-BIDI", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 20000, reachLabel: "BiDi", fiberType: "SMF", connector: "LC", wavelengths: "1310/1490nm", category: "Telecom", notes: "RAD BiDi GE SFP single-fibre WDM" }, + + // ── 25G SFP28 ──────────────────────────────────────────────────────────── + { pid: "RAD-SFP-25G-LR", formFactor: "SFP28", speedGbps: 25, speed: "25G", reachMeters: 10000, reachLabel: "LR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "25GBASE-LR" }, + + // ── 40G QSFP+ ──────────────────────────────────────────────────────────── + { pid: "RAD-QSFP-40G-LR4", formFactor: "QSFP+", speedGbps: 40, speed: "40G", reachMeters: 10000, reachLabel: "LR4", fiberType: "SMF", connector: "LC", wavelengths: "1270-1330nm", standard: "40GBASE-LR4" }, + + // ── 100G QSFP28 ────────────────────────────────────────────────────────── + { pid: "RAD-QSFP-100G-LR4", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 10000, reachLabel: "LR4", fiberType: "SMF", connector: "LC", wavelengths: "1295-1310nm", standard: "100GBASE-LR4" }, + + // ── 100G CFP ───────────────────────────────────────────────────────────── + { pid: "RAD-CFP-100G-LR4", formFactor: "CFP", speedGbps: 100, speed: "100G", reachMeters: 10000, reachLabel: "LR4", fiberType: "SMF", connector: "LC", wavelengths: "1295-1310nm", standard: "100GBASE-LR4", category: "Telecom", notes: "RAD CFP 100G LR4 for high-capacity ETX transport" }, +]; + +// PIDs that use 'Telecom' category (SONET/SDH, DWDM, CWDM, BiDi, ZR, CFP) +const TELECOM_PIDS = new Set([ + "RAD-SFP-10G-ZR", + "RAD-SFP-OC3-SR", + "RAD-SFP-OC3-LR", + "RAD-SFP-OC12-SR", + "RAD-SFP-OC12-LR", + "RAD-SFP-OC48-LR", + "RAD-SFP-STM1-LR", + "RAD-SFP-CWDM-1550", + "RAD-DWDM-SFP-C", + "RAD-SFP-GE-BIDI", + "RAD-CFP-100G-LR4", +]); + +export async function scrapeRadOem(): Promise { + console.log("=== RAD Data Communications OEM Transceiver Seed ===\n"); + + const vendorId = await ensureVendor( + "RAD Data Communications", + "oem", + "https://www.rad.com", + undefined + ); + + let inserted = 0; + let updated = 0; + let errors = 0; + + for (const p of RAD_PIDS) { + const slug = `rad-${p.pid.toLowerCase().replace(/[^a-z0-9]+/g, "-")}`; + const category = p.category ?? (TELECOM_PIDS.has(p.pid) ? "Telecom" : "DataCenter"); + try { + const res = await pool.query( + `INSERT INTO transceivers + (slug, part_number, vendor_id, form_factor, speed, speed_gbps, + reach_meters, reach_label, fiber_type, connector, wavelengths, + dom_support, ieee_reference, market_status, category, notes) + VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,true,$12,'Mainstream',$13,$14) + ON CONFLICT (slug) DO UPDATE SET + speed_gbps = EXCLUDED.speed_gbps, + reach_meters = CASE WHEN EXCLUDED.reach_meters > 0 THEN EXCLUDED.reach_meters ELSE transceivers.reach_meters END, + fiber_type = CASE WHEN EXCLUDED.fiber_type <> '' THEN EXCLUDED.fiber_type ELSE transceivers.fiber_type END, + wavelengths = COALESCE(EXCLUDED.wavelengths, transceivers.wavelengths), + updated_at = NOW() + RETURNING (xmax = 0) as was_inserted`, + [slug, p.pid, vendorId, p.formFactor, p.speed, p.speedGbps, + p.reachMeters, p.reachLabel, p.fiberType, p.connector, + p.wavelengths ?? null, p.standard ?? null, category, p.notes ?? null] + ); + if (res.rows[0]?.was_inserted) inserted++; else updated++; + } catch (err) { + console.warn(` Skip ${p.pid}: ${(err as Error).message.slice(0, 80)}`); + errors++; + } + } + + console.log(`\n=== RAD Data Communications OEM Seed Complete ===`); + console.log(` Inserted: ${inserted}`); + console.log(` Updated: ${updated}`); + console.log(` Errors: ${errors}`); + console.log(` Total PIDs: ${RAD_PIDS.length}\n`); +} + +if (require.main === module) { + scrapeRadOem() + .then(() => pool.end()) + .catch((err) => { + console.error("Fatal:", err); + pool.end(); + process.exit(1); + }); +} diff --git a/packages/scraper/src/scrapers/redlion-oem.ts b/packages/scraper/src/scrapers/redlion-oem.ts new file mode 100644 index 0000000..a930345 --- /dev/null +++ b/packages/scraper/src/scrapers/redlion-oem.ts @@ -0,0 +1,118 @@ +/** + * Red Lion Controls OEM Transceiver Catalog Seed + * + * Seeds transceiver PIDs for Red Lion Controls industrial-grade SFP modules + * used in NT series and SL series ICS/SCADA industrial networking switches. + * + * Sources: + * - Red Lion Controls SFP module product pages (redlion.net) + * - Red Lion NT/SL series hardware documentation + * + * Run: tsx packages/scraper/src/scrapers/redlion-oem.ts + * Cron: daily at 14:30 + */ + +import { pool, ensureVendor } from "../utils/db"; + +interface RedlionPID { + pid: string; + formFactor: string; + speedGbps: number; + speed: string; + reachMeters: number; + reachLabel: string; + fiberType: string; + connector: string; + wavelengths?: string; + standard?: string; + notes?: string; +} + +const REDLION_PIDS: RedlionPID[] = [ + // ── 100M SFP (legacy) ─────────────────────────────────────────────────── + { pid: "102FX-MM-SC", formFactor: "SFP", speedGbps: 0.1, speed: "100M", reachMeters: 2000, reachLabel: "FX", fiberType: "MMF", connector: "SC", wavelengths: "850nm", standard: "100BASE-FX", notes: "Red Lion 100M MM SFP" }, + { pid: "102FX-SM-SC", formFactor: "SFP", speedGbps: 0.1, speed: "100M", reachMeters: 40000, reachLabel: "LFX", fiberType: "SMF", connector: "SC", wavelengths: "1310nm", notes: "Red Lion 100M SM SFP 40km" }, + { pid: "102FX-SM-SC-BXU", formFactor: "SFP", speedGbps: 0.1, speed: "100M", reachMeters: 20000, reachLabel: "BiDi",fiberType: "SMF", connector: "SC", wavelengths: "TX1310/RX1550nm", notes: "Red Lion 100M BiDi SFP upstream" }, + + // ── 1G SFP ────────────────────────────────────────────────────────────── + { pid: "1000FX-MM-LC", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 550, reachLabel: "SX", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "1000BASE-SX" }, + { pid: "1000FX-SM10-LC", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 10000, reachLabel: "LX", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "1000BASE-LX" }, + { pid: "1000FX-SM40-LC", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 40000, reachLabel: "LH", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", notes: "Red Lion 1G SM SFP 40km" }, + { pid: "1000FX-SM80-LC", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 80000, reachLabel: "ZX", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "1000BASE-ZX" }, + { pid: "1000TX-RJ45", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 100, reachLabel: "T", fiberType: "DAC", connector: "RJ45", standard: "1000BASE-T" }, + { pid: "1000FX-BXU-LC", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 20000, reachLabel: "BiDi",fiberType: "SMF", connector: "LC", wavelengths: "TX1310/RX1550nm", notes: "Red Lion 1G BiDi SFP upstream" }, + { pid: "1000FX-BXD-LC", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 20000, reachLabel: "BiDi",fiberType: "SMF", connector: "LC", wavelengths: "TX1550/RX1310nm", notes: "Red Lion 1G BiDi SFP downstream" }, + + // ── 10G SFP+ ──────────────────────────────────────────────────────────── + { pid: "10GFX-SR-MM-LC", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 300, reachLabel: "SR", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "10GBASE-SR" }, + { pid: "10GFX-LR-SM-LC", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 10000, reachLabel: "LR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "10GBASE-LR" }, + { pid: "10GFX-ER-SM-LC", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 40000, reachLabel: "ER", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "10GBASE-ER" }, + { pid: "10GFX-ZR-SM-LC", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 80000, reachLabel: "ZR", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "10GBASE-ZR" }, + { pid: "10GFX-BXU-LC", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 10000, reachLabel: "BiDi",fiberType: "SMF", connector: "LC", wavelengths: "TX1270/RX1330nm", notes: "Red Lion 10G BiDi SFP+ upstream" }, + + // ── 25G SFP28 ─────────────────────────────────────────────────────────── + { pid: "25GFX-SR-MM-LC", formFactor: "SFP28", speedGbps: 25, speed: "25G", reachMeters: 100, reachLabel: "SR", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "25GBASE-SR" }, + { pid: "25GFX-LR-SM-LC", formFactor: "SFP28", speedGbps: 25, speed: "25G", reachMeters: 10000, reachLabel: "LR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "25GBASE-LR" }, + + // ── DAC ───────────────────────────────────────────────────────────────── + { pid: "DAC-10G-SFP+-1M", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 1, reachLabel: "DAC", fiberType: "DAC", connector: "LC" }, + { pid: "DAC-10G-SFP+-3M", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 3, reachLabel: "DAC", fiberType: "DAC", connector: "LC" }, +]; + +export async function scrapeRedlionOem(): Promise { + console.log("=== Red Lion Controls OEM Transceiver Seed ===\n"); + + const vendorId = await ensureVendor( + "Red Lion Controls", + "oem", + "https://www.redlion.net", + undefined + ); + + let inserted = 0; + let updated = 0; + let errors = 0; + + for (const p of REDLION_PIDS) { + const slug = `redlion-${p.pid.toLowerCase().replace(/[^a-z0-9]+/g, "-")}`; + try { + const res = await pool.query( + `INSERT INTO transceivers + (slug, part_number, vendor_id, form_factor, speed, speed_gbps, + reach_meters, reach_label, fiber_type, connector, wavelengths, + dom_support, ieee_reference, market_status, category, notes) + VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,true,$12,'Mainstream','Industrial',$13) + ON CONFLICT (slug) DO UPDATE SET + speed_gbps = EXCLUDED.speed_gbps, + reach_meters = CASE WHEN EXCLUDED.reach_meters > 0 THEN EXCLUDED.reach_meters ELSE transceivers.reach_meters END, + fiber_type = CASE WHEN EXCLUDED.fiber_type <> '' THEN EXCLUDED.fiber_type ELSE transceivers.fiber_type END, + wavelengths = COALESCE(EXCLUDED.wavelengths, transceivers.wavelengths), + updated_at = NOW() + RETURNING (xmax = 0) as was_inserted`, + [slug, p.pid, vendorId, p.formFactor, p.speed, p.speedGbps, + p.reachMeters, p.reachLabel, p.fiberType, p.connector, + p.wavelengths ?? null, p.standard ?? null, p.notes ?? null] + ); + if (res.rows[0]?.was_inserted) inserted++; else updated++; + } catch (err) { + console.warn(` Skip ${p.pid}: ${(err as Error).message.slice(0, 80)}`); + errors++; + } + } + + console.log(`\n=== Red Lion Controls OEM Seed Complete ===`); + console.log(` Inserted: ${inserted}`); + console.log(` Updated: ${updated}`); + console.log(` Errors: ${errors}`); + console.log(` Total PIDs: ${REDLION_PIDS.length}\n`); +} + +if (require.main === module) { + scrapeRedlionOem() + .then(() => pool.end()) + .catch((err) => { + console.error("Fatal:", err); + pool.end(); + process.exit(1); + }); +} diff --git a/packages/scraper/src/scrapers/ribbon-comms-oem.ts b/packages/scraper/src/scrapers/ribbon-comms-oem.ts new file mode 100644 index 0000000..25fd18a --- /dev/null +++ b/packages/scraper/src/scrapers/ribbon-comms-oem.ts @@ -0,0 +1,127 @@ +/** + * Ribbon Communications OEM Transceiver Catalog Seed + * + * Seeds Ribbon Communications branded transceiver PIDs for SBC (Session + * Border Controller), Apollo IP/Optical, and SPB series platforms. + * Includes SONET OC-3/12/48 optics inherited from the SONUS/GENBAND/ECI lineage, + * plus DWDM and CFP2 coherent modules for the optical transport portfolio. + * + * Sources: + * - Ribbon Communications Hardware Catalog (ribboncommunications.com) + * - Ribbon SBC 5110/5210/7000 Series Hardware Guide + * - Ribbon Apollo 9400/9500 IP/Optical Platform Reference + * - Telcordia GR-253-CORE SONET specifications + * + * Run: tsx packages/scraper/src/scrapers/ribbon-comms-oem.ts + * Cron: daily at 22:45 + */ + +import { pool, ensureVendor } from "../utils/db"; + +interface RibbonCommsPID { + pid: string; + formFactor: string; + speedGbps: number; + speed: string; + reachMeters: number; + reachLabel: string; + fiberType: string; + connector: string; + wavelengths?: string; + standard?: string; + notes?: string; + isTelecom?: boolean; +} + +const RIBBON_COMMS_PIDS: RibbonCommsPID[] = [ + // ── 1G SFP (SBC access / management ports) ────────────────────────────── + { pid: "SFP-GE-SX", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 550, reachLabel: "SX", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "1000BASE-SX" }, + { pid: "SFP-GE-LX", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 10000, reachLabel: "LX", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "1000BASE-LX" }, + { pid: "SFP-GE-T", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 100, reachLabel: "T", fiberType: "DAC", connector: "RJ45", standard: "1000BASE-T" }, + { pid: "SFP-GE-BIDI-1310", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 10000, reachLabel: "BiDi", fiberType: "SMF", connector: "LC", wavelengths: "1310/1490nm", notes: "1G BiDi single-fiber for SBC 5110 management" }, + + // ── 10G SFP+ (SBC media / trunk ports) ────────────────────────────────── + { pid: "SFP-10G-SR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 300, reachLabel: "SR", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "10GBASE-SR" }, + { pid: "SFP-10G-LR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 10000, reachLabel: "LR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "10GBASE-LR" }, + { pid: "SFP-10G-ER", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 40000, reachLabel: "ER", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "10GBASE-ER" }, + { pid: "SFP-10G-ZR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 80000, reachLabel: "ZR", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "10GBASE-ZR", notes: "10G ZR 80km for long-haul SBC inter-site trunks" }, + { pid: "SFP-10G-LR-S", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 10000, reachLabel: "LR-S", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", notes: "10G LR industrial temp for outdoor SBC deployments" }, + + // ── 25G SFP28 ──────────────────────────────────────────────────────────── + { pid: "SFP-25G-LR", formFactor: "SFP28", speedGbps: 25, speed: "25G", reachMeters: 10000, reachLabel: "LR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "25GBASE-LR" }, + + // ── 40G / 100G (Apollo 9400 uplinks) ───────────────────────────────────── + { pid: "QSFP-40G-LR4", formFactor: "QSFP+", speedGbps: 40, speed: "40G", reachMeters: 10000, reachLabel: "LR4", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "40GBASE-LR4" }, + { pid: "QSFP-100G-LR4", formFactor: "QSFP28",speedGbps: 100, speed: "100G", reachMeters: 10000, reachLabel: "LR4", fiberType: "SMF", connector: "LC", wavelengths: "1295-1310nm", standard: "100GBASE-LR4" }, + + // ── SONET / SDH optics (SBC TDM gateway, SONUS heritage) ───────────────── + { pid: "SFP-OC3-SR", formFactor: "SFP", speedGbps: 0.155, speed: "OC-3", reachMeters: 2000, reachLabel: "OC3-SR", fiberType: "MMF", connector: "LC", wavelengths: "1310nm", standard: "OC-3/STM-1", notes: "SONET OC-3 155Mbps SR for Ribbon SBC TDM gateway", isTelecom: true }, + { pid: "SFP-OC3-LR", formFactor: "SFP", speedGbps: 0.155, speed: "OC-3", reachMeters: 15000, reachLabel: "OC3-LR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "OC-3/STM-1", notes: "SONET OC-3 155Mbps LR for inter-CO SBC TDM gateway", isTelecom: true }, + { pid: "SFP-OC12-SR", formFactor: "SFP", speedGbps: 0.622, speed: "OC-12", reachMeters: 2000, reachLabel: "OC12-SR", fiberType: "MMF", connector: "LC", wavelengths: "1310nm", standard: "OC-12/STM-4", notes: "SONET OC-12 622Mbps SR for SONUS GSX SBC trunk", isTelecom: true }, + { pid: "SFP-OC12-LR", formFactor: "SFP", speedGbps: 0.622, speed: "OC-12", reachMeters: 40000, reachLabel: "OC12-LR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "OC-12/STM-4", notes: "SONET OC-12 622Mbps LR for long-haul SBC OC-12 trunks", isTelecom: true }, + { pid: "SFP-OC48-SR", formFactor: "SFP", speedGbps: 2.5, speed: "OC-48", reachMeters: 2000, reachLabel: "OC48-SR", fiberType: "MMF", connector: "LC", wavelengths: "1310nm", standard: "OC-48/STM-16",notes: "SONET OC-48 2.5Gbps SR for Ribbon SBC high-density SONET trunk", isTelecom: true }, + + // ── DWDM / Coherent (Apollo IP/Optical) ───────────────────────────────── + { pid: "DWDM-SFP-C", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 80000, reachLabel: "DWDM", fiberType: "SMF", connector: "LC", wavelengths: "C-band", notes: "10G DWDM SFP+ fixed-wavelength C-band for Apollo 9400 line card", isTelecom: true }, + { pid: "CFP2-100G-LR4", formFactor: "CFP2", speedGbps: 100, speed: "100G", reachMeters: 10000, reachLabel: "LR4", fiberType: "SMF", connector: "LC", wavelengths: "1295-1310nm", standard: "100GBASE-LR4", notes: "CFP2 100G LR4 for Apollo 9500 coherent line ports", isTelecom: true }, +]; + +export async function scrapeRibbonCommsOem(): Promise { + console.log("=== Ribbon Communications (ribbon-comms) OEM Transceiver Seed ===\n"); + + const vendorId = await ensureVendor( + "Ribbon Communications", + "oem", + "https://ribboncommunications.com", + undefined + ); + + let inserted = 0; + let updated = 0; + let errors = 0; + + for (const p of RIBBON_COMMS_PIDS) { + const slug = `ribbon-comms-${p.pid.toLowerCase().replace(/[^a-z0-9]+/g, "-")}`; + const category = p.isTelecom ? "Telecom" : "DataCenter"; + try { + const res = await pool.query( + `INSERT INTO transceivers + (slug, part_number, vendor_id, form_factor, speed, speed_gbps, + reach_meters, reach_label, fiber_type, connector, wavelengths, + dom_support, ieee_reference, market_status, category, notes) + VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,true,$12,'Mainstream',$13,$14) + ON CONFLICT (slug) DO UPDATE SET + speed_gbps = EXCLUDED.speed_gbps, + reach_meters = CASE WHEN EXCLUDED.reach_meters > 0 THEN EXCLUDED.reach_meters ELSE transceivers.reach_meters END, + fiber_type = CASE WHEN EXCLUDED.fiber_type <> '' THEN EXCLUDED.fiber_type ELSE transceivers.fiber_type END, + wavelengths = COALESCE(EXCLUDED.wavelengths, transceivers.wavelengths), + is_oem_seed = true, + updated_at = NOW() + RETURNING (xmax = 0) as was_inserted`, + [slug, p.pid, vendorId, p.formFactor, p.speed, p.speedGbps, + p.reachMeters, p.reachLabel, p.fiberType, p.connector, + p.wavelengths ?? null, p.standard ?? null, category, p.notes ?? null] + ); + if (res.rows[0]?.was_inserted) inserted++; else updated++; + } catch (err) { + console.warn(` Skip ${p.pid}: ${(err as Error).message.slice(0, 80)}`); + errors++; + } + } + + console.log(`\n=== Ribbon Communications OEM Seed Complete ===`); + console.log(` Inserted: ${inserted}`); + console.log(` Updated: ${updated}`); + console.log(` Errors: ${errors}`); + console.log(` Total PIDs: ${RIBBON_COMMS_PIDS.length}\n`); +} + +if (require.main === module) { + scrapeRibbonCommsOem() + .then(() => pool.end()) + .catch((err) => { + console.error("Fatal:", err); + pool.end(); + process.exit(1); + }); +} diff --git a/packages/scraper/src/scrapers/ribbon-oem.ts b/packages/scraper/src/scrapers/ribbon-oem.ts new file mode 100644 index 0000000..d7f47bc --- /dev/null +++ b/packages/scraper/src/scrapers/ribbon-oem.ts @@ -0,0 +1,129 @@ +/** + * Ribbon Communications OEM Transceiver Catalog Seed + * + * Seeds Ribbon-branded transceiver PIDs for Apollo, SBC, and + * IP/Optical networking platforms (formerly GENBAND/SONUS/ECI Telecom). + * + * Sources: + * - Ribbon Communications Hardware Catalog (ribboncommunications.com) + * - Ribbon Apollo 9400/9500 Series Hardware Guide + * - Ribbon SPB-Series Hardware Reference + * + * Run: tsx packages/scraper/src/scrapers/ribbon-oem.ts + * Cron: daily at 10:15 + */ + +import { pool, ensureVendor } from "../utils/db"; + +interface RibbonPID { + pid: string; + formFactor: string; + speedGbps: number; + speed: string; + reachMeters: number; + reachLabel: string; + fiberType: string; + connector: string; + wavelengths?: string; + standard?: string; + notes?: string; +} + +const RIBBON_PIDS: RibbonPID[] = [ + // ── 1G SFP ────────────────────────────────────────────────────────────── + { pid: "SFP-1G-SX", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 550, reachLabel: "SX", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "1000BASE-SX", notes: "Ribbon 1G SX SFP" }, + { pid: "SFP-1G-LX", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 10000, reachLabel: "LX", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "1000BASE-LX", notes: "Ribbon 1G LX SFP" }, + { pid: "SFP-1G-ZX", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 80000, reachLabel: "ZX", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "1000BASE-ZX" }, + { pid: "SFP-1G-T", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 100, reachLabel: "T", fiberType: "DAC", connector: "RJ45", standard: "1000BASE-T" }, + + // ── 10G SFP+ ──────────────────────────────────────────────────────────── + { pid: "SFP-10G-SR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 300, reachLabel: "SR", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "10GBASE-SR" }, + { pid: "SFP-10G-LR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 10000, reachLabel: "LR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "10GBASE-LR" }, + { pid: "SFP-10G-ER", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 40000, reachLabel: "ER", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "10GBASE-ER" }, + { pid: "SFP-10G-ZR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 80000, reachLabel: "ZR", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "10GBASE-ZR" }, + { pid: "SFP-10G-DWDM-T", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 80000, reachLabel: "DWDM", fiberType: "SMF", connector: "LC", wavelengths: "C-band", notes: "10G DWDM tunable for Apollo IP/Optical" }, + + // ── 25G SFP28 ─────────────────────────────────────────────────────────── + { pid: "SFP28-25G-SR", formFactor: "SFP28", speedGbps: 25, speed: "25G", reachMeters: 100, reachLabel: "SR", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "25GBASE-SR" }, + { pid: "SFP28-25G-LR", formFactor: "SFP28", speedGbps: 25, speed: "25G", reachMeters: 10000, reachLabel: "LR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "25GBASE-LR" }, + + // ── 40G QSFP+ ─────────────────────────────────────────────────────────── + { pid: "QSFP-40G-SR4", formFactor: "QSFP+", speedGbps: 40, speed: "40G", reachMeters: 150, reachLabel: "SR4", fiberType: "MMF", connector: "MPO", wavelengths: "850nm", standard: "40GBASE-SR4" }, + { pid: "QSFP-40G-LR4", formFactor: "QSFP+", speedGbps: 40, speed: "40G", reachMeters: 10000, reachLabel: "LR4", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "40GBASE-LR4" }, + + // ── 100G QSFP28 ───────────────────────────────────────────────────────── + { pid: "QSFP28-100G-SR4", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 100, reachLabel: "SR4", fiberType: "MMF", connector: "MPO", wavelengths: "850nm", standard: "100GBASE-SR4" }, + { pid: "QSFP28-100G-LR4", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 10000, reachLabel: "LR4", fiberType: "SMF", connector: "LC", wavelengths: "1295-1310nm", standard: "100GBASE-LR4" }, + { pid: "QSFP28-100G-CWDM4",formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 2000, reachLabel: "CWDM4", fiberType: "SMF", connector: "LC", wavelengths: "1271-1331nm", standard: "100GBASE-CWDM4" }, + { pid: "QSFP28-100G-DR", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 500, reachLabel: "DR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "100GBASE-DR" }, + + // ── 400G QSFP-DD (Apollo 9500) ─────────────────────────────────────────── + { pid: "QSFPDD-400G-SR8", formFactor: "QSFP-DD",speedGbps: 400, speed: "400G", reachMeters: 100, reachLabel: "SR8", fiberType: "MMF", connector: "MPO", wavelengths: "850nm", standard: "400GBASE-SR8" }, + { pid: "QSFPDD-400G-DR4", formFactor: "QSFP-DD",speedGbps: 400, speed: "400G", reachMeters: 500, reachLabel: "DR4", fiberType: "SMF", connector: "MPO", wavelengths: "1310nm", standard: "400GBASE-DR4" }, + { pid: "QSFPDD-400G-FR4", formFactor: "QSFP-DD",speedGbps: 400, speed: "400G", reachMeters: 2000, reachLabel: "FR4", fiberType: "SMF", connector: "LC", wavelengths: "1271-1331nm", standard: "400GBASE-FR4" }, + { pid: "QSFPDD-400G-ZR", formFactor: "QSFP-DD",speedGbps: 400, speed: "400G", reachMeters: 120000, reachLabel: "ZR", fiberType: "SMF", connector: "LC", wavelengths: "C-band", standard: "400ZR", notes: "400G coherent ZR for Apollo IP/Optical" }, + + // ── DAC ───────────────────────────────────────────────────────────────── + { pid: "DAC-10G-1M", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 1, reachLabel: "DAC-1M",fiberType: "DAC", connector: "SFP+", notes: "Ribbon 10G DAC 1m" }, + { pid: "DAC-10G-3M", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 3, reachLabel: "DAC-3M",fiberType: "DAC", connector: "SFP+", notes: "Ribbon 10G DAC 3m" }, + { pid: "DAC-100G-1M", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 1, reachLabel: "DAC-1M",fiberType: "DAC", connector: "QSFP28", notes: "Ribbon 100G DAC 1m" }, + { pid: "DAC-400G-1M", formFactor: "QSFP-DD",speedGbps: 400, speed: "400G", reachMeters: 1, reachLabel: "DAC-1M",fiberType: "DAC", connector: "QSFP-DD",notes: "Ribbon 400G DAC 1m" }, +]; + +export async function scrapeRibbonOem(): Promise { + console.log("=== Ribbon Communications OEM Transceiver Seed ===\n"); + + const vendorId = await ensureVendor( + "Ribbon Communications", + "oem", + "https://ribboncommunications.com", + undefined + ); + + let inserted = 0; + let updated = 0; + let errors = 0; + + for (const p of RIBBON_PIDS) { + const slug = `ribbon-${p.pid.toLowerCase().replace(/[^a-z0-9]+/g, "-")}`; + try { + const res = await pool.query( + `INSERT INTO transceivers + (slug, part_number, vendor_id, form_factor, speed, speed_gbps, + reach_meters, reach_label, fiber_type, connector, wavelengths, + dom_support, ieee_reference, market_status, category, notes) + VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,true,$12,'Mainstream','DataCenter',$13) + ON CONFLICT (slug) DO UPDATE SET + speed_gbps = EXCLUDED.speed_gbps, + reach_meters = CASE WHEN EXCLUDED.reach_meters > 0 THEN EXCLUDED.reach_meters ELSE transceivers.reach_meters END, + fiber_type = CASE WHEN EXCLUDED.fiber_type <> '' THEN EXCLUDED.fiber_type ELSE transceivers.fiber_type END, + wavelengths = COALESCE(EXCLUDED.wavelengths, transceivers.wavelengths), + updated_at = NOW() + RETURNING (xmax = 0) as was_inserted`, + [slug, p.pid, vendorId, p.formFactor, p.speed, p.speedGbps, + p.reachMeters, p.reachLabel, p.fiberType, p.connector, + p.wavelengths ?? null, p.standard ?? null, p.notes ?? null] + ); + if (res.rows[0]?.was_inserted) inserted++; else updated++; + } catch (err) { + console.warn(` Skip ${p.pid}: ${(err as Error).message.slice(0, 80)}`); + errors++; + } + } + + console.log(`\n=== Ribbon OEM Seed Complete ===`); + console.log(` Inserted: ${inserted}`); + console.log(` Updated: ${updated}`); + console.log(` Errors: ${errors}`); + console.log(` Total PIDs: ${RIBBON_PIDS.length}\n`); +} + +if (require.main === module) { + scrapeRibbonOem() + .then(() => pool.end()) + .catch((err) => { + console.error("Fatal:", err); + pool.end(); + process.exit(1); + }); +} diff --git a/packages/scraper/src/scrapers/rockwell-oem.ts b/packages/scraper/src/scrapers/rockwell-oem.ts new file mode 100644 index 0000000..c2b23bc --- /dev/null +++ b/packages/scraper/src/scrapers/rockwell-oem.ts @@ -0,0 +1,119 @@ +/** + * Rockwell Automation OEM Transceiver Catalog Seed + * + * Seeds transceiver PIDs for Rockwell Automation (Allen-Bradley)-branded + * SFP/SFP+/SFP28/QSFP+ modules used in Stratix industrial managed Ethernet + * switches for manufacturing, process control, and critical infrastructure. + * + * Sources: + * - Rockwell Automation Stratix 5700/5410/5400 Switch Selection Guide + * - Allen-Bradley 1783-SFP module catalog + * - rockwellautomation.com industrial networking portfolio + * + * Run: tsx packages/scraper/src/scrapers/rockwell-oem.ts + * Cron: daily at 16:45 + */ + +import { pool, ensureVendor } from "../utils/db"; + +interface RockwellPID { + pid: string; + formFactor: string; + speedGbps: number; + speed: string; + reachMeters: number; + reachLabel: string; + fiberType: string; + connector: string; + wavelengths?: string; + standard?: string; + notes?: string; +} + +const ROCKWELL_PIDS: RockwellPID[] = [ + // ── 1G SFP ────────────────────────────────────────────────────────────── + { pid: "RA-SFP-1G-SX", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 550, reachLabel: "SX", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "1000BASE-SX", notes: "Rockwell Automation Stratix SFP 1G SX multimode" }, + { pid: "RA-SFP-1G-LX", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 10000, reachLabel: "LX", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "1000BASE-LX", notes: "Rockwell Automation Stratix SFP 1G LX single-mode 10km" }, + { pid: "RA-SFP-1G-ZX", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 80000, reachLabel: "ZX", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "1000BASE-ZX", notes: "Rockwell Automation SFP 1G ZX long-reach 80km" }, + { pid: "RA-SFP-1G-T", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 100, reachLabel: "T", fiberType: "DAC", connector: "RJ45", standard: "1000BASE-T", notes: "Rockwell Automation SFP 1G copper RJ45 Stratix" }, + { pid: "RA-SFP-GE-T", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 100, reachLabel: "T", fiberType: "DAC", connector: "RJ45", standard: "1000BASE-T", notes: "Rockwell Automation SFP GE-T copper Allen-Bradley" }, + + // ── 1G SFP BiDi ───────────────────────────────────────────────────────── + { pid: "RA-SFP-1G-BIDI-1310", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 20000, reachLabel: "BiDi-TX1310", fiberType: "SMF", connector: "LC", wavelengths: "TX1310/RX1550nm", notes: "Rockwell Automation SFP 1G BiDi TX1310 single fiber 20km" }, + { pid: "RA-SFP-1G-BIDI-1550", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 20000, reachLabel: "BiDi-TX1550", fiberType: "SMF", connector: "LC", wavelengths: "TX1550/RX1310nm", notes: "Rockwell Automation SFP 1G BiDi TX1550 single fiber 20km" }, + + // ── 10G SFP+ ──────────────────────────────────────────────────────────── + { pid: "RA-SFP-10G-SR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 300, reachLabel: "SR", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "10GBASE-SR", notes: "Rockwell Automation SFP+ 10G SR Stratix multimode" }, + { pid: "RA-SFP-10G-LR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 10000, reachLabel: "LR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "10GBASE-LR", notes: "Rockwell Automation SFP+ 10G LR single-mode 10km" }, + { pid: "RA-SFP-10G-ER", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 40000, reachLabel: "ER", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "10GBASE-ER", notes: "Rockwell Automation SFP+ 10G ER extended-reach 40km" }, + + // ── 1G CWDM SFP (factory/DCS rings) ───────────────────────────────────── + { pid: "RA-SFP-CWDM-1470", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 40000, reachLabel: "CWDM-1470", fiberType: "SMF", connector: "LC", wavelengths: "1470nm", notes: "Rockwell Automation SFP CWDM 1470nm 40km factory ring" }, + { pid: "RA-SFP-CWDM-1530", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 40000, reachLabel: "CWDM-1530", fiberType: "SMF", connector: "LC", wavelengths: "1530nm", notes: "Rockwell Automation SFP CWDM 1530nm 40km factory ring" }, + { pid: "RA-SFP-CWDM-1550", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 40000, reachLabel: "CWDM-1550", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", notes: "Rockwell Automation SFP CWDM 1550nm 40km factory ring" }, + { pid: "RA-SFP-CWDM-1610", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 40000, reachLabel: "CWDM-1610", fiberType: "SMF", connector: "LC", wavelengths: "1610nm", notes: "Rockwell Automation SFP CWDM 1610nm 40km factory ring" }, + + // ── 40G QSFP+ ─────────────────────────────────────────────────────────── + { pid: "RA-QSFP-40G-LR4", formFactor: "QSFP+", speedGbps: 40, speed: "40G", reachMeters: 10000, reachLabel: "LR4", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "40GBASE-LR4", notes: "Rockwell Automation QSFP+ 40G LR4 Stratix backbone" }, + + // ── 25G SFP28 ─────────────────────────────────────────────────────────── + { pid: "RA-SFP28-25G-SR", formFactor: "SFP28", speedGbps: 25, speed: "25G", reachMeters: 100, reachLabel: "SR", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "25GBASE-SR", notes: "Rockwell Automation SFP28 25G SR industrial multimode" }, +]; + +export async function scrapeRockwellOem(): Promise { + console.log("=== Rockwell Automation OEM Transceiver Seed ===\n"); + + const vendorId = await ensureVendor( + "Rockwell Automation", + "oem", + "https://www.rockwellautomation.com/en-us/products/hardware/allen-bradley/networks-and-communications/stratix-industrial-managed-ethernet-switches.html", + undefined + ); + + let inserted = 0; + let updated = 0; + let errors = 0; + + for (const p of ROCKWELL_PIDS) { + const slug = `rockwell-${p.pid.toLowerCase().replace(/[^a-z0-9]+/g, "-")}`; + try { + const res = await pool.query( + `INSERT INTO transceivers + (slug, part_number, vendor_id, form_factor, speed, speed_gbps, + reach_meters, reach_label, fiber_type, connector, wavelengths, + dom_support, ieee_reference, market_status, category, notes) + VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,true,$12,'Mainstream','Industrial',$13) + ON CONFLICT (slug) DO UPDATE SET + speed_gbps = EXCLUDED.speed_gbps, + reach_meters = CASE WHEN EXCLUDED.reach_meters > 0 THEN EXCLUDED.reach_meters ELSE transceivers.reach_meters END, + fiber_type = CASE WHEN EXCLUDED.fiber_type <> '' THEN EXCLUDED.fiber_type ELSE transceivers.fiber_type END, + wavelengths = COALESCE(EXCLUDED.wavelengths, transceivers.wavelengths), + updated_at = NOW() + RETURNING (xmax = 0) as was_inserted`, + [slug, p.pid, vendorId, p.formFactor, p.speed, p.speedGbps, + p.reachMeters, p.reachLabel, p.fiberType, p.connector, + p.wavelengths ?? null, p.standard ?? null, p.notes ?? null] + ); + if (res.rows[0]?.was_inserted) inserted++; else updated++; + } catch (err) { + console.warn(` Skip ${p.pid}: ${(err as Error).message.slice(0, 80)}`); + errors++; + } + } + + console.log(`\n=== Rockwell Automation OEM Seed Complete ===`); + console.log(` Inserted: ${inserted}`); + console.log(` Updated: ${updated}`); + console.log(` Errors: ${errors}`); + console.log(` Total PIDs: ${ROCKWELL_PIDS.length}\n`); +} + +if (require.main === module) { + scrapeRockwellOem() + .then(() => pool.end()) + .catch((err) => { + console.error("Fatal:", err); + pool.end(); + process.exit(1); + }); +} diff --git a/packages/scraper/src/scrapers/ruggedcom-oem.ts b/packages/scraper/src/scrapers/ruggedcom-oem.ts new file mode 100644 index 0000000..e4649f9 --- /dev/null +++ b/packages/scraper/src/scrapers/ruggedcom-oem.ts @@ -0,0 +1,127 @@ +/** + * Siemens RUGGEDCOM OEM Transceiver Catalog Seed + * + * Seeds transceiver PIDs for Siemens RUGGEDCOM industrial-grade SFP/SFP+/SFP28/QSFP+/QSFP28 + * modules used in RX, RS, RX1500, ROX II, and ROS series industrial networking devices. + * + * Sources: + * - Siemens RUGGEDCOM SFP module datasheets (siemens.com/ruggedcom) + * - RUGGEDCOM hardware installation guides + * + * Run: tsx packages/scraper/src/scrapers/ruggedcom-oem.ts + * Cron: daily at 12:15 + */ + +import { pool, ensureVendor } from "../utils/db"; + +interface RuggedcomPID { + pid: string; + formFactor: string; + speedGbps: number; + speed: string; + reachMeters: number; + reachLabel: string; + fiberType: string; + connector: string; + wavelengths?: string; + standard?: string; + notes?: string; +} + +const RUGGEDCOM_PIDS: RuggedcomPID[] = [ + // ── 1G SFP (industrial grade) ─────────────────────────────────────────── + { pid: "6GK5991-2AA00-8AA0", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 550, reachLabel: "SX", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "1000BASE-SX", notes: "RUGGEDCOM industrial SFP SX" }, + { pid: "6GK5991-2AB00-8AA0", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 10000, reachLabel: "LX", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "1000BASE-LX", notes: "RUGGEDCOM industrial SFP LX" }, + { pid: "6GK5991-2AC00-8AA0", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 40000, reachLabel: "LH40", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", notes: "RUGGEDCOM industrial SFP LH40" }, + { pid: "6GK5991-2AD00-8AA0", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 80000, reachLabel: "ZX", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "1000BASE-ZX", notes: "RUGGEDCOM industrial SFP ZX" }, + { pid: "6GK5991-2AE00-8AA0", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 100, reachLabel: "T", fiberType: "DAC", connector: "RJ45", standard: "1000BASE-T", notes: "RUGGEDCOM industrial SFP-T" }, + { pid: "6GK5991-2AF00-8AA0", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 20000, reachLabel: "BiDi", fiberType: "SMF", connector: "LC", wavelengths: "1310/1550nm", notes: "RUGGEDCOM industrial SFP BiDi 20km" }, + + // ── 100M SFP (legacy) ─────────────────────────────────────────────────── + { pid: "6GK5991-1AF00-8AA0", formFactor: "SFP", speedGbps: 0.1, speed: "100M", reachMeters: 2000, reachLabel: "FX", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "100BASE-FX", notes: "RUGGEDCOM 100M MMF SFP" }, + { pid: "6GK5991-1AG00-8AA0", formFactor: "SFP", speedGbps: 0.1, speed: "100M", reachMeters: 40000, reachLabel: "LFX", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "100BASE-LFX", notes: "RUGGEDCOM 100M SMF SFP" }, + + // ── 10G SFP+ ──────────────────────────────────────────────────────────── + { pid: "6GK5991-2BA00-8AA0", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 300, reachLabel: "SR", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "10GBASE-SR" }, + { pid: "6GK5991-2BB00-8AA0", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 10000, reachLabel: "LR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "10GBASE-LR" }, + { pid: "6GK5991-2BC00-8AA0", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 40000, reachLabel: "ER", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "10GBASE-ER" }, + { pid: "6GK5991-2BD00-8AA0", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 80000, reachLabel: "ZR", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "10GBASE-ZR" }, + + // ── 10G SFP+ BiDi ─────────────────────────────────────────────────────── + { pid: "6GK5991-2BE00-8AA0", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 10000, reachLabel: "BiDi", fiberType: "SMF", connector: "LC", wavelengths: "TX1270/RX1330nm", notes: "RUGGEDCOM 10G SFP+ BiDi single fiber" }, + + // ── 25G SFP28 ─────────────────────────────────────────────────────────── + { pid: "6GK5991-2CA00-8AA0", formFactor: "SFP28", speedGbps: 25, speed: "25G", reachMeters: 100, reachLabel: "SR", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "25GBASE-SR" }, + { pid: "6GK5991-2CB00-8AA0", formFactor: "SFP28", speedGbps: 25, speed: "25G", reachMeters: 10000, reachLabel: "LR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "25GBASE-LR" }, + + // ── 40G QSFP+ ─────────────────────────────────────────────────────────── + { pid: "6GK5991-3AA00-8AA0", formFactor: "QSFP+", speedGbps: 40, speed: "40G", reachMeters: 150, reachLabel: "SR4", fiberType: "MMF", connector: "MPO", wavelengths: "850nm", standard: "40GBASE-SR4" }, + { pid: "6GK5991-3AB00-8AA0", formFactor: "QSFP+", speedGbps: 40, speed: "40G", reachMeters: 10000, reachLabel: "LR4", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "40GBASE-LR4" }, + + // ── 100G QSFP28 ───────────────────────────────────────────────────────── + { pid: "6GK5991-3CA00-8AA0", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 100, reachLabel: "SR4", fiberType: "MMF", connector: "MPO", wavelengths: "850nm", standard: "100GBASE-SR4" }, + { pid: "6GK5991-3CB00-8AA0", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 10000, reachLabel: "LR4", fiberType: "SMF", connector: "LC", wavelengths: "1295-1310nm", standard: "100GBASE-LR4" }, + + // ── DAC ───────────────────────────────────────────────────────────────── + { pid: "6GK5991-2BT01-8AA0", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 1, reachLabel: "DAC1m", fiberType: "DAC", connector: "SFP+", }, + { pid: "6GK5991-2BT03-8AA0", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 3, reachLabel: "DAC3m", fiberType: "DAC", connector: "SFP+", }, + { pid: "6GK5991-3CT01-8AA0", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 1, reachLabel: "DAC1m", fiberType: "DAC", connector: "QSFP28", }, +]; + +export async function scrapeRuggedcomOem(): Promise { + console.log("=== Siemens RUGGEDCOM OEM Transceiver Seed ===\n"); + + const vendorId = await ensureVendor( + "Siemens RUGGEDCOM", + "oem", + "https://www.siemens.com/ruggedcom", + undefined + ); + + let inserted = 0; + let updated = 0; + let errors = 0; + + for (const p of RUGGEDCOM_PIDS) { + const slug = `ruggedcom-${p.pid.toLowerCase().replace(/[^a-z0-9]+/g, "-")}`; + try { + const res = await pool.query( + `INSERT INTO transceivers + (slug, part_number, vendor_id, form_factor, speed, speed_gbps, + reach_meters, reach_label, fiber_type, connector, wavelengths, + dom_support, ieee_reference, market_status, category, notes) + VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,true,$12,'Mainstream','Industrial',$13) + ON CONFLICT (slug) DO UPDATE SET + speed_gbps = EXCLUDED.speed_gbps, + reach_meters = CASE WHEN EXCLUDED.reach_meters > 0 THEN EXCLUDED.reach_meters ELSE transceivers.reach_meters END, + fiber_type = CASE WHEN EXCLUDED.fiber_type <> '' THEN EXCLUDED.fiber_type ELSE transceivers.fiber_type END, + wavelengths = COALESCE(EXCLUDED.wavelengths, transceivers.wavelengths), + updated_at = NOW() + RETURNING (xmax = 0) as was_inserted`, + [slug, p.pid, vendorId, p.formFactor, p.speed, p.speedGbps, + p.reachMeters, p.reachLabel, p.fiberType, p.connector, + p.wavelengths ?? null, p.standard ?? null, p.notes ?? null] + ); + if (res.rows[0]?.was_inserted) inserted++; else updated++; + } catch (err) { + console.warn(` Skip ${p.pid}: ${(err as Error).message.slice(0, 80)}`); + errors++; + } + } + + console.log(`\n=== Siemens RUGGEDCOM OEM Seed Complete ===`); + console.log(` Inserted: ${inserted}`); + console.log(` Updated: ${updated}`); + console.log(` Errors: ${errors}`); + console.log(` Total PIDs: ${RUGGEDCOM_PIDS.length}\n`); +} + +if (require.main === module) { + scrapeRuggedcomOem() + .then(() => pool.end()) + .catch((err) => { + console.error("Fatal:", err); + pool.end(); + process.exit(1); + }); +} diff --git a/packages/scraper/src/scrapers/ruijie-oem.ts b/packages/scraper/src/scrapers/ruijie-oem.ts new file mode 100644 index 0000000..7c214ee --- /dev/null +++ b/packages/scraper/src/scrapers/ruijie-oem.ts @@ -0,0 +1,119 @@ +/** + * Ruijie Networks OEM Transceiver Catalog Seed + * + * Seeds Ruijie/RG-branded transceiver PIDs for RG-S-series campus + * switches, RG-NBS-series and RG-CS-series data center switches. + * + * Sources: + * - Ruijie Networks Transceiver Module Data Sheet (ruijienetworks.com) + * - Ruijie RG-S6000/S5760/S2900 Compatibility Lists + * - Reyee/RG Optical Module Specifications + * + * Run: tsx packages/scraper/src/scrapers/ruijie-oem.ts + * Cron: daily at 11:30 + */ + +import { pool, ensureVendor } from "../utils/db"; + +interface RuijiePID { + pid: string; + formFactor: string; + speedGbps: number; + speed: string; + reachMeters: number; + reachLabel: string; + fiberType: string; + connector: string; + wavelengths?: string; + standard?: string; + notes?: string; +} + +const RUIJIE_PIDS: RuijiePID[] = [ + // ── 1G SFP ────────────────────────────────────────────────────────────── + { pid: "RG-SFP-GE-SX", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 550, reachLabel: "SX", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "1000BASE-SX", notes: "Ruijie 1G SFP SX 550m MMF" }, + { pid: "RG-SFP-GE-LX", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 10000, reachLabel: "LX", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "1000BASE-LX", notes: "Ruijie 1G SFP LX 10km SMF" }, + { pid: "RG-SFP-GE-ZX", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 80000, reachLabel: "ZX", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "1000BASE-ZX", notes: "Ruijie 1G SFP ZX 80km SMF" }, + { pid: "RG-SFP-GE-T", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 100, reachLabel: "T", fiberType: "DAC", connector: "RJ45", standard: "1000BASE-T", notes: "Ruijie 1G SFP copper RJ45" }, + { pid: "RG-SFP-GE-BIDI-1310",formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 10000, reachLabel: "BiDi", fiberType: "SMF", connector: "LC", wavelengths: "1310/1490nm", standard: "1000BASE-BX", notes: "Ruijie 1G SFP BiDi TX1310/RX1490" }, + + // ── 10G SFP+ ──────────────────────────────────────────────────────────── + { pid: "RG-SFP-XG-SR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 300, reachLabel: "SR", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "10GBASE-SR", notes: "Ruijie 10G SFP+ SR 300m MMF" }, + { pid: "RG-SFP-XG-LR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 10000, reachLabel: "LR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "10GBASE-LR", notes: "Ruijie 10G SFP+ LR 10km SMF" }, + { pid: "RG-SFP-XG-ER", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 40000, reachLabel: "ER", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "10GBASE-ER", notes: "Ruijie 10G SFP+ ER 40km SMF" }, + { pid: "RG-SFP-XG-ZR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 80000, reachLabel: "ZR", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "10GBASE-ZR", notes: "Ruijie 10G SFP+ ZR 80km SMF" }, + { pid: "RG-SFP-XG-BIDI-1270",formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 10000, reachLabel: "BiDi", fiberType: "SMF", connector: "LC", wavelengths: "1270/1330nm", standard: "10GBASE-BX", notes: "Ruijie 10G SFP+ BiDi TX1270/RX1330" }, + + // ── 25G SFP28 ─────────────────────────────────────────────────────────── + { pid: "RG-SFP28-25G-SR", formFactor: "SFP28", speedGbps: 25, speed: "25G", reachMeters: 100, reachLabel: "SR", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "25GBASE-SR", notes: "Ruijie 25G SFP28 SR 100m MMF" }, + { pid: "RG-SFP28-25G-LR", formFactor: "SFP28", speedGbps: 25, speed: "25G", reachMeters: 10000, reachLabel: "LR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "25GBASE-LR", notes: "Ruijie 25G SFP28 LR 10km SMF" }, + + // ── 40G QSFP+ ─────────────────────────────────────────────────────────── + { pid: "RG-QSFP-40G-SR4", formFactor: "QSFP+", speedGbps: 40, speed: "40G", reachMeters: 150, reachLabel: "SR4", fiberType: "MMF", connector: "MPO", wavelengths: "850nm", standard: "40GBASE-SR4", notes: "Ruijie 40G QSFP+ SR4 150m MMF" }, + { pid: "RG-QSFP-40G-LR4", formFactor: "QSFP+", speedGbps: 40, speed: "40G", reachMeters: 10000, reachLabel: "LR4", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "40GBASE-LR4", notes: "Ruijie 40G QSFP+ LR4 10km SMF" }, + + // ── 100G QSFP28 ───────────────────────────────────────────────────────── + { pid: "RG-QSFP28-100G-SR4", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 100, reachLabel: "SR4", fiberType: "MMF", connector: "MPO", wavelengths: "850nm", standard: "100GBASE-SR4", notes: "Ruijie 100G QSFP28 SR4 100m MMF" }, + { pid: "RG-QSFP28-100G-LR4", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 10000, reachLabel: "LR4", fiberType: "SMF", connector: "LC", wavelengths: "1295-1310nm", standard: "100GBASE-LR4", notes: "Ruijie 100G QSFP28 LR4 10km SMF" }, + + // ── 400G QSFP-DD ──────────────────────────────────────────────────────── + { pid: "RG-QSFP-DD-400G-DR4",formFactor: "QSFP-DD",speedGbps: 400, speed: "400G", reachMeters: 500, reachLabel: "DR4", fiberType: "SMF", connector: "MPO", wavelengths: "1310nm", standard: "400GBASE-DR4", notes: "Ruijie 400G QSFP-DD DR4 500m SMF" }, +]; + +export async function scrapeRuijieOem(): Promise { + console.log("=== Ruijie Networks OEM Transceiver Seed ===\n"); + + const vendorId = await ensureVendor( + "Ruijie Networks", + "oem", + "https://www.ruijienetworks.com", + undefined + ); + + let inserted = 0; + let updated = 0; + let errors = 0; + + for (const p of RUIJIE_PIDS) { + const slug = `ruijie-${p.pid.toLowerCase().replace(/[^a-z0-9]+/g, "-")}`; + try { + const res = await pool.query( + `INSERT INTO transceivers + (slug, part_number, vendor_id, form_factor, speed, speed_gbps, + reach_meters, reach_label, fiber_type, connector, wavelengths, + dom_support, ieee_reference, market_status, category, notes) + VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,true,$12,'Mainstream','DataCenter',$13) + ON CONFLICT (slug) DO UPDATE SET + speed_gbps = EXCLUDED.speed_gbps, + reach_meters = CASE WHEN EXCLUDED.reach_meters > 0 THEN EXCLUDED.reach_meters ELSE transceivers.reach_meters END, + fiber_type = CASE WHEN EXCLUDED.fiber_type <> '' THEN EXCLUDED.fiber_type ELSE transceivers.fiber_type END, + wavelengths = COALESCE(EXCLUDED.wavelengths, transceivers.wavelengths), + updated_at = NOW() + RETURNING (xmax = 0) as was_inserted`, + [slug, p.pid, vendorId, p.formFactor, p.speed, p.speedGbps, + p.reachMeters, p.reachLabel, p.fiberType, p.connector, + p.wavelengths ?? null, p.standard ?? null, p.notes ?? null] + ); + if (res.rows[0]?.was_inserted) inserted++; else updated++; + } catch (err) { + console.warn(` Skip ${p.pid}: ${(err as Error).message.slice(0, 80)}`); + errors++; + } + } + + console.log(`\n=== Ruijie Networks OEM Seed Complete ===`); + console.log(` Inserted: ${inserted}`); + console.log(` Updated: ${updated}`); + console.log(` Errors: ${errors}`); + console.log(` Total PIDs: ${RUIJIE_PIDS.length}\n`); +} + +if (require.main === module) { + scrapeRuijieOem() + .then(() => pool.end()) + .catch((err) => { + console.error("Fatal:", err); + pool.end(); + process.exit(1); + }); +} diff --git a/packages/scraper/src/scrapers/samsung-networks-oem.ts b/packages/scraper/src/scrapers/samsung-networks-oem.ts new file mode 100644 index 0000000..e686411 --- /dev/null +++ b/packages/scraper/src/scrapers/samsung-networks-oem.ts @@ -0,0 +1,123 @@ +/** + * Samsung Networks OEM Transceiver Catalog Seed + * + * Seeds Samsung Networks-branded transceiver PIDs used in 5G RAN and + * vRAN deployments (eCPRI/CPRI fronthaul, midhaul, and data plane + * optical interfaces for Samsung gNB/RU/DU/CU units). + * + * Sources: + * - Samsung Networks Product Portfolio (samsung.com/us/business/networks) + * - 5G NR O-RAN fronthaul interface specifications + * - eCPRI Specification v2.0 optical transport requirements + * + * Run: tsx packages/scraper/src/scrapers/samsung-networks-oem.ts + * Cron: daily at 09:15 + */ + +import { pool, ensureVendor } from "../utils/db"; + +interface SamsungNetworksPID { + pid: string; + formFactor: string; + speedGbps: number; + speed: string; + reachMeters: number; + reachLabel: string; + fiberType: string; + connector: string; + wavelengths?: string; + standard?: string; + notes?: string; +} + +const SAMSUNG_NETWORKS_PIDS: SamsungNetworksPID[] = [ + // ── 1G SFP ────────────────────────────────────────────────────────────── + { pid: "SN-SFP-1G-SX", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 550, reachLabel: "SX", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "1000BASE-SX", notes: "Samsung Networks 1G SFP SX for management/backhaul" }, + { pid: "SN-SFP-1G-LX", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 10000, reachLabel: "LX", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "1000BASE-LX", notes: "Samsung Networks 1G SFP LX for cell site uplink" }, + + // ── 10G SFP+ ──────────────────────────────────────────────────────────── + { pid: "SN-SFP-10G-SR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 300, reachLabel: "SR", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "10GBASE-SR", notes: "Samsung Networks 10G SFP+ SR for 5G DU intra-site" }, + { pid: "SN-SFP-10G-LR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 10000, reachLabel: "LR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "10GBASE-LR", notes: "Samsung Networks 10G SFP+ LR for fronthaul/midhaul" }, + { pid: "SN-SFP-10G-ER", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 40000, reachLabel: "ER", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "10GBASE-ER", notes: "Samsung Networks 10G SFP+ ER for long-reach fronthaul" }, + + // ── 40G QSFP+ ─────────────────────────────────────────────────────────── + { pid: "SN-QSFP-40G-SR4", formFactor: "QSFP+", speedGbps: 40, speed: "40G", reachMeters: 150, reachLabel: "SR4", fiberType: "MMF", connector: "MPO", wavelengths: "850nm", standard: "40GBASE-SR4", notes: "Samsung Networks 40G QSFP+ SR4 for 5G aggregation" }, + { pid: "SN-QSFP-40G-LR4", formFactor: "QSFP+", speedGbps: 40, speed: "40G", reachMeters: 10000, reachLabel: "LR4", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "40GBASE-LR4" }, + + // ── 25G SFP28 ─────────────────────────────────────────────────────────── + { pid: "SN-SFP28-25G-SR", formFactor: "SFP28", speedGbps: 25, speed: "25G", reachMeters: 100, reachLabel: "SR", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "25GBASE-SR", notes: "Samsung Networks 25G SFP28 SR for eCPRI fronthaul (Option 7-2x)" }, + { pid: "SN-SFP28-25G-LR", formFactor: "SFP28", speedGbps: 25, speed: "25G", reachMeters: 10000, reachLabel: "LR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "25GBASE-LR", notes: "Samsung Networks 25G SFP28 LR for eCPRI fronthaul long-reach" }, + + // ── 100G QSFP28 ───────────────────────────────────────────────────────── + { pid: "SN-QSFP28-100G-SR4", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 100, reachLabel: "SR4", fiberType: "MMF", connector: "MPO", wavelengths: "850nm", standard: "100GBASE-SR4", notes: "Samsung Networks 100G QSFP28 SR4 for 5G DU aggregation" }, + { pid: "SN-QSFP28-100G-LR4", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 10000, reachLabel: "LR4", fiberType: "SMF", connector: "LC", wavelengths: "1295-1310nm", standard: "100GBASE-LR4", notes: "Samsung Networks 100G QSFP28 LR4 for 5G midhaul/backhaul" }, + + // ── 400G QSFP-DD ──────────────────────────────────────────────────────── + { pid: "SN-QSFP-DD-400G-DR4", formFactor: "QSFP-DD", speedGbps: 400, speed: "400G", reachMeters: 500, reachLabel: "DR4", fiberType: "SMF", connector: "MPO", wavelengths: "1310nm", standard: "400GBASE-DR4", notes: "Samsung Networks 400G QSFP-DD for 5G core/CU backhaul" }, + { pid: "SN-QSFP-DD-400G-SR8", formFactor: "QSFP-DD", speedGbps: 400, speed: "400G", reachMeters: 100, reachLabel: "SR8", fiberType: "MMF", connector: "MPO", wavelengths: "850nm", standard: "400GBASE-SR8", notes: "Samsung Networks 400G QSFP-DD SR8 for intra-DC 5G CU" }, + + // ── Copper SFP ────────────────────────────────────────────────────────── + { pid: "SN-SFP-GE-T", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 100, reachLabel: "T", fiberType: "DAC", connector: "RJ45", standard: "1000BASE-T", notes: "Samsung Networks copper GE SFP for management" }, + + // ── BiDi SFP+ (eCPRI fronthaul single-fiber) ──────────────────────────── + { pid: "SN-SFP-10G-BIDI-1270", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 20000, reachLabel: "BIDI", fiberType: "SMF", connector: "LC", wavelengths: "1270/1330nm", notes: "Samsung Networks BiDi SFP+ Tx1270/Rx1330 for eCPRI fronthaul single-fiber runs" }, + { pid: "SN-SFP28-25G-BIDI", formFactor: "SFP28", speedGbps: 25, speed: "25G", reachMeters: 15000, reachLabel: "BIDI", fiberType: "SMF", connector: "LC", wavelengths: "1270/1330nm", notes: "Samsung Networks 25G BiDi SFP28 for 5G NR eCPRI single-fiber fronthaul" }, +]; + +export async function scrapeSamsungNetworksOem(): Promise { + console.log("=== Samsung Networks OEM Transceiver Seed ===\n"); + + const vendorId = await ensureVendor( + "Samsung Networks", + "oem", + "https://www.samsung.com/us/business/networks/", + undefined + ); + + let inserted = 0; + let updated = 0; + let errors = 0; + + for (const p of SAMSUNG_NETWORKS_PIDS) { + const slug = `samsung-net-${p.pid.toLowerCase().replace(/[^a-z0-9]+/g, "-")}`; + try { + const res = await pool.query( + `INSERT INTO transceivers + (slug, part_number, vendor_id, form_factor, speed, speed_gbps, + reach_meters, reach_label, fiber_type, connector, wavelengths, + dom_support, ieee_reference, market_status, category, notes) + VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,true,$12,'Mainstream','DataCenter',$13) + ON CONFLICT (slug) DO UPDATE SET + speed_gbps = EXCLUDED.speed_gbps, + reach_meters = CASE WHEN EXCLUDED.reach_meters > 0 THEN EXCLUDED.reach_meters ELSE transceivers.reach_meters END, + fiber_type = CASE WHEN EXCLUDED.fiber_type <> '' THEN EXCLUDED.fiber_type ELSE transceivers.fiber_type END, + wavelengths = COALESCE(EXCLUDED.wavelengths, transceivers.wavelengths), + updated_at = NOW() + RETURNING (xmax = 0) as was_inserted`, + [slug, p.pid, vendorId, p.formFactor, p.speed, p.speedGbps, + p.reachMeters, p.reachLabel, p.fiberType, p.connector, + p.wavelengths ?? null, p.standard ?? null, p.notes ?? null] + ); + if (res.rows[0]?.was_inserted) inserted++; else updated++; + } catch (err) { + console.warn(` Skip ${p.pid}: ${(err as Error).message.slice(0, 80)}`); + errors++; + } + } + + console.log(`\n=== Samsung Networks OEM Seed Complete ===`); + console.log(` Inserted: ${inserted}`); + console.log(` Updated: ${updated}`); + console.log(` Errors: ${errors}`); + console.log(` Total PIDs: ${SAMSUNG_NETWORKS_PIDS.length}\n`); +} + +if (require.main === module) { + scrapeSamsungNetworksOem() + .then(() => pool.end()) + .catch((err) => { + console.error("Fatal:", err); + pool.end(); + process.exit(1); + }); +} diff --git a/packages/scraper/src/scrapers/schneider-oem.ts b/packages/scraper/src/scrapers/schneider-oem.ts new file mode 100644 index 0000000..5bb0326 --- /dev/null +++ b/packages/scraper/src/scrapers/schneider-oem.ts @@ -0,0 +1,119 @@ +/** + * Schneider Electric OEM Transceiver Catalog Seed + * + * Seeds transceiver PIDs for Schneider Electric-branded SFP/SFP+/SFP28/QSFP+ + * modules used in ConneXium managed switches, Modicon controllers, and + * EcoStruxure industrial networking infrastructure. + * + * Sources: + * - Schneider Electric ConneXium Managed Switches product range + * - EcoStruxure Automation Expert transceiver compatibility guide + * - se.com industrial networking catalog + * + * Run: tsx packages/scraper/src/scrapers/schneider-oem.ts + * Cron: daily at 16:30 + */ + +import { pool, ensureVendor } from "../utils/db"; + +interface SchneiderPID { + pid: string; + formFactor: string; + speedGbps: number; + speed: string; + reachMeters: number; + reachLabel: string; + fiberType: string; + connector: string; + wavelengths?: string; + standard?: string; + notes?: string; +} + +const SCHNEIDER_PIDS: SchneiderPID[] = [ + // ── 1G SFP ────────────────────────────────────────────────────────────── + { pid: "SE-SFP-1G-SX", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 550, reachLabel: "SX", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "1000BASE-SX", notes: "Schneider Electric SFP 1G SX ConneXium multimode" }, + { pid: "SE-SFP-1G-LX", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 10000, reachLabel: "LX", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "1000BASE-LX", notes: "Schneider Electric SFP 1G LX ConneXium 10km" }, + { pid: "SE-SFP-1G-ZX", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 80000, reachLabel: "ZX", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "1000BASE-ZX", notes: "Schneider Electric SFP 1G ZX long-reach 80km" }, + { pid: "SE-SFP-1G-T", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 100, reachLabel: "T", fiberType: "DAC", connector: "RJ45", standard: "1000BASE-T", notes: "Schneider Electric SFP 1G copper RJ45 industrial" }, + { pid: "SE-SFP-GE-T", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 100, reachLabel: "T", fiberType: "DAC", connector: "RJ45", standard: "1000BASE-T", notes: "Schneider Electric SFP GE-T copper EcoStruxure" }, + + // ── 1G SFP BiDi ───────────────────────────────────────────────────────── + { pid: "SE-SFP-1G-BIDI-1310", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 20000, reachLabel: "BiDi-TX1310", fiberType: "SMF", connector: "LC", wavelengths: "TX1310/RX1550nm", notes: "Schneider Electric SFP 1G BiDi TX1310 single fiber 20km" }, + { pid: "SE-SFP-1G-BIDI-1550", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 20000, reachLabel: "BiDi-TX1550", fiberType: "SMF", connector: "LC", wavelengths: "TX1550/RX1310nm", notes: "Schneider Electric SFP 1G BiDi TX1550 single fiber 20km" }, + + // ── 10G SFP+ ──────────────────────────────────────────────────────────── + { pid: "SE-SFP-10G-SR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 300, reachLabel: "SR", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "10GBASE-SR", notes: "Schneider Electric SFP+ 10G SR ConneXium multimode" }, + { pid: "SE-SFP-10G-LR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 10000, reachLabel: "LR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "10GBASE-LR", notes: "Schneider Electric SFP+ 10G LR single-mode 10km" }, + { pid: "SE-SFP-10G-ER", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 40000, reachLabel: "ER", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "10GBASE-ER", notes: "Schneider Electric SFP+ 10G ER extended-reach 40km" }, + + // ── 1G CWDM SFP (process/utility rings) ───────────────────────────────── + { pid: "SE-SFP-CWDM-1470", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 40000, reachLabel: "CWDM-1470", fiberType: "SMF", connector: "LC", wavelengths: "1470nm", notes: "Schneider Electric SFP CWDM 1470nm 40km process ring" }, + { pid: "SE-SFP-CWDM-1530", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 40000, reachLabel: "CWDM-1530", fiberType: "SMF", connector: "LC", wavelengths: "1530nm", notes: "Schneider Electric SFP CWDM 1530nm 40km process ring" }, + { pid: "SE-SFP-CWDM-1550", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 40000, reachLabel: "CWDM-1550", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", notes: "Schneider Electric SFP CWDM 1550nm 40km process ring" }, + { pid: "SE-SFP-CWDM-1570", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 40000, reachLabel: "CWDM-1570", fiberType: "SMF", connector: "LC", wavelengths: "1570nm", notes: "Schneider Electric SFP CWDM 1570nm 40km process ring" }, + + // ── 40G QSFP+ ─────────────────────────────────────────────────────────── + { pid: "SE-QSFP-40G-LR4", formFactor: "QSFP+", speedGbps: 40, speed: "40G", reachMeters: 10000, reachLabel: "LR4", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "40GBASE-LR4", notes: "Schneider Electric QSFP+ 40G LR4 EcoStruxure backbone" }, + + // ── 25G SFP28 ─────────────────────────────────────────────────────────── + { pid: "SE-SFP28-25G-LR", formFactor: "SFP28", speedGbps: 25, speed: "25G", reachMeters: 10000, reachLabel: "LR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "25GBASE-LR", notes: "Schneider Electric SFP28 25G LR industrial" }, +]; + +export async function scrapeSchneiderOem(): Promise { + console.log("=== Schneider Electric OEM Transceiver Seed ===\n"); + + const vendorId = await ensureVendor( + "Schneider Electric", + "oem", + "https://www.se.com/us/en/product-range/62159-connexium-managed-switches/", + undefined + ); + + let inserted = 0; + let updated = 0; + let errors = 0; + + for (const p of SCHNEIDER_PIDS) { + const slug = `schneider-${p.pid.toLowerCase().replace(/[^a-z0-9]+/g, "-")}`; + try { + const res = await pool.query( + `INSERT INTO transceivers + (slug, part_number, vendor_id, form_factor, speed, speed_gbps, + reach_meters, reach_label, fiber_type, connector, wavelengths, + dom_support, ieee_reference, market_status, category, notes) + VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,true,$12,'Mainstream','Industrial',$13) + ON CONFLICT (slug) DO UPDATE SET + speed_gbps = EXCLUDED.speed_gbps, + reach_meters = CASE WHEN EXCLUDED.reach_meters > 0 THEN EXCLUDED.reach_meters ELSE transceivers.reach_meters END, + fiber_type = CASE WHEN EXCLUDED.fiber_type <> '' THEN EXCLUDED.fiber_type ELSE transceivers.fiber_type END, + wavelengths = COALESCE(EXCLUDED.wavelengths, transceivers.wavelengths), + updated_at = NOW() + RETURNING (xmax = 0) as was_inserted`, + [slug, p.pid, vendorId, p.formFactor, p.speed, p.speedGbps, + p.reachMeters, p.reachLabel, p.fiberType, p.connector, + p.wavelengths ?? null, p.standard ?? null, p.notes ?? null] + ); + if (res.rows[0]?.was_inserted) inserted++; else updated++; + } catch (err) { + console.warn(` Skip ${p.pid}: ${(err as Error).message.slice(0, 80)}`); + errors++; + } + } + + console.log(`\n=== Schneider Electric OEM Seed Complete ===`); + console.log(` Inserted: ${inserted}`); + console.log(` Updated: ${updated}`); + console.log(` Errors: ${errors}`); + console.log(` Total PIDs: ${SCHNEIDER_PIDS.length}\n`); +} + +if (require.main === module) { + scrapeSchneiderOem() + .then(() => pool.end()) + .catch((err) => { + console.error("Fatal:", err); + pool.end(); + process.exit(1); + }); +} diff --git a/packages/scraper/src/scrapers/schweitzer-oem.ts b/packages/scraper/src/scrapers/schweitzer-oem.ts new file mode 100644 index 0000000..0d604c8 --- /dev/null +++ b/packages/scraper/src/scrapers/schweitzer-oem.ts @@ -0,0 +1,118 @@ +/** + * Schweitzer Engineering Laboratories (SEL) OEM Transceiver Catalog Seed + * + * Seeds transceiver PIDs for SEL industrial SFP/SFP+/SFP28/QSFP+ modules + * used in protective relay networking, substation automation, and power + * system communication hardware (SEL-2740S, SEL-2730M, SEL relay platforms). + * + * Sources: + * - SEL product catalog (selinc.com) + * - SEL networking accessories datasheets + * + * Run: tsx packages/scraper/src/scrapers/schweitzer-oem.ts + * Cron: daily at 17:30 + */ + +import { pool, ensureVendor } from "../utils/db"; + +interface SchweiterPID { + pid: string; + formFactor: string; + speedGbps: number; + speed: string; + reachMeters: number; + reachLabel: string; + fiberType: string; + connector: string; + wavelengths?: string; + standard?: string; + notes?: string; +} + +const SCHWEITER_PIDS: SchweiterPID[] = [ + // ── 1G SFP ────────────────────────────────────────────────────────────── + { pid: "SEL-SFP-1G-SX", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 550, reachLabel: "SX", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "1000BASE-SX", notes: "SEL SFP 1G SX protective relay / substation networking" }, + { pid: "SEL-SFP-1G-LX", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 10000, reachLabel: "LX", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "1000BASE-LX", notes: "SEL SFP 1G LX protective relay / substation networking" }, + { pid: "SEL-SFP-1G-ZX", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 80000, reachLabel: "ZX", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "1000BASE-ZX", notes: "SEL SFP 1G ZX 80km long-haul substation link" }, + { pid: "SEL-SFP-1G-T", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 100, reachLabel: "T", fiberType: "DAC", connector: "RJ45", standard: "1000BASE-T", notes: "SEL SFP 1G copper RJ45" }, + { pid: "SEL-SFP-GE-T", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 100, reachLabel: "T", fiberType: "DAC", connector: "RJ45", standard: "1000BASE-T", notes: "SEL SFP GE copper industrial relay networking" }, + + // ── 1G SFP BiDi ───────────────────────────────────────────────────────── + { pid: "SEL-SFP-1G-BIDI-1310", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 20000, reachLabel: "BiDi-TX1310", fiberType: "SMF", connector: "LC", wavelengths: "TX1310/RX1550nm", notes: "SEL SFP 1G BiDi TX1310 single fiber substation" }, + { pid: "SEL-SFP-1G-BIDI-1550", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 20000, reachLabel: "BiDi-TX1550", fiberType: "SMF", connector: "LC", wavelengths: "TX1550/RX1310nm", notes: "SEL SFP 1G BiDi TX1550 single fiber substation" }, + + // ── 10G SFP+ ──────────────────────────────────────────────────────────── + { pid: "SEL-SFP-10G-SR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 300, reachLabel: "SR", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "10GBASE-SR", notes: "SEL SFP+ 10G SR relay networking" }, + { pid: "SEL-SFP-10G-LR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 10000, reachLabel: "LR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "10GBASE-LR", notes: "SEL SFP+ 10G LR relay networking" }, + { pid: "SEL-SFP-10G-ER", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 40000, reachLabel: "ER", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "10GBASE-ER", notes: "SEL SFP+ 10G ER relay networking" }, + + // ── 1G CWDM SFP (protection/pilot rings) ──────────────────────────────── + { pid: "SEL-SFP-CWDM-1470", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 40000, reachLabel: "CWDM-1470", fiberType: "SMF", connector: "LC", wavelengths: "1470nm", notes: "SEL SFP CWDM 1470nm 40km protection ring" }, + { pid: "SEL-SFP-CWDM-1510", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 40000, reachLabel: "CWDM-1510", fiberType: "SMF", connector: "LC", wavelengths: "1510nm", notes: "SEL SFP CWDM 1510nm 40km protection ring" }, + { pid: "SEL-SFP-CWDM-1550", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 40000, reachLabel: "CWDM-1550", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", notes: "SEL SFP CWDM 1550nm 40km protection ring" }, + { pid: "SEL-SFP-CWDM-1590", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 40000, reachLabel: "CWDM-1590", fiberType: "SMF", connector: "LC", wavelengths: "1590nm", notes: "SEL SFP CWDM 1590nm 40km protection ring" }, + + // ── 40G QSFP+ ─────────────────────────────────────────────────────────── + { pid: "SEL-QSFP-40G-LR4", formFactor: "QSFP+", speedGbps: 40, speed: "40G", reachMeters: 10000, reachLabel: "LR4", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "40GBASE-LR4", notes: "SEL QSFP+ 40G LR4 substation core" }, + + // ── 25G SFP28 ─────────────────────────────────────────────────────────── + { pid: "SEL-SFP28-25G-LR", formFactor: "SFP28", speedGbps: 25, speed: "25G", reachMeters: 10000, reachLabel: "LR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "25GBASE-LR", notes: "SEL SFP28 25G LR industrial relay platform" }, +]; + +export async function scrapeSchweiterEngOem(): Promise { + console.log("=== Schweitzer Engineering (SEL) OEM Transceiver Seed ===\n"); + + const vendorId = await ensureVendor( + "Schweitzer Engineering", + "oem", + "https://selinc.com", + undefined + ); + + let inserted = 0; + let updated = 0; + let errors = 0; + + for (const p of SCHWEITER_PIDS) { + const slug = `sel-${p.pid.toLowerCase().replace(/[^a-z0-9]+/g, "-")}`; + try { + const res = await pool.query( + `INSERT INTO transceivers + (slug, part_number, vendor_id, form_factor, speed, speed_gbps, + reach_meters, reach_label, fiber_type, connector, wavelengths, + dom_support, ieee_reference, market_status, category, notes) + VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,true,$12,'Mainstream','Industrial',$13) + ON CONFLICT (slug) DO UPDATE SET + speed_gbps = EXCLUDED.speed_gbps, + reach_meters = CASE WHEN EXCLUDED.reach_meters > 0 THEN EXCLUDED.reach_meters ELSE transceivers.reach_meters END, + fiber_type = CASE WHEN EXCLUDED.fiber_type <> '' THEN EXCLUDED.fiber_type ELSE transceivers.fiber_type END, + wavelengths = COALESCE(EXCLUDED.wavelengths, transceivers.wavelengths), + updated_at = NOW() + RETURNING (xmax = 0) as was_inserted`, + [slug, p.pid, vendorId, p.formFactor, p.speed, p.speedGbps, + p.reachMeters, p.reachLabel, p.fiberType, p.connector, + p.wavelengths ?? null, p.standard ?? null, p.notes ?? null] + ); + if (res.rows[0]?.was_inserted) inserted++; else updated++; + } catch (err) { + console.warn(` Skip ${p.pid}: ${(err as Error).message.slice(0, 80)}`); + errors++; + } + } + + console.log(`\n=== Schweitzer Engineering (SEL) OEM Seed Complete ===`); + console.log(` Inserted: ${inserted}`); + console.log(` Updated: ${updated}`); + console.log(` Errors: ${errors}`); + console.log(` Total PIDs: ${SCHWEITER_PIDS.length}\n`); +} + +if (require.main === module) { + scrapeSchweiterEngOem() + .then(() => pool.end()) + .catch((err) => { + console.error("Fatal:", err); + pool.end(); + process.exit(1); + }); +} diff --git a/packages/scraper/src/scrapers/siemens-oem.ts b/packages/scraper/src/scrapers/siemens-oem.ts new file mode 100644 index 0000000..5bc8131 --- /dev/null +++ b/packages/scraper/src/scrapers/siemens-oem.ts @@ -0,0 +1,121 @@ +/** + * Siemens SCALANCE OEM Transceiver Catalog Seed + * + * Seeds transceiver PIDs for Siemens SCALANCE-branded SFP/SFP+/QSFP+ + * modules used in SCALANCE industrial Ethernet switches for factory + * automation, process industries, and critical infrastructure. + * + * Note: ruggedcom-oem.ts covers the Siemens RUGGEDCOM line. + * This file covers the SCALANCE line exclusively. + * + * Sources: + * - Siemens SCALANCE X-500 / XR-500 Media Modules datasheet + * - Siemens Industry Online Support (support.industry.siemens.com) + * + * Run: tsx packages/scraper/src/scrapers/siemens-oem.ts + * Cron: daily at 16:15 + */ + +import { pool, ensureVendor } from "../utils/db"; + +interface SiemensPID { + pid: string; + formFactor: string; + speedGbps: number; + speed: string; + reachMeters: number; + reachLabel: string; + fiberType: string; + connector: string; + wavelengths?: string; + standard?: string; + notes?: string; +} + +const SIEMENS_PIDS: SiemensPID[] = [ + // ── 1G SFP ────────────────────────────────────────────────────────────── + { pid: "SCALANCE-SFP-1G-SX", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 550, reachLabel: "SX", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "1000BASE-SX", notes: "Siemens SCALANCE SFP 1G SX multimode industrial" }, + { pid: "SCALANCE-SFP-1G-LX", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 10000, reachLabel: "LX", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "1000BASE-LX", notes: "Siemens SCALANCE SFP 1G LX single-mode 10km" }, + { pid: "SCALANCE-SFP-1G-LH", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 80000, reachLabel: "LH", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "1000BASE-ZX", notes: "Siemens SCALANCE SFP 1G LH long-haul 80km" }, + { pid: "SCALANCE-SFP-1G-T", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 100, reachLabel: "T", fiberType: "DAC", connector: "RJ45", standard: "1000BASE-T", notes: "Siemens SCALANCE SFP 1G copper RJ45 industrial" }, + + // ── 1G SFP BiDi ───────────────────────────────────────────────────────── + { pid: "SCALANCE-SFP-1G-BIDI-1310", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 20000, reachLabel: "BiDi-TX1310", fiberType: "SMF", connector: "LC", wavelengths: "TX1310/RX1550nm", notes: "Siemens SCALANCE SFP 1G BiDi TX1310 single fiber 20km" }, + { pid: "SCALANCE-SFP-1G-BIDI-1550", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 20000, reachLabel: "BiDi-TX1550", fiberType: "SMF", connector: "LC", wavelengths: "TX1550/RX1310nm", notes: "Siemens SCALANCE SFP 1G BiDi TX1550 single fiber 20km" }, + + // ── 10G SFP+ ──────────────────────────────────────────────────────────── + { pid: "SCALANCE-SFP-10G-SR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 300, reachLabel: "SR", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "10GBASE-SR", notes: "Siemens SCALANCE SFP+ 10G SR multimode" }, + { pid: "SCALANCE-SFP-10G-LR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 10000, reachLabel: "LR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "10GBASE-LR", notes: "Siemens SCALANCE SFP+ 10G LR single-mode 10km" }, + { pid: "SCALANCE-SFP-10G-ER", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 40000, reachLabel: "ER", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "10GBASE-ER", notes: "Siemens SCALANCE SFP+ 10G ER extended-reach 40km" }, + + // ── 1G CWDM SFP (plant/process rings) ─────────────────────────────────── + { pid: "SCALANCE-SFP-CWDM-1470", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 40000, reachLabel: "CWDM-1470", fiberType: "SMF", connector: "LC", wavelengths: "1470nm", notes: "Siemens SCALANCE SFP CWDM 1470nm 40km plant ring" }, + { pid: "SCALANCE-SFP-CWDM-1490", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 40000, reachLabel: "CWDM-1490", fiberType: "SMF", connector: "LC", wavelengths: "1490nm", notes: "Siemens SCALANCE SFP CWDM 1490nm 40km plant ring" }, + { pid: "SCALANCE-SFP-CWDM-1510", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 40000, reachLabel: "CWDM-1510", fiberType: "SMF", connector: "LC", wavelengths: "1510nm", notes: "Siemens SCALANCE SFP CWDM 1510nm 40km plant ring" }, + { pid: "SCALANCE-SFP-CWDM-1530", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 40000, reachLabel: "CWDM-1530", fiberType: "SMF", connector: "LC", wavelengths: "1530nm", notes: "Siemens SCALANCE SFP CWDM 1530nm 40km plant ring" }, + { pid: "SCALANCE-SFP-CWDM-1550", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 40000, reachLabel: "CWDM-1550", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", notes: "Siemens SCALANCE SFP CWDM 1550nm 40km plant ring" }, + { pid: "SCALANCE-SFP-CWDM-1570", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 40000, reachLabel: "CWDM-1570", fiberType: "SMF", connector: "LC", wavelengths: "1570nm", notes: "Siemens SCALANCE SFP CWDM 1570nm 40km plant ring" }, + { pid: "SCALANCE-SFP-CWDM-1590", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 40000, reachLabel: "CWDM-1590", fiberType: "SMF", connector: "LC", wavelengths: "1590nm", notes: "Siemens SCALANCE SFP CWDM 1590nm 40km plant ring" }, + { pid: "SCALANCE-SFP-CWDM-1610", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 40000, reachLabel: "CWDM-1610", fiberType: "SMF", connector: "LC", wavelengths: "1610nm", notes: "Siemens SCALANCE SFP CWDM 1610nm 40km plant ring" }, + + // ── 40G QSFP+ ─────────────────────────────────────────────────────────── + { pid: "SCALANCE-QSFP-40G-LR4", formFactor: "QSFP+", speedGbps: 40, speed: "40G", reachMeters: 10000, reachLabel: "LR4", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "40GBASE-LR4", notes: "Siemens SCALANCE QSFP+ 40G LR4 industrial backbone" }, +]; + +export async function scrapeSiemensOem(): Promise { + console.log("=== Siemens SCALANCE OEM Transceiver Seed ===\n"); + + const vendorId = await ensureVendor( + "Siemens SCALANCE", + "oem", + "https://www.siemens.com/global/en/products/automation/industrial-communication/industrial-ethernet-switches.html", + undefined + ); + + let inserted = 0; + let updated = 0; + let errors = 0; + + for (const p of SIEMENS_PIDS) { + const slug = `siemens-sc-${p.pid.toLowerCase().replace(/[^a-z0-9]+/g, "-")}`; + try { + const res = await pool.query( + `INSERT INTO transceivers + (slug, part_number, vendor_id, form_factor, speed, speed_gbps, + reach_meters, reach_label, fiber_type, connector, wavelengths, + dom_support, ieee_reference, market_status, category, notes) + VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,true,$12,'Mainstream','Industrial',$13) + ON CONFLICT (slug) DO UPDATE SET + speed_gbps = EXCLUDED.speed_gbps, + reach_meters = CASE WHEN EXCLUDED.reach_meters > 0 THEN EXCLUDED.reach_meters ELSE transceivers.reach_meters END, + fiber_type = CASE WHEN EXCLUDED.fiber_type <> '' THEN EXCLUDED.fiber_type ELSE transceivers.fiber_type END, + wavelengths = COALESCE(EXCLUDED.wavelengths, transceivers.wavelengths), + updated_at = NOW() + RETURNING (xmax = 0) as was_inserted`, + [slug, p.pid, vendorId, p.formFactor, p.speed, p.speedGbps, + p.reachMeters, p.reachLabel, p.fiberType, p.connector, + p.wavelengths ?? null, p.standard ?? null, p.notes ?? null] + ); + if (res.rows[0]?.was_inserted) inserted++; else updated++; + } catch (err) { + console.warn(` Skip ${p.pid}: ${(err as Error).message.slice(0, 80)}`); + errors++; + } + } + + console.log(`\n=== Siemens SCALANCE OEM Seed Complete ===`); + console.log(` Inserted: ${inserted}`); + console.log(` Updated: ${updated}`); + console.log(` Errors: ${errors}`); + console.log(` Total PIDs: ${SIEMENS_PIDS.length}\n`); +} + +if (require.main === module) { + scrapeSiemensOem() + .then(() => pool.end()) + .catch((err) => { + console.error("Fatal:", err); + pool.end(); + process.exit(1); + }); +} diff --git a/packages/scraper/src/scrapers/siklu-oem.ts b/packages/scraper/src/scrapers/siklu-oem.ts new file mode 100644 index 0000000..f8ef053 --- /dev/null +++ b/packages/scraper/src/scrapers/siklu-oem.ts @@ -0,0 +1,120 @@ +/** + * Siklu OEM Transceiver Catalog Seed + * + * Seeds Siklu-branded transceiver PIDs used in mmWave wireless backhaul + * products (EtherHaul, MultiHaul, BreezeUltra series). Siklu was acquired + * by Ceragon Networks and operates as a subsidiary brand. + * + * Sources: + * - Siklu Product Catalog (siklu.com) + * - EtherHaul / MultiHaul hardware interface guides + * - mmWave backhaul optical link specifications + * + * Run: tsx packages/scraper/src/scrapers/siklu-oem.ts + * Cron: daily at 03:30 + */ + +import { pool, ensureVendor } from "../utils/db"; + +interface SikluPID { + pid: string; + formFactor: string; + speedGbps: number; + speed: string; + reachMeters: number; + reachLabel: string; + fiberType: string; + connector: string; + wavelengths?: string; + standard?: string; + notes?: string; +} + +const SIKLU_PIDS: SikluPID[] = [ + // ── 1G SFP ────────────────────────────────────────────────────────────── + { pid: "SFP-1G-SX", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 550, reachLabel: "SX", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "1000BASE-SX", notes: "Siklu 1G SFP SX for EtherHaul backhaul aggregation" }, + { pid: "SFP-1G-LX", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 10000, reachLabel: "LX", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "1000BASE-LX" }, + { pid: "SFP-1G-T", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 100, reachLabel: "T", fiberType: "DAC", connector: "RJ45", standard: "1000BASE-T" }, + + // ── 10G SFP+ ──────────────────────────────────────────────────────────── + { pid: "SFP-10G-SR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 300, reachLabel: "SR", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "10GBASE-SR", notes: "Siklu 10G SFP+ SR for MultiHaul mmWave uplink" }, + { pid: "SFP-10G-LR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 10000, reachLabel: "LR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "10GBASE-LR" }, + { pid: "SFP-10G-ER", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 40000, reachLabel: "ER", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "10GBASE-ER" }, + { pid: "SFP-10G-ZR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 80000, reachLabel: "ZR", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "10GBASE-ZR", notes: "Siklu 10G ZR for long-haul fiber aggregation links" }, + { pid: "SFP-10G-T", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 30, reachLabel: "T", fiberType: "DAC", connector: "RJ45", standard: "10GBASE-T" }, + + // ── BiDi SFP ──────────────────────────────────────────────────────────── + { pid: "SFP-GE-BIDI-1310", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 20000, reachLabel: "BIDI", fiberType: "SMF", connector: "LC", wavelengths: "1310/1550nm", standard: "1000BASE-BX", notes: "BiDi SFP Tx1310/Rx1550 for single-fiber runs to mmWave node" }, + { pid: "SFP-GE-BIDI-1550", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 20000, reachLabel: "BIDI", fiberType: "SMF", connector: "LC", wavelengths: "1550/1310nm", standard: "1000BASE-BX", notes: "BiDi SFP Tx1550/Rx1310 counterpart for single-fiber runs" }, + + // ── 25G SFP28 ─────────────────────────────────────────────────────────── + { pid: "SFP28-25G-SR", formFactor: "SFP28", speedGbps: 25, speed: "25G", reachMeters: 100, reachLabel: "SR", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "25GBASE-SR" }, + { pid: "SFP28-25G-LR", formFactor: "SFP28", speedGbps: 25, speed: "25G", reachMeters: 10000, reachLabel: "LR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "25GBASE-LR", notes: "Siklu 25G SFP28 LR for 5G backhaul aggregation node" }, + + // ── 40G QSFP+ ─────────────────────────────────────────────────────────── + { pid: "QSFP-40G-LR4", formFactor: "QSFP+", speedGbps: 40, speed: "40G", reachMeters: 10000, reachLabel: "LR4", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "40GBASE-LR4", notes: "Siklu 40G QSFP+ LR4 for mmWave hub site uplink" }, + + // ── 100G QSFP28 ───────────────────────────────────────────────────────── + { pid: "QSFP28-100G-LR4", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 10000, reachLabel: "LR4", fiberType: "SMF", connector: "LC", wavelengths: "1295-1310nm", standard: "100GBASE-LR4", notes: "Siklu 100G QSFP28 for high-capacity 5G backhaul ring" }, + + // ── 400G QSFP-DD ──────────────────────────────────────────────────────── + { pid: "QSFP-DD-400G-DR4", formFactor: "QSFP-DD", speedGbps: 400, speed: "400G", reachMeters: 500, reachLabel: "DR4", fiberType: "SMF", connector: "MPO", wavelengths: "1310nm", standard: "400GBASE-DR4", notes: "Siklu 400G QSFP-DD for next-gen mmWave aggregation core" }, +]; + +export async function scrapeSikluOem(): Promise { + console.log("=== Siklu OEM Transceiver Seed ===\n"); + + const vendorId = await ensureVendor( + "Siklu", + "oem", + "https://www.siklu.com", + undefined + ); + + let inserted = 0; + let updated = 0; + let errors = 0; + + for (const p of SIKLU_PIDS) { + const slug = `siklu-${p.pid.toLowerCase().replace(/[^a-z0-9]+/g, "-")}`; + try { + const res = await pool.query( + `INSERT INTO transceivers + (slug, part_number, vendor_id, form_factor, speed, speed_gbps, + reach_meters, reach_label, fiber_type, connector, wavelengths, + dom_support, ieee_reference, market_status, category, notes) + VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,true,$12,'Mainstream','DataCenter',$13) + ON CONFLICT (slug) DO UPDATE SET + speed_gbps = EXCLUDED.speed_gbps, + reach_meters = CASE WHEN EXCLUDED.reach_meters > 0 THEN EXCLUDED.reach_meters ELSE transceivers.reach_meters END, + fiber_type = CASE WHEN EXCLUDED.fiber_type <> '' THEN EXCLUDED.fiber_type ELSE transceivers.fiber_type END, + wavelengths = COALESCE(EXCLUDED.wavelengths, transceivers.wavelengths), + updated_at = NOW() + RETURNING (xmax = 0) as was_inserted`, + [slug, p.pid, vendorId, p.formFactor, p.speed, p.speedGbps, + p.reachMeters, p.reachLabel, p.fiberType, p.connector, + p.wavelengths ?? null, p.standard ?? null, p.notes ?? null] + ); + if (res.rows[0]?.was_inserted) inserted++; else updated++; + } catch (err) { + console.warn(` Skip ${p.pid}: ${(err as Error).message.slice(0, 80)}`); + errors++; + } + } + + console.log(`\n=== Siklu OEM Seed Complete ===`); + console.log(` Inserted: ${inserted}`); + console.log(` Updated: ${updated}`); + console.log(` Errors: ${errors}`); + console.log(` Total PIDs: ${SIKLU_PIDS.length}\n`); +} + +if (require.main === module) { + scrapeSikluOem() + .then(() => pool.end()) + .catch((err) => { + console.error("Fatal:", err); + pool.end(); + process.exit(1); + }); +} diff --git a/packages/scraper/src/scrapers/solarflare-oem.ts b/packages/scraper/src/scrapers/solarflare-oem.ts new file mode 100644 index 0000000..c8f52fa --- /dev/null +++ b/packages/scraper/src/scrapers/solarflare-oem.ts @@ -0,0 +1,131 @@ +/** + * Solarflare OEM Transceiver Catalog Seed + * + * Seeds Solarflare (AMD Solarflare / Xilinx Alveo) transceiver PIDs for + * RDMA/DPDK-capable NICs: SFN8000 series, XtremeScale, and Alveo SmartNICs. + * + * Sources: + * - Solarflare SFN8522/SFN8542/SFN8642 NIC Hardware Guides + * - AMD Solarflare Optical Transceiver Compatibility Matrix + * - Xilinx Alveo U25N/U200 SmartNIC transceiver support list + * + * Run: tsx packages/scraper/src/scrapers/solarflare-oem.ts + * Cron: daily at 21:45 + */ + +import { pool, ensureVendor } from "../utils/db"; + +interface SolarflarePID { + pid: string; + formFactor: string; + speedGbps: number; + speed: string; + reachMeters: number; + reachLabel: string; + fiberType: string; + connector: string; + wavelengths?: string; + standard?: string; + notes?: string; +} + +const SOLARFLARE_PIDS: SolarflarePID[] = [ + // ── NIC Cards (SFP+ / SFP28 / QSFP28 host adapters) ──────────────────── + { pid: "SFN8522-PLUS", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 300, reachLabel: "SR", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "10GBASE-SR", notes: "Solarflare dual-port 10GbE SFP+ PCIe NIC, DPDK/RDMA" }, + { pid: "SFN8542-PLUS", formFactor: "SFP28", speedGbps: 25, speed: "25G", reachMeters: 100, reachLabel: "SR", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "25GBASE-SR", notes: "Solarflare dual-port 25GbE SFP28 PCIe NIC, DPDK/RDMA" }, + { pid: "SFN8642-PLUS", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 100, reachLabel: "SR4", fiberType: "MMF", connector: "MPO", wavelengths: "850nm", standard: "100GBASE-SR4",notes: "Solarflare dual-port 100GbE QSFP28 PCIe NIC" }, + + // ── 1G SFP ────────────────────────────────────────────────────────────── + { pid: "SFL-SFP-1G-SX", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 550, reachLabel: "SX", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "1000BASE-SX" }, + { pid: "SFL-SFP-1G-LX", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 10000, reachLabel: "LX", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "1000BASE-LX" }, + + // ── 10G SFP+ ──────────────────────────────────────────────────────────── + { pid: "SFL-SFP-10G-SR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 300, reachLabel: "SR", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "10GBASE-SR" }, + { pid: "SFL-SFP-10G-LR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 10000, reachLabel: "LR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "10GBASE-LR" }, + { pid: "SFL-SFP-10G-ER", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 40000, reachLabel: "ER", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "10GBASE-ER" }, + { pid: "SFL-SFP-10G-ZR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 80000, reachLabel: "ZR", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "10GBASE-ZR" }, + { pid: "SFL-SFP-10G-T", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 30, reachLabel: "T", fiberType: "DAC", connector: "RJ45", standard: "10GBASE-T", notes: "Solarflare 10GBASE-T copper SFP+ for server uplink" }, + + // ── 25G SFP28 ─────────────────────────────────────────────────────────── + { pid: "SFL-SFP-25G-SR", formFactor: "SFP28", speedGbps: 25, speed: "25G", reachMeters: 100, reachLabel: "SR", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "25GBASE-SR" }, + { pid: "SFL-SFP-25G-LR", formFactor: "SFP28", speedGbps: 25, speed: "25G", reachMeters: 10000, reachLabel: "LR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "25GBASE-LR" }, + { pid: "SFL-SFP-28G-SR", formFactor: "SFP28", speedGbps: 25, speed: "25G", reachMeters: 70, reachLabel: "SR", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "25GBASE-SR", notes: "Solarflare 25G SFP28 high-density SR for HPC" }, + { pid: "SFL-SFP-28G-LR", formFactor: "SFP28", speedGbps: 25, speed: "25G", reachMeters: 10000, reachLabel: "LR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "25GBASE-LR", notes: "Solarflare 25G SFP28 LR for inter-rack" }, + + // ── 40G QSFP+ ─────────────────────────────────────────────────────────── + { pid: "SFL-QSFP-40G-SR4", formFactor: "QSFP+", speedGbps: 40, speed: "40G", reachMeters: 150, reachLabel: "SR4", fiberType: "MMF", connector: "MPO", wavelengths: "850nm", standard: "40GBASE-SR4" }, + { pid: "SFL-QSFP-40G-LR4", formFactor: "QSFP+", speedGbps: 40, speed: "40G", reachMeters: 10000, reachLabel: "LR4", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "40GBASE-LR4" }, + + // ── 100G QSFP28 ───────────────────────────────────────────────────────── + { pid: "SFL-QSFP-100G-SR4", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 100, reachLabel: "SR4", fiberType: "MMF", connector: "MPO", wavelengths: "850nm", standard: "100GBASE-SR4" }, + { pid: "SFL-QSFP-100G-LR4", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 10000, reachLabel: "LR4", fiberType: "SMF", connector: "LC", wavelengths: "1295-1310nm", standard: "100GBASE-LR4" }, + + // ── 100G QSFP-DD ──────────────────────────────────────────────────────── + { pid: "SFL-QSFPDD-100G-SR4",formFactor: "QSFP-DD", speedGbps: 100, speed: "100G", reachMeters: 100, reachLabel: "SR4", fiberType: "MMF", connector: "MPO", wavelengths: "850nm", standard: "100GBASE-SR4",notes: "Solarflare Alveo 100G QSFP-DD SR4" }, + { pid: "SFL-QSFPDD-100G-LR4",formFactor: "QSFP-DD", speedGbps: 100, speed: "100G", reachMeters: 10000, reachLabel: "LR4", fiberType: "SMF", connector: "LC", wavelengths: "1295-1310nm", standard: "100GBASE-LR4",notes: "Solarflare Alveo 100G QSFP-DD LR4" }, + + // ── DAC ───────────────────────────────────────────────────────────────── + { pid: "SFL-DAC-10G-1M", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 1, reachLabel: "DAC-1M", fiberType: "DAC", connector: "SFP+", notes: "Solarflare 10G DAC 1m" }, + { pid: "SFL-DAC-10G-3M", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 3, reachLabel: "DAC-3M", fiberType: "DAC", connector: "SFP+", notes: "Solarflare 10G DAC 3m" }, + { pid: "SFL-DAC-25G-1M", formFactor: "SFP28", speedGbps: 25, speed: "25G", reachMeters: 1, reachLabel: "DAC-1M", fiberType: "DAC", connector: "SFP28", notes: "Solarflare 25G DAC 1m" }, + { pid: "SFL-DAC-100G-1M", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 1, reachLabel: "DAC-1M", fiberType: "DAC", connector: "QSFP28", notes: "Solarflare 100G DAC 1m" }, + { pid: "SFL-DAC-100G-3M", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 3, reachLabel: "DAC-3M", fiberType: "DAC", connector: "QSFP28", notes: "Solarflare 100G DAC 3m" }, +]; + +export async function scrapeSolarflareOem(): Promise { + console.log("=== Solarflare OEM Transceiver Seed ===\n"); + + const vendorId = await ensureVendor( + "Solarflare", + "oem", + "https://www.xilinx.com/products/boards-and-kits/alveo.html", + undefined + ); + + let inserted = 0; + let updated = 0; + let errors = 0; + + for (const p of SOLARFLARE_PIDS) { + const slug = `solarflare-${p.pid.toLowerCase().replace(/[^a-z0-9]+/g, "-")}`; + try { + const res = await pool.query( + `INSERT INTO transceivers + (slug, part_number, vendor_id, form_factor, speed, speed_gbps, + reach_meters, reach_label, fiber_type, connector, wavelengths, + dom_support, ieee_reference, market_status, category, notes) + VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,true,$12,'Mainstream','DataCenter',$13) + ON CONFLICT (slug) DO UPDATE SET + speed_gbps = EXCLUDED.speed_gbps, + reach_meters = CASE WHEN EXCLUDED.reach_meters > 0 THEN EXCLUDED.reach_meters ELSE transceivers.reach_meters END, + fiber_type = CASE WHEN EXCLUDED.fiber_type <> '' THEN EXCLUDED.fiber_type ELSE transceivers.fiber_type END, + wavelengths = COALESCE(EXCLUDED.wavelengths, transceivers.wavelengths), + updated_at = NOW() + RETURNING (xmax = 0) as was_inserted`, + [slug, p.pid, vendorId, p.formFactor, p.speed, p.speedGbps, + p.reachMeters, p.reachLabel, p.fiberType, p.connector, + p.wavelengths ?? null, p.standard ?? null, p.notes ?? null] + ); + if (res.rows[0]?.was_inserted) inserted++; else updated++; + } catch (err) { + console.warn(` Skip ${p.pid}: ${(err as Error).message.slice(0, 80)}`); + errors++; + } + } + + console.log(`\n=== Solarflare OEM Seed Complete ===`); + console.log(` Inserted: ${inserted}`); + console.log(` Updated: ${updated}`); + console.log(` Errors: ${errors}`); + console.log(` Total PIDs: ${SOLARFLARE_PIDS.length}\n`); +} + +if (require.main === module) { + scrapeSolarflareOem() + .then(() => pool.end()) + .catch((err) => { + console.error("Fatal:", err); + pool.end(); + process.exit(1); + }); +} diff --git a/packages/scraper/src/scrapers/sonic-oem.ts b/packages/scraper/src/scrapers/sonic-oem.ts new file mode 100644 index 0000000..47e9c60 --- /dev/null +++ b/packages/scraper/src/scrapers/sonic-oem.ts @@ -0,0 +1,123 @@ +/** + * SONiC OEM Transceiver Catalog Seed + * + * Seeds SONiC-branded transceiver PIDs for Azure SONiC (Software for + * Open Networking in the Cloud) open-source NOS running on Open Compute + * Platform and compatible white-box switch hardware. + * + * Sources: + * - SONiC Project (sonic-net.github.io/SONiC/) + * - Open Compute Project (OCP) Hardware Requirements + * - Microsoft Azure SONiC Platform Transceiver HCL + * + * Run: tsx packages/scraper/src/scrapers/sonic-oem.ts + * Cron: daily at 11:00 + */ + +import { pool, ensureVendor } from "../utils/db"; + +interface SonicPID { + pid: string; + formFactor: string; + speedGbps: number; + speed: string; + reachMeters: number; + reachLabel: string; + fiberType: string; + connector: string; + wavelengths?: string; + standard?: string; + notes?: string; +} + +const SONIC_PIDS: SonicPID[] = [ + // ── 1G SFP ────────────────────────────────────────────────────────────── + { pid: "SONIC-SFP-1G-SX", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 550, reachLabel: "SX", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "1000BASE-SX" }, + { pid: "SONIC-SFP-1G-LX", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 10000, reachLabel: "LX", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "1000BASE-LX" }, + + // ── 10G SFP+ ──────────────────────────────────────────────────────────── + { pid: "SONIC-SFP-10G-SR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 300, reachLabel: "SR", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "10GBASE-SR" }, + { pid: "SONIC-SFP-10G-LR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 10000, reachLabel: "LR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "10GBASE-LR" }, + { pid: "SONIC-SFP-10G-ER", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 40000, reachLabel: "ER", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "10GBASE-ER" }, + + // ── 25G SFP28 ─────────────────────────────────────────────────────────── + { pid: "SONIC-SFP28-25G-SR", formFactor: "SFP28", speedGbps: 25, speed: "25G", reachMeters: 100, reachLabel: "SR", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "25GBASE-SR" }, + { pid: "SONIC-SFP28-25G-LR", formFactor: "SFP28", speedGbps: 25, speed: "25G", reachMeters: 10000, reachLabel: "LR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "25GBASE-LR" }, + + // ── 40G QSFP+ ─────────────────────────────────────────────────────────── + { pid: "SONIC-QSFP-40G-SR4", formFactor: "QSFP+", speedGbps: 40, speed: "40G", reachMeters: 150, reachLabel: "SR4", fiberType: "MMF", connector: "MPO", wavelengths: "850nm", standard: "40GBASE-SR4" }, + { pid: "SONIC-QSFP-40G-LR4", formFactor: "QSFP+", speedGbps: 40, speed: "40G", reachMeters: 10000, reachLabel: "LR4", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "40GBASE-LR4" }, + + // ── 100G QSFP28 ───────────────────────────────────────────────────────── + { pid: "SONIC-QSFP28-100G-SR4", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 100, reachLabel: "SR4", fiberType: "MMF", connector: "MPO", wavelengths: "850nm", standard: "100GBASE-SR4" }, + { pid: "SONIC-QSFP28-100G-LR4", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 10000, reachLabel: "LR4", fiberType: "SMF", connector: "LC", wavelengths: "1295-1310nm", standard: "100GBASE-LR4" }, + { pid: "SONIC-SFP28-100G-ER4", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 40000, reachLabel: "ER4", fiberType: "SMF", connector: "LC", wavelengths: "1295-1310nm", standard: "100GBASE-ER4", notes: "Extended reach, used on Azure WAN edge" }, + + // ── 400G QSFP-DD ──────────────────────────────────────────────────────── + { pid: "SONIC-QSFP-DD-400G-DR4", formFactor: "QSFP-DD", speedGbps: 400, speed: "400G", reachMeters: 500, reachLabel: "DR4", fiberType: "SMF", connector: "MPO", wavelengths: "1310nm", standard: "400GBASE-DR4" }, + { pid: "SONIC-QSFP-DD-400G-SR8", formFactor: "QSFP-DD", speedGbps: 400, speed: "400G", reachMeters: 100, reachLabel: "SR8", fiberType: "MMF", connector: "MPO", wavelengths: "850nm", standard: "400GBASE-SR8" }, + + // ── 800G QSFP-DD ──────────────────────────────────────────────────────── + { pid: "SONIC-QSFP-DD-800G-DR8", formFactor: "QSFP-DD", speedGbps: 800, speed: "800G", reachMeters: 500, reachLabel: "DR8", fiberType: "SMF", connector: "MPO", wavelengths: "1310nm", standard: "800GBASE-DR8", notes: "Next-gen hyperscale fabric, OCP SAI-ready" }, + + // ── Copper SFP ────────────────────────────────────────────────────────── + { pid: "SONIC-SFP-GE-T", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 100, reachLabel: "T", fiberType: "DAC", connector: "RJ45", standard: "1000BASE-T", notes: "GE copper for management plane ports" }, +]; + +export async function scrapeSonicOem(): Promise { + console.log("=== SONiC OEM Transceiver Seed ===\n"); + + const vendorId = await ensureVendor( + "SONiC", + "oem", + "https://sonic-net.github.io/SONiC/", + undefined + ); + + let inserted = 0; + let updated = 0; + let errors = 0; + + for (const p of SONIC_PIDS) { + const slug = `sonic-${p.pid.toLowerCase().replace(/[^a-z0-9]+/g, "-")}`; + try { + const res = await pool.query( + `INSERT INTO transceivers + (slug, part_number, vendor_id, form_factor, speed, speed_gbps, + reach_meters, reach_label, fiber_type, connector, wavelengths, + dom_support, ieee_reference, market_status, category, notes) + VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,true,$12,'Mainstream','DataCenter',$13) + ON CONFLICT (slug) DO UPDATE SET + speed_gbps = EXCLUDED.speed_gbps, + reach_meters = CASE WHEN EXCLUDED.reach_meters > 0 THEN EXCLUDED.reach_meters ELSE transceivers.reach_meters END, + fiber_type = CASE WHEN EXCLUDED.fiber_type <> '' THEN EXCLUDED.fiber_type ELSE transceivers.fiber_type END, + wavelengths = COALESCE(EXCLUDED.wavelengths, transceivers.wavelengths), + updated_at = NOW() + RETURNING (xmax = 0) as was_inserted`, + [slug, p.pid, vendorId, p.formFactor, p.speed, p.speedGbps, + p.reachMeters, p.reachLabel, p.fiberType, p.connector, + p.wavelengths ?? null, p.standard ?? null, p.notes ?? null] + ); + if (res.rows[0]?.was_inserted) inserted++; else updated++; + } catch (err) { + console.warn(` Skip ${p.pid}: ${(err as Error).message.slice(0, 80)}`); + errors++; + } + } + + console.log(`\n=== SONiC OEM Seed Complete ===`); + console.log(` Inserted: ${inserted}`); + console.log(` Updated: ${updated}`); + console.log(` Errors: ${errors}`); + console.log(` Total PIDs: ${SONIC_PIDS.length}\n`); +} + +if (require.main === module) { + scrapeSonicOem() + .then(() => pool.end()) + .catch((err) => { + console.error("Fatal:", err); + pool.end(); + process.exit(1); + }); +} diff --git a/packages/scraper/src/scrapers/sonicwall-oem.ts b/packages/scraper/src/scrapers/sonicwall-oem.ts new file mode 100644 index 0000000..601769e --- /dev/null +++ b/packages/scraper/src/scrapers/sonicwall-oem.ts @@ -0,0 +1,123 @@ +/** + * SonicWall OEM Transceiver Catalog Seed + * + * Seeds SonicWall-branded transceiver PIDs for NSa, NSsp, and TZ series + * network security appliances. + * + * Sources: + * - SonicWall NSa/NSsp Hardware Compatibility Guide (sonicwall.com) + * - SonicWall TZ Series Hardware Guide + * - SonicWall 01-SSC- Part Number Reference + * + * Run: tsx packages/scraper/src/scrapers/sonicwall-oem.ts + * Cron: daily at 14:00 + */ + +import { pool, ensureVendor } from "../utils/db"; + +interface SonicwallPID { + pid: string; + formFactor: string; + speedGbps: number; + speed: string; + reachMeters: number; + reachLabel: string; + fiberType: string; + connector: string; + wavelengths?: string; + standard?: string; + notes?: string; +} + +const SONICWALL_PIDS: SonicwallPID[] = [ + // ── 1G SFP ────────────────────────────────────────────────────────────── + { pid: "01-SSC-9789", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 550, reachLabel: "SX", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "1000BASE-SX", notes: "SonicWall 1G SFP MM 550m" }, + { pid: "01-SSC-9790", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 10000, reachLabel: "LX", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "1000BASE-LX", notes: "SonicWall 1G SFP SM 10km" }, + { pid: "01-SSC-9791", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 80000, reachLabel: "ZX", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "1000BASE-ZX" }, + { pid: "01-SSC-9792", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 100, reachLabel: "T", fiberType: "DAC", connector: "RJ45", standard: "1000BASE-T" }, + + // ── 10G SFP+ ──────────────────────────────────────────────────────────── + { pid: "01-SSC-9779", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 300, reachLabel: "SR", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "10GBASE-SR" }, + { pid: "01-SSC-9780", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 10000, reachLabel: "LR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "10GBASE-LR" }, + { pid: "01-SSC-9781", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 40000, reachLabel: "ER", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "10GBASE-ER" }, + { pid: "01-SSC-9782", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 80000, reachLabel: "ZR", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "10GBASE-ZR" }, + { pid: "01-SSC-9783", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 30, reachLabel: "T", fiberType: "DAC", connector: "RJ45", standard: "10GBASE-T" }, + + // ── 25G SFP28 ─────────────────────────────────────────────────────────── + { pid: "01-SSC-9770", formFactor: "SFP28", speedGbps: 25, speed: "25G", reachMeters: 100, reachLabel: "SR", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "25GBASE-SR" }, + { pid: "01-SSC-9771", formFactor: "SFP28", speedGbps: 25, speed: "25G", reachMeters: 10000, reachLabel: "LR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "25GBASE-LR" }, + + // ── 40G QSFP+ ─────────────────────────────────────────────────────────── + { pid: "01-SSC-9760", formFactor: "QSFP+", speedGbps: 40, speed: "40G", reachMeters: 150, reachLabel: "SR4", fiberType: "MMF", connector: "MPO", wavelengths: "850nm", standard: "40GBASE-SR4" }, + { pid: "01-SSC-9761", formFactor: "QSFP+", speedGbps: 40, speed: "40G", reachMeters: 10000, reachLabel: "LR4", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "40GBASE-LR4" }, + + // ── 100G QSFP28 ───────────────────────────────────────────────────────── + { pid: "01-SSC-9750", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 100, reachLabel: "SR4", fiberType: "MMF", connector: "MPO", wavelengths: "850nm", standard: "100GBASE-SR4" }, + { pid: "01-SSC-9751", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 10000, reachLabel: "LR4", fiberType: "SMF", connector: "LC", wavelengths: "1295-1310nm", standard: "100GBASE-LR4" }, + { pid: "01-SSC-9752", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 2000, reachLabel: "CWDM4", fiberType: "SMF", connector: "LC", wavelengths: "1271-1331nm", standard: "100GBASE-CWDM4" }, + { pid: "01-SSC-9753", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 500, reachLabel: "DR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "100GBASE-DR" }, + + // ── DAC ───────────────────────────────────────────────────────────────── + { pid: "01-SSC-9784", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 1, reachLabel: "DAC-1M", fiberType: "DAC", connector: "SFP+" }, + { pid: "01-SSC-9785", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 3, reachLabel: "DAC-3M", fiberType: "DAC", connector: "SFP+" }, + { pid: "01-SSC-9754", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 1, reachLabel: "DAC-1M", fiberType: "DAC", connector: "QSFP28" }, + { pid: "01-SSC-9755", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 3, reachLabel: "DAC-3M", fiberType: "DAC", connector: "QSFP28" }, +]; + +export async function scrapeSonicwallOem(): Promise { + console.log("=== SonicWall OEM Transceiver Seed ===\n"); + + const vendorId = await ensureVendor( + "SonicWall", + "oem", + "https://www.sonicwall.com", + undefined + ); + + let inserted = 0; + let updated = 0; + let errors = 0; + + for (const p of SONICWALL_PIDS) { + const slug = `sonicwall-${p.pid.toLowerCase().replace(/[^a-z0-9]+/g, "-")}`; + try { + const res = await pool.query( + `INSERT INTO transceivers + (slug, part_number, vendor_id, form_factor, speed, speed_gbps, + reach_meters, reach_label, fiber_type, connector, wavelengths, + dom_support, ieee_reference, market_status, category, notes) + VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,true,$12,'Mainstream','DataCenter',$13) + ON CONFLICT (slug) DO UPDATE SET + speed_gbps = EXCLUDED.speed_gbps, + reach_meters = CASE WHEN EXCLUDED.reach_meters > 0 THEN EXCLUDED.reach_meters ELSE transceivers.reach_meters END, + fiber_type = CASE WHEN EXCLUDED.fiber_type <> '' THEN EXCLUDED.fiber_type ELSE transceivers.fiber_type END, + wavelengths = COALESCE(EXCLUDED.wavelengths, transceivers.wavelengths), + updated_at = NOW() + RETURNING (xmax = 0) as was_inserted`, + [slug, p.pid, vendorId, p.formFactor, p.speed, p.speedGbps, + p.reachMeters, p.reachLabel, p.fiberType, p.connector, + p.wavelengths ?? null, p.standard ?? null, p.notes ?? null] + ); + if (res.rows[0]?.was_inserted) inserted++; else updated++; + } catch (err) { + console.warn(` Skip ${p.pid}: ${(err as Error).message.slice(0, 80)}`); + errors++; + } + } + + console.log(`\n=== SonicWall OEM Seed Complete ===`); + console.log(` Inserted: ${inserted}`); + console.log(` Updated: ${updated}`); + console.log(` Errors: ${errors}`); + console.log(` Total PIDs: ${SONICWALL_PIDS.length}\n`); +} + +if (require.main === module) { + scrapeSonicwallOem() + .then(() => pool.end()) + .catch((err) => { + console.error("Fatal:", err); + pool.end(); + process.exit(1); + }); +} diff --git a/packages/scraper/src/scrapers/sophos-oem.ts b/packages/scraper/src/scrapers/sophos-oem.ts new file mode 100644 index 0000000..819d16d --- /dev/null +++ b/packages/scraper/src/scrapers/sophos-oem.ts @@ -0,0 +1,122 @@ +/** + * Sophos OEM Transceiver Catalog Seed + * + * Seeds Sophos-branded transceiver PIDs for XGS Firewall and XG series + * security appliances using SFP, SFP+, SFP28, QSFP+, and QSFP28 modules. + * + * Sources: + * - Sophos XGS Series Hardware Installation Guide + * - Sophos Transceivers & DAC Cables Compatibility Guide + * - Sophos Hardware Compatibility List (docs.sophos.com) + * + * Run: tsx packages/scraper/src/scrapers/sophos-oem.ts + * Cron: daily at 18:00 + */ + +import { pool, ensureVendor } from "../utils/db"; + +interface SophosPID { + pid: string; + formFactor: string; + speedGbps: number; + speed: string; + reachMeters: number; + reachLabel: string; + fiberType: string; + connector: string; + wavelengths?: string; + standard?: string; + notes?: string; +} + +const SOPHOS_PIDS: SophosPID[] = [ + // ── 1G SFP ────────────────────────────────────────────────────────────── + { pid: "SFPA-SX", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 550, reachLabel: "SX", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "1000BASE-SX" }, + { pid: "SFPA-LX", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 10000, reachLabel: "LX", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "1000BASE-LX" }, + { pid: "SFPA-ZX", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 80000, reachLabel: "ZX", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "1000BASE-ZX" }, + { pid: "SFPA-T", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 100, reachLabel: "T", fiberType: "DAC", connector: "RJ45", standard: "1000BASE-T" }, + { pid: "SFPA-BIDI-U", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 20000, reachLabel: "BiDi", fiberType: "SMF", connector: "LC", wavelengths: "TX1310/RX1550nm", notes: "Sophos 1G BiDi SFP upstream" }, + + // ── 10G SFP+ ──────────────────────────────────────────────────────────── + { pid: "SFPB-SR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 300, reachLabel: "SR", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "10GBASE-SR" }, + { pid: "SFPB-LR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 10000, reachLabel: "LR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "10GBASE-LR" }, + { pid: "SFPB-ER", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 40000, reachLabel: "ER", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "10GBASE-ER" }, + { pid: "SFPB-ZR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 80000, reachLabel: "ZR", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "10GBASE-ZR" }, + { pid: "SFPB-T", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 30, reachLabel: "T", fiberType: "DAC", connector: "RJ45", standard: "10GBASE-T" }, + + // ── 25G SFP28 ─────────────────────────────────────────────────────────── + { pid: "SFPC-SR", formFactor: "SFP28", speedGbps: 25, speed: "25G", reachMeters: 100, reachLabel: "SR", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "25GBASE-SR" }, + { pid: "SFPC-LR", formFactor: "SFP28", speedGbps: 25, speed: "25G", reachMeters: 10000, reachLabel: "LR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "25GBASE-LR" }, + + // ── 40G QSFP+ ─────────────────────────────────────────────────────────── + { pid: "QSFPA-SR4", formFactor: "QSFP+", speedGbps: 40, speed: "40G", reachMeters: 150, reachLabel: "SR4", fiberType: "MMF", connector: "MPO", wavelengths: "850nm", standard: "40GBASE-SR4" }, + { pid: "QSFPA-LR4", formFactor: "QSFP+", speedGbps: 40, speed: "40G", reachMeters: 10000, reachLabel: "LR4", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "40GBASE-LR4" }, + + // ── 100G QSFP28 ───────────────────────────────────────────────────────── + { pid: "QSFPB-SR4", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 100, reachLabel: "SR4", fiberType: "MMF", connector: "MPO", wavelengths: "850nm", standard: "100GBASE-SR4" }, + { pid: "QSFPB-LR4", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 10000, reachLabel: "LR4", fiberType: "SMF", connector: "LC", wavelengths: "1295-1310nm", standard: "100GBASE-LR4" }, + { pid: "QSFPB-CWDM4", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 2000, reachLabel: "CWDM4", fiberType: "SMF", connector: "LC", wavelengths: "1271-1331nm", standard: "100GBASE-CWDM4" }, + + // ── DAC ───────────────────────────────────────────────────────────────── + { pid: "DACA-10G-1M", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 1, reachLabel: "DAC-1M", fiberType: "DAC", connector: "SFP+" }, + { pid: "DACA-10G-3M", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 3, reachLabel: "DAC-3M", fiberType: "DAC", connector: "SFP+" }, + { pid: "DACB-100G-1M", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 1, reachLabel: "DAC-1M", fiberType: "DAC", connector: "QSFP28" }, +]; + +export async function scrapeSophosOem(): Promise { + console.log("=== Sophos OEM Transceiver Seed ===\n"); + + const vendorId = await ensureVendor( + "Sophos", + "oem", + "https://www.sophos.com", + undefined + ); + + let inserted = 0; + let updated = 0; + let errors = 0; + + for (const p of SOPHOS_PIDS) { + const slug = `sophos-${p.pid.toLowerCase().replace(/[^a-z0-9]+/g, "-")}`; + try { + const res = await pool.query( + `INSERT INTO transceivers + (slug, part_number, vendor_id, form_factor, speed, speed_gbps, + reach_meters, reach_label, fiber_type, connector, wavelengths, + dom_support, ieee_reference, market_status, category, notes) + VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,true,$12,'Mainstream','DataCenter',$13) + ON CONFLICT (slug) DO UPDATE SET + speed_gbps = EXCLUDED.speed_gbps, + reach_meters = CASE WHEN EXCLUDED.reach_meters > 0 THEN EXCLUDED.reach_meters ELSE transceivers.reach_meters END, + fiber_type = CASE WHEN EXCLUDED.fiber_type <> '' THEN EXCLUDED.fiber_type ELSE transceivers.fiber_type END, + wavelengths = COALESCE(EXCLUDED.wavelengths, transceivers.wavelengths), + updated_at = NOW() + RETURNING (xmax = 0) as was_inserted`, + [slug, p.pid, vendorId, p.formFactor, p.speed, p.speedGbps, + p.reachMeters, p.reachLabel, p.fiberType, p.connector, + p.wavelengths ?? null, p.standard ?? null, p.notes ?? null] + ); + if (res.rows[0]?.was_inserted) inserted++; else updated++; + } catch (err) { + console.warn(` Skip ${p.pid}: ${(err as Error).message.slice(0, 80)}`); + errors++; + } + } + + console.log(`\n=== Sophos OEM Seed Complete ===`); + console.log(` Inserted: ${inserted}`); + console.log(` Updated: ${updated}`); + console.log(` Errors: ${errors}`); + console.log(` Total PIDs: ${SOPHOS_PIDS.length}\n`); +} + +if (require.main === module) { + scrapeSophosOem() + .then(() => pool.end()) + .catch((err) => { + console.error("Fatal:", err); + pool.end(); + process.exit(1); + }); +} diff --git a/packages/scraper/src/scrapers/source-photonics-oem.ts b/packages/scraper/src/scrapers/source-photonics-oem.ts new file mode 100644 index 0000000..5379eec --- /dev/null +++ b/packages/scraper/src/scrapers/source-photonics-oem.ts @@ -0,0 +1,144 @@ +/** + * Source Photonics OEM Transceiver Catalog Seed + * + * Seeds Source Photonics-branded transceiver PIDs. Source Photonics is a + * vertically integrated optical transceiver OEM specializing in PON access + * (GPON, XGS-PON, 10G-PON) and high-volume DataCenter transceivers. + * Acquired by Huawei in 2017; independent operations continue under the + * Source Photonics brand. + * + * Sources: + * - Source Photonics Product Catalog (sourcephotonics.com/products) + * - IEEE 802.3 Standards (SX, LX, SR, LR, SR4, LR4) + * - ITU-T G.984 (GPON), G.9807 (XGS-PON), G.987 (XG-PON) specs + * - ITU-T G.694.2 CWDM wavelength grid + * + * Run: tsx packages/scraper/src/scrapers/source-photonics-oem.ts + * Cron: daily at 20:45 + */ + +import { pool, ensureVendor } from "../utils/db"; + +interface SourcePhotonicsPID { + pid: string; + formFactor: string; + speedGbps: number; + speed: string; + reachMeters: number; + reachLabel: string; + fiberType: string; + connector: string; + wavelengths?: string; + standard?: string; + category?: string; + notes?: string; +} + +// PIDs that belong to the Telecom category (PON, CWDM) +const TELECOM_PIDS = new Set([ + "SP-GPON-OLT-C", + "SP-XGSPON-OLT-C", + "SP-10GPON-OLT-C", + "SP-CWDM-SFP10G-1470", + "SP-CWDM-SFP10G-1490", + "SP-CWDM-SFP10G-1510", + "SP-CWDM-SFP10G-1530", +]); + +const SOURCE_PHOTONICS_PIDS: SourcePhotonicsPID[] = [ + // ── 1G SFP ────────────────────────────────────────────────────────────── + { pid: "SP-SFP-GE-SX", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 550, reachLabel: "SX", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "1000BASE-SX", notes: "Source Photonics 1G SFP SX 550m MMF" }, + { pid: "SP-SFP-GE-LX", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 10000, reachLabel: "LX", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "1000BASE-LX", notes: "Source Photonics 1G SFP LX 10km SMF" }, + { pid: "SP-SFP-GE-BIDI", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 10000, reachLabel: "BiDi", fiberType: "SMF", connector: "LC", wavelengths: "1310/1490nm", standard: "1000BASE-BX", notes: "Source Photonics 1G SFP BiDi TX1310/RX1490" }, + + // ── 10G SFP+ ──────────────────────────────────────────────────────────── + { pid: "SP-SFP10G-SR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 300, reachLabel: "SR", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "10GBASE-SR", notes: "Source Photonics 10G SFP+ SR 300m MMF" }, + { pid: "SP-SFP10G-LR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 10000, reachLabel: "LR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "10GBASE-LR", notes: "Source Photonics 10G SFP+ LR 10km SMF" }, + { pid: "SP-SFP10G-ER", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 40000, reachLabel: "ER", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "10GBASE-ER", notes: "Source Photonics 10G SFP+ ER 40km SMF" }, + + // ── 25G SFP28 ─────────────────────────────────────────────────────────── + { pid: "SP-SFP28-25G-SR", formFactor: "SFP28", speedGbps: 25, speed: "25G", reachMeters: 300, reachLabel: "SR", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "25GBASE-SR", notes: "Source Photonics 25G SFP28 SR 300m MMF" }, + { pid: "SP-SFP28-25G-LR", formFactor: "SFP28", speedGbps: 25, speed: "25G", reachMeters: 10000, reachLabel: "LR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "25GBASE-LR", notes: "Source Photonics 25G SFP28 LR 10km SMF" }, + + // ── 40G QSFP+ ─────────────────────────────────────────────────────────── + { pid: "SP-QSFP-40G-SR4", formFactor: "QSFP+", speedGbps: 40, speed: "40G", reachMeters: 150, reachLabel: "SR4", fiberType: "MMF", connector: "MPO", wavelengths: "850nm", standard: "40GBASE-SR4", notes: "Source Photonics 40G QSFP+ SR4 150m MMF" }, + { pid: "SP-QSFP-40G-LR4", formFactor: "QSFP+", speedGbps: 40, speed: "40G", reachMeters: 10000, reachLabel: "LR4", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "40GBASE-LR4", notes: "Source Photonics 40G QSFP+ LR4 10km SMF" }, + + // ── 100G QSFP28 ───────────────────────────────────────────────────────── + { pid: "SP-QSFP28-100G-SR4", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 100, reachLabel: "SR4", fiberType: "MMF", connector: "MPO", wavelengths: "850nm", standard: "100GBASE-SR4", notes: "Source Photonics 100G QSFP28 SR4 100m MMF" }, + { pid: "SP-QSFP28-100G-LR4", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 10000, reachLabel: "LR4", fiberType: "SMF", connector: "LC", wavelengths: "1295-1310nm", standard: "100GBASE-LR4", notes: "Source Photonics 100G QSFP28 LR4 10km SMF" }, + + // ── GPON OLT SFP (Telecom) ─────────────────────────────────────────────── + { pid: "SP-GPON-OLT-C", formFactor: "SFP", speedGbps: 2.5, speed: "2.5G", reachMeters: 20000, reachLabel: "GPON", fiberType: "SMF", connector: "LC", wavelengths: "1490/1310nm", standard: "ITU-T G.984", category: "Telecom", notes: "Source Photonics GPON OLT SFP Class C+ TX1490/RX1310nm, 20km" }, + + // ── XGS-PON OLT SFP+ (Telecom) ────────────────────────────────────────── + { pid: "SP-XGSPON-OLT-C", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 20000, reachLabel: "XGS-PON", fiberType: "SMF", connector: "LC", wavelengths: "1577/1270nm", standard: "ITU-T G.9807", category: "Telecom", notes: "Source Photonics XGS-PON OLT SFP+ Class C+ TX1577/RX1270nm, 20km" }, + + // ── 10G-PON OLT SFP+ (Telecom) ────────────────────────────────────────── + { pid: "SP-10GPON-OLT-C", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 20000, reachLabel: "10G-PON", fiberType: "SMF", connector: "LC", wavelengths: "1577/1270nm", standard: "ITU-T G.987", category: "Telecom", notes: "Source Photonics 10G-PON (XG-PON1) OLT SFP+ TX1577/RX1270nm, 20km" }, + + // ── CWDM SFP+ (Telecom) ───────────────────────────────────────────────── + { pid: "SP-CWDM-SFP10G-1470", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 40000, reachLabel: "CWDM", fiberType: "SMF", connector: "LC", wavelengths: "1470nm", standard: "ITU-T G.694.2", category: "Telecom", notes: "Source Photonics 10G CWDM SFP+ 1470nm 40km" }, + { pid: "SP-CWDM-SFP10G-1490", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 40000, reachLabel: "CWDM", fiberType: "SMF", connector: "LC", wavelengths: "1490nm", standard: "ITU-T G.694.2", category: "Telecom", notes: "Source Photonics 10G CWDM SFP+ 1490nm 40km" }, + { pid: "SP-CWDM-SFP10G-1510", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 40000, reachLabel: "CWDM", fiberType: "SMF", connector: "LC", wavelengths: "1510nm", standard: "ITU-T G.694.2", category: "Telecom", notes: "Source Photonics 10G CWDM SFP+ 1510nm 40km" }, + { pid: "SP-CWDM-SFP10G-1530", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 40000, reachLabel: "CWDM", fiberType: "SMF", connector: "LC", wavelengths: "1530nm", standard: "ITU-T G.694.2", category: "Telecom", notes: "Source Photonics 10G CWDM SFP+ 1530nm 40km" }, +]; + +export async function scrapeSourcePhotonicsOem(): Promise { + console.log("=== Source Photonics OEM Transceiver Seed ===\n"); + + const vendorId = await ensureVendor( + "Source Photonics", + "oem", + "https://www.sourcephotonics.com", + undefined + ); + + let inserted = 0; + let updated = 0; + let errors = 0; + + for (const p of SOURCE_PHOTONICS_PIDS) { + const slug = `source-photonics-${p.pid.toLowerCase().replace(/[^a-z0-9]+/g, "-")}`; + const category = p.category ?? (TELECOM_PIDS.has(p.pid) ? "Telecom" : "DataCenter"); + try { + const res = await pool.query( + `INSERT INTO transceivers + (slug, part_number, vendor_id, form_factor, speed, speed_gbps, + reach_meters, reach_label, fiber_type, connector, wavelengths, + dom_support, ieee_reference, market_status, category, notes) + VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,true,$12,'Mainstream',$13,$14) + ON CONFLICT (slug) DO UPDATE SET + speed_gbps = EXCLUDED.speed_gbps, + reach_meters = CASE WHEN EXCLUDED.reach_meters > 0 THEN EXCLUDED.reach_meters ELSE transceivers.reach_meters END, + fiber_type = CASE WHEN EXCLUDED.fiber_type <> '' THEN EXCLUDED.fiber_type ELSE transceivers.fiber_type END, + wavelengths = COALESCE(EXCLUDED.wavelengths, transceivers.wavelengths), + updated_at = NOW() + RETURNING (xmax = 0) as was_inserted`, + [slug, p.pid, vendorId, p.formFactor, p.speed, p.speedGbps, + p.reachMeters, p.reachLabel, p.fiberType, p.connector, + p.wavelengths ?? null, p.standard ?? null, category, p.notes ?? null] + ); + if (res.rows[0]?.was_inserted) inserted++; else updated++; + } catch (err) { + console.warn(` Skip ${p.pid}: ${(err as Error).message.slice(0, 80)}`); + errors++; + } + } + + console.log(`\n=== Source Photonics OEM Seed Complete ===`); + console.log(` Inserted: ${inserted}`); + console.log(` Updated: ${updated}`); + console.log(` Errors: ${errors}`); + console.log(` Total PIDs: ${SOURCE_PHOTONICS_PIDS.length}\n`); +} + +if (require.main === module) { + scrapeSourcePhotonicsOem() + .then(() => pool.end()) + .catch((err) => { + console.error("Fatal:", err); + pool.end(); + process.exit(1); + }); +} diff --git a/packages/scraper/src/scrapers/spirent-oem.ts b/packages/scraper/src/scrapers/spirent-oem.ts new file mode 100644 index 0000000..3a89bb3 --- /dev/null +++ b/packages/scraper/src/scrapers/spirent-oem.ts @@ -0,0 +1,134 @@ +/** + * Spirent Communications OEM Transceiver Catalog Seed + * + * Seeds Spirent-branded transceiver PIDs for TestCenter and Landslide + * network test platforms (STC-SFP prefix). + * + * Sources: + * - Spirent TestCenter Hardware Reference (spirent.com) + * - Spirent TestCenter Module Data Sheets + * - Spirent Landslide Platform Hardware Guide + * + * Run: tsx packages/scraper/src/scrapers/spirent-oem.ts + * Cron: daily at 17:15 + */ + +import { pool, ensureVendor } from "../utils/db"; + +interface SpirentPID { + pid: string; + formFactor: string; + speedGbps: number; + speed: string; + reachMeters: number; + reachLabel: string; + fiberType: string; + connector: string; + wavelengths?: string; + standard?: string; + notes?: string; +} + +const SPIRENT_PIDS: SpirentPID[] = [ + // ── 1G SFP ────────────────────────────────────────────────────────────── + { pid: "STC-SFP-1G-SX", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 550, reachLabel: "SX", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "1000BASE-SX" }, + { pid: "STC-SFP-1G-LX", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 10000, reachLabel: "LX", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "1000BASE-LX" }, + { pid: "STC-SFP-1G-ZX", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 80000, reachLabel: "ZX", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "1000BASE-ZX" }, + { pid: "STC-SFP-1G-T", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 100, reachLabel: "T", fiberType: "DAC", connector: "RJ45", standard: "1000BASE-T" }, + + // ── 10G SFP+ ──────────────────────────────────────────────────────────── + { pid: "STC-SFP-10G-SR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 300, reachLabel: "SR", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "10GBASE-SR" }, + { pid: "STC-SFP-10G-LR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 10000, reachLabel: "LR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "10GBASE-LR" }, + { pid: "STC-SFP-10G-ER", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 40000, reachLabel: "ER", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "10GBASE-ER" }, + { pid: "STC-SFP-10G-ZR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 80000, reachLabel: "ZR", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "10GBASE-ZR" }, + { pid: "STC-SFP-10G-T", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 30, reachLabel: "T", fiberType: "DAC", connector: "RJ45", standard: "10GBASE-T" }, + + // ── 25G SFP28 ─────────────────────────────────────────────────────────── + { pid: "STC-SFP28-25G-SR", formFactor: "SFP28", speedGbps: 25, speed: "25G", reachMeters: 100, reachLabel: "SR", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "25GBASE-SR" }, + { pid: "STC-SFP28-25G-LR", formFactor: "SFP28", speedGbps: 25, speed: "25G", reachMeters: 10000, reachLabel: "LR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "25GBASE-LR" }, + + // ── 40G QSFP+ ─────────────────────────────────────────────────────────── + { pid: "STC-QSFP-40G-SR4", formFactor: "QSFP+", speedGbps: 40, speed: "40G", reachMeters: 150, reachLabel: "SR4", fiberType: "MMF", connector: "MPO", wavelengths: "850nm", standard: "40GBASE-SR4" }, + { pid: "STC-QSFP-40G-LR4", formFactor: "QSFP+", speedGbps: 40, speed: "40G", reachMeters: 10000, reachLabel: "LR4", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "40GBASE-LR4" }, + + // ── 100G QSFP28 ───────────────────────────────────────────────────────── + { pid: "STC-QSFP28-100G-SR4", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 100, reachLabel: "SR4", fiberType: "MMF", connector: "MPO", wavelengths: "850nm", standard: "100GBASE-SR4" }, + { pid: "STC-QSFP28-100G-LR4", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 10000, reachLabel: "LR4", fiberType: "SMF", connector: "LC", wavelengths: "1295-1310nm", standard: "100GBASE-LR4" }, + { pid: "STC-QSFP28-100G-CWDM4", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 2000, reachLabel: "CWDM4", fiberType: "SMF", connector: "LC", wavelengths: "1271-1331nm", standard: "100GBASE-CWDM4" }, + { pid: "STC-QSFP28-100G-DR", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 500, reachLabel: "DR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "100GBASE-DR" }, + + // ── 400G QSFP-DD ──────────────────────────────────────────────────────── + { pid: "STC-QSFPDD-400G-SR8", formFactor: "QSFP-DD", speedGbps: 400, speed: "400G", reachMeters: 100, reachLabel: "SR8", fiberType: "MMF", connector: "MPO", wavelengths: "850nm", standard: "400GBASE-SR8" }, + { pid: "STC-QSFPDD-400G-DR4", formFactor: "QSFP-DD", speedGbps: 400, speed: "400G", reachMeters: 500, reachLabel: "DR4", fiberType: "SMF", connector: "MPO", wavelengths: "1310nm", standard: "400GBASE-DR4" }, + { pid: "STC-QSFPDD-400G-FR4", formFactor: "QSFP-DD", speedGbps: 400, speed: "400G", reachMeters: 2000, reachLabel: "FR4", fiberType: "SMF", connector: "LC", wavelengths: "1271-1331nm", standard: "400GBASE-FR4" }, + { pid: "STC-QSFPDD-400G-LR4", formFactor: "QSFP-DD", speedGbps: 400, speed: "400G", reachMeters: 10000, reachLabel: "LR4", fiberType: "SMF", connector: "LC", wavelengths: "1295-1310nm", standard: "400GBASE-LR4" }, + + // ── 800G OSFP ─────────────────────────────────────────────────────────── + { pid: "STC-OSFP-800G-SR8", formFactor: "OSFP", speedGbps: 800, speed: "800G", reachMeters: 500, reachLabel: "SR8", fiberType: "MMF", connector: "MPO", wavelengths: "850nm", standard: "800GBASE-SR8" }, + { pid: "STC-OSFP-800G-DR8", formFactor: "OSFP", speedGbps: 800, speed: "800G", reachMeters: 2000, reachLabel: "DR8", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "800GBASE-DR8" }, + + // ── DAC ───────────────────────────────────────────────────────────────── + { pid: "STC-DAC-10G-1M", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 1, reachLabel: "DAC-1M", fiberType: "DAC", connector: "SFP+" }, + { pid: "STC-DAC-10G-3M", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 3, reachLabel: "DAC-3M", fiberType: "DAC", connector: "SFP+" }, + { pid: "STC-DAC-100G-1M", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 1, reachLabel: "DAC-1M", fiberType: "DAC", connector: "QSFP28" }, + { pid: "STC-DAC-100G-3M", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 3, reachLabel: "DAC-3M", fiberType: "DAC", connector: "QSFP28" }, + { pid: "STC-DAC-400G-1M", formFactor: "QSFP-DD", speedGbps: 400, speed: "400G", reachMeters: 1, reachLabel: "DAC-1M", fiberType: "DAC", connector: "QSFP-DD" }, +]; + +export async function scrapeSpirentOem(): Promise { + console.log("=== Spirent Communications OEM Transceiver Seed ===\n"); + + const vendorId = await ensureVendor( + "Spirent Communications", + "oem", + "https://www.spirent.com", + undefined + ); + + let inserted = 0; + let updated = 0; + let errors = 0; + + for (const p of SPIRENT_PIDS) { + const slug = `spirent-${p.pid.toLowerCase().replace(/[^a-z0-9]+/g, "-")}`; + try { + const res = await pool.query( + `INSERT INTO transceivers + (slug, part_number, vendor_id, form_factor, speed, speed_gbps, + reach_meters, reach_label, fiber_type, connector, wavelengths, + dom_support, ieee_reference, market_status, category, notes) + VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,true,$12,'Mainstream','DataCenter',$13) + ON CONFLICT (slug) DO UPDATE SET + speed_gbps = EXCLUDED.speed_gbps, + reach_meters = CASE WHEN EXCLUDED.reach_meters > 0 THEN EXCLUDED.reach_meters ELSE transceivers.reach_meters END, + fiber_type = CASE WHEN EXCLUDED.fiber_type <> '' THEN EXCLUDED.fiber_type ELSE transceivers.fiber_type END, + wavelengths = COALESCE(EXCLUDED.wavelengths, transceivers.wavelengths), + updated_at = NOW() + RETURNING (xmax = 0) as was_inserted`, + [slug, p.pid, vendorId, p.formFactor, p.speed, p.speedGbps, + p.reachMeters, p.reachLabel, p.fiberType, p.connector, + p.wavelengths ?? null, p.standard ?? null, p.notes ?? null] + ); + if (res.rows[0]?.was_inserted) inserted++; else updated++; + } catch (err) { + console.warn(` Skip ${p.pid}: ${(err as Error).message.slice(0, 80)}`); + errors++; + } + } + + console.log(`\n=== Spirent OEM Seed Complete ===`); + console.log(` Inserted: ${inserted}`); + console.log(` Updated: ${updated}`); + console.log(` Errors: ${errors}`); + console.log(` Total PIDs: ${SPIRENT_PIDS.length}\n`); +} + +if (require.main === module) { + scrapeSpirentOem() + .then(() => pool.end()) + .catch((err) => { + console.error("Fatal:", err); + pool.end(); + process.exit(1); + }); +} diff --git a/packages/scraper/src/scrapers/stordis-oem.ts b/packages/scraper/src/scrapers/stordis-oem.ts new file mode 100644 index 0000000..42e53a4 --- /dev/null +++ b/packages/scraper/src/scrapers/stordis-oem.ts @@ -0,0 +1,124 @@ +/** + * Stordis OEM Transceiver Catalog Seed + * + * Seeds Stordis-branded transceiver PIDs for disaggregated open networking + * switches running SONiC / Open Network Linux (BF2556X, BF6064X platforms). + * + * Sources: + * - Stordis Product Portfolio (stordis.com) + * - BF2556X-1T / BF6064X Hardware Compatibility + * + * Run: tsx packages/scraper/src/scrapers/stordis-oem.ts + * Cron: daily at 19:45 + */ + +import { pool, ensureVendor } from "../utils/db"; + +interface StordisPID { + pid: string; + formFactor: string; + speedGbps: number; + speed: string; + reachMeters: number; + reachLabel: string; + fiberType: string; + connector: string; + wavelengths?: string; + standard?: string; + notes?: string; +} + +const STORDIS_PIDS: StordisPID[] = [ + // ── 10G SFP+ ──────────────────────────────────────────────────────────── + { pid: "SD-SFP-10G-SR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 300, reachLabel: "SR", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "10GBASE-SR" }, + { pid: "SD-SFP-10G-LR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 10000, reachLabel: "LR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "10GBASE-LR" }, + { pid: "SD-SFP-10G-ER", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 40000, reachLabel: "ER", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "10GBASE-ER" }, + { pid: "SD-SFP-10G-ZR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 80000, reachLabel: "ZR", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "10GBASE-ZR" }, + + // ── 25G SFP28 ─────────────────────────────────────────────────────────── + { pid: "SD-SFP28-25G-SR", formFactor: "SFP28", speedGbps: 25, speed: "25G", reachMeters: 100, reachLabel: "SR", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "25GBASE-SR" }, + { pid: "SD-SFP28-25G-LR", formFactor: "SFP28", speedGbps: 25, speed: "25G", reachMeters: 10000, reachLabel: "LR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "25GBASE-LR" }, + { pid: "SD-SFP28-25G-ER", formFactor: "SFP28", speedGbps: 25, speed: "25G", reachMeters: 30000, reachLabel: "ER", fiberType: "SMF", connector: "LC", wavelengths: "1310nm" }, + + // ── 100G QSFP28 ───────────────────────────────────────────────────────── + { pid: "SD-QSFP28-100G-SR4", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 100, reachLabel: "SR4", fiberType: "MMF", connector: "MPO", wavelengths: "850nm", standard: "100GBASE-SR4" }, + { pid: "SD-QSFP28-100G-LR4", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 10000, reachLabel: "LR4", fiberType: "SMF", connector: "LC", wavelengths: "1295-1310nm", standard: "100GBASE-LR4" }, + { pid: "SD-QSFP28-100G-CWDM4", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 2000, reachLabel: "CWDM4", fiberType: "SMF", connector: "LC", wavelengths: "1271-1331nm", standard: "100GBASE-CWDM4" }, + { pid: "SD-QSFP28-100G-DR", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 500, reachLabel: "DR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "100GBASE-DR" }, + { pid: "SD-QSFP28-100G-FR", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 2000, reachLabel: "FR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "100GBASE-FR" }, + + // ── 400G QSFP-DD ──────────────────────────────────────────────────────── + { pid: "SD-QSFPDD-400G-SR8", formFactor: "QSFP-DD", speedGbps: 400, speed: "400G", reachMeters: 100, reachLabel: "SR8", fiberType: "MMF", connector: "MPO", wavelengths: "850nm", standard: "400GBASE-SR8" }, + { pid: "SD-QSFPDD-400G-DR4", formFactor: "QSFP-DD", speedGbps: 400, speed: "400G", reachMeters: 500, reachLabel: "DR4", fiberType: "SMF", connector: "MPO", wavelengths: "1310nm", standard: "400GBASE-DR4" }, + { pid: "SD-QSFPDD-400G-FR4", formFactor: "QSFP-DD", speedGbps: 400, speed: "400G", reachMeters: 2000, reachLabel: "FR4", fiberType: "SMF", connector: "LC", wavelengths: "1271-1331nm", standard: "400GBASE-FR4" }, + { pid: "SD-QSFPDD-400G-LR4", formFactor: "QSFP-DD", speedGbps: 400, speed: "400G", reachMeters: 10000, reachLabel: "LR4", fiberType: "SMF", connector: "LC", wavelengths: "1295-1310nm", standard: "400GBASE-LR4" }, + + // ── 800G OSFP ─────────────────────────────────────────────────────────── + { pid: "SD-OSFP-800G-SR8", formFactor: "OSFP", speedGbps: 800, speed: "800G", reachMeters: 500, reachLabel: "SR8", fiberType: "MMF", connector: "MPO", wavelengths: "850nm", standard: "800GBASE-SR8" }, + { pid: "SD-OSFP-800G-DR8", formFactor: "OSFP", speedGbps: 800, speed: "800G", reachMeters: 2000, reachLabel: "DR8", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "800GBASE-DR8" }, + + // ── DAC ───────────────────────────────────────────────────────────────── + { pid: "SD-DAC-10G-1M", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 1, reachLabel: "DAC-1M", fiberType: "DAC", connector: "SFP+" }, + { pid: "SD-DAC-10G-3M", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 3, reachLabel: "DAC-3M", fiberType: "DAC", connector: "SFP+" }, + { pid: "SD-DAC-100G-1M", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 1, reachLabel: "DAC-1M", fiberType: "DAC", connector: "QSFP28" }, + { pid: "SD-DAC-100G-3M", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 3, reachLabel: "DAC-3M", fiberType: "DAC", connector: "QSFP28" }, + { pid: "SD-DAC-400G-1M", formFactor: "QSFP-DD", speedGbps: 400, speed: "400G", reachMeters: 1, reachLabel: "DAC-1M", fiberType: "DAC", connector: "QSFP-DD" }, +]; + +export async function scrapeStordisOem(): Promise { + console.log("=== Stordis OEM Transceiver Seed ===\n"); + + const vendorId = await ensureVendor( + "Stordis", + "oem", + "https://www.stordis.com", + undefined + ); + + let inserted = 0; + let updated = 0; + let errors = 0; + + for (const p of STORDIS_PIDS) { + const slug = `stordis-${p.pid.toLowerCase().replace(/[^a-z0-9]+/g, "-")}`; + try { + const res = await pool.query( + `INSERT INTO transceivers + (slug, part_number, vendor_id, form_factor, speed, speed_gbps, + reach_meters, reach_label, fiber_type, connector, wavelengths, + dom_support, ieee_reference, market_status, category, notes) + VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,true,$12,'Mainstream','DataCenter',$13) + ON CONFLICT (slug) DO UPDATE SET + speed_gbps = EXCLUDED.speed_gbps, + reach_meters = CASE WHEN EXCLUDED.reach_meters > 0 THEN EXCLUDED.reach_meters ELSE transceivers.reach_meters END, + fiber_type = CASE WHEN EXCLUDED.fiber_type <> '' THEN EXCLUDED.fiber_type ELSE transceivers.fiber_type END, + wavelengths = COALESCE(EXCLUDED.wavelengths, transceivers.wavelengths), + updated_at = NOW() + RETURNING (xmax = 0) as was_inserted`, + [slug, p.pid, vendorId, p.formFactor, p.speed, p.speedGbps, + p.reachMeters, p.reachLabel, p.fiberType, p.connector, + p.wavelengths ?? null, p.standard ?? null, p.notes ?? null] + ); + if (res.rows[0]?.was_inserted) inserted++; else updated++; + } catch (err) { + console.warn(` Skip ${p.pid}: ${(err as Error).message.slice(0, 80)}`); + errors++; + } + } + + console.log(`\n=== Stordis OEM Seed Complete ===`); + console.log(` Inserted: ${inserted}`); + console.log(` Updated: ${updated}`); + console.log(` Errors: ${errors}`); + console.log(` Total PIDs: ${STORDIS_PIDS.length}\n`); +} + +if (require.main === module) { + scrapeStordisOem() + .then(() => pool.end()) + .catch((err) => { + console.error("Fatal:", err); + pool.end(); + process.exit(1); + }); +} diff --git a/packages/scraper/src/scrapers/sumitomo-electric-oem.ts b/packages/scraper/src/scrapers/sumitomo-electric-oem.ts new file mode 100644 index 0000000..ec0e995 --- /dev/null +++ b/packages/scraper/src/scrapers/sumitomo-electric-oem.ts @@ -0,0 +1,139 @@ +/** + * Sumitomo Electric Networks OEM Transceiver Catalog Seed + * + * Seeds Sumitomo Electric-branded transceiver PIDs. Sumitomo Electric + * Industries (Osaka, Japan) manufactures optical transceivers for + * enterprise, telecom, and industrial applications alongside their + * optical fiber and cable products. + * + * Sources: + * - Sumitomo Electric Networks Product Catalog (sumitomoelectric.com) + * - Sumitomo SFP/SFP+/QSFP Transceiver Specification Sheets + * - Sumitomo Optical Transceiver Application Guide + * + * Run: tsx packages/scraper/src/scrapers/sumitomo-electric-oem.ts + * Cron: daily at 21:45 + */ + +import { pool, ensureVendor } from "../utils/db"; + +interface SumiPID { + pid: string; + formFactor: string; + speedGbps: number; + speed: string; + reachMeters: number; + reachLabel: string; + fiberType: string; + connector: string; + wavelengths?: string; + standard?: string; + category?: string; + notes?: string; +} + +const TELECOM_PIDS = new Set([ + "SEI-SFP-10G-ZR", + "SEI-DWDM-SFP10G-C", + "SEI-SFP-GPON-OLT", + "SEI-SFP-XGS-PON-OLT", + "SEI-CFP2-DCO-100G", +]); + +const SUMITOMO_PIDS: SumiPID[] = [ + // ── 1G SFP ────────────────────────────────────────────────────────────── + { pid: "SEI-SFP-1G-SX", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 550, reachLabel: "SX", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "1000BASE-SX", notes: "Sumitomo Electric 1G SFP SX 550m MMF" }, + { pid: "SEI-SFP-1G-LX", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 10000, reachLabel: "LX", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "1000BASE-LX", notes: "Sumitomo Electric 1G SFP LX 10km SMF" }, + { pid: "SEI-SFP-1G-ZX", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 80000, reachLabel: "ZX", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "1000BASE-ZX", notes: "Sumitomo Electric 1G SFP ZX 80km SMF" }, + + // ── 10G SFP+ ──────────────────────────────────────────────────────────── + { pid: "SEI-SFP-10G-SR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 300, reachLabel: "SR", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "10GBASE-SR", notes: "Sumitomo Electric 10G SFP+ SR 300m MMF" }, + { pid: "SEI-SFP-10G-LR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 10000, reachLabel: "LR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "10GBASE-LR", notes: "Sumitomo Electric 10G SFP+ LR 10km SMF" }, + { pid: "SEI-SFP-10G-ER", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 40000, reachLabel: "ER", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "10GBASE-ER", notes: "Sumitomo Electric 10G SFP+ ER 40km SMF" }, + { pid: "SEI-SFP-10G-ZR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 80000, reachLabel: "ZR", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "10GBASE-ZR", notes: "Sumitomo Electric 10G SFP+ ZR 80km SMF" }, + + // ── 25G SFP28 ─────────────────────────────────────────────────────────── + { pid: "SEI-SFP28-25G-SR", formFactor: "SFP28", speedGbps: 25, speed: "25G", reachMeters: 100, reachLabel: "SR", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "25GBASE-SR", notes: "Sumitomo Electric 25G SFP28 SR 100m MMF" }, + { pid: "SEI-SFP28-25G-LR", formFactor: "SFP28", speedGbps: 25, speed: "25G", reachMeters: 10000, reachLabel: "LR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "25GBASE-LR", notes: "Sumitomo Electric 25G SFP28 LR 10km SMF" }, + + // ── 40G QSFP+ ─────────────────────────────────────────────────────────── + { pid: "SEI-QSFP-40G-SR4", formFactor: "QSFP+", speedGbps: 40, speed: "40G", reachMeters: 150, reachLabel: "SR4", fiberType: "MMF", connector: "MPO", wavelengths: "850nm", standard: "40GBASE-SR4", notes: "Sumitomo Electric 40G QSFP+ SR4 150m MMF" }, + { pid: "SEI-QSFP-40G-LR4", formFactor: "QSFP+", speedGbps: 40, speed: "40G", reachMeters: 10000, reachLabel: "LR4", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "40GBASE-LR4", notes: "Sumitomo Electric 40G QSFP+ LR4 10km SMF" }, + + // ── 100G QSFP28 ───────────────────────────────────────────────────────── + { pid: "SEI-QSFP28-100G-SR4", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 100, reachLabel: "SR4", fiberType: "MMF", connector: "MPO", wavelengths: "850nm", standard: "100GBASE-SR4", notes: "Sumitomo Electric 100G QSFP28 SR4 100m MMF" }, + { pid: "SEI-QSFP28-100G-LR4", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 10000, reachLabel: "LR4", fiberType: "SMF", connector: "LC", wavelengths: "1295-1310nm", standard: "100GBASE-LR4", notes: "Sumitomo Electric 100G QSFP28 LR4 10km SMF" }, + + // ── 400G QSFP-DD ──────────────────────────────────────────────────────── + { pid: "SEI-QSFP-DD-400G-DR4", formFactor: "QSFP-DD", speedGbps: 400, speed: "400G", reachMeters: 500, reachLabel: "DR4", fiberType: "SMF", connector: "MPO", wavelengths: "1310nm", standard: "400GBASE-DR4", notes: "Sumitomo Electric 400G QSFP-DD DR4 500m SMF" }, + { pid: "SEI-QSFP-DD-400G-FR4", formFactor: "QSFP-DD", speedGbps: 400, speed: "400G", reachMeters: 2000, reachLabel: "FR4", fiberType: "SMF", connector: "LC", wavelengths: "1271-1331nm", standard: "400GBASE-FR4", notes: "Sumitomo Electric 400G QSFP-DD FR4 2km SMF" }, + + // ── PON / Access (Telecom) ─────────────────────────────────────────────── + { pid: "SEI-SFP-GPON-OLT", formFactor: "SFP", speedGbps: 2.5, speed: "2.5G", reachMeters: 20000, reachLabel: "GPON", fiberType: "SMF", connector: "SC", wavelengths: "1490/1310nm", standard: "ITU-T G.984", notes: "Sumitomo Electric GPON OLT SFP TX1490/RX1310 20km" }, + { pid: "SEI-SFP-XGS-PON-OLT", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 20000, reachLabel: "XGS-PON",fiberType: "SMF", connector: "SC", wavelengths: "1577/1270nm", standard: "ITU-T G.9807", notes: "Sumitomo Electric XGS-PON OLT SFP+ TX1577/RX1270 20km" }, + + // ── DWDM (Telecom) ─────────────────────────────────────────────────────── + { pid: "SEI-DWDM-SFP10G-C", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 80000, reachLabel: "DWDM", fiberType: "SMF", connector: "LC", wavelengths: "C-band tunable", standard: "ITU-T G.694.1", notes: "Sumitomo Electric 10G DWDM SFP+ C-band tunable 80km" }, + + // ── CFP2-DCO (Telecom coherent) ────────────────────────────────────────── + { pid: "SEI-CFP2-DCO-100G", formFactor: "CFP2", speedGbps: 100, speed: "100G", reachMeters: 1000000, reachLabel: "DCO", fiberType: "SMF", connector: "LC", wavelengths: "C-band tunable", standard: "OIF CFP2-DCO", notes: "Sumitomo Electric 100G CFP2 DCO coherent C-band, 1000km" }, +]; + +export async function scrapeSumitomoElectricOem(): Promise { + console.log("=== Sumitomo Electric Networks OEM Transceiver Seed ===\n"); + + const vendorId = await ensureVendor( + "Sumitomo Electric Networks", + "oem", + "https://www.sumitomoelectric.com", + undefined + ); + + let inserted = 0; + let updated = 0; + let errors = 0; + + for (const p of SUMITOMO_PIDS) { + const slug = `sumitomo-electric-${p.pid.toLowerCase().replace(/[^a-z0-9]+/g, "-")}`; + const category = p.category ?? (TELECOM_PIDS.has(p.pid) ? "Telecom" : "DataCenter"); + try { + const res = await pool.query( + `INSERT INTO transceivers + (slug, part_number, vendor_id, form_factor, speed, speed_gbps, + reach_meters, reach_label, fiber_type, connector, wavelengths, + dom_support, ieee_reference, market_status, category, notes) + VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,true,$12,'Mainstream',$13,$14) + ON CONFLICT (slug) DO UPDATE SET + speed_gbps = EXCLUDED.speed_gbps, + reach_meters = CASE WHEN EXCLUDED.reach_meters > 0 THEN EXCLUDED.reach_meters ELSE transceivers.reach_meters END, + fiber_type = CASE WHEN EXCLUDED.fiber_type <> '' THEN EXCLUDED.fiber_type ELSE transceivers.fiber_type END, + wavelengths = COALESCE(EXCLUDED.wavelengths, transceivers.wavelengths), + updated_at = NOW() + RETURNING (xmax = 0) as was_inserted`, + [slug, p.pid, vendorId, p.formFactor, p.speed, p.speedGbps, + p.reachMeters, p.reachLabel, p.fiberType, p.connector, + p.wavelengths ?? null, p.standard ?? null, category, p.notes ?? null] + ); + if (res.rows[0]?.was_inserted) inserted++; else updated++; + } catch (err) { + console.warn(` Skip ${p.pid}: ${(err as Error).message.slice(0, 80)}`); + errors++; + } + } + + console.log(`\n=== Sumitomo Electric OEM Seed Complete ===`); + console.log(` Inserted: ${inserted}`); + console.log(` Updated: ${updated}`); + console.log(` Errors: ${errors}`); + console.log(` Total PIDs: ${SUMITOMO_PIDS.length}\n`); +} + +if (require.main === module) { + scrapeSumitomoElectricOem() + .then(() => pool.end()) + .catch((err) => { + console.error("Fatal:", err); + pool.end(); + process.exit(1); + }); +} diff --git a/packages/scraper/src/scrapers/supermicro-oem.ts b/packages/scraper/src/scrapers/supermicro-oem.ts new file mode 100644 index 0000000..b0d9b45 --- /dev/null +++ b/packages/scraper/src/scrapers/supermicro-oem.ts @@ -0,0 +1,123 @@ +/** + * Supermicro OEM Transceiver Catalog Seed + * + * Seeds Supermicro-branded transceiver PIDs for server/storage NICs + * across the SuperServer, SuperStorage, and SuperBlade product lines, + * including Active Optical Cables (AOC) and Direct Attach Copper (DAC). + * + * Sources: + * - Supermicro Networking Accessories Data Sheet (supermicro.com) + * - Supermicro AOC/DAC Cable Specification Sheet + * - Supermicro Server/NIC Optical Module Compatibility Matrix + * + * Run: tsx packages/scraper/src/scrapers/supermicro-oem.ts + * Cron: daily at 12:00 + */ + +import { pool, ensureVendor } from "../utils/db"; + +interface SupermicroPID { + pid: string; + formFactor: string; + speedGbps: number; + speed: string; + reachMeters: number; + reachLabel: string; + fiberType: string; + connector: string; + wavelengths?: string | null; + standard?: string; + notes?: string; +} + +const SUPERMICRO_PIDS: SupermicroPID[] = [ + // ── 1G SFP ────────────────────────────────────────────────────────────── + { pid: "SM-SFP-1G-SX", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 550, reachLabel: "SX", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "1000BASE-SX", notes: "Supermicro 1G SFP SX 550m MMF" }, + { pid: "SM-SFP-1G-LX", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 10000, reachLabel: "LX", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "1000BASE-LX", notes: "Supermicro 1G SFP LX 10km SMF" }, + { pid: "SM-SFP-1G-T", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 100, reachLabel: "T", fiberType: "DAC", connector: "RJ45", wavelengths: null, standard: "1000BASE-T", notes: "Supermicro 1G SFP copper RJ45" }, + { pid: "SM-SFP-GE-T", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 100, reachLabel: "T", fiberType: "DAC", connector: "RJ45", wavelengths: null, standard: "1000BASE-T", notes: "Supermicro 1G SFP GE-T copper RJ45 (alt PID)" }, + + // ── 10G SFP+ ──────────────────────────────────────────────────────────── + { pid: "SM-SFP-10G-SR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 300, reachLabel: "SR", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "10GBASE-SR", notes: "Supermicro 10G SFP+ SR 300m MMF" }, + { pid: "SM-SFP-10G-LR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 10000, reachLabel: "LR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "10GBASE-LR", notes: "Supermicro 10G SFP+ LR 10km SMF" }, + { pid: "SM-SFP-10G-T", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 30, reachLabel: "T", fiberType: "DAC", connector: "RJ45", wavelengths: null, standard: "10GBASE-T", notes: "Supermicro 10G SFP+ copper RJ45" }, + + // ── 25G SFP28 ─────────────────────────────────────────────────────────── + { pid: "SM-SFP28-25G-SR", formFactor: "SFP28", speedGbps: 25, speed: "25G", reachMeters: 100, reachLabel: "SR", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "25GBASE-SR", notes: "Supermicro 25G SFP28 SR 100m MMF" }, + { pid: "SM-SFP28-25G-LR", formFactor: "SFP28", speedGbps: 25, speed: "25G", reachMeters: 10000, reachLabel: "LR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "25GBASE-LR", notes: "Supermicro 25G SFP28 LR 10km SMF" }, + + // ── 100G QSFP28 ───────────────────────────────────────────────────────── + { pid: "SM-QSFP28-100G-SR4", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 100, reachLabel: "SR4", fiberType: "MMF", connector: "MPO", wavelengths: "850nm", standard: "100GBASE-SR4", notes: "Supermicro 100G QSFP28 SR4 100m MMF" }, + { pid: "SM-QSFP28-100G-LR4", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 10000, reachLabel: "LR4", fiberType: "SMF", connector: "LC", wavelengths: "1295-1310nm", standard: "100GBASE-LR4", notes: "Supermicro 100G QSFP28 LR4 10km SMF" }, + + // ── 400G QSFP-DD ──────────────────────────────────────────────────────── + { pid: "SM-QSFP-DD-400G-DR4",formFactor: "QSFP-DD",speedGbps: 400, speed: "400G", reachMeters: 500, reachLabel: "DR4", fiberType: "SMF", connector: "MPO", wavelengths: "1310nm", standard: "400GBASE-DR4", notes: "Supermicro 400G QSFP-DD DR4 500m SMF" }, + { pid: "SM-QSFP-DD-400G-SR8",formFactor: "QSFP-DD",speedGbps: 400, speed: "400G", reachMeters: 100, reachLabel: "SR8", fiberType: "MMF", connector: "MPO", wavelengths: "850nm", standard: "400GBASE-SR8", notes: "Supermicro 400G QSFP-DD SR8 100m MMF" }, + + // ── AOC — Active Optical Cables ───────────────────────────────────────── + { pid: "SM-AOC-10G-1M", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 1, reachLabel: "AOC-1M", fiberType: "AOC", connector: "LC", wavelengths: null, standard: "10GBASE-SR", notes: "Supermicro 10G Active Optical Cable 1m" }, + { pid: "SM-AOC-10G-3M", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 3, reachLabel: "AOC-3M", fiberType: "AOC", connector: "LC", wavelengths: null, standard: "10GBASE-SR", notes: "Supermicro 10G Active Optical Cable 3m" }, + { pid: "SM-AOC-25G-3M", formFactor: "SFP28", speedGbps: 25, speed: "25G", reachMeters: 3, reachLabel: "AOC-3M", fiberType: "AOC", connector: "LC", wavelengths: null, standard: "25GBASE-SR", notes: "Supermicro 25G Active Optical Cable 3m" }, + + // ── DAC — Direct Attach Copper ────────────────────────────────────────── + { pid: "SM-DAC-100G-1M", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 1, reachLabel: "DAC-1M", fiberType: "DAC", connector: "QSFP28", wavelengths: null, standard: "100GBASE-CR4", notes: "Supermicro 100G Direct Attach Copper 1m" }, + { pid: "SM-DAC-100G-3M", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 3, reachLabel: "DAC-3M", fiberType: "DAC", connector: "QSFP28", wavelengths: null, standard: "100GBASE-CR4", notes: "Supermicro 100G Direct Attach Copper 3m" }, +]; + +export async function scrapeSupermicroOem(): Promise { + console.log("=== Supermicro OEM Transceiver Seed ===\n"); + + const vendorId = await ensureVendor( + "Supermicro", + "oem", + "https://www.supermicro.com", + undefined + ); + + let inserted = 0; + let updated = 0; + let errors = 0; + + for (const p of SUPERMICRO_PIDS) { + const slug = `supermicro-${p.pid.toLowerCase().replace(/[^a-z0-9]+/g, "-")}`; + try { + const res = await pool.query( + `INSERT INTO transceivers + (slug, part_number, vendor_id, form_factor, speed, speed_gbps, + reach_meters, reach_label, fiber_type, connector, wavelengths, + dom_support, ieee_reference, market_status, category, notes) + VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,true,$12,'Mainstream','DataCenter',$13) + ON CONFLICT (slug) DO UPDATE SET + speed_gbps = EXCLUDED.speed_gbps, + reach_meters = CASE WHEN EXCLUDED.reach_meters > 0 THEN EXCLUDED.reach_meters ELSE transceivers.reach_meters END, + fiber_type = CASE WHEN EXCLUDED.fiber_type <> '' THEN EXCLUDED.fiber_type ELSE transceivers.fiber_type END, + wavelengths = COALESCE(EXCLUDED.wavelengths, transceivers.wavelengths), + updated_at = NOW() + RETURNING (xmax = 0) as was_inserted`, + [slug, p.pid, vendorId, p.formFactor, p.speed, p.speedGbps, + p.reachMeters, p.reachLabel, p.fiberType, p.connector, + p.wavelengths ?? null, p.standard ?? null, p.notes ?? null] + ); + if (res.rows[0]?.was_inserted) inserted++; else updated++; + } catch (err) { + console.warn(` Skip ${p.pid}: ${(err as Error).message.slice(0, 80)}`); + errors++; + } + } + + console.log(`\n=== Supermicro OEM Seed Complete ===`); + console.log(` Inserted: ${inserted}`); + console.log(` Updated: ${updated}`); + console.log(` Errors: ${errors}`); + console.log(` Total PIDs: ${SUPERMICRO_PIDS.length}\n`); +} + +if (require.main === module) { + scrapeSupermicroOem() + .then(() => pool.end()) + .catch((err) => { + console.error("Fatal:", err); + pool.end(); + process.exit(1); + }); +} diff --git a/packages/scraper/src/scrapers/sycamore-oem.ts b/packages/scraper/src/scrapers/sycamore-oem.ts new file mode 100644 index 0000000..53123a7 --- /dev/null +++ b/packages/scraper/src/scrapers/sycamore-oem.ts @@ -0,0 +1,128 @@ +/** + * Sycamore Networks OEM Transceiver Catalog Seed + * + * Seeds Sycamore-branded transceiver PIDs for SN series WDM platforms. + * + * Sources: + * - Sycamore Networks SN Series Product Portfolio (sycamorenet.com) + * - Sycamore SN Series Hardware Installation & Interface Guide + * + * Run: tsx packages/scraper/src/scrapers/sycamore-oem.ts + * Cron: daily at 20:15 + */ + +import { pool, ensureVendor } from "../utils/db"; + +interface SycamorePID { + pid: string; + formFactor: string; + speedGbps: number; + speed: string; + reachMeters: number; + reachLabel: string; + fiberType: string; + connector: string; + wavelengths?: string; + standard?: string; + category?: string; + notes?: string; +} + +const SYCAMORE_PIDS: SycamorePID[] = [ + // ── 1G SFP ────────────────────────────────────────────────────────────── + { pid: "SYC-SFP-1G-SX", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 550, reachLabel: "SX", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "1000BASE-SX" }, + { pid: "SYC-SFP-1G-LX", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 10000, reachLabel: "LX", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "1000BASE-LX" }, + { pid: "SYC-SFP-1G-ZX", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 80000, reachLabel: "ZX", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "1000BASE-ZX" }, + + // ── 10G SFP+ ──────────────────────────────────────────────────────────── + { pid: "SYC-SFP-10G-SR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 300, reachLabel: "SR", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "10GBASE-SR" }, + { pid: "SYC-SFP-10G-LR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 10000, reachLabel: "LR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "10GBASE-LR" }, + { pid: "SYC-SFP-10G-ER", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 40000, reachLabel: "ER", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "10GBASE-ER" }, + { pid: "SYC-SFP-10G-ZR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 80000, reachLabel: "ZR", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "10GBASE-ZR" }, + + // ── 10G DWDM SFP+ ─────────────────────────────────────────────────────── + { pid: "SYC-SFP-10G-DW-TUNE", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 80000, reachLabel: "DWDM", fiberType: "SMF", connector: "LC", wavelengths: "C-band DWDM", category: "Telecom", notes: "Sycamore 10G DWDM tunable SFP+" }, + + // ── 100G QSFP28 ───────────────────────────────────────────────────────── + { pid: "SYC-QSFP28-100G-SR4", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 100, reachLabel: "SR4", fiberType: "MMF", connector: "MPO", wavelengths: "850nm", standard: "100GBASE-SR4" }, + { pid: "SYC-QSFP28-100G-LR4", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 10000, reachLabel: "LR4", fiberType: "SMF", connector: "LC", wavelengths: "1295-1310nm", standard: "100GBASE-LR4" }, + { pid: "SYC-QSFP28-100G-CWDM4",formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 2000, reachLabel: "CWDM4", fiberType: "SMF", connector: "LC", wavelengths: "1271-1331nm", standard: "100GBASE-CWDM4" }, + + // ── 100G CFP2 Coherent ─────────────────────────────────────────────────── + { pid: "SYC-CFP2-100G-DCO", formFactor: "CFP2", speedGbps: 100, speed: "100G", reachMeters: 1500000, reachLabel: "DCO", fiberType: "SMF", connector: "LC", wavelengths: "C-band", category: "Telecom", notes: "Sycamore 100G CFP2 DCO coherent" }, + + // ── 400G QSFP-DD ──────────────────────────────────────────────────────── + { pid: "SYC-QSFPDD-400G-FR4", formFactor: "QSFP-DD", speedGbps: 400, speed: "400G", reachMeters: 2000, reachLabel: "FR4", fiberType: "SMF", connector: "LC", wavelengths: "1271-1331nm", standard: "400GBASE-FR4" }, + { pid: "SYC-QSFPDD-400G-LR4", formFactor: "QSFP-DD", speedGbps: 400, speed: "400G", reachMeters: 10000, reachLabel: "LR4", fiberType: "SMF", connector: "LC", wavelengths: "1295-1310nm", standard: "400GBASE-LR4" }, + { pid: "SYC-QSFPDD-400G-ZR", formFactor: "QSFP-DD", speedGbps: 400, speed: "400G", reachMeters: 120000, reachLabel: "ZR", fiberType: "SMF", connector: "LC", wavelengths: "C-band", standard: "400ZR", category: "Telecom", notes: "Sycamore 400G ZR coherent QSFP-DD" }, + + // ── DAC ───────────────────────────────────────────────────────────────── + { pid: "SYC-DAC-10G-1M", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 1, reachLabel: "DAC-1M", fiberType: "DAC", connector: "SFP+" }, + { pid: "SYC-DAC-100G-1M", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 1, reachLabel: "DAC-1M", fiberType: "DAC", connector: "QSFP28" }, +]; + +// PIDs that use 'Telecom' category (coherent/DWDM) +const TELECOM_PIDS = new Set([ + "SYC-SFP-10G-DW-TUNE", + "SYC-CFP2-100G-DCO", + "SYC-QSFPDD-400G-ZR", +]); + +export async function scrapeSycamoreOem(): Promise { + console.log("=== Sycamore Networks OEM Transceiver Seed ===\n"); + + const vendorId = await ensureVendor( + "Sycamore Networks", + "oem", + "https://www.sycamorenet.com", + undefined + ); + + let inserted = 0; + let updated = 0; + let errors = 0; + + for (const p of SYCAMORE_PIDS) { + const slug = `sycamore-${p.pid.toLowerCase().replace(/[^a-z0-9]+/g, "-")}`; + const category = p.category ?? (TELECOM_PIDS.has(p.pid) ? "Telecom" : "DataCenter"); + try { + const res = await pool.query( + `INSERT INTO transceivers + (slug, part_number, vendor_id, form_factor, speed, speed_gbps, + reach_meters, reach_label, fiber_type, connector, wavelengths, + dom_support, ieee_reference, market_status, category, notes) + VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,true,$12,'Mainstream',$13,$14) + ON CONFLICT (slug) DO UPDATE SET + speed_gbps = EXCLUDED.speed_gbps, + reach_meters = CASE WHEN EXCLUDED.reach_meters > 0 THEN EXCLUDED.reach_meters ELSE transceivers.reach_meters END, + fiber_type = CASE WHEN EXCLUDED.fiber_type <> '' THEN EXCLUDED.fiber_type ELSE transceivers.fiber_type END, + wavelengths = COALESCE(EXCLUDED.wavelengths, transceivers.wavelengths), + updated_at = NOW() + RETURNING (xmax = 0) as was_inserted`, + [slug, p.pid, vendorId, p.formFactor, p.speed, p.speedGbps, + p.reachMeters, p.reachLabel, p.fiberType, p.connector, + p.wavelengths ?? null, p.standard ?? null, category, p.notes ?? null] + ); + if (res.rows[0]?.was_inserted) inserted++; else updated++; + } catch (err) { + console.warn(` Skip ${p.pid}: ${(err as Error).message.slice(0, 80)}`); + errors++; + } + } + + console.log(`\n=== Sycamore Networks OEM Seed Complete ===`); + console.log(` Inserted: ${inserted}`); + console.log(` Updated: ${updated}`); + console.log(` Errors: ${errors}`); + console.log(` Total PIDs: ${SYCAMORE_PIDS.length}\n`); +} + +if (require.main === module) { + scrapeSycamoreOem() + .then(() => pool.end()) + .catch((err) => { + console.error("Fatal:", err); + pool.end(); + process.exit(1); + }); +} diff --git a/packages/scraper/src/scrapers/tejas-networks-oem.ts b/packages/scraper/src/scrapers/tejas-networks-oem.ts new file mode 100644 index 0000000..5ad524c --- /dev/null +++ b/packages/scraper/src/scrapers/tejas-networks-oem.ts @@ -0,0 +1,141 @@ +/** + * Tejas Networks OEM Transceiver Catalog Seed + * + * Seeds Tejas Networks-branded transceiver PIDs for OTN, MPLS-TP, and + * packet-optical transport platforms (TJ1400, TJ1600, TJ100 series). + * Tejas Networks is an Indian telecom equipment vendor, now a Tata Group company. + * + * Sources: + * - Tejas Networks TJ1400/TJ1600 Optical Module Compatibility List (tejasnetworks.com) + * - Tejas Networks OTN Platform Optics Portfolio + * - Tejas Networks CWDM/DWDM Module Guide + * + * Run: tsx packages/scraper/src/scrapers/tejas-networks-oem.ts + * Cron: daily at 00:00 + */ + +import { pool, ensureVendor } from "../utils/db"; + +interface TejasNetworksPID { + pid: string; + formFactor: string; + speedGbps: number; + speed: string; + reachMeters: number; + reachLabel: string; + fiberType: string; + connector: string; + wavelengths?: string; + standard?: string; + category?: string; + notes?: string; +} + +const TEJAS_NETWORKS_PIDS: TejasNetworksPID[] = [ + // ── 1G SFP ─────────────────────────────────────────────────────────────── + { pid: "SFP-1G-SX", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 550, reachLabel: "SX", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "1000BASE-SX" }, + { pid: "SFP-1G-LX", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 10000, reachLabel: "LX", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "1000BASE-LX" }, + + // ── 10G SFP+ ───────────────────────────────────────────────────────────── + { pid: "SFP-10G-SR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 300, reachLabel: "SR", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "10GBASE-SR" }, + { pid: "SFP-10G-LR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 10000, reachLabel: "LR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "10GBASE-LR" }, + { pid: "SFP-10G-ER", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 40000, reachLabel: "ER", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "10GBASE-ER" }, + { pid: "SFP-10G-ZR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 80000, reachLabel: "ZR", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "10GBASE-ZR" }, + + // ── SONET/SDH SFP ───────────────────────────────────────────────────────── + { pid: "SFP-OC3-SR", formFactor: "SFP", speedGbps: 0.155,speed: "OC3", reachMeters: 2000, reachLabel: "SR", fiberType: "MMF", connector: "LC", wavelengths: "850nm", category: "Telecom", notes: "Tejas OC-3/STM-1 155M SFP SR" }, + { pid: "SFP-OC3-LR", formFactor: "SFP", speedGbps: 0.155,speed: "OC3", reachMeters: 40000, reachLabel: "LR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", category: "Telecom", notes: "Tejas OC-3/STM-1 155M SFP LR" }, + { pid: "SFP-OC12-SR", formFactor: "SFP", speedGbps: 0.622,speed: "OC12", reachMeters: 2000, reachLabel: "SR", fiberType: "MMF", connector: "LC", wavelengths: "850nm", category: "Telecom", notes: "Tejas OC-12/STM-4 622M SFP SR" }, + { pid: "SFP-OC12-LR", formFactor: "SFP", speedGbps: 0.622,speed: "OC12", reachMeters: 40000, reachLabel: "LR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", category: "Telecom", notes: "Tejas OC-12/STM-4 622M SFP LR" }, + { pid: "SFP-OC48-SR", formFactor: "SFP", speedGbps: 2.5, speed: "OC48", reachMeters: 2000, reachLabel: "SR", fiberType: "MMF", connector: "LC", wavelengths: "850nm", category: "Telecom", notes: "Tejas OC-48/STM-16 2.488G SFP SR" }, + + // ── OTN SFP+ ────────────────────────────────────────────────────────────── + { pid: "SFP-OTU1-GE", formFactor: "SFP", speedGbps: 1.25, speed: "OTU1", reachMeters: 10000, reachLabel: "LR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", category: "Telecom", notes: "Tejas OTU1 GbE mapped SFP for OTN transport" }, + { pid: "SFP-OTU2-10G", formFactor: "SFP+", speedGbps: 10, speed: "OTU2", reachMeters: 40000, reachLabel: "LR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", category: "Telecom", notes: "Tejas OTU2 10.709G SFP+ for OTN transport" }, + + // ── CWDM SFP ────────────────────────────────────────────────────────────── + { pid: "CWDM-SFP-1550", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 60000, reachLabel: "CWDM", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", category: "Telecom", notes: "Tejas CWDM SFP 1550nm for metro/access" }, + + // ── DWDM SFP+ ───────────────────────────────────────────────────────────── + { pid: "DWDM-SFP10G-C", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 80000, reachLabel: "DWDM", fiberType: "SMF", connector: "LC", wavelengths: "C-band ITU DWDM", category: "Telecom", notes: "Tejas DWDM 10G SFP+ C-band for OTN line side" }, + + // ── 40G QSFP+ ───────────────────────────────────────────────────────────── + { pid: "QSFP-40G-LR4", formFactor: "QSFP+", speedGbps: 40, speed: "40G", reachMeters: 10000, reachLabel: "LR4", fiberType: "SMF", connector: "LC", wavelengths: "1295-1310nm", standard: "40GBASE-LR4" }, + + // ── 100G QSFP28 / CFP ───────────────────────────────────────────────────── + { pid: "QSFP-100G-LR4", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 10000, reachLabel: "LR4", fiberType: "SMF", connector: "LC", wavelengths: "1295-1310nm", standard: "100GBASE-LR4" }, + { pid: "CFP-100G-LR4", formFactor: "CFP", speedGbps: 100, speed: "100G", reachMeters: 10000, reachLabel: "LR4", fiberType: "SMF", connector: "LC", wavelengths: "1295-1310nm", category: "Telecom", notes: "Tejas 100G CFP LR4 for OTN/MPLS-TP line cards" }, +]; + +// PIDs that use 'Telecom' category (SONET/SDH, OTN, CWDM, DWDM, CFP line-side) +const TELECOM_PIDS = new Set([ + "SFP-OC3-SR", + "SFP-OC3-LR", + "SFP-OC12-SR", + "SFP-OC12-LR", + "SFP-OC48-SR", + "SFP-OTU1-GE", + "SFP-OTU2-10G", + "CWDM-SFP-1550", + "DWDM-SFP10G-C", + "CFP-100G-LR4", +]); + +export async function scrapeTejasNetworksOem(): Promise { + console.log("=== Tejas Networks OEM Transceiver Seed ===\n"); + + const vendorId = await ensureVendor( + "Tejas Networks", + "oem", + "https://www.tejasnetworks.com", + undefined + ); + + let inserted = 0; + let updated = 0; + let errors = 0; + + for (const p of TEJAS_NETWORKS_PIDS) { + const slug = `tejas-${p.pid.toLowerCase().replace(/[^a-z0-9]+/g, "-")}`; + const category = p.category ?? (TELECOM_PIDS.has(p.pid) ? "Telecom" : "DataCenter"); + try { + const res = await pool.query( + `INSERT INTO transceivers + (slug, part_number, vendor_id, form_factor, speed, speed_gbps, + reach_meters, reach_label, fiber_type, connector, wavelengths, + dom_support, ieee_reference, market_status, category, notes) + VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,true,$12,'Mainstream',$13,$14) + ON CONFLICT (slug) DO UPDATE SET + speed_gbps = EXCLUDED.speed_gbps, + reach_meters = CASE WHEN EXCLUDED.reach_meters > 0 THEN EXCLUDED.reach_meters ELSE transceivers.reach_meters END, + fiber_type = CASE WHEN EXCLUDED.fiber_type <> '' THEN EXCLUDED.fiber_type ELSE transceivers.fiber_type END, + wavelengths = COALESCE(EXCLUDED.wavelengths, transceivers.wavelengths), + updated_at = NOW() + RETURNING (xmax = 0) as was_inserted`, + [slug, p.pid, vendorId, p.formFactor, p.speed, p.speedGbps, + p.reachMeters, p.reachLabel, p.fiberType, p.connector, + p.wavelengths ?? null, p.standard ?? null, category, p.notes ?? null] + ); + if (res.rows[0]?.was_inserted) inserted++; else updated++; + } catch (err) { + console.warn(` Skip ${p.pid}: ${(err as Error).message.slice(0, 80)}`); + errors++; + } + } + + console.log(`\n=== Tejas Networks OEM Seed Complete ===`); + console.log(` Inserted: ${inserted}`); + console.log(` Updated: ${updated}`); + console.log(` Errors: ${errors}`); + console.log(` Total PIDs: ${TEJAS_NETWORKS_PIDS.length}\n`); +} + +if (require.main === module) { + scrapeTejasNetworksOem() + .then(() => pool.end()) + .catch((err) => { + console.error("Fatal:", err); + pool.end(); + process.exit(1); + }); +} diff --git a/packages/scraper/src/scrapers/telco-systems-oem.ts b/packages/scraper/src/scrapers/telco-systems-oem.ts new file mode 100644 index 0000000..fe161f7 --- /dev/null +++ b/packages/scraper/src/scrapers/telco-systems-oem.ts @@ -0,0 +1,145 @@ +/** + * TELCO Systems OEM Transceiver Catalog Seed + * + * Seeds TELCO Systems branded transceiver PIDs for carrier Ethernet and + * MEF-compliant networking equipment. TELCO Systems is a RAD subsidiary + * specializing in carrier Ethernet, MEF CE 2.0 certified CPE/NID devices, + * and optical transport platforms including the T-Metro, BEF, and SAMBA + * product families. + * + * Sources: + * - TELCO Systems T-Metro 8100 Optical Interface Specifications + * - TELCO Systems BEF Series Compatible Transceiver Guide + * - TELCO Systems SAMBA MEF CE 2.0 Platform Transceiver Matrix + * - TELCO Systems/RAD Product Compatibility Reference (telco.com/products) + * + * Run: tsx packages/scraper/src/scrapers/telco-systems-oem.ts + * Cron: daily at 01:00 + */ + +import { pool, ensureVendor } from "../utils/db"; + +interface TelcoSystemsPID { + pid: string; + formFactor: string; + speedGbps: number; + speed: string; + reachMeters: number; + reachLabel: string; + fiberType: string; + connector: string; + wavelengths?: string; + standard?: string; + category?: string; + notes?: string; +} + +const TELCO_SYSTEMS_PIDS: TelcoSystemsPID[] = [ + // ── 1G SFP ────────────────────────────────────────────────────────────── + { pid: "SFP-1G-SX", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 550, reachLabel: "SX", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "1000BASE-SX" }, + { pid: "SFP-1G-LX", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 10000, reachLabel: "LX", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "1000BASE-LX" }, + { pid: "SFP-1G-T", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 100, reachLabel: "1000BASE-T", fiberType: "Cu", connector: "RJ45" }, + + // ── 10G SFP+ ──────────────────────────────────────────────────────────── + { pid: "SFP-10G-SR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 300, reachLabel: "SR", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "10GBASE-SR" }, + { pid: "SFP-10G-LR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 10000, reachLabel: "LR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "10GBASE-LR" }, + { pid: "SFP-10G-ER", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 40000, reachLabel: "ER", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "10GBASE-ER" }, + { pid: "SFP-10G-ZR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 80000, reachLabel: "ZR", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "10GBASE-ZR", category: "Telecom", notes: "TELCO Systems 80km ZR SFP+ for T-Metro/BEF extended reach uplinks" }, + + // ── SDH/SONET SFP (T-Metro OC-3/OC-12 interfaces) ──────────────────────── + { pid: "SFP-OC3-SR", formFactor: "SFP", speedGbps: 0.155, speed: "OC-3/STM-1", reachMeters: 2000, reachLabel: "SR", fiberType: "MMF", connector: "LC", wavelengths: "1310nm", standard: "OC-3/STM-1", category: "Telecom", notes: "TELCO Systems T-Metro OC-3 / STM-1 short reach SFP" }, + { pid: "SFP-OC3-LR", formFactor: "SFP", speedGbps: 0.155, speed: "OC-3/STM-1", reachMeters: 40000, reachLabel: "LR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "OC-3/STM-1", category: "Telecom", notes: "TELCO Systems T-Metro OC-3 / STM-1 long reach SFP" }, + { pid: "SFP-OC12-SR", formFactor: "SFP", speedGbps: 0.622, speed: "OC-12/STM-4", reachMeters: 2000, reachLabel: "SR", fiberType: "MMF", connector: "LC", wavelengths: "1310nm", standard: "OC-12/STM-4", category: "Telecom", notes: "TELCO Systems T-Metro OC-12 / STM-4 short reach SFP" }, + { pid: "SFP-OC12-LR", formFactor: "SFP", speedGbps: 0.622, speed: "OC-12/STM-4", reachMeters: 40000, reachLabel: "LR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "OC-12/STM-4", category: "Telecom", notes: "TELCO Systems T-Metro OC-12 / STM-4 long reach SFP" }, + + // ── 40G QSFP+ ─────────────────────────────────────────────────────────── + { pid: "QSFP-40G-LR4", formFactor: "QSFP+", speedGbps: 40, speed: "40G", reachMeters: 10000, reachLabel: "LR4", fiberType: "SMF", connector: "LC", wavelengths: "1270-1330nm", standard: "40GBASE-LR4" }, + + // ── 100G QSFP28 ───────────────────────────────────────────────────────── + { pid: "QSFP-100G-LR4", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 10000, reachLabel: "LR4", fiberType: "SMF", connector: "LC", wavelengths: "1295-1310nm", standard: "100GBASE-LR4" }, + + // ── CWDM SFP ───────────────────────────────────────────────────────────── + { pid: "SFP-CWDM-1550", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 40000, reachLabel: "CWDM-1550", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "1000BASE-CWDM", category: "Telecom", notes: "TELCO Systems CWDM SFP 1550nm for WDM uplinks on BEF/SAMBA" }, + + // ── DWDM SFP+ ──────────────────────────────────────────────────────────── + { pid: "DWDM-SFP-C", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 80000, reachLabel: "DWDM", fiberType: "SMF", connector: "LC", wavelengths: "C-band DWDM", category: "Telecom", notes: "TELCO Systems C-band DWDM SFP+ fixed-wavelength for WDM transport" }, + + // ── BiDi SFP ───────────────────────────────────────────────────────────── + { pid: "SFP-GE-BIDI-1310", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 20000, reachLabel: "BiDi-1310", fiberType: "SMF", connector: "LC", wavelengths: "1310nm TX / 1490nm RX", standard: "1000BASE-BX", category: "Telecom", notes: "TELCO Systems BiDi SFP 1310TX/1490RX single-fiber for NID backhaul" }, + + // ── 25G SFP28 ─────────────────────────────────────────────────────────── + { pid: "SFP-25G-LR", formFactor: "SFP28", speedGbps: 25, speed: "25G", reachMeters: 10000, reachLabel: "LR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "25GBASE-LR" }, + + // ── 100G CFP Coherent ──────────────────────────────────────────────────── + { pid: "CFP-100G-LR4", formFactor: "CFP", speedGbps: 100, speed: "100G", reachMeters: 10000, reachLabel: "LR4", fiberType: "SMF", connector: "LC", wavelengths: "1295-1310nm", standard: "100GBASE-LR4", category: "Telecom", notes: "TELCO Systems CFP 100G LR4 for T-Metro 100G coherent transport interfaces" }, +]; + +// PIDs that belong to the Telecom category (OC-3/12, CWDM, DWDM, CFP, BiDi, ZR) +const TELECOM_PIDS = new Set([ + "SFP-10G-ZR", + "SFP-OC3-SR", "SFP-OC3-LR", + "SFP-OC12-SR", "SFP-OC12-LR", + "SFP-CWDM-1550", + "DWDM-SFP-C", + "SFP-GE-BIDI-1310", + "CFP-100G-LR4", +]); + +export async function scrapeTelcoSystemsOem(): Promise { + console.log("=== TELCO Systems OEM Transceiver Seed ===\n"); + + const vendorId = await ensureVendor( + "TELCO Systems", + "oem", + "https://www.telco.com", + undefined + ); + + let inserted = 0; + let updated = 0; + let errors = 0; + + for (const p of TELCO_SYSTEMS_PIDS) { + const slug = `telco-systems-${p.pid.toLowerCase().replace(/[^a-z0-9]+/g, "-")}`; + const category = p.category ?? (TELECOM_PIDS.has(p.pid) ? "Telecom" : "DataCenter"); + try { + const res = await pool.query( + `INSERT INTO transceivers + (slug, part_number, vendor_id, form_factor, speed, speed_gbps, + reach_meters, reach_label, fiber_type, connector, wavelengths, + dom_support, ieee_reference, market_status, category, notes) + VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,true,$12,'Mainstream',$13,$14) + ON CONFLICT (slug) DO UPDATE SET + speed_gbps = EXCLUDED.speed_gbps, + reach_meters = CASE WHEN EXCLUDED.reach_meters > 0 THEN EXCLUDED.reach_meters ELSE transceivers.reach_meters END, + fiber_type = CASE WHEN EXCLUDED.fiber_type <> '' THEN EXCLUDED.fiber_type ELSE transceivers.fiber_type END, + wavelengths = COALESCE(EXCLUDED.wavelengths, transceivers.wavelengths), + updated_at = NOW() + RETURNING (xmax = 0) as was_inserted`, + [slug, p.pid, vendorId, p.formFactor, p.speed, p.speedGbps, + p.reachMeters, p.reachLabel, p.fiberType, p.connector, + p.wavelengths ?? null, p.standard ?? null, category, p.notes ?? null] + ); + if (res.rows[0]?.was_inserted) inserted++; else updated++; + } catch (err) { + console.warn(` Skip ${p.pid}: ${(err as Error).message.slice(0, 80)}`); + errors++; + } + } + + console.log(`\n=== TELCO Systems OEM Seed Complete ===`); + console.log(` Inserted: ${inserted}`); + console.log(` Updated: ${updated}`); + console.log(` Errors: ${errors}`); + console.log(` Total PIDs: ${TELCO_SYSTEMS_PIDS.length}\n`); +} + +if (require.main === module) { + scrapeTelcoSystemsOem() + .then(() => pool.end()) + .catch((err) => { + console.error("Fatal:", err); + pool.end(); + process.exit(1); + }); +} diff --git a/packages/scraper/src/scrapers/teleste-oem.ts b/packages/scraper/src/scrapers/teleste-oem.ts new file mode 100644 index 0000000..a6a7431 --- /dev/null +++ b/packages/scraper/src/scrapers/teleste-oem.ts @@ -0,0 +1,139 @@ +/** + * Teleste OEM Transceiver Catalog Seed + * + * Seeds Teleste-branded transceiver PIDs for CATV/HFC hybrid-fibre-coax + * infrastructure, broadband access, and optical transport platforms. + * Teleste is a Finnish vendor specialising in cable TV and broadband networks. + * + * Sources: + * - Teleste Optical Products Portfolio (teleste.com) + * - Teleste HFC Network Optics Datasheet + * - Teleste CWDM/BiDi Access Module Guide + * + * Run: tsx packages/scraper/src/scrapers/teleste-oem.ts + * Cron: daily at 23:45 + */ + +import { pool, ensureVendor } from "../utils/db"; + +interface TelestePID { + pid: string; + formFactor: string; + speedGbps: number; + speed: string; + reachMeters: number; + reachLabel: string; + fiberType: string; + connector: string; + wavelengths?: string; + standard?: string; + category?: string; + notes?: string; +} + +const TELESTE_PIDS: TelestePID[] = [ + // ── 1G SFP ─────────────────────────────────────────────────────────────── + { pid: "SFP-1G-SX", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 550, reachLabel: "SX", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "1000BASE-SX" }, + { pid: "SFP-1G-LX", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 10000, reachLabel: "LX", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "1000BASE-LX" }, + { pid: "SFP-GE-T", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 100, reachLabel: "RJ45", fiberType: "Cu", connector: "RJ45", standard: "1000BASE-T" }, + + // ── 10G SFP+ ───────────────────────────────────────────────────────────── + { pid: "SFP-10G-SR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 300, reachLabel: "SR", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "10GBASE-SR" }, + { pid: "SFP-10G-LR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 10000, reachLabel: "LR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "10GBASE-LR" }, + { pid: "SFP-10G-ER", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 40000, reachLabel: "ER", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "10GBASE-ER" }, + + // ── BiDi SFP ───────────────────────────────────────────────────────────── + { pid: "SFP-BIDI-1310-1550", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 20000, reachLabel: "BIDI", fiberType: "SMF", connector: "LC", wavelengths: "1310/1550nm", category: "Telecom", notes: "Teleste 1G BiDi SFP 1310Tx/1550Rx for HFC upstream/downstream" }, + + // ── 1G CWDM SFP (HFC access wavelengths) ───────────────────────────────── + { pid: "SFP-CWDM-1470", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 40000, reachLabel: "CWDM", fiberType: "SMF", connector: "LC", wavelengths: "1470nm", category: "Telecom", notes: "Teleste CWDM SFP 1470nm for HFC overlay" }, + { pid: "SFP-CWDM-1490", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 40000, reachLabel: "CWDM", fiberType: "SMF", connector: "LC", wavelengths: "1490nm", category: "Telecom", notes: "Teleste CWDM SFP 1490nm for HFC overlay" }, + { pid: "SFP-CWDM-1510", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 40000, reachLabel: "CWDM", fiberType: "SMF", connector: "LC", wavelengths: "1510nm", category: "Telecom", notes: "Teleste CWDM SFP 1510nm for HFC overlay" }, + { pid: "SFP-CWDM-1530", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 40000, reachLabel: "CWDM", fiberType: "SMF", connector: "LC", wavelengths: "1530nm", category: "Telecom", notes: "Teleste CWDM SFP 1530nm for HFC overlay" }, + { pid: "SFP-CWDM-1550", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 60000, reachLabel: "CWDM", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", category: "Telecom", notes: "Teleste CWDM SFP 1550nm for HFC overlay" }, + { pid: "SFP-CWDM-1570", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 40000, reachLabel: "CWDM", fiberType: "SMF", connector: "LC", wavelengths: "1570nm", category: "Telecom", notes: "Teleste CWDM SFP 1570nm for HFC overlay" }, + { pid: "SFP-CWDM-1590", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 40000, reachLabel: "CWDM", fiberType: "SMF", connector: "LC", wavelengths: "1590nm", category: "Telecom", notes: "Teleste CWDM SFP 1590nm for HFC overlay" }, + { pid: "SFP-CWDM-1610", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 40000, reachLabel: "CWDM", fiberType: "SMF", connector: "LC", wavelengths: "1610nm", category: "Telecom", notes: "Teleste CWDM SFP 1610nm for HFC overlay" }, + + // ── CATV Analogue Optical ───────────────────────────────────────────────── + { pid: "SFP-CATV-1550", formFactor: "SFP", speedGbps: 1, speed: "CATV", reachMeters: 30000, reachLabel: "CATV", fiberType: "SMF", connector: "SC", wavelengths: "1550nm", category: "Telecom", notes: "Teleste CATV analogue optical SFP 1550nm for HFC RF overlay" }, + + // ── 10G CWDM SFP+ ──────────────────────────────────────────────────────── + { pid: "SFP-10G-CWDM-1470", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 40000, reachLabel: "CWDM", fiberType: "SMF", connector: "LC", wavelengths: "1470nm", category: "Telecom", notes: "Teleste 10G CWDM SFP+ 1470nm" }, + { pid: "SFP-10G-CWDM-1550", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 60000, reachLabel: "CWDM", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", category: "Telecom", notes: "Teleste 10G CWDM SFP+ 1550nm" }, +]; + +// PIDs that use 'Telecom' category (CWDM, CATV analogue, BiDi HFC) +const TELECOM_PIDS = new Set([ + "SFP-BIDI-1310-1550", + "SFP-CWDM-1470", + "SFP-CWDM-1490", + "SFP-CWDM-1510", + "SFP-CWDM-1530", + "SFP-CWDM-1550", + "SFP-CWDM-1570", + "SFP-CWDM-1590", + "SFP-CWDM-1610", + "SFP-CATV-1550", + "SFP-10G-CWDM-1470", + "SFP-10G-CWDM-1550", +]); + +export async function scrapeTelesteOem(): Promise { + console.log("=== Teleste OEM Transceiver Seed ===\n"); + + const vendorId = await ensureVendor( + "Teleste", + "oem", + "https://www.teleste.com", + undefined + ); + + let inserted = 0; + let updated = 0; + let errors = 0; + + for (const p of TELESTE_PIDS) { + const slug = `teleste-${p.pid.toLowerCase().replace(/[^a-z0-9]+/g, "-")}`; + const category = p.category ?? (TELECOM_PIDS.has(p.pid) ? "Telecom" : "DataCenter"); + try { + const res = await pool.query( + `INSERT INTO transceivers + (slug, part_number, vendor_id, form_factor, speed, speed_gbps, + reach_meters, reach_label, fiber_type, connector, wavelengths, + dom_support, ieee_reference, market_status, category, notes) + VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,true,$12,'Mainstream',$13,$14) + ON CONFLICT (slug) DO UPDATE SET + speed_gbps = EXCLUDED.speed_gbps, + reach_meters = CASE WHEN EXCLUDED.reach_meters > 0 THEN EXCLUDED.reach_meters ELSE transceivers.reach_meters END, + fiber_type = CASE WHEN EXCLUDED.fiber_type <> '' THEN EXCLUDED.fiber_type ELSE transceivers.fiber_type END, + wavelengths = COALESCE(EXCLUDED.wavelengths, transceivers.wavelengths), + updated_at = NOW() + RETURNING (xmax = 0) as was_inserted`, + [slug, p.pid, vendorId, p.formFactor, p.speed, p.speedGbps, + p.reachMeters, p.reachLabel, p.fiberType, p.connector, + p.wavelengths ?? null, p.standard ?? null, category, p.notes ?? null] + ); + if (res.rows[0]?.was_inserted) inserted++; else updated++; + } catch (err) { + console.warn(` Skip ${p.pid}: ${(err as Error).message.slice(0, 80)}`); + errors++; + } + } + + console.log(`\n=== Teleste OEM Seed Complete ===`); + console.log(` Inserted: ${inserted}`); + console.log(` Updated: ${updated}`); + console.log(` Errors: ${errors}`); + console.log(` Total PIDs: ${TELESTE_PIDS.length}\n`); +} + +if (require.main === module) { + scrapeTelesteOem() + .then(() => pool.end()) + .catch((err) => { + console.error("Fatal:", err); + pool.end(); + process.exit(1); + }); +} diff --git a/packages/scraper/src/scrapers/telrad-oem.ts b/packages/scraper/src/scrapers/telrad-oem.ts new file mode 100644 index 0000000..ed2c717 --- /dev/null +++ b/packages/scraper/src/scrapers/telrad-oem.ts @@ -0,0 +1,122 @@ +/** + * Telrad Networks OEM Transceiver Catalog Seed + * + * Seeds Telrad-branded transceiver PIDs used in LTE/5G small cell + * and fronthaul deployments (BreezeMAX, BreezeNET, BREEZECOMPACT). + * + * Sources: + * - Telrad Networks Product Catalog (telrad.com) + * - BreezeMAX 5G NR hardware compatibility guides + * - LTE/5G fronthaul optical interface specifications + * + * Run: tsx packages/scraper/src/scrapers/telrad-oem.ts + * Cron: daily at 03:15 + */ + +import { pool, ensureVendor } from "../utils/db"; + +interface TelradPID { + pid: string; + formFactor: string; + speedGbps: number; + speed: string; + reachMeters: number; + reachLabel: string; + fiberType: string; + connector: string; + wavelengths?: string; + standard?: string; + notes?: string; +} + +const TELRAD_PIDS: TelradPID[] = [ + // ── 1G SFP ────────────────────────────────────────────────────────────── + { pid: "SFP-1G-SX", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 550, reachLabel: "SX", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "1000BASE-SX", notes: "Telrad 1G SFP SX for BreezeMAX/small cell uplink" }, + { pid: "SFP-1G-LX", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 10000, reachLabel: "LX", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "1000BASE-LX" }, + { pid: "SFP-1G-T", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 100, reachLabel: "T", fiberType: "DAC", connector: "RJ45", standard: "1000BASE-T" }, + + // ── 10G SFP+ ──────────────────────────────────────────────────────────── + { pid: "SFP-10G-SR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 300, reachLabel: "SR", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "10GBASE-SR", notes: "Telrad 10G SFP+ SR; LTE fronthaul eCPRI transport" }, + { pid: "SFP-10G-LR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 10000, reachLabel: "LR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "10GBASE-LR" }, + { pid: "SFP-10G-ER", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 40000, reachLabel: "ER", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "10GBASE-ER" }, + + // ── BiDi SFP ──────────────────────────────────────────────────────────── + { pid: "SFP-GE-BIDI-1310", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 20000, reachLabel: "BIDI", fiberType: "SMF", connector: "LC", wavelengths: "1310/1550nm", standard: "1000BASE-BX", notes: "BiDi SFP Tx1310/Rx1550 for single-fiber fronthaul" }, + { pid: "SFP-10G-BIDI", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 20000, reachLabel: "BIDI", fiberType: "SMF", connector: "LC", wavelengths: "1270/1330nm", notes: "BiDi SFP+ 10G for 5G NR fronthaul on single fiber" }, + + // ── 25G SFP28 ─────────────────────────────────────────────────────────── + { pid: "SFP28-25G-SR", formFactor: "SFP28", speedGbps: 25, speed: "25G", reachMeters: 100, reachLabel: "SR", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "25GBASE-SR", notes: "Telrad 25G SFP28; 5G NR eCPRI fronthaul" }, + { pid: "SFP28-25G-LR", formFactor: "SFP28", speedGbps: 25, speed: "25G", reachMeters: 10000, reachLabel: "LR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "25GBASE-LR" }, + + // ── 40G QSFP+ ─────────────────────────────────────────────────────────── + { pid: "QSFP-40G-SR4", formFactor: "QSFP+", speedGbps: 40, speed: "40G", reachMeters: 150, reachLabel: "SR4", fiberType: "MMF", connector: "MPO", wavelengths: "850nm", standard: "40GBASE-SR4" }, + { pid: "QSFP-40G-LR4", formFactor: "QSFP+", speedGbps: 40, speed: "40G", reachMeters: 10000, reachLabel: "LR4", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "40GBASE-LR4" }, + + // ── 100G QSFP28 ───────────────────────────────────────────────────────── + { pid: "QSFP28-100G-SR4", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 100, reachLabel: "SR4", fiberType: "MMF", connector: "MPO", wavelengths: "850nm", standard: "100GBASE-SR4" }, + { pid: "QSFP28-100G-LR4", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 10000, reachLabel: "LR4", fiberType: "SMF", connector: "LC", wavelengths: "1295-1310nm", standard: "100GBASE-LR4", notes: "Telrad 100G QSFP28 LR4 for 5G aggregation backhaul" }, + + // ── 400G QSFP-DD ──────────────────────────────────────────────────────── + { pid: "QSFP-DD-400G-DR4", formFactor: "QSFP-DD", speedGbps: 400, speed: "400G", reachMeters: 500, reachLabel: "DR4", fiberType: "SMF", connector: "MPO", wavelengths: "1310nm", standard: "400GBASE-DR4", notes: "Telrad 400G QSFP-DD for next-gen 5G core backhaul" }, + + // ── 1G Copper SFP ─────────────────────────────────────────────────────── + { pid: "SFP-GE-T", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 100, reachLabel: "T", fiberType: "DAC", connector: "RJ45", standard: "1000BASE-T", notes: "Copper GE SFP for management/backhaul" }, +]; + +export async function scrapeTelradOem(): Promise { + console.log("=== Telrad Networks OEM Transceiver Seed ===\n"); + + const vendorId = await ensureVendor( + "Telrad Networks", + "oem", + "https://www.telrad.com", + undefined + ); + + let inserted = 0; + let updated = 0; + let errors = 0; + + for (const p of TELRAD_PIDS) { + const slug = `telrad-${p.pid.toLowerCase().replace(/[^a-z0-9]+/g, "-")}`; + try { + const res = await pool.query( + `INSERT INTO transceivers + (slug, part_number, vendor_id, form_factor, speed, speed_gbps, + reach_meters, reach_label, fiber_type, connector, wavelengths, + dom_support, ieee_reference, market_status, category, notes) + VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,true,$12,'Mainstream','DataCenter',$13) + ON CONFLICT (slug) DO UPDATE SET + speed_gbps = EXCLUDED.speed_gbps, + reach_meters = CASE WHEN EXCLUDED.reach_meters > 0 THEN EXCLUDED.reach_meters ELSE transceivers.reach_meters END, + fiber_type = CASE WHEN EXCLUDED.fiber_type <> '' THEN EXCLUDED.fiber_type ELSE transceivers.fiber_type END, + wavelengths = COALESCE(EXCLUDED.wavelengths, transceivers.wavelengths), + updated_at = NOW() + RETURNING (xmax = 0) as was_inserted`, + [slug, p.pid, vendorId, p.formFactor, p.speed, p.speedGbps, + p.reachMeters, p.reachLabel, p.fiberType, p.connector, + p.wavelengths ?? null, p.standard ?? null, p.notes ?? null] + ); + if (res.rows[0]?.was_inserted) inserted++; else updated++; + } catch (err) { + console.warn(` Skip ${p.pid}: ${(err as Error).message.slice(0, 80)}`); + errors++; + } + } + + console.log(`\n=== Telrad OEM Seed Complete ===`); + console.log(` Inserted: ${inserted}`); + console.log(` Updated: ${updated}`); + console.log(` Errors: ${errors}`); + console.log(` Total PIDs: ${TELRAD_PIDS.length}\n`); +} + +if (require.main === module) { + scrapeTelradOem() + .then(() => pool.end()) + .catch((err) => { + console.error("Fatal:", err); + pool.end(); + process.exit(1); + }); +} diff --git a/packages/scraper/src/scrapers/tplink-oem.ts b/packages/scraper/src/scrapers/tplink-oem.ts new file mode 100644 index 0000000..f158f96 --- /dev/null +++ b/packages/scraper/src/scrapers/tplink-oem.ts @@ -0,0 +1,119 @@ +/** + * TP-Link OEM Transceiver Catalog Seed + * + * Seeds transceiver PIDs for TP-Link branded optics used in TL-SG, + * TL-SX, and Omada series managed switches. + * + * Sources: + * - TP-Link TL-SM series datasheet (tp-link.com) + * - TP-Link Omada switch hardware guides + * + * Run: tsx packages/scraper/src/scrapers/tplink-oem.ts + * Cron: daily at 10:45 + */ + +import { pool, ensureVendor } from "../utils/db"; + +interface TplinkPID { + pid: string; + formFactor: string; + speedGbps: number; + speed: string; + reachMeters: number; + reachLabel: string; + fiberType: string; + connector: string; + wavelengths?: string; + standard?: string; + notes?: string; +} + +const TPLINK_PIDS: TplinkPID[] = [ + // ── 1G SFP ────────────────────────────────────────────────────────────── + { pid: "TL-SM311LM", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 550, reachLabel: "SX", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "1000BASE-SX", notes: "TP-Link 1G MM SFP" }, + { pid: "TL-SM311LS", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 10000, reachLabel: "LX", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "1000BASE-LX", notes: "TP-Link 1G SM SFP" }, + { pid: "TL-SM311LS20", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 20000, reachLabel: "LX-20", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", notes: "TP-Link 1G SM SFP 20km" }, + { pid: "TL-SM311LS40", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 40000, reachLabel: "LH40", fiberType: "SMF", connector: "LC", wavelengths: "1310nm" }, + { pid: "TL-SM311LS80", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 80000, reachLabel: "ZX", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "1000BASE-ZX" }, + { pid: "TL-SM5310-T", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 100, reachLabel: "T", fiberType: "DAC", connector: "RJ45", standard: "1000BASE-T" }, + { pid: "TL-SM311LB-2", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 20000, reachLabel: "BiDi-1310", fiberType: "SMF", connector: "LC", wavelengths: "1310/1550nm", notes: "BiDi TX1310 20km" }, + { pid: "TL-SM311LB-2D", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 20000, reachLabel: "BiDi-1550", fiberType: "SMF", connector: "LC", wavelengths: "1550/1310nm", notes: "BiDi TX1550 20km" }, + + // ── 10G SFP+ ──────────────────────────────────────────────────────────── + { pid: "TL-SM5110-SR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 300, reachLabel: "SR", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "10GBASE-SR" }, + { pid: "TL-SM5110-LR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 10000, reachLabel: "LR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "10GBASE-LR" }, + { pid: "TL-SM5110-ER", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 40000, reachLabel: "ER", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "10GBASE-ER" }, + { pid: "TL-SM5110-ZR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 80000, reachLabel: "ZR", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "10GBASE-ZR" }, + { pid: "TL-SM5310-T-10G",formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 30, reachLabel: "T", fiberType: "DAC", connector: "RJ45", standard: "10GBASE-T", notes: "TP-Link 10G copper SFP+" }, + { pid: "TL-SM5110-2H", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 20000, reachLabel: "BiDi", fiberType: "SMF", connector: "LC", wavelengths: "1270/1330nm", notes: "10G BiDi TX1270" }, + + // ── 25G SFP28 ─────────────────────────────────────────────────────────── + { pid: "TL-SM5220-SR", formFactor: "SFP28", speedGbps: 25, speed: "25G", reachMeters: 100, reachLabel: "SR", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "25GBASE-SR" }, + { pid: "TL-SM5220-LR", formFactor: "SFP28", speedGbps: 25, speed: "25G", reachMeters: 10000, reachLabel: "LR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "25GBASE-LR" }, + + // ── 100G QSFP28 ───────────────────────────────────────────────────────── + { pid: "TL-SM6220-SR4", formFactor: "QSFP28",speedGbps: 100, speed: "100G", reachMeters: 100, reachLabel: "SR4", fiberType: "MMF", connector: "MPO", wavelengths: "850nm", standard: "100GBASE-SR4" }, + { pid: "TL-SM6220-LR4", formFactor: "QSFP28",speedGbps: 100, speed: "100G", reachMeters: 10000, reachLabel: "LR4", fiberType: "SMF", connector: "LC", wavelengths: "1295-1310nm", standard: "100GBASE-LR4" }, + + // ── DAC ───────────────────────────────────────────────────────────────── + { pid: "TL-SM5220-1M", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 1, reachLabel: "DAC-1M", fiberType: "DAC", connector: "SFP+", notes: "TP-Link 10G DAC 1m" }, + { pid: "TL-SM5220-3M", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 3, reachLabel: "DAC-3M", fiberType: "DAC", connector: "SFP+" }, +]; + +export async function scrapeTplinkOem(): Promise { + console.log("=== TP-Link OEM Transceiver Seed ===\n"); + + const vendorId = await ensureVendor( + "TP-Link", + "oem", + "https://www.tp-link.com", + undefined + ); + + let inserted = 0; + let updated = 0; + let errors = 0; + + for (const p of TPLINK_PIDS) { + const slug = `tplink-${p.pid.toLowerCase().replace(/[^a-z0-9]+/g, "-")}`; + try { + const res = await pool.query( + `INSERT INTO transceivers + (slug, part_number, vendor_id, form_factor, speed, speed_gbps, + reach_meters, reach_label, fiber_type, connector, wavelengths, + dom_support, ieee_reference, market_status, category, notes) + VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,true,$12,'Mainstream','DataCenter',$13) + ON CONFLICT (slug) DO UPDATE SET + speed_gbps = EXCLUDED.speed_gbps, + reach_meters = CASE WHEN EXCLUDED.reach_meters > 0 THEN EXCLUDED.reach_meters ELSE transceivers.reach_meters END, + fiber_type = CASE WHEN EXCLUDED.fiber_type <> '' THEN EXCLUDED.fiber_type ELSE transceivers.fiber_type END, + wavelengths = COALESCE(EXCLUDED.wavelengths, transceivers.wavelengths), + updated_at = NOW() + RETURNING (xmax = 0) as was_inserted`, + [slug, p.pid, vendorId, p.formFactor, p.speed, p.speedGbps, + p.reachMeters, p.reachLabel, p.fiberType, p.connector, + p.wavelengths ?? null, p.standard ?? null, p.notes ?? null] + ); + if (res.rows[0]?.was_inserted) inserted++; else updated++; + } catch (err) { + console.warn(` Skip ${p.pid}: ${(err as Error).message.slice(0, 80)}`); + errors++; + } + } + + console.log(`\n=== TP-Link OEM Seed Complete ===`); + console.log(` Inserted: ${inserted}`); + console.log(` Updated: ${updated}`); + console.log(` Errors: ${errors}`); + console.log(` Total PIDs: ${TPLINK_PIDS.length}\n`); +} + +if (require.main === module) { + scrapeTplinkOem() + .then(() => pool.end()) + .catch((err) => { + console.error("Fatal:", err); + pool.end(); + process.exit(1); + }); +} diff --git a/packages/scraper/src/scrapers/transition-networks-oem.ts b/packages/scraper/src/scrapers/transition-networks-oem.ts new file mode 100644 index 0000000..dc7d6b5 --- /dev/null +++ b/packages/scraper/src/scrapers/transition-networks-oem.ts @@ -0,0 +1,334 @@ +/** + * Transition Networks OEM Transceiver Catalog Seed + * + * Seeds transceiver PIDs for Transition Networks SFP modules used in + * ION and SISPM series fiber media converters and industrial networking gear. + * + * Sources: + * - Transition Networks SFP module datasheets (transition.com) + * - ION / SISPM series hardware installation guides + * + * Run: tsx packages/scraper/src/scrapers/transition-networks-oem.ts + * Cron: daily at 15:45 + */ + +import { pool, ensureVendor } from "../utils/db"; + +interface TransitionNetworksPID { + pid: string; + formFactor: string; + speedGbps: number; + speed: string; + reachMeters: number; + reachLabel: string; + fiberType: string; + connector: string; + wavelengths?: string; + standard?: string; + notes?: string; +} + +const TRANSITION_NETWORKS_PIDS: TransitionNetworksPID[] = [ + // ── 100M SFP ──────────────────────────────────────────────────────────── + { + pid: "TN-SFP-FE", + formFactor: "SFP", + speedGbps: 0.1, + speed: "100M", + reachMeters: 2000, + reachLabel: "FX", + fiberType: "MMF", + connector: "LC", + wavelengths: "850nm", + standard: "100BASE-FX", + }, + { + pid: "TN-SFP-FE-SC", + formFactor: "SFP", + speedGbps: 0.1, + speed: "100M", + reachMeters: 2000, + reachLabel: "FX", + fiberType: "MMF", + connector: "SC", + wavelengths: "850nm", + standard: "100BASE-FX", + notes: "Transition Networks 100M MM SFP SC", + }, + { + pid: "TN-SFP-FE-SM", + formFactor: "SFP", + speedGbps: 0.1, + speed: "100M", + reachMeters: 40000, + reachLabel: "LFX", + fiberType: "SMF", + connector: "LC", + wavelengths: "1310nm", + standard: "100BASE-LFX", + }, + + // ── 1G SFP ────────────────────────────────────────────────────────────── + { + pid: "TN-SFP-GE-SX", + formFactor: "SFP", + speedGbps: 1, + speed: "1G", + reachMeters: 550, + reachLabel: "SX", + fiberType: "MMF", + connector: "LC", + wavelengths: "850nm", + standard: "1000BASE-SX", + }, + { + pid: "TN-SFP-GE-LX", + formFactor: "SFP", + speedGbps: 1, + speed: "1G", + reachMeters: 10000, + reachLabel: "LX", + fiberType: "SMF", + connector: "LC", + wavelengths: "1310nm", + standard: "1000BASE-LX", + }, + { + pid: "TN-SFP-GE-LH", + formFactor: "SFP", + speedGbps: 1, + speed: "1G", + reachMeters: 40000, + reachLabel: "LH", + fiberType: "SMF", + connector: "LC", + wavelengths: "1310nm", + notes: "Transition Networks 1G SM SFP 40km", + }, + { + pid: "TN-SFP-GE-ZX", + formFactor: "SFP", + speedGbps: 1, + speed: "1G", + reachMeters: 80000, + reachLabel: "ZX", + fiberType: "SMF", + connector: "LC", + wavelengths: "1550nm", + standard: "1000BASE-ZX", + }, + { + pid: "TN-SFP-GE-T", + formFactor: "SFP", + speedGbps: 1, + speed: "1G", + reachMeters: 100, + reachLabel: "T", + fiberType: "DAC", + connector: "RJ45", + standard: "1000BASE-T", + }, + { + pid: "TN-SFP-GE-BX20U", + formFactor: "SFP", + speedGbps: 1, + speed: "1G", + reachMeters: 20000, + reachLabel: "BiDi", + fiberType: "SMF", + connector: "LC", + wavelengths: "TX1310/RX1550", + notes: "Transition Networks 1G BiDi SFP upstream", + }, + { + pid: "TN-SFP-GE-BX20D", + formFactor: "SFP", + speedGbps: 1, + speed: "1G", + reachMeters: 20000, + reachLabel: "BiDi", + fiberType: "SMF", + connector: "LC", + wavelengths: "TX1550/RX1310", + notes: "Transition Networks 1G BiDi SFP downstream", + }, + + // ── 10G SFP+ ──────────────────────────────────────────────────────────── + { + pid: "TN-SFP-10G-SR", + formFactor: "SFP+", + speedGbps: 10, + speed: "10G", + reachMeters: 300, + reachLabel: "SR", + fiberType: "MMF", + connector: "LC", + wavelengths: "850nm", + standard: "10GBASE-SR", + }, + { + pid: "TN-SFP-10G-LR", + formFactor: "SFP+", + speedGbps: 10, + speed: "10G", + reachMeters: 10000, + reachLabel: "LR", + fiberType: "SMF", + connector: "LC", + wavelengths: "1310nm", + standard: "10GBASE-LR", + }, + { + pid: "TN-SFP-10G-ER", + formFactor: "SFP+", + speedGbps: 10, + speed: "10G", + reachMeters: 40000, + reachLabel: "ER", + fiberType: "SMF", + connector: "LC", + wavelengths: "1550nm", + standard: "10GBASE-ER", + }, + { + pid: "TN-SFP-10G-ZR", + formFactor: "SFP+", + speedGbps: 10, + speed: "10G", + reachMeters: 80000, + reachLabel: "ZR", + fiberType: "SMF", + connector: "LC", + wavelengths: "1550nm", + standard: "10GBASE-ZR", + }, + { + pid: "TN-SFP-10G-T", + formFactor: "SFP+", + speedGbps: 10, + speed: "10G", + reachMeters: 30, + reachLabel: "T", + fiberType: "DAC", + connector: "RJ45", + standard: "10GBASE-T", + }, + { + pid: "TN-SFP-10G-BXU", + formFactor: "SFP+", + speedGbps: 10, + speed: "10G", + reachMeters: 10000, + reachLabel: "BiDi", + fiberType: "SMF", + connector: "LC", + wavelengths: "TX1270/RX1330", + notes: "Transition Networks 10G BiDi SFP+ upstream", + }, + + // ── 25G SFP28 ─────────────────────────────────────────────────────────── + { + pid: "TN-SFP28-25G-SR", + formFactor: "SFP28", + speedGbps: 25, + speed: "25G", + reachMeters: 100, + reachLabel: "SR", + fiberType: "MMF", + connector: "LC", + wavelengths: "850nm", + standard: "25GBASE-SR", + }, + { + pid: "TN-SFP28-25G-LR", + formFactor: "SFP28", + speedGbps: 25, + speed: "25G", + reachMeters: 10000, + reachLabel: "LR", + fiberType: "SMF", + connector: "LC", + wavelengths: "1310nm", + standard: "25GBASE-LR", + }, + + // ── DAC ───────────────────────────────────────────────────────────────── + { + pid: "TN-DAC-10G-1M", + formFactor: "SFP+", + speedGbps: 10, + speed: "10G", + reachMeters: 1, + reachLabel: "DAC-1m", + fiberType: "DAC", + connector: "SFP+", + }, + { + pid: "TN-DAC-10G-3M", + formFactor: "SFP+", + speedGbps: 10, + speed: "10G", + reachMeters: 3, + reachLabel: "DAC-3m", + fiberType: "DAC", + connector: "SFP+", + }, +]; + +export async function scrapeTransitionNetworksOem(): Promise { + console.log("=== Transition Networks OEM Transceiver Seed ===\n"); + + const vendorId = await ensureVendor( + "Transition Networks", + "oem", + "https://www.transition.com", + undefined + ); + + let inserted = 0; + let updated = 0; + let errors = 0; + + for (const p of TRANSITION_NETWORKS_PIDS) { + const slug = `transition-networks-${p.pid.toLowerCase().replace(/[^a-z0-9]+/g, "-")}`; + try { + const res = await pool.query( + `INSERT INTO transceivers + (slug, part_number, vendor_id, form_factor, speed, speed_gbps, + reach_meters, reach_label, fiber_type, connector, wavelengths, + dom_support, ieee_reference, market_status, category, notes) + VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,true,$12,'Mainstream','Industrial',$13) + ON CONFLICT (slug) DO UPDATE SET + speed_gbps = EXCLUDED.speed_gbps, + reach_meters = CASE WHEN EXCLUDED.reach_meters > 0 THEN EXCLUDED.reach_meters ELSE transceivers.reach_meters END, + fiber_type = CASE WHEN EXCLUDED.fiber_type <> '' THEN EXCLUDED.fiber_type ELSE transceivers.fiber_type END, + wavelengths = COALESCE(EXCLUDED.wavelengths, transceivers.wavelengths), + updated_at = NOW() + RETURNING (xmax = 0) as was_inserted`, + [slug, p.pid, vendorId, p.formFactor, p.speed, p.speedGbps, + p.reachMeters, p.reachLabel, p.fiberType, p.connector, + p.wavelengths ?? null, p.standard ?? null, p.notes ?? null] + ); + if (res.rows[0]?.was_inserted) inserted++; else updated++; + } catch (err) { + console.warn(` Skip ${p.pid}: ${(err as Error).message.slice(0, 80)}`); + errors++; + } + } + + console.log(`\n=== Transition Networks OEM Seed Complete ===`); + console.log(` Inserted: ${inserted}`); + console.log(` Updated: ${updated}`); + console.log(` Errors: ${errors}`); + console.log(` Total PIDs: ${TRANSITION_NETWORKS_PIDS.length}\n`); +} + +if (require.main === module) { + scrapeTransitionNetworksOem() + .then(() => pool.end()) + .catch((err) => { + console.error("Fatal:", err); + pool.end(); + process.exit(1); + }); +} diff --git a/packages/scraper/src/scrapers/ubiquiti-oem.ts b/packages/scraper/src/scrapers/ubiquiti-oem.ts new file mode 100644 index 0000000..0223874 --- /dev/null +++ b/packages/scraper/src/scrapers/ubiquiti-oem.ts @@ -0,0 +1,121 @@ +/** + * Ubiquiti OEM Transceiver Catalog Seed + * Seeds Ubiquiti-branded transceiver PIDs for UniFi and EdgeSwitch platforms. + * Sources: Ubiquiti Store / UniFi Compatibility (store.ui.com, ui.com) + * Run: tsx packages/scraper/src/scrapers/ubiquiti-oem.ts + * Cron: daily at 07:45 + */ + +import { pool, ensureVendor } from "../utils/db"; + +interface UbiquitiPID { + pid: string; + formFactor: string; + speedGbps: number; + speed: string; + reachMeters: number; + reachLabel: string; + fiberType: string; + connector: string; + wavelengths?: string; + standard?: string; + notes?: string; +} + +const UBIQUITI_PIDS: UbiquitiPID[] = [ + // ── 1G SFP ────────────────────────────────────────────────────────────── + { pid: "UF-MM-1G", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 550, reachLabel: "SX", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "1000BASE-SX", notes: "UniFi 1G MM SFP" }, + { pid: "UF-SM-1G", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 10000, reachLabel: "LX", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "1000BASE-LX", notes: "UniFi 1G SM SFP" }, + { pid: "UF-SM-1G-S", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 10000, reachLabel: "BiDi", fiberType: "SMF", connector: "LC", wavelengths: "1310/1550nm", notes: "UniFi 1G BiDi SFP single fiber" }, + { pid: "UF-RJ45-1G", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 100, reachLabel: "T", fiberType: "DAC", connector: "RJ45", standard: "1000BASE-T" }, + + // ── 10G SFP+ ──────────────────────────────────────────────────────────── + { pid: "UF-MM-10G", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 300, reachLabel: "SR", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "10GBASE-SR", notes: "UniFi 10G MM SFP+" }, + { pid: "UF-SM-10G", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 10000, reachLabel: "LR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "10GBASE-LR", notes: "UniFi 10G SM SFP+" }, + { pid: "UF-SM-10G-S", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 10000, reachLabel: "BiDi", fiberType: "SMF", connector: "LC", wavelengths: "1270/1330nm", notes: "UniFi 10G BiDi SFP+ single fiber" }, + { pid: "UF-RJ45-10G", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 30, reachLabel: "T", fiberType: "DAC", connector: "RJ45", standard: "10GBASE-T" }, + + // ── 25G SFP28 ─────────────────────────────────────────────────────────── + { pid: "UF-MM-25G", formFactor: "SFP28", speedGbps: 25, speed: "25G", reachMeters: 100, reachLabel: "SR", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "25GBASE-SR" }, + { pid: "UF-SM-25G", formFactor: "SFP28", speedGbps: 25, speed: "25G", reachMeters: 10000, reachLabel: "LR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "25GBASE-LR" }, + + // ── 40G QSFP+ ─────────────────────────────────────────────────────────── + { pid: "UF-MM-40G", formFactor: "QSFP+", speedGbps: 40, speed: "40G", reachMeters: 150, reachLabel: "SR4", fiberType: "MMF", connector: "MPO", wavelengths: "850nm", standard: "40GBASE-SR4" }, + { pid: "UF-SM-40G", formFactor: "QSFP+", speedGbps: 40, speed: "40G", reachMeters: 10000, reachLabel: "LR4", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "40GBASE-LR4" }, + + // ── 100G QSFP28 ───────────────────────────────────────────────────────── + { pid: "UF-MM-100G", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 100, reachLabel: "SR4", fiberType: "MMF", connector: "MPO", wavelengths: "850nm", standard: "100GBASE-SR4" }, + { pid: "UF-SM-100G", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 10000, reachLabel: "LR4", fiberType: "SMF", connector: "LC", wavelengths: "1295-1310nm", standard: "100GBASE-LR4" }, + { pid: "UF-SM-100G-CWDM4", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 2000, reachLabel: "CWDM4", fiberType: "SMF", connector: "LC", wavelengths: "1271-1331nm", standard: "100GBASE-CWDM4" }, + + // ── 400G QSFP-DD (UniFi Pro Max) ──────────────────────────────────────── + { pid: "UF-MM-400G", formFactor: "QSFP-DD", speedGbps: 400, speed: "400G", reachMeters: 100, reachLabel: "SR8", fiberType: "MMF", connector: "MPO", wavelengths: "850nm", standard: "400GBASE-SR8" }, + { pid: "UF-SM-400G-DR4", formFactor: "QSFP-DD", speedGbps: 400, speed: "400G", reachMeters: 500, reachLabel: "DR4", fiberType: "SMF", connector: "MPO", wavelengths: "1310nm", standard: "400GBASE-DR4" }, + { pid: "UF-SM-400G-FR4", formFactor: "QSFP-DD", speedGbps: 400, speed: "400G", reachMeters: 2000, reachLabel: "FR4", fiberType: "SMF", connector: "LC", wavelengths: "1271-1331nm", standard: "400GBASE-FR4" }, + + // ── DAC (UDC = UniFi Direct Attach Cable) ─────────────────────────────── + { pid: "UDC-1", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 1, reachLabel: "DAC-1M", fiberType: "DAC", connector: "SFP+", notes: "UniFi DAC SFP+ 1m" }, + { pid: "UDC-2", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 2, reachLabel: "DAC-2M", fiberType: "DAC", connector: "SFP+" }, + { pid: "UDC-3", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 3, reachLabel: "DAC-3M", fiberType: "DAC", connector: "SFP+" }, + { pid: "UDC-4", formFactor: "QSFP+", speedGbps: 40, speed: "40G", reachMeters: 1, reachLabel: "DAC-1M", fiberType: "DAC", connector: "QSFP+" }, + { pid: "UDC-5", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 1, reachLabel: "DAC-1M", fiberType: "DAC", connector: "QSFP28" }, + { pid: "UDC-6", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 3, reachLabel: "DAC-3M", fiberType: "DAC", connector: "QSFP28" }, +]; + +export async function scrapeUbiquitiOem(): Promise { + console.log("=== Ubiquiti OEM Transceiver Seed ===\n"); + + const vendorId = await ensureVendor( + "Ubiquiti", + "oem", + "https://ui.com", + undefined + ); + + let inserted = 0; + let updated = 0; + let errors = 0; + + for (const p of UBIQUITI_PIDS) { + const slug = `ubiquiti-${p.pid.toLowerCase().replace(/[^a-z0-9]+/g, "-")}`; + try { + const res = await pool.query( + `INSERT INTO transceivers + (slug, part_number, vendor_id, form_factor, speed, speed_gbps, + reach_meters, reach_label, fiber_type, connector, wavelengths, + dom_support, ieee_reference, market_status, category, notes) + VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,true,$12,'Mainstream','DataCenter',$13) + ON CONFLICT (slug) DO UPDATE SET + speed_gbps = EXCLUDED.speed_gbps, + reach_meters = CASE WHEN EXCLUDED.reach_meters > 0 THEN EXCLUDED.reach_meters ELSE transceivers.reach_meters END, + fiber_type = CASE WHEN EXCLUDED.fiber_type <> '' THEN EXCLUDED.fiber_type ELSE transceivers.fiber_type END, + wavelengths = COALESCE(EXCLUDED.wavelengths, transceivers.wavelengths), + updated_at = NOW() + RETURNING (xmax = 0) as was_inserted`, + [slug, p.pid, vendorId, p.formFactor, p.speed, p.speedGbps, + p.reachMeters, p.reachLabel, p.fiberType, p.connector, + p.wavelengths ?? null, p.standard ?? null, p.notes ?? null] + ); + if (res.rows[0]?.was_inserted) inserted++; else updated++; + } catch (err) { + console.warn(` Skip ${p.pid}: ${(err as Error).message.slice(0, 80)}`); + errors++; + } + } + + console.log(`\n=== Ubiquiti OEM Seed Complete ===`); + console.log(` Inserted: ${inserted}`); + console.log(` Updated: ${updated}`); + console.log(` Errors: ${errors}`); + console.log(` Total PIDs: ${UBIQUITI_PIDS.length}\n`); +} + +if (require.main === module) { + scrapeUbiquitiOem() + .then(() => pool.end()) + .catch((err) => { + console.error("Fatal:", err); + pool.end(); + process.exit(1); + }); +} diff --git a/packages/scraper/src/scrapers/vecima-oem.ts b/packages/scraper/src/scrapers/vecima-oem.ts new file mode 100644 index 0000000..438d931 --- /dev/null +++ b/packages/scraper/src/scrapers/vecima-oem.ts @@ -0,0 +1,116 @@ +/** + * Vecima Networks OEM Transceiver Catalog Seed + * + * Seeds Vecima-branded transceiver PIDs for EN Series and TSW Series + * Remote PHY nodes and cable/DOCSIS access equipment. + * + * Sources: + * - Vecima Networks EN Series Hardware Compatibility Guide (vecima.com) + * - Vecima TSW SFP Module Product Specifications + * + * Run: tsx packages/scraper/src/scrapers/vecima-oem.ts + * Cron: daily at 19:30 + */ + +import { pool, ensureVendor } from "../utils/db"; + +interface VecimaPID { + pid: string; + formFactor: string; + speedGbps: number; + speed: string; + reachMeters: number; + reachLabel: string; + fiberType: string; + connector: string; + wavelengths?: string; + standard?: string; + notes?: string; +} + +const VECIMA_PIDS: VecimaPID[] = [ + // ── 1G SFP ────────────────────────────────────────────────────────────── + { pid: "VEC-SFP-1G-SX", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 550, reachLabel: "SX", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "1000BASE-SX" }, + { pid: "VEC-SFP-1G-LX", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 10000, reachLabel: "LX", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "1000BASE-LX" }, + { pid: "VEC-SFP-1G-ZX", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 80000, reachLabel: "ZX", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "1000BASE-ZX" }, + { pid: "VEC-SFP-1G-T", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 100, reachLabel: "T", fiberType: "DAC", connector: "RJ45", standard: "1000BASE-T" }, + + // ── 10G SFP+ ──────────────────────────────────────────────────────────── + { pid: "VEC-SFP-10G-SR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 300, reachLabel: "SR", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "10GBASE-SR" }, + { pid: "VEC-SFP-10G-LR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 10000, reachLabel: "LR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "10GBASE-LR" }, + { pid: "VEC-SFP-10G-ER", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 40000, reachLabel: "ER", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "10GBASE-ER" }, + { pid: "VEC-SFP-10G-ZR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 80000, reachLabel: "ZR", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "10GBASE-ZR" }, + + // ── 25G SFP28 ─────────────────────────────────────────────────────────── + { pid: "VEC-SFP28-25G-SR", formFactor: "SFP28", speedGbps: 25, speed: "25G", reachMeters: 100, reachLabel: "SR", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "25GBASE-SR" }, + { pid: "VEC-SFP28-25G-LR", formFactor: "SFP28", speedGbps: 25, speed: "25G", reachMeters: 10000, reachLabel: "LR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "25GBASE-LR" }, + + // ── 100G QSFP28 ───────────────────────────────────────────────────────── + { pid: "VEC-QSFP28-100G-SR4", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 100, reachLabel: "SR4", fiberType: "MMF", connector: "MPO", wavelengths: "850nm", standard: "100GBASE-SR4" }, + { pid: "VEC-QSFP28-100G-LR4", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 10000, reachLabel: "LR4", fiberType: "SMF", connector: "LC", wavelengths: "1295-1310nm", standard: "100GBASE-LR4" }, + { pid: "VEC-QSFP28-100G-CWDM4", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 2000, reachLabel: "CWDM4", fiberType: "SMF", connector: "LC", wavelengths: "1271-1331nm", standard: "100GBASE-CWDM4" }, + { pid: "VEC-QSFP28-100G-DR", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 500, reachLabel: "DR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "100GBASE-DR" }, + + // ── DAC ───────────────────────────────────────────────────────────────── + { pid: "VEC-DAC-10G-1M", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 1, reachLabel: "DAC-1M", fiberType: "DAC", connector: "SFP+" }, + { pid: "VEC-DAC-10G-3M", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 3, reachLabel: "DAC-3M", fiberType: "DAC", connector: "SFP+" }, + { pid: "VEC-DAC-100G-1M", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 1, reachLabel: "DAC-1M", fiberType: "DAC", connector: "QSFP28" }, +]; + +export async function scrapeVecimaOem(): Promise { + console.log("=== Vecima Networks OEM Transceiver Seed ===\n"); + + const vendorId = await ensureVendor( + "Vecima Networks", + "oem", + "https://www.vecima.com", + undefined + ); + + let inserted = 0; + let updated = 0; + let errors = 0; + + for (const p of VECIMA_PIDS) { + const slug = `vecima-${p.pid.toLowerCase().replace(/[^a-z0-9]+/g, "-")}`; + try { + const res = await pool.query( + `INSERT INTO transceivers + (slug, part_number, vendor_id, form_factor, speed, speed_gbps, + reach_meters, reach_label, fiber_type, connector, wavelengths, + dom_support, ieee_reference, market_status, category, notes) + VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,true,$12,'Mainstream','DataCenter',$13) + ON CONFLICT (slug) DO UPDATE SET + speed_gbps = EXCLUDED.speed_gbps, + reach_meters = CASE WHEN EXCLUDED.reach_meters > 0 THEN EXCLUDED.reach_meters ELSE transceivers.reach_meters END, + fiber_type = CASE WHEN EXCLUDED.fiber_type <> '' THEN EXCLUDED.fiber_type ELSE transceivers.fiber_type END, + wavelengths = COALESCE(EXCLUDED.wavelengths, transceivers.wavelengths), + updated_at = NOW() + RETURNING (xmax = 0) as was_inserted`, + [slug, p.pid, vendorId, p.formFactor, p.speed, p.speedGbps, + p.reachMeters, p.reachLabel, p.fiberType, p.connector, + p.wavelengths ?? null, p.standard ?? null, p.notes ?? null] + ); + if (res.rows[0]?.was_inserted) inserted++; else updated++; + } catch (err) { + console.warn(` Skip ${p.pid}: ${(err as Error).message.slice(0, 80)}`); + errors++; + } + } + + console.log(`\n=== Vecima Networks OEM Seed Complete ===`); + console.log(` Inserted: ${inserted}`); + console.log(` Updated: ${updated}`); + console.log(` Errors: ${errors}`); + console.log(` Total PIDs: ${VECIMA_PIDS.length}\n`); +} + +if (require.main === module) { + scrapeVecimaOem() + .then(() => pool.end()) + .catch((err) => { + console.error("Fatal:", err); + pool.end(); + process.exit(1); + }); +} diff --git a/packages/scraper/src/scrapers/versa-networks-oem.ts b/packages/scraper/src/scrapers/versa-networks-oem.ts new file mode 100644 index 0000000..5148d0e --- /dev/null +++ b/packages/scraper/src/scrapers/versa-networks-oem.ts @@ -0,0 +1,117 @@ +/** + * Versa Networks OEM Transceiver Catalog Seed + * + * Seeds Versa Networks-branded SFP/SFP+/SFP28/QSFP+/QSFP28/QSFP-DD transceiver + * PIDs for SASE and SD-WAN appliances (VOS FlexVNF, CSG series). + * + * Sources: + * - Versa Networks hardware compatibility guides (versa-networks.com) + * - CSG/Titan appliance series datasheet optics specifications + * + * Run: tsx packages/scraper/src/scrapers/versa-networks-oem.ts + * Cron: daily at 04:30 + */ + +import { pool, ensureVendor } from "../utils/db"; + +interface VersaPID { + pid: string; + formFactor: string; + speedGbps: number; + speed: string; + reachMeters: number; + reachLabel: string; + fiberType: string; + connector: string; + wavelengths?: string; + standard?: string; + notes?: string; +} + +const VERSA_PIDS: VersaPID[] = [ + // ── 1G SFP ────────────────────────────────────────────────────────────── + { pid: "VN-SFP-1G-SX", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 550, reachLabel: "SX", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "1000BASE-SX", notes: "Versa 1G MM SFP for CSG appliance LAN ports" }, + { pid: "VN-SFP-1G-LX", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 10000, reachLabel: "LX", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "1000BASE-LX" }, + { pid: "VN-SFP-1G-T", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 100, reachLabel: "T", fiberType: "DAC", connector: "RJ45", standard: "1000BASE-T", notes: "Copper SFP for Versa SASE branch appliance WAN/LAN" }, + { pid: "VN-SFP-GE-T", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 100, reachLabel: "GE-T", fiberType: "DAC", connector: "RJ45", standard: "1000BASE-T", notes: "GE copper variant for Versa FlexVNF appliances" }, + { pid: "VN-SFP-GE-BIDI", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 20000, reachLabel: "BiDi", fiberType: "SMF", connector: "LC", wavelengths: "TX1310/RX1550", standard: "1000BASE-BX", notes: "1G BiDi SFP for single-fiber WAN last-mile" }, + + // ── 10G SFP+ ──────────────────────────────────────────────────────────── + { pid: "VN-SFP-10G-SR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 300, reachLabel: "SR", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "10GBASE-SR" }, + { pid: "VN-SFP-10G-LR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 10000, reachLabel: "LR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "10GBASE-LR" }, + { pid: "VN-SFP-10G-ER", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 40000, reachLabel: "ER", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "10GBASE-ER", notes: "40km ER for Versa edge-to-hub WAN interconnects" }, + { pid: "VN-SFP-10G-ZR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 80000, reachLabel: "ZR", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "10GBASE-ZR", notes: "80km ZR for regional PoP aggregation over dark fiber" }, + + // ── 25G SFP28 ─────────────────────────────────────────────────────────── + { pid: "VN-SFP28-25G-SR", formFactor: "SFP28", speedGbps: 25, speed: "25G", reachMeters: 100, reachLabel: "SR", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "25GBASE-SR", notes: "25G SR for Versa Titan cloud SASE appliances" }, + { pid: "VN-SFP28-25G-LR", formFactor: "SFP28", speedGbps: 25, speed: "25G", reachMeters: 10000, reachLabel: "LR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "25GBASE-LR" }, + + // ── 40G QSFP+ ─────────────────────────────────────────────────────────── + { pid: "VN-QSFP-40G-SR4", formFactor: "QSFP+", speedGbps: 40, speed: "40G", reachMeters: 150, reachLabel: "SR4", fiberType: "MMF", connector: "MPO", wavelengths: "850nm", standard: "40GBASE-SR4", notes: "40G for Versa high-throughput SASE gateways" }, + { pid: "VN-QSFP-40G-LR4", formFactor: "QSFP+", speedGbps: 40, speed: "40G", reachMeters: 10000, reachLabel: "LR4", fiberType: "SMF", connector: "LC", wavelengths: "1295-1310nm", standard: "40GBASE-LR4" }, + + // ── 100G QSFP28 ───────────────────────────────────────────────────────── + { pid: "VN-QSFP28-100G-SR4", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 100, reachLabel: "SR4", fiberType: "MMF", connector: "MPO", wavelengths: "850nm", standard: "100GBASE-SR4" }, + { pid: "VN-QSFP28-100G-LR4", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 10000, reachLabel: "LR4", fiberType: "SMF", connector: "LC", wavelengths: "1295-1310nm", standard: "100GBASE-LR4" }, + + // ── 400G QSFP-DD ──────────────────────────────────────────────────────── + { pid: "VN-QSFP-DD-400G-DR4", formFactor: "QSFP-DD", speedGbps: 400, speed: "400G", reachMeters: 500, reachLabel: "DR4", fiberType: "SMF", connector: "MPO", wavelengths: "1310nm", standard: "400GBASE-DR4", notes: "400G DR4 for next-gen Versa SASE PoP fabric uplinks" }, +]; + +export async function scrapeVersaNetworksOem(): Promise { + console.log("=== Versa Networks OEM Transceiver Seed ===\n"); + + const vendorId = await ensureVendor( + "Versa Networks", + "oem", + "https://www.versa-networks.com", + undefined + ); + + let inserted = 0; + let updated = 0; + let errors = 0; + + for (const p of VERSA_PIDS) { + const slug = `versa-${p.pid.toLowerCase().replace(/[^a-z0-9]+/g, "-")}`; + try { + const res = await pool.query( + `INSERT INTO transceivers + (slug, part_number, vendor_id, form_factor, speed, speed_gbps, + reach_meters, reach_label, fiber_type, connector, wavelengths, + dom_support, ieee_reference, market_status, category, notes) + VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,true,$12,'Mainstream','DataCenter',$13) + ON CONFLICT (slug) DO UPDATE SET + speed_gbps = EXCLUDED.speed_gbps, + reach_meters = CASE WHEN EXCLUDED.reach_meters > 0 THEN EXCLUDED.reach_meters ELSE transceivers.reach_meters END, + fiber_type = CASE WHEN EXCLUDED.fiber_type <> '' THEN EXCLUDED.fiber_type ELSE transceivers.fiber_type END, + wavelengths = COALESCE(EXCLUDED.wavelengths, transceivers.wavelengths), + updated_at = NOW() + RETURNING (xmax = 0) as was_inserted`, + [slug, p.pid, vendorId, p.formFactor, p.speed, p.speedGbps, + p.reachMeters, p.reachLabel, p.fiberType, p.connector, + p.wavelengths ?? null, p.standard ?? null, p.notes ?? null] + ); + if (res.rows[0]?.was_inserted) inserted++; else updated++; + } catch (err) { + console.warn(` Skip ${p.pid}: ${(err as Error).message.slice(0, 80)}`); + errors++; + } + } + + console.log(`\n=== Versa Networks OEM Seed Complete ===`); + console.log(` Inserted: ${inserted}`); + console.log(` Updated: ${updated}`); + console.log(` Errors: ${errors}`); + console.log(` Total PIDs: ${VERSA_PIDS.length}\n`); +} + +if (require.main === module) { + scrapeVersaNetworksOem() + .then(() => pool.end()) + .catch((err) => { + console.error("Fatal:", err); + pool.end(); + process.exit(1); + }); +} diff --git a/packages/scraper/src/scrapers/viasat-oem.ts b/packages/scraper/src/scrapers/viasat-oem.ts new file mode 100644 index 0000000..89cec4c --- /dev/null +++ b/packages/scraper/src/scrapers/viasat-oem.ts @@ -0,0 +1,118 @@ +/** + * Viasat OEM Transceiver Catalog Seed + * + * Seeds Viasat-branded transceiver PIDs for satellite networking ground + * equipment: SurfBeam 3 gateway modems, Viasat-3 ground infrastructure, + * ViaSat-2 teleport equipment, and tactical communications platforms. + * + * Sources: + * - Viasat Product Catalog (viasat.com) + * - Viasat SurfBeam 3 Gateway Hardware Reference + * - Viasat-3 Ground System Infrastructure Guide + * - Viasat Tactical Networking Platform Hardware Notes + * + * Run: tsx packages/scraper/src/scrapers/viasat-oem.ts + * Cron: daily at 19:00 + */ + +import { pool, ensureVendor } from "../utils/db"; + +interface ViasatPID { + pid: string; + formFactor: string; + speedGbps: number; + speed: string; + reachMeters: number; + reachLabel: string; + fiberType: string; + connector: string; + wavelengths?: string; + standard?: string; + notes?: string; +} + +const VIASAT_PIDS: ViasatPID[] = [ + // ── 1G SFP ────────────────────────────────────────────────────────────── + { pid: "VS-SFP-1G-SX", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 550, reachLabel: "SX", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "1000BASE-SX", notes: "Viasat 1G SX SFP for SurfBeam 3 gateway modem intra-site links" }, + { pid: "VS-SFP-1G-LX", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 10000, reachLabel: "LX", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "1000BASE-LX", notes: "Viasat 1G LX SFP for teleport equipment inter-building connectivity" }, + { pid: "VS-SFP-GE-T", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 100, reachLabel: "T", fiberType: "DAC", connector: "RJ45", standard: "1000BASE-T", notes: "Viasat 1G copper SFP for ground equipment management ports" }, + + // ── 10G SFP+ ──────────────────────────────────────────────────────────── + { pid: "VS-SFP-10G-SR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 300, reachLabel: "SR", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "10GBASE-SR", notes: "Viasat 10G SR SFP+ for gateway aggregation within teleport facility" }, + { pid: "VS-SFP-10G-LR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 10000, reachLabel: "LR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "10GBASE-LR", notes: "Viasat 10G LR for teleport campus backbone" }, + { pid: "VS-SFP-10G-ER", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 40000, reachLabel: "ER", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "10GBASE-ER", notes: "Viasat 10G ER for extended-reach ground station backhaul" }, + { pid: "VS-SFP-10G-ZR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 80000, reachLabel: "ZR", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "10GBASE-ZR", notes: "Viasat 10G ZR for ground station long-haul fiber links to PoP" }, + + // ── 25G SFP28 ─────────────────────────────────────────────────────────── + { pid: "VS-SFP28-25G-SR", formFactor: "SFP28", speedGbps: 25, speed: "25G", reachMeters: 100, reachLabel: "SR", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "25GBASE-SR", notes: "Viasat 25G SR for high-density SurfBeam 3 gateway server rack" }, + { pid: "VS-SFP28-25G-LR", formFactor: "SFP28", speedGbps: 25, speed: "25G", reachMeters: 10000, reachLabel: "LR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "25GBASE-LR", notes: "Viasat 25G LR for inter-building ground system links" }, + + // ── 40G QSFP+ ─────────────────────────────────────────────────────────── + { pid: "VS-QSFP-40G-SR4", formFactor: "QSFP+", speedGbps: 40, speed: "40G", reachMeters: 150, reachLabel: "SR4", fiberType: "MMF", connector: "MPO", wavelengths: "850nm", standard: "40GBASE-SR4" }, + { pid: "VS-QSFP-40G-LR4", formFactor: "QSFP+", speedGbps: 40, speed: "40G", reachMeters: 10000, reachLabel: "LR4", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "40GBASE-LR4" }, + + // ── 100G QSFP28 ───────────────────────────────────────────────────────── + { pid: "VS-QSFP28-100G-SR4", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 100, reachLabel: "SR4", fiberType: "MMF", connector: "MPO", wavelengths: "850nm", standard: "100GBASE-SR4" }, + { pid: "VS-QSFP28-100G-LR4", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 10000, reachLabel: "LR4", fiberType: "SMF", connector: "LC", wavelengths: "1295-1310nm", standard: "100GBASE-LR4", notes: "Viasat 100G LR4 for Viasat-3 ground system high-capacity trunking" }, + + // ── 400G QSFP-DD ──────────────────────────────────────────────────────── + { pid: "VS-QSFP-DD-400G-DR4", formFactor: "QSFP-DD", speedGbps: 400, speed: "400G", reachMeters: 500, reachLabel: "DR4", fiberType: "SMF", connector: "MPO", wavelengths: "1310nm", standard: "400GBASE-DR4", notes: "Viasat 400G DR4 for next-gen Viasat-3 ground aggregation fabric" }, +]; + +export async function scrapeViasatOem(): Promise { + console.log("=== Viasat OEM Transceiver Seed ===\n"); + + const vendorId = await ensureVendor( + "Viasat", + "oem", + "https://www.viasat.com", + undefined + ); + + let inserted = 0; + let updated = 0; + let errors = 0; + + for (const p of VIASAT_PIDS) { + const slug = `viasat-${p.pid.toLowerCase().replace(/[^a-z0-9]+/g, "-")}`; + try { + const res = await pool.query( + `INSERT INTO transceivers + (slug, part_number, vendor_id, form_factor, speed, speed_gbps, + reach_meters, reach_label, fiber_type, connector, wavelengths, + dom_support, ieee_reference, market_status, category, notes) + VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,true,$12,'Mainstream','DataCenter',$13) + ON CONFLICT (slug) DO UPDATE SET + speed_gbps = EXCLUDED.speed_gbps, + reach_meters = CASE WHEN EXCLUDED.reach_meters > 0 THEN EXCLUDED.reach_meters ELSE transceivers.reach_meters END, + fiber_type = CASE WHEN EXCLUDED.fiber_type <> '' THEN EXCLUDED.fiber_type ELSE transceivers.fiber_type END, + wavelengths = COALESCE(EXCLUDED.wavelengths, transceivers.wavelengths), + updated_at = NOW() + RETURNING (xmax = 0) as was_inserted`, + [slug, p.pid, vendorId, p.formFactor, p.speed, p.speedGbps, + p.reachMeters, p.reachLabel, p.fiberType, p.connector, + p.wavelengths ?? null, p.standard ?? null, p.notes ?? null] + ); + if (res.rows[0]?.was_inserted) inserted++; else updated++; + } catch (err) { + console.warn(` Skip ${p.pid}: ${(err as Error).message.slice(0, 80)}`); + errors++; + } + } + + console.log(`\n=== Viasat OEM Seed Complete ===`); + console.log(` Inserted: ${inserted}`); + console.log(` Updated: ${updated}`); + console.log(` Errors: ${errors}`); + console.log(` Total PIDs: ${VIASAT_PIDS.length}\n`); +} + +if (require.main === module) { + scrapeViasatOem() + .then(() => pool.end()) + .catch((err) => { + console.error("Fatal:", err); + pool.end(); + process.exit(1); + }); +} diff --git a/packages/scraper/src/scrapers/viavi-oem.ts b/packages/scraper/src/scrapers/viavi-oem.ts new file mode 100644 index 0000000..1ac9941 --- /dev/null +++ b/packages/scraper/src/scrapers/viavi-oem.ts @@ -0,0 +1,144 @@ +/** + * Viavi Solutions OEM Transceiver Catalog Seed + * + * Seeds Viavi Solutions (formerly JDSU) branded transceiver PIDs. + * Viavi manufactures transceivers OEM-branded for network vendors + * alongside their test & measurement product lines. + * + * Sources: + * - Viavi Solutions Transceiver Product Portfolio (viavisolutions.com) + * - JDSU/Viavi optical transceiver datasheets + * - SFF-8024 MSA compliance references + * + * Run: tsx packages/scraper/src/scrapers/viavi-oem.ts + * Cron: daily at 13:00 + */ + +import { pool, ensureVendor } from "../utils/db"; + +interface ViaviPID { + pid: string; + formFactor: string; + speedGbps: number; + speed: string; + reachMeters: number; + reachLabel: string; + fiberType: string; + connector: string; + wavelengths?: string; + standard?: string; + notes?: string; +} + +const TELECOM_PIDS = new Set([ + "JDS-SFP-10GE-DW-TUNE", + "JDS-QSFPDD-400GE-ZR", +]); + +const VIAVI_PIDS: ViaviPID[] = [ + // ── 1G SFP ────────────────────────────────────────────────────────────── + { pid: "JDS-SFP-1GE-SX", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 550, reachLabel: "SX", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "1000BASE-SX" }, + { pid: "JDS-SFP-1GE-LX", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 10000, reachLabel: "LX", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "1000BASE-LX" }, + { pid: "JDS-SFP-1GE-ZX", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 80000, reachLabel: "ZX", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "1000BASE-ZX" }, + { pid: "JDS-SFP-1GE-T", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 100, reachLabel: "T", fiberType: "DAC", connector: "RJ45", standard: "1000BASE-T" }, + + // ── 10G SFP+ ──────────────────────────────────────────────────────────── + { pid: "JDS-SFP-10GE-SR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 300, reachLabel: "SR", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "10GBASE-SR" }, + { pid: "JDS-SFP-10GE-LR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 10000, reachLabel: "LR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "10GBASE-LR" }, + { pid: "JDS-SFP-10GE-ER", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 40000, reachLabel: "ER", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "10GBASE-ER" }, + { pid: "JDS-SFP-10GE-ZR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 80000, reachLabel: "ZR", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "10GBASE-ZR" }, + { pid: "JDS-SFP-10GE-LRM", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 220, reachLabel: "LRM", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "10GBASE-LRM" }, + + // ── 10G DWDM SFP+ ─────────────────────────────────────────────────────── + { pid: "JDS-SFP-10GE-DW-TUNE", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 80000, reachLabel: "DW-TUNE", fiberType: "SMF", connector: "LC", wavelengths: "C-band DWDM", notes: "Viavi 10G DWDM tunable SFP+" }, + + // ── 25G SFP28 ─────────────────────────────────────────────────────────── + { pid: "JDS-SFP28-25GE-SR", formFactor: "SFP28", speedGbps: 25, speed: "25G", reachMeters: 100, reachLabel: "SR", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "25GBASE-SR" }, + { pid: "JDS-SFP28-25GE-LR", formFactor: "SFP28", speedGbps: 25, speed: "25G", reachMeters: 10000, reachLabel: "LR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "25GBASE-LR" }, + { pid: "JDS-SFP28-25GE-ER", formFactor: "SFP28", speedGbps: 25, speed: "25G", reachMeters: 30000, reachLabel: "ER", fiberType: "SMF", connector: "LC", wavelengths: "1310nm" }, + + // ── 40G QSFP+ ─────────────────────────────────────────────────────────── + { pid: "JDS-QSFP-40GE-SR4", formFactor: "QSFP+", speedGbps: 40, speed: "40G", reachMeters: 150, reachLabel: "SR4", fiberType: "MMF", connector: "MPO", wavelengths: "850nm", standard: "40GBASE-SR4" }, + { pid: "JDS-QSFP-40GE-LR4", formFactor: "QSFP+", speedGbps: 40, speed: "40G", reachMeters: 10000, reachLabel: "LR4", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "40GBASE-LR4" }, + { pid: "JDS-QSFP-40GE-ER4", formFactor: "QSFP+", speedGbps: 40, speed: "40G", reachMeters: 40000, reachLabel: "ER4", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "40GBASE-ER4" }, + + // ── 100G QSFP28 ───────────────────────────────────────────────────────── + { pid: "JDS-QSFP28-100GE-SR4", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 100, reachLabel: "SR4", fiberType: "MMF", connector: "MPO", wavelengths: "850nm", standard: "100GBASE-SR4" }, + { pid: "JDS-QSFP28-100GE-LR4", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 10000, reachLabel: "LR4", fiberType: "SMF", connector: "LC", wavelengths: "1295-1310nm", standard: "100GBASE-LR4" }, + { pid: "JDS-QSFP28-100GE-CWDM4", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 2000, reachLabel: "CWDM4", fiberType: "SMF", connector: "LC", wavelengths: "1271-1331nm", standard: "100GBASE-CWDM4" }, + { pid: "JDS-QSFP28-100GE-DR", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 500, reachLabel: "DR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "100GBASE-DR" }, + { pid: "JDS-QSFP28-100GE-FR", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 2000, reachLabel: "FR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "100GBASE-FR" }, + + // ── 400G QSFP-DD ──────────────────────────────────────────────────────── + { pid: "JDS-QSFPDD-400GE-SR8", formFactor: "QSFP-DD", speedGbps: 400, speed: "400G", reachMeters: 100, reachLabel: "SR8", fiberType: "MMF", connector: "MPO", wavelengths: "850nm", standard: "400GBASE-SR8" }, + { pid: "JDS-QSFPDD-400GE-DR4", formFactor: "QSFP-DD", speedGbps: 400, speed: "400G", reachMeters: 500, reachLabel: "DR4", fiberType: "SMF", connector: "MPO", wavelengths: "1310nm", standard: "400GBASE-DR4" }, + { pid: "JDS-QSFPDD-400GE-FR4", formFactor: "QSFP-DD", speedGbps: 400, speed: "400G", reachMeters: 2000, reachLabel: "FR4", fiberType: "SMF", connector: "LC", wavelengths: "1271-1331nm", standard: "400GBASE-FR4" }, + { pid: "JDS-QSFPDD-400GE-LR4", formFactor: "QSFP-DD", speedGbps: 400, speed: "400G", reachMeters: 10000, reachLabel: "LR4", fiberType: "SMF", connector: "LC", wavelengths: "1295-1310nm", standard: "400GBASE-LR4" }, + { pid: "JDS-QSFPDD-400GE-ZR", formFactor: "QSFP-DD", speedGbps: 400, speed: "400G", reachMeters: 120000, reachLabel: "ZR", fiberType: "SMF", connector: "LC", wavelengths: "C-band", standard: "400ZR", notes: "Viavi 400G ZR coherent QSFP-DD" }, + + // ── DAC ───────────────────────────────────────────────────────────────── + { pid: "JDS-DAC-10GE-1M", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 1, reachLabel: "DAC-1M", fiberType: "DAC", connector: "SFP+" }, + { pid: "JDS-DAC-10GE-3M", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 3, reachLabel: "DAC-3M", fiberType: "DAC", connector: "SFP+" }, + { pid: "JDS-DAC-100GE-1M", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 1, reachLabel: "DAC-1M", fiberType: "DAC", connector: "QSFP28" }, + { pid: "JDS-DAC-100GE-3M", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 3, reachLabel: "DAC-3M", fiberType: "DAC", connector: "QSFP28" }, + { pid: "JDS-DAC-400GE-1M", formFactor: "QSFP-DD", speedGbps: 400, speed: "400G", reachMeters: 1, reachLabel: "DAC-1M", fiberType: "DAC", connector: "QSFP-DD" }, +]; + +export async function scrapeViaviOem(): Promise { + console.log("=== Viavi Solutions OEM Transceiver Seed ===\n"); + + const vendorId = await ensureVendor( + "Viavi Solutions", + "oem", + "https://www.viavisolutions.com", + undefined + ); + + let inserted = 0; + let updated = 0; + let errors = 0; + + for (const p of VIAVI_PIDS) { + const slug = `viavi-${p.pid.toLowerCase().replace(/[^a-z0-9]+/g, "-")}`; + const category = TELECOM_PIDS.has(p.pid) ? "Telecom" : "DataCenter"; + try { + const res = await pool.query( + `INSERT INTO transceivers + (slug, part_number, vendor_id, form_factor, speed, speed_gbps, + reach_meters, reach_label, fiber_type, connector, wavelengths, + dom_support, ieee_reference, market_status, category, notes) + VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,true,$12,'Mainstream',$13,$14) + ON CONFLICT (slug) DO UPDATE SET + speed_gbps = EXCLUDED.speed_gbps, + reach_meters = CASE WHEN EXCLUDED.reach_meters > 0 THEN EXCLUDED.reach_meters ELSE transceivers.reach_meters END, + fiber_type = CASE WHEN EXCLUDED.fiber_type <> '' THEN EXCLUDED.fiber_type ELSE transceivers.fiber_type END, + wavelengths = COALESCE(EXCLUDED.wavelengths, transceivers.wavelengths), + updated_at = NOW() + RETURNING (xmax = 0) as was_inserted`, + [slug, p.pid, vendorId, p.formFactor, p.speed, p.speedGbps, + p.reachMeters, p.reachLabel, p.fiberType, p.connector, + p.wavelengths ?? null, p.standard ?? null, category, p.notes ?? null] + ); + if (res.rows[0]?.was_inserted) inserted++; else updated++; + } catch (err) { + console.warn(` Skip ${p.pid}: ${(err as Error).message.slice(0, 80)}`); + errors++; + } + } + + console.log(`\n=== Viavi Solutions OEM Seed Complete ===`); + console.log(` Inserted: ${inserted}`); + console.log(` Updated: ${updated}`); + console.log(` Errors: ${errors}`); + console.log(` Total PIDs: ${VIAVI_PIDS.length}\n`); +} + +if (require.main === module) { + scrapeViaviOem() + .then(() => pool.end()) + .catch((err) => { + console.error("Fatal:", err); + pool.end(); + process.exit(1); + }); +} diff --git a/packages/scraper/src/scrapers/viptela-oem.ts b/packages/scraper/src/scrapers/viptela-oem.ts new file mode 100644 index 0000000..ab0183d --- /dev/null +++ b/packages/scraper/src/scrapers/viptela-oem.ts @@ -0,0 +1,117 @@ +/** + * Viptela (Cisco SD-WAN) OEM Transceiver Catalog Seed + * + * Seeds Viptela-branded SFP/SFP+/SFP28/QSFP+/QSFP28/QSFP-DD transceiver PIDs + * for vEdge router and Cisco SD-WAN platform optic requirements. + * + * Sources: + * - Cisco SD-WAN vEdge router hardware compatibility lists + * - https://www.cisco.com/c/en/us/solutions/enterprise-networks/sd-wan + * + * Run: tsx packages/scraper/src/scrapers/viptela-oem.ts + * Cron: daily at 04:15 + */ + +import { pool, ensureVendor } from "../utils/db"; + +interface ViptelaPID { + pid: string; + formFactor: string; + speedGbps: number; + speed: string; + reachMeters: number; + reachLabel: string; + fiberType: string; + connector: string; + wavelengths?: string; + standard?: string; + notes?: string; +} + +const VIPTELA_PIDS: ViptelaPID[] = [ + // ── 1G SFP ────────────────────────────────────────────────────────────── + { pid: "VIP-SFP-1G-SX", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 550, reachLabel: "SX", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "1000BASE-SX", notes: "Viptela 1G MM SFP for vEdge-100/1000/2000" }, + { pid: "VIP-SFP-1G-LX", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 10000, reachLabel: "LX", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "1000BASE-LX" }, + { pid: "VIP-SFP-1G-T", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 100, reachLabel: "T", fiberType: "DAC", connector: "RJ45", standard: "1000BASE-T", notes: "Copper SFP for vEdge management/WAN ports" }, + { pid: "VIP-SFP-GE-T", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 100, reachLabel: "GE-T", fiberType: "DAC", connector: "RJ45", standard: "1000BASE-T", notes: "GE copper SFP variant for vEdge-100b/m" }, + { pid: "VIP-SFP-GE-BIDI", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 20000, reachLabel: "BiDi", fiberType: "SMF", connector: "LC", wavelengths: "TX1310/RX1550", standard: "1000BASE-BX", notes: "1G BiDi SFP for single-strand WAN links" }, + + // ── 10G SFP+ ──────────────────────────────────────────────────────────── + { pid: "VIP-SFP-10G-SR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 300, reachLabel: "SR", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "10GBASE-SR" }, + { pid: "VIP-SFP-10G-LR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 10000, reachLabel: "LR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "10GBASE-LR" }, + { pid: "VIP-SFP-10G-ER", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 40000, reachLabel: "ER", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "10GBASE-ER", notes: "Extended reach for vEdge-2000/5000 WAN" }, + { pid: "VIP-SFP-10G-ZR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 80000, reachLabel: "ZR", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "10GBASE-ZR", notes: "80km ZR for long-haul SD-WAN edge links" }, + + // ── 25G SFP28 ─────────────────────────────────────────────────────────── + { pid: "VIP-SFP28-25G-SR", formFactor: "SFP28", speedGbps: 25, speed: "25G", reachMeters: 100, reachLabel: "SR", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "25GBASE-SR", notes: "25G MM for vEdge Cloud and next-gen SD-WAN" }, + { pid: "VIP-SFP28-25G-LR", formFactor: "SFP28", speedGbps: 25, speed: "25G", reachMeters: 10000, reachLabel: "LR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "25GBASE-LR" }, + + // ── 40G QSFP+ ─────────────────────────────────────────────────────────── + { pid: "VIP-QSFP-40G-SR4", formFactor: "QSFP+", speedGbps: 40, speed: "40G", reachMeters: 150, reachLabel: "SR4", fiberType: "MMF", connector: "MPO", wavelengths: "850nm", standard: "40GBASE-SR4", notes: "40G MPO for vEdge-5000 and high-density PoPs" }, + { pid: "VIP-QSFP-40G-LR4", formFactor: "QSFP+", speedGbps: 40, speed: "40G", reachMeters: 10000, reachLabel: "LR4", fiberType: "SMF", connector: "LC", wavelengths: "1295-1310nm", standard: "40GBASE-LR4" }, + + // ── 100G QSFP28 ───────────────────────────────────────────────────────── + { pid: "VIP-QSFP28-100G-SR4", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 100, reachLabel: "SR4", fiberType: "MMF", connector: "MPO", wavelengths: "850nm", standard: "100GBASE-SR4" }, + { pid: "VIP-QSFP28-100G-LR4", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 10000, reachLabel: "LR4", fiberType: "SMF", connector: "LC", wavelengths: "1295-1310nm", standard: "100GBASE-LR4" }, + + // ── 400G QSFP-DD ──────────────────────────────────────────────────────── + { pid: "VIP-QSFP-DD-400G-DR4", formFactor: "QSFP-DD", speedGbps: 400, speed: "400G", reachMeters: 500, reachLabel: "DR4", fiberType: "SMF", connector: "MPO", wavelengths: "1310nm", standard: "400GBASE-DR4", notes: "400G DR4 for next-gen Cisco SD-WAN edge/aggregation" }, +]; + +export async function scrapeViptelaOem(): Promise { + console.log("=== Viptela (Cisco SD-WAN) OEM Transceiver Seed ===\n"); + + const vendorId = await ensureVendor( + "Viptela", + "oem", + "https://www.cisco.com/c/en/us/solutions/enterprise-networks/sd-wan", + undefined + ); + + let inserted = 0; + let updated = 0; + let errors = 0; + + for (const p of VIPTELA_PIDS) { + const slug = `viptela-${p.pid.toLowerCase().replace(/[^a-z0-9]+/g, "-")}`; + try { + const res = await pool.query( + `INSERT INTO transceivers + (slug, part_number, vendor_id, form_factor, speed, speed_gbps, + reach_meters, reach_label, fiber_type, connector, wavelengths, + dom_support, ieee_reference, market_status, category, notes) + VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,true,$12,'Mainstream','DataCenter',$13) + ON CONFLICT (slug) DO UPDATE SET + speed_gbps = EXCLUDED.speed_gbps, + reach_meters = CASE WHEN EXCLUDED.reach_meters > 0 THEN EXCLUDED.reach_meters ELSE transceivers.reach_meters END, + fiber_type = CASE WHEN EXCLUDED.fiber_type <> '' THEN EXCLUDED.fiber_type ELSE transceivers.fiber_type END, + wavelengths = COALESCE(EXCLUDED.wavelengths, transceivers.wavelengths), + updated_at = NOW() + RETURNING (xmax = 0) as was_inserted`, + [slug, p.pid, vendorId, p.formFactor, p.speed, p.speedGbps, + p.reachMeters, p.reachLabel, p.fiberType, p.connector, + p.wavelengths ?? null, p.standard ?? null, p.notes ?? null] + ); + if (res.rows[0]?.was_inserted) inserted++; else updated++; + } catch (err) { + console.warn(` Skip ${p.pid}: ${(err as Error).message.slice(0, 80)}`); + errors++; + } + } + + console.log(`\n=== Viptela OEM Seed Complete ===`); + console.log(` Inserted: ${inserted}`); + console.log(` Updated: ${updated}`); + console.log(` Errors: ${errors}`); + console.log(` Total PIDs: ${VIPTELA_PIDS.length}\n`); +} + +if (require.main === module) { + scrapeViptelaOem() + .then(() => pool.end()) + .catch((err) => { + console.error("Fatal:", err); + pool.end(); + process.exit(1); + }); +} diff --git a/packages/scraper/src/scrapers/vmware-oem.ts b/packages/scraper/src/scrapers/vmware-oem.ts new file mode 100644 index 0000000..e4f12d0 --- /dev/null +++ b/packages/scraper/src/scrapers/vmware-oem.ts @@ -0,0 +1,117 @@ +/** + * VMware OEM Transceiver Catalog Seed + * + * Seeds VMware-branded SFP/SFP+/SFP28/QSFP+/QSFP28/QSFP-DD transceiver PIDs + * for NSX Edge, VeloCloud SD-WAN Edge, and vSphere host connectivity. + * + * Sources: + * - VMware VeloCloud SD-WAN Edge hardware compatibility list + * - VMware NSX hardware compatibility guide (vmware.com) + * + * Run: tsx packages/scraper/src/scrapers/vmware-oem.ts + * Cron: daily at 04:45 + */ + +import { pool, ensureVendor } from "../utils/db"; + +interface VmwarePID { + pid: string; + formFactor: string; + speedGbps: number; + speed: string; + reachMeters: number; + reachLabel: string; + fiberType: string; + connector: string; + wavelengths?: string; + standard?: string; + notes?: string; +} + +const VMWARE_PIDS: VmwarePID[] = [ + // ── 1G SFP ────────────────────────────────────────────────────────────── + { pid: "VM-SFP-1G-SX", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 550, reachLabel: "SX", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "1000BASE-SX", notes: "VMware 1G MM SFP for VeloCloud Edge 510/540/620/840 LAN" }, + { pid: "VM-SFP-1G-LX", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 10000, reachLabel: "LX", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "1000BASE-LX" }, + { pid: "VM-SFP-1G-T", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 100, reachLabel: "T", fiberType: "DAC", connector: "RJ45", standard: "1000BASE-T", notes: "Copper SFP for VeloCloud Edge and NSX Gateway appliances" }, + { pid: "VM-SFP-GE-T", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 100, reachLabel: "GE-T", fiberType: "DAC", connector: "RJ45", standard: "1000BASE-T", notes: "GE copper SFP variant for VMware host NICs" }, + + // ── 10G SFP+ ──────────────────────────────────────────────────────────── + { pid: "VM-SFP-10G-SR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 300, reachLabel: "SR", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "10GBASE-SR", notes: "VMware 10G SR for ESXi host uplinks and NSX overlay fabric" }, + { pid: "VM-SFP-10G-LR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 10000, reachLabel: "LR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "10GBASE-LR" }, + { pid: "VM-SFP-10G-ER", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 40000, reachLabel: "ER", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "10GBASE-ER", notes: "40km ER for stretched cluster and multi-site NSX deployments" }, + { pid: "VM-SFP-10G-ZR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 80000, reachLabel: "ZR", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "10GBASE-ZR", notes: "80km ZR for VMware Cloud on AWS/Azure DX/ExpressRoute hand-off" }, + + // ── 25G SFP28 ─────────────────────────────────────────────────────────── + { pid: "VM-SFP28-25G-SR", formFactor: "SFP28", speedGbps: 25, speed: "25G", reachMeters: 100, reachLabel: "SR", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "25GBASE-SR", notes: "25G SR for VeloCloud Edge 3800 and NSX-T fabric" }, + { pid: "VM-SFP28-25G-LR", formFactor: "SFP28", speedGbps: 25, speed: "25G", reachMeters: 10000, reachLabel: "LR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "25GBASE-LR" }, + + // ── 40G QSFP+ ─────────────────────────────────────────────────────────── + { pid: "VM-QSFP-40G-SR4", formFactor: "QSFP+", speedGbps: 40, speed: "40G", reachMeters: 150, reachLabel: "SR4", fiberType: "MMF", connector: "MPO", wavelengths: "850nm", standard: "40GBASE-SR4", notes: "40G MPO for VMware vSAN all-flash and NSX top-of-rack" }, + { pid: "VM-QSFP-40G-LR4", formFactor: "QSFP+", speedGbps: 40, speed: "40G", reachMeters: 10000, reachLabel: "LR4", fiberType: "SMF", connector: "LC", wavelengths: "1295-1310nm", standard: "40GBASE-LR4" }, + + // ── 100G QSFP28 ───────────────────────────────────────────────────────── + { pid: "VM-QSFP28-100G-SR4", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 100, reachLabel: "SR4", fiberType: "MMF", connector: "MPO", wavelengths: "850nm", standard: "100GBASE-SR4" }, + { pid: "VM-QSFP28-100G-LR4", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 10000, reachLabel: "LR4", fiberType: "SMF", connector: "LC", wavelengths: "1295-1310nm", standard: "100GBASE-LR4" }, + + // ── 400G QSFP-DD ──────────────────────────────────────────────────────── + { pid: "VM-QSFP-DD-400G-SR8", formFactor: "QSFP-DD", speedGbps: 400, speed: "400G", reachMeters: 100, reachLabel: "SR8", fiberType: "MMF", connector: "MPO", wavelengths: "850nm", standard: "400GBASE-SR8", notes: "400G SR8 for VMware Project Monterey SmartNIC fabric" }, + { pid: "VM-QSFP-DD-400G-DR4", formFactor: "QSFP-DD", speedGbps: 400, speed: "400G", reachMeters: 500, reachLabel: "DR4", fiberType: "SMF", connector: "MPO", wavelengths: "1310nm", standard: "400GBASE-DR4", notes: "400G DR4 for VMware Cloud Foundation spine uplinks" }, +]; + +export async function scrapeVmwareOem(): Promise { + console.log("=== VMware OEM Transceiver Seed ===\n"); + + const vendorId = await ensureVendor( + "VMware", + "oem", + "https://www.vmware.com", + undefined + ); + + let inserted = 0; + let updated = 0; + let errors = 0; + + for (const p of VMWARE_PIDS) { + const slug = `vmware-${p.pid.toLowerCase().replace(/[^a-z0-9]+/g, "-")}`; + try { + const res = await pool.query( + `INSERT INTO transceivers + (slug, part_number, vendor_id, form_factor, speed, speed_gbps, + reach_meters, reach_label, fiber_type, connector, wavelengths, + dom_support, ieee_reference, market_status, category, notes) + VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,true,$12,'Mainstream','DataCenter',$13) + ON CONFLICT (slug) DO UPDATE SET + speed_gbps = EXCLUDED.speed_gbps, + reach_meters = CASE WHEN EXCLUDED.reach_meters > 0 THEN EXCLUDED.reach_meters ELSE transceivers.reach_meters END, + fiber_type = CASE WHEN EXCLUDED.fiber_type <> '' THEN EXCLUDED.fiber_type ELSE transceivers.fiber_type END, + wavelengths = COALESCE(EXCLUDED.wavelengths, transceivers.wavelengths), + updated_at = NOW() + RETURNING (xmax = 0) as was_inserted`, + [slug, p.pid, vendorId, p.formFactor, p.speed, p.speedGbps, + p.reachMeters, p.reachLabel, p.fiberType, p.connector, + p.wavelengths ?? null, p.standard ?? null, p.notes ?? null] + ); + if (res.rows[0]?.was_inserted) inserted++; else updated++; + } catch (err) { + console.warn(` Skip ${p.pid}: ${(err as Error).message.slice(0, 80)}`); + errors++; + } + } + + console.log(`\n=== VMware OEM Seed Complete ===`); + console.log(` Inserted: ${inserted}`); + console.log(` Updated: ${updated}`); + console.log(` Errors: ${errors}`); + console.log(` Total PIDs: ${VMWARE_PIDS.length}\n`); +} + +if (require.main === module) { + scrapeVmwareOem() + .then(() => pool.end()) + .catch((err) => { + console.error("Fatal:", err); + pool.end(); + process.exit(1); + }); +} diff --git a/packages/scraper/src/scrapers/watchguard-oem.ts b/packages/scraper/src/scrapers/watchguard-oem.ts new file mode 100644 index 0000000..83dfeb7 --- /dev/null +++ b/packages/scraper/src/scrapers/watchguard-oem.ts @@ -0,0 +1,120 @@ +/** + * WatchGuard OEM Transceiver Catalog Seed + * + * Seeds WatchGuard-branded transceiver PIDs for Firebox M and T series + * network security appliances. + * + * Sources: + * - WatchGuard Firebox Hardware Compatibility (watchguard.com) + * - WatchGuard Firebox M/T Series Datasheet + * + * Run: tsx packages/scraper/src/scrapers/watchguard-oem.ts + * Cron: daily at 13:45 + */ + +import { pool, ensureVendor } from "../utils/db"; + +interface WatchguardPID { + pid: string; + formFactor: string; + speedGbps: number; + speed: string; + reachMeters: number; + reachLabel: string; + fiberType: string; + connector: string; + wavelengths?: string; + standard?: string; + notes?: string; +} + +const WATCHGUARD_PIDS: WatchguardPID[] = [ + // ── 1G SFP ────────────────────────────────────────────────────────────── + { pid: "WG8573", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 550, reachLabel: "SX", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "1000BASE-SX" }, + { pid: "WG8574", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 10000, reachLabel: "LX", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "1000BASE-LX" }, + { pid: "WG8575", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 80000, reachLabel: "ZX", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "1000BASE-ZX" }, + { pid: "WG8576", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 100, reachLabel: "T", fiberType: "DAC", connector: "RJ45", standard: "1000BASE-T" }, + + // ── 10G SFP+ ──────────────────────────────────────────────────────────── + { pid: "WG8570", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 300, reachLabel: "SR", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "10GBASE-SR" }, + { pid: "WG8571", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 10000, reachLabel: "LR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "10GBASE-LR" }, + { pid: "WG8572", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 40000, reachLabel: "ER", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "10GBASE-ER" }, + { pid: "WG8577", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 30, reachLabel: "T", fiberType: "DAC", connector: "RJ45", standard: "10GBASE-T" }, + { pid: "WG8578", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 80000, reachLabel: "ZR", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "10GBASE-ZR" }, + + // ── 25G SFP28 ─────────────────────────────────────────────────────────── + { pid: "WG8580", formFactor: "SFP28", speedGbps: 25, speed: "25G", reachMeters: 100, reachLabel: "SR", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "25GBASE-SR" }, + { pid: "WG8581", formFactor: "SFP28", speedGbps: 25, speed: "25G", reachMeters: 10000, reachLabel: "LR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "25GBASE-LR" }, + + // ── 40G QSFP+ ─────────────────────────────────────────────────────────── + { pid: "WG8590", formFactor: "QSFP+", speedGbps: 40, speed: "40G", reachMeters: 150, reachLabel: "SR4", fiberType: "MMF", connector: "MPO", wavelengths: "850nm", standard: "40GBASE-SR4" }, + { pid: "WG8591", formFactor: "QSFP+", speedGbps: 40, speed: "40G", reachMeters: 10000, reachLabel: "LR4", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "40GBASE-LR4" }, + + // ── 100G QSFP28 ───────────────────────────────────────────────────────── + { pid: "WG8600", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 100, reachLabel: "SR4", fiberType: "MMF", connector: "MPO", wavelengths: "850nm", standard: "100GBASE-SR4" }, + { pid: "WG8601", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 10000, reachLabel: "LR4", fiberType: "SMF", connector: "LC", wavelengths: "1295-1310nm", standard: "100GBASE-LR4" }, + { pid: "WG8602", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 2000, reachLabel: "CWDM4", fiberType: "SMF", connector: "LC", wavelengths: "1271-1331nm", standard: "100GBASE-CWDM4" }, + + // ── DAC ───────────────────────────────────────────────────────────────── + { pid: "WG8560", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 1, reachLabel: "DAC-1M", fiberType: "DAC", connector: "SFP+" }, + { pid: "WG8561", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 3, reachLabel: "DAC-3M", fiberType: "DAC", connector: "SFP+" }, + { pid: "WG8562", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 1, reachLabel: "DAC-1M", fiberType: "DAC", connector: "QSFP28" }, +]; + +export async function scrapeWatchguardOem(): Promise { + console.log("=== WatchGuard OEM Transceiver Seed ===\n"); + + const vendorId = await ensureVendor( + "WatchGuard", + "oem", + "https://www.watchguard.com", + undefined + ); + + let inserted = 0; + let updated = 0; + let errors = 0; + + for (const p of WATCHGUARD_PIDS) { + const slug = `watchguard-${p.pid.toLowerCase().replace(/[^a-z0-9]+/g, "-")}`; + try { + const res = await pool.query( + `INSERT INTO transceivers + (slug, part_number, vendor_id, form_factor, speed, speed_gbps, + reach_meters, reach_label, fiber_type, connector, wavelengths, + dom_support, ieee_reference, market_status, category, notes) + VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,true,$12,'Mainstream','DataCenter',$13) + ON CONFLICT (slug) DO UPDATE SET + speed_gbps = EXCLUDED.speed_gbps, + reach_meters = CASE WHEN EXCLUDED.reach_meters > 0 THEN EXCLUDED.reach_meters ELSE transceivers.reach_meters END, + fiber_type = CASE WHEN EXCLUDED.fiber_type <> '' THEN EXCLUDED.fiber_type ELSE transceivers.fiber_type END, + wavelengths = COALESCE(EXCLUDED.wavelengths, transceivers.wavelengths), + updated_at = NOW() + RETURNING (xmax = 0) as was_inserted`, + [slug, p.pid, vendorId, p.formFactor, p.speed, p.speedGbps, + p.reachMeters, p.reachLabel, p.fiberType, p.connector, + p.wavelengths ?? null, p.standard ?? null, p.notes ?? null] + ); + if (res.rows[0]?.was_inserted) inserted++; else updated++; + } catch (err) { + console.warn(` Skip ${p.pid}: ${(err as Error).message.slice(0, 80)}`); + errors++; + } + } + + console.log(`\n=== WatchGuard OEM Seed Complete ===`); + console.log(` Inserted: ${inserted}`); + console.log(` Updated: ${updated}`); + console.log(` Errors: ${errors}`); + console.log(` Total PIDs: ${WATCHGUARD_PIDS.length}\n`); +} + +if (require.main === module) { + scrapeWatchguardOem() + .then(() => pool.end()) + .catch((err) => { + console.error("Fatal:", err); + pool.end(); + process.exit(1); + }); +} diff --git a/packages/scraper/src/scrapers/westermo-oem.ts b/packages/scraper/src/scrapers/westermo-oem.ts new file mode 100644 index 0000000..00e41cb --- /dev/null +++ b/packages/scraper/src/scrapers/westermo-oem.ts @@ -0,0 +1,117 @@ +/** + * Westermo OEM Transceiver Catalog Seed + * + * Seeds transceiver PIDs for Westermo industrial-grade SFP modules used in + * RAIL and substation industrial Ethernet managed switches. + * + * Sources: + * - Westermo SFP module datasheet (westermo.com) + * - Westermo industrial switch hardware installation guides + * + * Run: tsx packages/scraper/src/scrapers/westermo-oem.ts + * Cron: daily at 13:15 + */ + +import { pool, ensureVendor } from "../utils/db"; + +interface WestermoPID { + pid: string; + formFactor: string; + speedGbps: number; + speed: string; + reachMeters: number; + reachLabel: string; + fiberType: string; + connector: string; + wavelengths?: string; + standard?: string; + notes?: string; +} + +const WESTERMO_PIDS: WestermoPID[] = [ + // ── 100M SFP (industrial legacy) ──────────────────────────────────────── + { pid: "3629-0000", formFactor: "SFP", speedGbps: 0.1, speed: "100M", reachMeters: 2000, reachLabel: "FX", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "100BASE-FX", notes: "Westermo 100M MM SFP" }, + { pid: "3629-0001", formFactor: "SFP", speedGbps: 0.1, speed: "100M", reachMeters: 15000, reachLabel: "LFX", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "100BASE-LFX", notes: "Westermo 100M SM SFP 15km" }, + { pid: "3629-0002", formFactor: "SFP", speedGbps: 0.1, speed: "100M", reachMeters: 40000, reachLabel: "LFX", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", notes: "Westermo 100M SM SFP 40km" }, + + // ── 1G SFP ────────────────────────────────────────────────────────────── + { pid: "3630-0000", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 550, reachLabel: "SX", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "1000BASE-SX", notes: "Westermo 1G MM SFP SX" }, + { pid: "3630-0001", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 10000, reachLabel: "LX", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "1000BASE-LX", notes: "Westermo 1G SM SFP LX 10km" }, + { pid: "3630-0002", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 40000, reachLabel: "LH", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", notes: "Westermo 1G SM SFP LH 40km" }, + { pid: "3630-0003", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 80000, reachLabel: "ZX", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "1000BASE-ZX", notes: "Westermo 1G SM SFP ZX 80km" }, + { pid: "3630-0004", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 100, reachLabel: "T", fiberType: "DAC", connector: "RJ45", standard: "1000BASE-T", notes: "Westermo 1G copper SFP-T" }, + { pid: "3630-0005", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 20000, reachLabel: "BiDi-20K", fiberType: "SMF", connector: "LC", wavelengths: "TX1310/RX1550", notes: "Westermo 1G BiDi SFP single fiber" }, + + // ── 10G SFP+ ──────────────────────────────────────────────────────────── + { pid: "3640-0000", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 300, reachLabel: "SR", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "10GBASE-SR", notes: "Westermo 10G MM SFP+ SR" }, + { pid: "3640-0001", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 10000, reachLabel: "LR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "10GBASE-LR", notes: "Westermo 10G SM SFP+ LR" }, + { pid: "3640-0002", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 40000, reachLabel: "ER", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "10GBASE-ER", notes: "Westermo 10G SM SFP+ ER" }, + { pid: "3640-0003", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 80000, reachLabel: "ZR", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "10GBASE-ZR", notes: "Westermo 10G SM SFP+ ZR" }, + { pid: "3640-0004", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 10000, reachLabel: "BiDi-10K", fiberType: "SMF", connector: "LC", wavelengths: "TX1270/RX1330", notes: "Westermo 10G BiDi SFP+ single fiber" }, + + // ── 25G SFP28 ─────────────────────────────────────────────────────────── + { pid: "3650-0000", formFactor: "SFP28", speedGbps: 25, speed: "25G", reachMeters: 100, reachLabel: "SR", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "25GBASE-SR" }, + { pid: "3650-0001", formFactor: "SFP28", speedGbps: 25, speed: "25G", reachMeters: 10000, reachLabel: "LR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "25GBASE-LR" }, + + // ── DAC ───────────────────────────────────────────────────────────────── + { pid: "3641-0001", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 1, reachLabel: "DAC-1m", fiberType: "DAC", connector: "SFP+" }, + { pid: "3641-0003", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 3, reachLabel: "DAC-3m", fiberType: "DAC", connector: "SFP+" }, +]; + +export async function scrapeWestermoOem(): Promise { + console.log("=== Westermo OEM Transceiver Seed ===\n"); + + const vendorId = await ensureVendor( + "Westermo", + "oem", + "https://www.westermo.com", + undefined + ); + + let inserted = 0; + let updated = 0; + let errors = 0; + + for (const p of WESTERMO_PIDS) { + const slug = `westermo-${p.pid.toLowerCase().replace(/[^a-z0-9]+/g, "-")}`; + try { + const res = await pool.query( + `INSERT INTO transceivers + (slug, part_number, vendor_id, form_factor, speed, speed_gbps, + reach_meters, reach_label, fiber_type, connector, wavelengths, + dom_support, ieee_reference, market_status, category, notes) + VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,true,$12,'Mainstream','Industrial',$13) + ON CONFLICT (slug) DO UPDATE SET + speed_gbps = EXCLUDED.speed_gbps, + reach_meters = CASE WHEN EXCLUDED.reach_meters > 0 THEN EXCLUDED.reach_meters ELSE transceivers.reach_meters END, + fiber_type = CASE WHEN EXCLUDED.fiber_type <> '' THEN EXCLUDED.fiber_type ELSE transceivers.fiber_type END, + wavelengths = COALESCE(EXCLUDED.wavelengths, transceivers.wavelengths), + updated_at = NOW() + RETURNING (xmax = 0) as was_inserted`, + [slug, p.pid, vendorId, p.formFactor, p.speed, p.speedGbps, + p.reachMeters, p.reachLabel, p.fiberType, p.connector, + p.wavelengths ?? null, p.standard ?? null, p.notes ?? null] + ); + if (res.rows[0]?.was_inserted) inserted++; else updated++; + } catch (err) { + console.warn(` Skip ${p.pid}: ${(err as Error).message.slice(0, 80)}`); + errors++; + } + } + + console.log(`\n=== Westermo OEM Seed Complete ===`); + console.log(` Inserted: ${inserted}`); + console.log(` Updated: ${updated}`); + console.log(` Errors: ${errors}`); + console.log(` Total PIDs: ${WESTERMO_PIDS.length}\n`); +} + +if (require.main === module) { + scrapeWestermoOem() + .then(() => pool.end()) + .catch((err) => { + console.error("Fatal:", err); + pool.end(); + process.exit(1); + }); +} diff --git a/packages/scraper/src/scrapers/zte-access-oem.ts b/packages/scraper/src/scrapers/zte-access-oem.ts new file mode 100644 index 0000000..b59cade --- /dev/null +++ b/packages/scraper/src/scrapers/zte-access-oem.ts @@ -0,0 +1,141 @@ +/** + * ZTE Access OEM Transceiver Catalog Seed + * + * Seeds ZTE Access-branded transceiver PIDs for C600 / C650 / C680 OLT + * platforms supporting GPON, XGS-PON, and 10G-EPON line cards. + * + * Sources: + * - ZTE Fixed Network Access OLT Product Page (zte.com.cn/global) + * - ZTE C650 / C680 OLT Hardware Description + * - ZTE XGS-PON Optical Module Data Sheets + * + * Run: tsx packages/scraper/src/scrapers/zte-access-oem.ts + * Cron: daily at 08:45 + */ + +import { pool, ensureVendor } from "../utils/db"; + +interface ZteAccessPID { + pid: string; + formFactor: string; + speedGbps: number; + speed: string; + reachMeters: number; + reachLabel: string; + fiberType: string; + connector: string; + wavelengths?: string; + standard?: string; + notes?: string; + isTelecom?: boolean; +} + +const TELECOM_PIDS: Set = new Set([ + "ZTE-GPON-OLT-B", + "ZTE-GPON-OLT-C", + "ZTE-XGSPON-OLT-1577", + "ZTE-XGSPON-ONU-1270", + "ZTE-EPON-OLT", + "ZTE-10G-EPON-OLT", + "ZTE-SFP-CWDM-1550", + "ZTE-SFP-BIDI-1310", + "ZTE-SFP-BIDI-1490", + "ZTE-SFP-10G-BIDI-1270", +]); + +const ZTE_ACCESS_PIDS: ZteAccessPID[] = [ + // ── GPON OLT SFP ───────────────────────────────────────────────────────── + { pid: "ZTE-GPON-OLT-B", formFactor: "SFP", speedGbps: 2.488, speed: "GPON", reachMeters: 20000, reachLabel: "GPON-20K", fiberType: "SMF", connector: "SC", wavelengths: "1490/1310nm", standard: "G.984", notes: "ZTE Access GPON OLT SFP Class B+, C600/C650 platform", isTelecom: true }, + { pid: "ZTE-GPON-OLT-C", formFactor: "SFP", speedGbps: 2.488, speed: "GPON", reachMeters: 20000, reachLabel: "GPON-C+", fiberType: "SMF", connector: "SC", wavelengths: "1490/1310nm", standard: "G.984", notes: "ZTE Access GPON OLT SFP Class C+, extended reach", isTelecom: true }, + + // ── XGS-PON OLT / ONU SFP+ ─────────────────────────────────────────────── + { pid: "ZTE-XGSPON-OLT-1577", formFactor: "SFP+", speedGbps: 10, speed: "XGS-PON", reachMeters: 20000, reachLabel: "XGS-PON-20K", fiberType: "SMF", connector: "SC", wavelengths: "1577/1270nm", standard: "G.9807.1", notes: "ZTE Access XGS-PON OLT SFP+ for C650/C680", isTelecom: true }, + { pid: "ZTE-XGSPON-ONU-1270", formFactor: "SFP+", speedGbps: 10, speed: "XGS-PON", reachMeters: 20000, reachLabel: "XGS-ONU-20K", fiberType: "SMF", connector: "SC", wavelengths: "1270/1577nm", standard: "G.9807.1", notes: "ZTE Access XGS-PON ONU SFP+ 1270nm TX", isTelecom: true }, + + // ── EPON OLT SFP ───────────────────────────────────────────────────────── + { pid: "ZTE-EPON-OLT", formFactor: "SFP", speedGbps: 1, speed: "EPON", reachMeters: 20000, reachLabel: "EPON-20K", fiberType: "SMF", connector: "SC", wavelengths: "1490/1310nm", standard: "802.3ah", notes: "ZTE Access EPON OLT SFP 1G/1G", isTelecom: true }, + { pid: "ZTE-10G-EPON-OLT", formFactor: "SFP+", speedGbps: 10, speed: "10G-EPON", reachMeters: 20000, reachLabel: "10G-EPON-20K",fiberType: "SMF", connector: "SC", wavelengths: "1577/1270nm", standard: "802.3av", notes: "ZTE Access 10G-EPON OLT SFP+", isTelecom: true }, + + // ── Standard 1G SFP ────────────────────────────────────────────────────── + { pid: "ZTE-SFP-GE-SX", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 550, reachLabel: "SX", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "1000BASE-SX" }, + { pid: "ZTE-SFP-GE-LX", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 10000, reachLabel: "LX", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "1000BASE-LX" }, + + // ── Standard 10G SFP+ ──────────────────────────────────────────────────── + { pid: "ZTE-SFP-10G-SR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 300, reachLabel: "SR", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "10GBASE-SR" }, + { pid: "ZTE-SFP-10G-LR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 10000, reachLabel: "LR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "10GBASE-LR" }, + { pid: "ZTE-SFP-10G-ER", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 40000, reachLabel: "ER", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "10GBASE-ER" }, + + // ── CWDM SFP ───────────────────────────────────────────────────────────── + { pid: "ZTE-SFP-CWDM-1550", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 40000, reachLabel: "CWDM-1550", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "CWDM", notes: "ZTE Access CWDM SFP 1550nm", isTelecom: true }, + + // ── BiDi SFP ───────────────────────────────────────────────────────────── + { pid: "ZTE-SFP-BIDI-1310", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 20000, reachLabel: "BiDi-1310", fiberType: "SMF", connector: "SC", wavelengths: "1310/1490nm", notes: "ZTE Access 1G BiDi SFP 1310nm TX / 1490nm RX", isTelecom: true }, + { pid: "ZTE-SFP-BIDI-1490", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 20000, reachLabel: "BiDi-1490", fiberType: "SMF", connector: "SC", wavelengths: "1490/1310nm", notes: "ZTE Access 1G BiDi SFP 1490nm TX / 1310nm RX", isTelecom: true }, + { pid: "ZTE-SFP-10G-BIDI-1270", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 20000, reachLabel: "BiDi-1270", fiberType: "SMF", connector: "LC", wavelengths: "1270/1330nm", notes: "ZTE Access 10G BiDi SFP+ 1270nm TX", isTelecom: true }, + + // ── 25G SFP28 ──────────────────────────────────────────────────────────── + { pid: "ZTE-SFP-25G-LR", formFactor: "SFP28", speedGbps: 25, speed: "25G", reachMeters: 10000, reachLabel: "LR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "25GBASE-LR" }, + + // ── 40G / 100G QSFP ────────────────────────────────────────────────────── + { pid: "ZTE-QSFP-40G-LR4", formFactor: "QSFP+", speedGbps: 40, speed: "40G", reachMeters: 10000, reachLabel: "LR4", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "40GBASE-LR4" }, + { pid: "ZTE-QSFP-100G-LR4", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 10000, reachLabel: "LR4", fiberType: "SMF", connector: "LC", wavelengths: "1295-1310nm", standard: "100GBASE-LR4" }, +]; + +export async function scrapeZteAccessOem(): Promise { + console.log("=== ZTE Access OEM Transceiver Seed ===\n"); + + const vendorId = await ensureVendor( + "ZTE Access", + "oem", + "https://www.zte.com.cn/global/solutions_latest/fixed/OLT.html", + undefined + ); + + let inserted = 0; + let updated = 0; + let errors = 0; + + for (const p of ZTE_ACCESS_PIDS) { + const slug = `zte-access-${p.pid.toLowerCase().replace(/[^a-z0-9]+/g, "-")}`; + const category = TELECOM_PIDS.has(p.pid) ? "Telecom" : "DataCenter"; + try { + const res = await pool.query( + `INSERT INTO transceivers + (slug, part_number, vendor_id, form_factor, speed, speed_gbps, + reach_meters, reach_label, fiber_type, connector, wavelengths, + dom_support, ieee_reference, market_status, category, notes) + VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,true,$12,'Mainstream',$13,$14) + ON CONFLICT (slug) DO UPDATE SET + speed_gbps = EXCLUDED.speed_gbps, + reach_meters = CASE WHEN EXCLUDED.reach_meters > 0 THEN EXCLUDED.reach_meters ELSE transceivers.reach_meters END, + fiber_type = CASE WHEN EXCLUDED.fiber_type <> '' THEN EXCLUDED.fiber_type ELSE transceivers.fiber_type END, + wavelengths = COALESCE(EXCLUDED.wavelengths, transceivers.wavelengths), + updated_at = NOW() + RETURNING (xmax = 0) as was_inserted`, + [slug, p.pid, vendorId, p.formFactor, p.speed, p.speedGbps, + p.reachMeters, p.reachLabel, p.fiberType, p.connector, + p.wavelengths ?? null, p.standard ?? null, category, p.notes ?? null] + ); + if (res.rows[0]?.was_inserted) inserted++; else updated++; + } catch (err) { + console.warn(` Skip ${p.pid}: ${(err as Error).message.slice(0, 80)}`); + errors++; + } + } + + console.log(`\n=== ZTE Access OEM Seed Complete ===`); + console.log(` Inserted: ${inserted}`); + console.log(` Updated: ${updated}`); + console.log(` Errors: ${errors}`); + console.log(` Total PIDs: ${ZTE_ACCESS_PIDS.length}\n`); +} + +if (require.main === module) { + scrapeZteAccessOem() + .then(() => pool.end()) + .catch((err) => { + console.error("Fatal:", err); + pool.end(); + process.exit(1); + }); +} diff --git a/packages/scraper/src/scrapers/zte-oem.ts b/packages/scraper/src/scrapers/zte-oem.ts new file mode 100644 index 0000000..cbf01bf --- /dev/null +++ b/packages/scraper/src/scrapers/zte-oem.ts @@ -0,0 +1,146 @@ +/** + * ZTE OEM Transceiver Catalog Seed + * + * Seeds ZTE-branded transceiver PIDs for ZXROS/ZXONE switches, + * OTN platforms (ZXMP M6000), and ZXR10 campus switches. + * + * Sources: + * - ZTE Product Catalog (zte.com.cn) + * - ZTE OTN/DWDM Transceiver Compatibility Guide + * - ZXR10 Hardware Configuration Guides + * + * Run: tsx packages/scraper/src/scrapers/zte-oem.ts + * Cron: daily at 06:15 + */ + +import { pool, ensureVendor } from "../utils/db"; + +interface ZtePID { + pid: string; + formFactor: string; + speedGbps: number; + speed: string; + reachMeters: number; + reachLabel: string; + fiberType: string; + connector: string; + wavelengths?: string; + standard?: string; + notes?: string; +} + +const ZTE_PIDS: ZtePID[] = [ + // ── 1G SFP ────────────────────────────────────────────────────────────── + { pid: "SFP-GE-SX", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 550, reachLabel: "SX", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "1000BASE-SX" }, + { pid: "SFP-GE-LX", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 10000, reachLabel: "LX", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "1000BASE-LX" }, + { pid: "SFP-GE-ZX", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 80000, reachLabel: "ZX", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "1000BASE-ZX" }, + { pid: "SFP-GE-T", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 100, reachLabel: "T", fiberType: "DAC", connector: "RJ45", standard: "1000BASE-T" }, + { pid: "SFP-GE-LH40", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 40000, reachLabel: "LH40", fiberType: "SMF", connector: "LC", wavelengths: "1310nm" }, + { pid: "SFP-GE-LH80", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 80000, reachLabel: "LH80", fiberType: "SMF", connector: "LC", wavelengths: "1550nm" }, + + // ── 10G SFP+ ──────────────────────────────────────────────────────────── + { pid: "SFP-10GE-SR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 300, reachLabel: "SR", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "10GBASE-SR" }, + { pid: "SFP-10GE-LR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 10000, reachLabel: "LR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "10GBASE-LR" }, + { pid: "SFP-10GE-ER", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 40000, reachLabel: "ER", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "10GBASE-ER" }, + { pid: "SFP-10GE-ZR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 80000, reachLabel: "ZR", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "10GBASE-ZR" }, + { pid: "SFP-10GE-LRM", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 220, reachLabel: "LRM", fiberType: "MMF", connector: "LC", wavelengths: "1310nm", standard: "10GBASE-LRM" }, + { pid: "SFP-10GE-T", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 30, reachLabel: "T", fiberType: "DAC", connector: "RJ45", standard: "10GBASE-T" }, + { pid: "SFP-10GE-BIDI", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 10000, reachLabel: "BiDi", fiberType: "SMF", connector: "LC", wavelengths: "1270/1330nm", notes: "10G BiDi single fiber" }, + + // ── 25G SFP28 ─────────────────────────────────────────────────────────── + { pid: "SFP-25GE-SR", formFactor: "SFP28", speedGbps: 25, speed: "25G", reachMeters: 100, reachLabel: "SR", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "25GBASE-SR" }, + { pid: "SFP-25GE-LR", formFactor: "SFP28", speedGbps: 25, speed: "25G", reachMeters: 10000, reachLabel: "LR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "25GBASE-LR" }, + { pid: "SFP-25GE-ER", formFactor: "SFP28", speedGbps: 25, speed: "25G", reachMeters: 30000, reachLabel: "ER", fiberType: "SMF", connector: "LC", wavelengths: "1310nm" }, + + // ── 40G QSFP+ ─────────────────────────────────────────────────────────── + { pid: "QSFP-40GE-SR4", formFactor: "QSFP+", speedGbps: 40, speed: "40G", reachMeters: 150, reachLabel: "SR4", fiberType: "MMF", connector: "MPO", wavelengths: "850nm", standard: "40GBASE-SR4" }, + { pid: "QSFP-40GE-LR4", formFactor: "QSFP+", speedGbps: 40, speed: "40G", reachMeters: 10000, reachLabel: "LR4", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "40GBASE-LR4" }, + { pid: "QSFP-40GE-ER4", formFactor: "QSFP+", speedGbps: 40, speed: "40G", reachMeters: 40000, reachLabel: "ER4", fiberType: "SMF", connector: "LC", wavelengths: "1310nm" }, + { pid: "QSFP-40GE-BIDI", formFactor: "QSFP+", speedGbps: 40, speed: "40G", reachMeters: 150, reachLabel: "BiDi", fiberType: "MMF", connector: "LC", wavelengths: "832/853nm", notes: "40G BiDi 2-fiber" }, + + // ── 100G QSFP28 ───────────────────────────────────────────────────────── + { pid: "QSFP-100GE-SR4", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 100, reachLabel: "SR4", fiberType: "MMF", connector: "MPO", wavelengths: "850nm", standard: "100GBASE-SR4" }, + { pid: "QSFP-100GE-LR4", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 10000, reachLabel: "LR4", fiberType: "SMF", connector: "LC", wavelengths: "1295-1310nm", standard: "100GBASE-LR4" }, + { pid: "QSFP-100GE-ER4", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 40000, reachLabel: "ER4", fiberType: "SMF", connector: "LC", wavelengths: "1295-1310nm" }, + { pid: "QSFP-100GE-CWDM4", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 2000, reachLabel: "CWDM4", fiberType: "SMF", connector: "LC", wavelengths: "1271-1331nm", standard: "100GBASE-CWDM4" }, + { pid: "QSFP-100GE-DR", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 500, reachLabel: "DR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "100GBASE-DR" }, + { pid: "QSFP-100GE-FR", formFactor: "QSFP28", speedGbps: 100, speed: "100G", reachMeters: 2000, reachLabel: "FR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "100GBASE-FR" }, + + // ── 200G QSFP56 ───────────────────────────────────────────────────────── + { pid: "QSFP56-200GE-SR4", formFactor: "QSFP56", speedGbps: 200, speed: "200G", reachMeters: 100, reachLabel: "SR4", fiberType: "MMF", connector: "MPO", wavelengths: "850nm" }, + { pid: "QSFP56-200GE-FR4", formFactor: "QSFP56", speedGbps: 200, speed: "200G", reachMeters: 2000, reachLabel: "FR4", fiberType: "SMF", connector: "LC", wavelengths: "1271-1331nm" }, + { pid: "QSFP56-200GE-LR4", formFactor: "QSFP56", speedGbps: 200, speed: "200G", reachMeters: 10000, reachLabel: "LR4", fiberType: "SMF", connector: "LC", wavelengths: "1295-1310nm" }, + + // ── 400G QSFP-DD ──────────────────────────────────────────────────────── + { pid: "QSFPDD-400GE-SR8", formFactor: "QSFP-DD",speedGbps: 400, speed: "400G", reachMeters: 100, reachLabel: "SR8", fiberType: "MMF", connector: "MPO", wavelengths: "850nm", standard: "400GBASE-SR8" }, + { pid: "QSFPDD-400GE-DR4", formFactor: "QSFP-DD",speedGbps: 400, speed: "400G", reachMeters: 500, reachLabel: "DR4", fiberType: "SMF", connector: "MPO", wavelengths: "1310nm", standard: "400GBASE-DR4" }, + { pid: "QSFPDD-400GE-FR4", formFactor: "QSFP-DD",speedGbps: 400, speed: "400G", reachMeters: 2000, reachLabel: "FR4", fiberType: "SMF", connector: "LC", wavelengths: "1271-1331nm", standard: "400GBASE-FR4" }, + { pid: "QSFPDD-400GE-LR4", formFactor: "QSFP-DD",speedGbps: 400, speed: "400G", reachMeters: 10000, reachLabel: "LR4", fiberType: "SMF", connector: "LC", wavelengths: "1295-1310nm", standard: "400GBASE-LR4" }, + + // ── DAC ───────────────────────────────────────────────────────────────── + { pid: "DAC-SFP-10GE-1M", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 1, reachLabel: "DAC-1M",fiberType: "DAC", connector: "SFP+", notes: "10G Direct Attach Copper 1m" }, + { pid: "DAC-SFP-10GE-3M", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 3, reachLabel: "DAC-3M",fiberType: "DAC", connector: "SFP+", notes: "10G Direct Attach Copper 3m" }, + { pid: "DAC-QSFP-40GE-1M", formFactor: "QSFP+", speedGbps: 40, speed: "40G", reachMeters: 1, reachLabel: "DAC-1M",fiberType: "DAC", connector: "QSFP+", notes: "40G Direct Attach Copper 1m" }, + { pid: "DAC-QSFP-40GE-3M", formFactor: "QSFP+", speedGbps: 40, speed: "40G", reachMeters: 3, reachLabel: "DAC-3M",fiberType: "DAC", connector: "QSFP+", notes: "40G Direct Attach Copper 3m" }, + { pid: "DAC-QSFP28-100GE-1M",formFactor:"QSFP28", speedGbps: 100, speed: "100G", reachMeters: 1, reachLabel: "DAC-1M",fiberType: "DAC", connector: "QSFP28",notes: "100G Direct Attach Copper 1m" }, + { pid: "DAC-QSFP28-100GE-3M",formFactor:"QSFP28", speedGbps: 100, speed: "100G", reachMeters: 3, reachLabel: "DAC-3M",fiberType: "DAC", connector: "QSFP28",notes: "100G Direct Attach Copper 3m" }, + { pid: "DAC-QSFPDD-400GE-1M",formFactor:"QSFP-DD",speedGbps: 400, speed: "400G", reachMeters: 1, reachLabel: "DAC-1M",fiberType: "DAC", connector: "QSFP-DD",notes: "400G Direct Attach Copper 1m" }, +]; + +export async function scrapeZteOem(): Promise { + console.log("=== ZTE OEM Transceiver Seed ===\n"); + + const vendorId = await ensureVendor( + "ZTE", + "oem", + "https://www.zte.com.cn/global/", + undefined + ); + + let inserted = 0; + let updated = 0; + let errors = 0; + + for (const p of ZTE_PIDS) { + const slug = `zte-${p.pid.toLowerCase().replace(/[^a-z0-9]+/g, "-")}`; + try { + const res = await pool.query( + `INSERT INTO transceivers + (slug, part_number, vendor_id, form_factor, speed, speed_gbps, + reach_meters, reach_label, fiber_type, connector, wavelengths, + dom_support, ieee_reference, market_status, category, notes) + VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,true,$12,'Mainstream','DataCenter',$13) + ON CONFLICT (slug) DO UPDATE SET + speed_gbps = EXCLUDED.speed_gbps, + reach_meters = CASE WHEN EXCLUDED.reach_meters > 0 THEN EXCLUDED.reach_meters ELSE transceivers.reach_meters END, + fiber_type = CASE WHEN EXCLUDED.fiber_type <> '' THEN EXCLUDED.fiber_type ELSE transceivers.fiber_type END, + wavelengths = COALESCE(EXCLUDED.wavelengths, transceivers.wavelengths), + updated_at = NOW() + RETURNING (xmax = 0) as was_inserted`, + [slug, p.pid, vendorId, p.formFactor, p.speed, p.speedGbps, + p.reachMeters, p.reachLabel, p.fiberType, p.connector, + p.wavelengths ?? null, p.standard ?? null, p.notes ?? null] + ); + if (res.rows[0]?.was_inserted) inserted++; else updated++; + } catch (err) { + console.warn(` Skip ${p.pid}: ${(err as Error).message.slice(0, 80)}`); + errors++; + } + } + + console.log(`\n=== ZTE OEM Seed Complete ===`); + console.log(` Inserted: ${inserted}`); + console.log(` Updated: ${updated}`); + console.log(` Errors: ${errors}`); + console.log(` Total PIDs: ${ZTE_PIDS.length}\n`); +} + +if (require.main === module) { + scrapeZteOem() + .then(() => pool.end()) + .catch((err) => { + console.error("Fatal:", err); + pool.end(); + process.exit(1); + }); +} diff --git a/packages/scraper/src/scrapers/zyxel-oem.ts b/packages/scraper/src/scrapers/zyxel-oem.ts new file mode 100644 index 0000000..54f8ca8 --- /dev/null +++ b/packages/scraper/src/scrapers/zyxel-oem.ts @@ -0,0 +1,122 @@ +/** + * Zyxel OEM Transceiver Catalog Seed + * + * Seeds Zyxel-branded transceiver PIDs for XGS, XS, GS, and + * Nebula series managed switches. + * + * Sources: Zyxel Transceiver Module Compatibility Guide (zyxel.com) + * + * Run: tsx packages/scraper/src/scrapers/zyxel-oem.ts + * Cron: daily at 09:30 + */ + +import { pool, ensureVendor } from "../utils/db"; + +interface ZyxelPID { + pid: string; + formFactor: string; + speedGbps: number; + speed: string; + reachMeters: number; + reachLabel: string; + fiberType: string; + connector: string; + wavelengths?: string; + standard?: string; + notes?: string; +} + +const ZYXEL_PIDS: ZyxelPID[] = [ + // ── 1G SFP ────────────────────────────────────────────────────────────── + { pid: "SFP-SX-D", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 550, reachLabel: "SX", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "1000BASE-SX" }, + { pid: "SFP-LX-10-D", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 10000, reachLabel: "LX", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "1000BASE-LX" }, + { pid: "SFP-ZX-80-D", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 80000, reachLabel: "ZX", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "1000BASE-ZX" }, + { pid: "SFP-T", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 100, reachLabel: "T", fiberType: "DAC", connector: "RJ45", standard: "1000BASE-T" }, + { pid: "SFP-BX1310-10", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 10000, reachLabel: "BiDi-1310", fiberType: "SMF", connector: "LC", wavelengths: "1310/1550nm", notes: "BiDi TX1310" }, + { pid: "SFP-BX1550-10", formFactor: "SFP", speedGbps: 1, speed: "1G", reachMeters: 10000, reachLabel: "BiDi-1550", fiberType: "SMF", connector: "LC", wavelengths: "1550/1310nm", notes: "BiDi TX1550" }, + + // ── 10G SFP+ ──────────────────────────────────────────────────────────── + { pid: "SFP10G-SR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 300, reachLabel: "SR", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "10GBASE-SR" }, + { pid: "SFP10G-LR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 10000, reachLabel: "LR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "10GBASE-LR" }, + { pid: "SFP10G-ER", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 40000, reachLabel: "ER", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "10GBASE-ER" }, + { pid: "SFP10G-ZR", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 80000, reachLabel: "ZR", fiberType: "SMF", connector: "LC", wavelengths: "1550nm", standard: "10GBASE-ZR" }, + { pid: "SFP10G-T", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 30, reachLabel: "T", fiberType: "DAC", connector: "RJ45", standard: "10GBASE-T" }, + + // ── 25G SFP28 ─────────────────────────────────────────────────────────── + { pid: "SFP25G-SR", formFactor: "SFP28", speedGbps: 25, speed: "25G", reachMeters: 100, reachLabel: "SR", fiberType: "MMF", connector: "LC", wavelengths: "850nm", standard: "25GBASE-SR" }, + { pid: "SFP25G-LR", formFactor: "SFP28", speedGbps: 25, speed: "25G", reachMeters: 10000, reachLabel: "LR", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "25GBASE-LR" }, + + // ── 40G QSFP+ ─────────────────────────────────────────────────────────── + { pid: "QSFP-SR4", formFactor: "QSFP+", speedGbps: 40, speed: "40G", reachMeters: 150, reachLabel: "SR4", fiberType: "MMF", connector: "MPO", wavelengths: "850nm", standard: "40GBASE-SR4" }, + { pid: "QSFP-LR4", formFactor: "QSFP+", speedGbps: 40, speed: "40G", reachMeters: 10000, reachLabel: "LR4", fiberType: "SMF", connector: "LC", wavelengths: "1310nm", standard: "40GBASE-LR4" }, + + // ── 100G QSFP28 ───────────────────────────────────────────────────────── + { pid: "QSFP28-SR4", formFactor: "QSFP28",speedGbps: 100, speed: "100G", reachMeters: 100, reachLabel: "SR4", fiberType: "MMF", connector: "MPO", wavelengths: "850nm", standard: "100GBASE-SR4" }, + { pid: "QSFP28-LR4", formFactor: "QSFP28",speedGbps: 100, speed: "100G", reachMeters: 10000, reachLabel: "LR4", fiberType: "SMF", connector: "LC", wavelengths: "1295-1310nm", standard: "100GBASE-LR4" }, + { pid: "QSFP28-CWDM4", formFactor: "QSFP28",speedGbps: 100, speed: "100G", reachMeters: 2000, reachLabel: "CWDM4", fiberType: "SMF", connector: "LC", wavelengths: "1271-1331nm", standard: "100GBASE-CWDM4" }, + + // ── DAC ───────────────────────────────────────────────────────────────── + { pid: "DAC10G-1M", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 1, reachLabel: "DAC-1M", fiberType: "DAC", connector: "SFP+" }, + { pid: "DAC10G-3M", formFactor: "SFP+", speedGbps: 10, speed: "10G", reachMeters: 3, reachLabel: "DAC-3M", fiberType: "DAC", connector: "SFP+" }, + { pid: "DAC40G-1M", formFactor: "QSFP+", speedGbps: 40, speed: "40G", reachMeters: 1, reachLabel: "DAC-1M", fiberType: "DAC", connector: "QSFP+" }, + { pid: "DAC100G-1M", formFactor: "QSFP28",speedGbps: 100, speed: "100G", reachMeters: 1, reachLabel: "DAC-1M", fiberType: "DAC", connector: "QSFP28" }, + { pid: "DAC100G-3M", formFactor: "QSFP28",speedGbps: 100, speed: "100G", reachMeters: 3, reachLabel: "DAC-3M", fiberType: "DAC", connector: "QSFP28" }, +]; + +export async function scrapeZyxelOem(): Promise { + console.log("=== Zyxel OEM Transceiver Seed ===\n"); + + const vendorId = await ensureVendor( + "Zyxel", + "oem", + "https://www.zyxel.com", + undefined + ); + + let inserted = 0; + let updated = 0; + let errors = 0; + + for (const p of ZYXEL_PIDS) { + const slug = `zyxel-${p.pid.toLowerCase().replace(/[^a-z0-9]+/g, "-")}`; + try { + const res = await pool.query( + `INSERT INTO transceivers + (slug, part_number, vendor_id, form_factor, speed, speed_gbps, + reach_meters, reach_label, fiber_type, connector, wavelengths, + dom_support, ieee_reference, market_status, category, notes) + VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,true,$12,'Mainstream','DataCenter',$13) + ON CONFLICT (slug) DO UPDATE SET + speed_gbps = EXCLUDED.speed_gbps, + reach_meters = CASE WHEN EXCLUDED.reach_meters > 0 THEN EXCLUDED.reach_meters ELSE transceivers.reach_meters END, + fiber_type = CASE WHEN EXCLUDED.fiber_type <> '' THEN EXCLUDED.fiber_type ELSE transceivers.fiber_type END, + wavelengths = COALESCE(EXCLUDED.wavelengths, transceivers.wavelengths), + updated_at = NOW() + RETURNING (xmax = 0) as was_inserted`, + [slug, p.pid, vendorId, p.formFactor, p.speed, p.speedGbps, + p.reachMeters, p.reachLabel, p.fiberType, p.connector, + p.wavelengths ?? null, p.standard ?? null, p.notes ?? null] + ); + if (res.rows[0]?.was_inserted) inserted++; else updated++; + } catch (err) { + console.warn(` Skip ${p.pid}: ${(err as Error).message.slice(0, 80)}`); + errors++; + } + } + + console.log(`\n=== Zyxel OEM Seed Complete ===`); + console.log(` Inserted: ${inserted}`); + console.log(` Updated: ${updated}`); + console.log(` Errors: ${errors}`); + console.log(` Total PIDs: ${ZYXEL_PIDS.length}\n`); +} + +if (require.main === module) { + scrapeZyxelOem() + .then(() => pool.end()) + .catch((err) => { + console.error("Fatal:", err); + pool.end(); + process.exit(1); + }); +} diff --git a/packages/scraper/tsconfig.json b/packages/scraper/tsconfig.json index 87cde83..8c1b141 100644 --- a/packages/scraper/tsconfig.json +++ b/packages/scraper/tsconfig.json @@ -11,7 +11,8 @@ "forceConsistentCasingInFileNames": true, "resolveJsonModule": true, "declaration": true, - "sourceMap": true + "sourceMap": true, + "incremental": true }, "include": ["src/**/*"], "exclude": ["node_modules", "dist"]