├── .dockerignore ├── .github └── workflows │ ├── bun-formatcheck.yml │ ├── bun-test.yml │ ├── bun-typecheck.yml │ └── fly-deploy.yml ├── .gitignore ├── Dockerfile ├── LICENSE ├── README.md ├── biome.json ├── bun.lockb ├── docs └── generated │ ├── adcdacdata_conversion.md │ ├── amplifiers.md │ ├── amplifierscomparators.md │ ├── analog_ics.md │ ├── audio_componentsvibration_motors.md │ ├── audio_products__vibration_motors.md │ ├── audio_productsmicromotors.md │ ├── audio_productsmotors.md │ ├── battery_products.md │ ├── beadfilteremi_optimization.md │ ├── buzzers__speakers__microphones.md │ ├── capacitors.md │ ├── circuit_protection.md │ ├── clock_and_timing.md │ ├── clocktiming.md │ ├── communication_interface_chip.md │ ├── communication_interface_chipuart485232.md │ ├── component-overview.md │ ├── connectors.md │ ├── crystal_oscillatoroscillatorresonator.md │ ├── crystals.md │ ├── crystals_oscillators_resonators.md │ ├── crystalsoscillatorsresonators.md │ ├── data_acquisition.md │ ├── data_converters.md │ ├── diodes.md │ ├── display_modules__led_drivers__display_drivers.md │ ├── display_screen.md │ ├── displays.md │ ├── driver_ics.md │ ├── electromechanical_devices__components.md │ ├── embedded_peripheral_ics.md │ ├── embedded_processors__controllers.md │ ├── filters.md │ ├── filtersemi_optimization.md │ ├── functional_modules.md │ ├── fuses.md │ ├── gallium_nitride_gan_devices.md │ ├── inductors__chokes__transformers.md │ ├── inductors_coils_chokes.md │ ├── inductorscoilstransformers.md │ ├── interface.md │ ├── interface_ics.md │ ├── iotcommunication_modules.md │ ├── isolators.md │ ├── keyswitch.md │ ├── led_drivers.md │ ├── ledphotoelectric_devices.md │ ├── logic.md │ ├── logic_ics.md │ ├── magnetic_sensors.md │ ├── memory.md │ ├── motor_driver_ics.md │ ├── nixie_tube_driverled_driver.md │ ├── operational_amplifiercomparator.md │ ├── optocoupler.md │ ├── optocouplerleddigital_tubephotoelectric_device.md │ ├── optocouplers__leds__infrared.md │ ├── optocouplersphotocouplers.md │ ├── optoelectronics.md │ ├── optoisolators.md │ ├── photoelectric_devices.md │ ├── power_management.md │ ├── power_management_ics.md │ ├── power_management_pmic.md │ ├── power_modules.md │ ├── power_supply_chip.md │ ├── pushbutton_switches__relays.md │ ├── radio_frequency_chipantenna.md │ ├── relays.md │ ├── resistors.md │ ├── resonatorsoscillators.md │ ├── rf__radio.md │ ├── rf_and_wireless.md │ ├── rtcclock_chip.md │ ├── sensors.md │ ├── signal_isolation_devices.md │ ├── silicon_carbide_sic_devices.md │ ├── single_chip_microcomputermicrocontroller.md │ ├── switches.md │ ├── transistors.md │ ├── transistorsthyristors.md │ ├── triodemos_tubetransistor.md │ └── tvsfuseboard_level_protection.md ├── fly.toml ├── lib ├── db │ ├── derivedtables │ │ ├── accelerometer.ts │ │ ├── adc.ts │ │ ├── analog_multiplexer.ts │ │ ├── bjt_transistor.ts │ │ ├── boost_converter.ts │ │ ├── capacitor.ts │ │ ├── component-base.ts │ │ ├── dac.ts │ │ ├── diode.ts │ │ ├── fuse.ts │ │ ├── gas_sensor.ts │ │ ├── gyroscope.ts │ │ ├── header.ts │ │ ├── io_expander.ts │ │ ├── lcd_display.ts │ │ ├── led.ts │ │ ├── led_dot_matrix_display.ts │ │ ├── led_driver.ts │ │ ├── led_segment_display.ts │ │ ├── led_with_ic.ts │ │ ├── microcontroller.ts │ │ ├── mosfet.ts │ │ ├── oled_display.ts │ │ ├── potentiometer.ts │ │ ├── resistor.ts │ │ ├── switch.ts │ │ ├── types.ts │ │ ├── voltage_regulator.ts │ │ └── wifi_module.ts │ ├── generated │ │ └── kysely.ts │ ├── get-db-client.ts │ ├── kysely-types.ts │ └── optimizations │ │ ├── component-category-index.ts │ │ ├── component-in-stock-category-index.ts │ │ ├── component-in-stock-column.ts │ │ ├── component-indexes.ts │ │ ├── component-search-fts.ts │ │ ├── component-stock-index.ts │ │ ├── in-stock-column.ts │ │ ├── remove-stale-components.ts │ │ └── types.ts ├── middlewares │ ├── with-cache-headers.ts │ ├── with-cors.ts │ ├── with-ctx-error.ts │ ├── with-ctx-react.tsx │ ├── with-db.ts │ ├── with-error-response.ts │ ├── with-is-api-request.ts │ └── with-request-logging.ts ├── ui │ ├── Table.tsx │ └── time-ago.tsx ├── util │ ├── convert-to-possible-footprinter-strings.ts │ ├── extract-min-quantity-price.ts │ ├── format-price.ts │ ├── format-si-unit.ts │ ├── parse-and-convert-si-unit.ts │ └── parse-int-or-null.ts └── with-winter-spec.ts ├── package.json ├── routes ├── [...anyroute].ts ├── accelerometers │ ├── list.json.tsx │ └── list.tsx ├── adcs │ ├── list.json.tsx │ └── list.tsx ├── admin │ ├── index.tsx │ └── system │ │ └── create-indexes.tsx ├── analog_multiplexers │ ├── list.json.tsx │ └── list.tsx ├── api │ └── search.tsx ├── bjt_transistors │ ├── list.json.tsx │ └── list.tsx ├── boost_converters │ ├── list.json.tsx │ └── list.tsx ├── capacitors │ ├── list.json.tsx │ └── list.tsx ├── categories │ ├── list.json.tsx │ └── list.tsx ├── components │ ├── list.json.tsx │ └── list.tsx ├── dacs │ ├── list.json.tsx │ └── list.tsx ├── diodes │ ├── list.json.tsx │ └── list.tsx ├── footprint_index │ └── list.tsx ├── fuses │ ├── list.json.tsx │ └── list.tsx ├── gas_sensors │ ├── list.json.tsx │ └── list.tsx ├── gyroscopes │ ├── list.json.tsx │ └── list.tsx ├── headers │ ├── list.json.ts │ └── list.tsx ├── health.ts ├── index.tsx ├── io_expanders │ ├── list.json.tsx │ └── list.tsx ├── lcd_display │ ├── list.json.tsx │ └── list.tsx ├── led_dot_matrix_display │ ├── list.json.tsx │ └── list.tsx ├── led_drivers │ ├── list.json.tsx │ └── list.tsx ├── led_segment_display │ ├── list.json.tsx │ └── list.tsx ├── led_with_ic │ ├── list.json.tsx │ └── list.tsx ├── leds │ ├── list.json.tsx │ └── list.tsx ├── microcontrollers │ ├── list.json.tsx │ └── list.tsx ├── mosfets │ ├── list.json.tsx │ └── list.tsx ├── oled_display │ ├── list.json.tsx │ └── list.tsx ├── potentiometers │ ├── list.json.tsx │ └── list.tsx ├── resistors │ ├── list.json.tsx │ └── list.tsx ├── switches │ ├── list.json.tsx │ └── list.tsx ├── voltage_regulators │ ├── list.json.tsx │ └── list.tsx └── wifi_modules │ ├── list.json.tsx │ └── list.tsx ├── scripts ├── download-cache-fragments.ts ├── extract-data-examples.ts ├── setup-7z.ts ├── setup-db-optimizations.ts ├── setup-derived-tables.ts └── start-server.ts ├── tests ├── fixtures │ └── get-test-server.ts └── routes │ ├── [...anyroute].test.ts │ ├── accelerometers │ └── list.test.ts │ ├── analog_multiplexers │ └── list.test.ts │ ├── api │ └── search.test.ts │ ├── bjt_transistors │ └── list.test.ts │ ├── boost_converters │ └── list.test.ts │ ├── capacitors │ └── list.test.ts │ ├── categories │ └── list.test.ts │ ├── components │ └── list.test.ts │ ├── diodes │ └── list.test.ts │ ├── fuses │ └── list.test.ts │ ├── gas_sensors │ └── list.test.ts │ ├── gyroscopes │ └── list.test.ts │ ├── headers │ └── list.test.ts │ ├── health.test.ts │ ├── lcd_display │ └── list.test.ts │ ├── led_dot_matrix_display │ └── list.test.ts │ ├── led_drivers │ └── list.test.ts │ ├── led_segment_display │ └── list.test.ts │ ├── led_with_ic │ └── list.test.ts │ ├── leds │ └── list.test.ts │ ├── microcontrollers │ └── list.test.ts │ ├── mosfets │ └── list.test.ts │ ├── oled_display │ └── list.test.ts │ ├── resistors │ └── list.test.ts │ ├── switches │ └── list.test.ts │ └── voltage_regulators │ └── list.test.ts ├── tsconfig.json └── winterspec.config.ts /.dockerignore: -------------------------------------------------------------------------------- 1 | # Based on https://raw.githubusercontent.com/github/gitignore/main/Node.gitignore 2 | 3 | # Logs 4 | 5 | logs 6 | _.log 7 | npm-debug.log_ 8 | yarn-debug.log* 9 | yarn-error.log* 10 | lerna-debug.log* 11 | .pnpm-debug.log* 12 | 13 | # Caches 14 | 15 | .cache 16 | 17 | # Diagnostic reports (https://nodejs.org/api/report.html) 18 | 19 | report.[0-9]_.[0-9]_.[0-9]_.[0-9]_.json 20 | 21 | # Runtime data 22 | 23 | pids 24 | _.pid 25 | _.seed 26 | *.pid.lock 27 | 28 | # Directory for instrumented libs generated by jscoverage/JSCover 29 | 30 | lib-cov 31 | 32 | # Coverage directory used by tools like istanbul 33 | 34 | coverage 35 | *.lcov 36 | 37 | # nyc test coverage 38 | 39 | .nyc_output 40 | 41 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) 42 | 43 | .grunt 44 | 45 | # Bower dependency directory (https://bower.io/) 46 | 47 | bower_components 48 | 49 | # node-waf configuration 50 | 51 | .lock-wscript 52 | 53 | # Compiled binary addons (https://nodejs.org/api/addons.html) 54 | 55 | build/Release 56 | 57 | # Dependency directories 58 | 59 | node_modules/ 60 | jspm_packages/ 61 | 62 | # Snowpack dependency directory (https://snowpack.dev/) 63 | 64 | web_modules/ 65 | 66 | # TypeScript cache 67 | 68 | *.tsbuildinfo 69 | 70 | # Optional npm cache directory 71 | 72 | .npm 73 | 74 | # Optional eslint cache 75 | 76 | .eslintcache 77 | 78 | # Optional stylelint cache 79 | 80 | .stylelintcache 81 | 82 | # Microbundle cache 83 | 84 | .rpt2_cache/ 85 | .rts2_cache_cjs/ 86 | .rts2_cache_es/ 87 | .rts2_cache_umd/ 88 | 89 | # Optional REPL history 90 | 91 | .node_repl_history 92 | 93 | # Output of 'npm pack' 94 | 95 | *.tgz 96 | 97 | # Yarn Integrity file 98 | 99 | .yarn-integrity 100 | 101 | # dotenv environment variable files 102 | 103 | .env 104 | .env.development.local 105 | .env.test.local 106 | .env.production.local 107 | .env.local 108 | 109 | # parcel-bundler cache (https://parceljs.org/) 110 | 111 | .parcel-cache 112 | 113 | # Next.js build output 114 | 115 | .next 116 | out 117 | 118 | # Nuxt.js build / generate output 119 | 120 | .nuxt 121 | dist 122 | 123 | # Gatsby files 124 | 125 | # Comment in the public line in if your project uses Gatsby and not Next.js 126 | 127 | # https://nextjs.org/blog/next-9-1#public-directory-support 128 | 129 | # public 130 | 131 | # vuepress build output 132 | 133 | .vuepress/dist 134 | 135 | # vuepress v2.x temp and cache directory 136 | 137 | .temp 138 | 139 | # Docusaurus cache and generated files 140 | 141 | .docusaurus 142 | 143 | # Serverless directories 144 | 145 | .serverless/ 146 | 147 | # FuseBox cache 148 | 149 | .fusebox/ 150 | 151 | # DynamoDB Local files 152 | 153 | .dynamodb/ 154 | 155 | # TernJS port file 156 | 157 | .tern-port 158 | 159 | # Stores VSCode versions used for testing VSCode extensions 160 | 161 | .vscode-test 162 | 163 | # yarn v2 164 | 165 | .yarn/cache 166 | .yarn/unplugged 167 | .yarn/build-state.yml 168 | .yarn/install-state.gz 169 | .pnp.* 170 | 171 | # IntelliJ based IDEs 172 | .idea 173 | 174 | # Finder (MacOS) folder config 175 | .DS_Store 176 | 177 | .vscode 178 | .aider* 179 | db.sqlite3 180 | .buildtmp 181 | .winterspec 182 | db.backup.sqlite3 183 | .bin -------------------------------------------------------------------------------- /.github/workflows/bun-formatcheck.yml: -------------------------------------------------------------------------------- 1 | # Created using @tscircuit/plop (npm install -g @tscircuit/plop) 2 | name: Format Check 3 | 4 | on: 5 | push: 6 | branches: [main] 7 | pull_request: 8 | branches: [main] 9 | 10 | jobs: 11 | format-check: 12 | runs-on: ubuntu-latest 13 | 14 | steps: 15 | - uses: actions/checkout@v4 16 | 17 | - name: Setup bun 18 | uses: oven-sh/setup-bun@v2 19 | with: 20 | bun-version: latest 21 | 22 | - name: Install dependencies 23 | run: bun install 24 | 25 | - name: Run format check 26 | run: bun run format:check 27 | -------------------------------------------------------------------------------- /.github/workflows/bun-test.yml: -------------------------------------------------------------------------------- 1 | # Created using @tscircuit/plop (npm install -g @tscircuit/plop) 2 | name: Bun Test 3 | 4 | on: 5 | pull_request: 6 | 7 | jobs: 8 | test: 9 | runs-on: ubuntu-latest 10 | timeout-minutes: 20 11 | 12 | steps: 13 | - name: Checkout code 14 | uses: actions/checkout@v4 15 | 16 | - name: Setup bun 17 | uses: oven-sh/setup-bun@v2 18 | with: 19 | bun-version: latest 20 | 21 | - name: Install dependencies 22 | run: bun install 23 | 24 | - name: Cache setup artifacts 25 | id: cache-setup 26 | uses: actions/cache@v4 27 | with: 28 | path: ./db.sqlite3 29 | key: db-sqlite3-${{ hashFiles('scripts/setup-*.ts') }} 30 | 31 | - name: Run setup if cache miss 32 | if: steps.cache-setup.outputs.cache-hit != 'true' 33 | run: bun run setup 34 | 35 | - name: Run tests 36 | run: bun test 37 | -------------------------------------------------------------------------------- /.github/workflows/bun-typecheck.yml: -------------------------------------------------------------------------------- 1 | # Created using @tscircuit/plop (npm install -g @tscircuit/plop) 2 | name: Type Check 3 | 4 | on: 5 | push: 6 | branches: [main] 7 | pull_request: 8 | branches: [main] 9 | 10 | jobs: 11 | type-check: 12 | runs-on: ubuntu-latest 13 | 14 | steps: 15 | - uses: actions/checkout@v4 16 | 17 | - name: Setup bun 18 | uses: oven-sh/setup-bun@v2 19 | with: 20 | bun-version: latest 21 | 22 | - name: Install dependencies 23 | run: bun i 24 | 25 | - name: Run type check 26 | run: bunx tsc --noEmit 27 | -------------------------------------------------------------------------------- /.github/workflows/fly-deploy.yml: -------------------------------------------------------------------------------- 1 | # See https://fly.io/docs/app-guides/continuous-deployment-with-github-actions/ 2 | 3 | name: Fly Deploy 4 | on: 5 | push: 6 | branches: 7 | - main 8 | jobs: 9 | deploy: 10 | name: Deploy app 11 | runs-on: ubuntu-latest 12 | concurrency: deploy-group # optional: ensure only one action runs at a time 13 | steps: 14 | - uses: actions/checkout@v4 15 | - uses: superfly/flyctl-actions/setup-flyctl@master 16 | - run: flyctl deploy --remote-only 17 | env: 18 | FLY_API_TOKEN: ${{ secrets.FLY_API_TOKEN }} 19 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Based on https://raw.githubusercontent.com/github/gitignore/main/Node.gitignore 2 | 3 | # Logs 4 | 5 | logs 6 | _.log 7 | npm-debug.log_ 8 | yarn-debug.log* 9 | yarn-error.log* 10 | lerna-debug.log* 11 | .pnpm-debug.log* 12 | 13 | # Caches 14 | 15 | .cache 16 | 17 | # Diagnostic reports (https://nodejs.org/api/report.html) 18 | 19 | report.[0-9]_.[0-9]_.[0-9]_.[0-9]_.json 20 | 21 | # Runtime data 22 | 23 | pids 24 | _.pid 25 | _.seed 26 | *.pid.lock 27 | 28 | # Directory for instrumented libs generated by jscoverage/JSCover 29 | 30 | lib-cov 31 | 32 | # Coverage directory used by tools like istanbul 33 | 34 | coverage 35 | *.lcov 36 | 37 | # nyc test coverage 38 | 39 | .nyc_output 40 | 41 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) 42 | 43 | .grunt 44 | 45 | # Bower dependency directory (https://bower.io/) 46 | 47 | bower_components 48 | 49 | # node-waf configuration 50 | 51 | .lock-wscript 52 | 53 | # Compiled binary addons (https://nodejs.org/api/addons.html) 54 | 55 | build/Release 56 | 57 | # Dependency directories 58 | 59 | node_modules/ 60 | jspm_packages/ 61 | 62 | # Snowpack dependency directory (https://snowpack.dev/) 63 | 64 | web_modules/ 65 | 66 | # TypeScript cache 67 | 68 | *.tsbuildinfo 69 | 70 | # Optional npm cache directory 71 | 72 | .npm 73 | 74 | # Optional eslint cache 75 | 76 | .eslintcache 77 | 78 | # Optional stylelint cache 79 | 80 | .stylelintcache 81 | 82 | # Microbundle cache 83 | 84 | .rpt2_cache/ 85 | .rts2_cache_cjs/ 86 | .rts2_cache_es/ 87 | .rts2_cache_umd/ 88 | 89 | # Optional REPL history 90 | 91 | .node_repl_history 92 | 93 | # Output of 'npm pack' 94 | 95 | *.tgz 96 | 97 | # Yarn Integrity file 98 | 99 | .yarn-integrity 100 | 101 | # dotenv environment variable files 102 | 103 | .env 104 | .env.development.local 105 | .env.test.local 106 | .env.production.local 107 | .env.local 108 | 109 | # parcel-bundler cache (https://parceljs.org/) 110 | 111 | .parcel-cache 112 | 113 | # Next.js build output 114 | 115 | .next 116 | out 117 | 118 | # Nuxt.js build / generate output 119 | 120 | .nuxt 121 | dist 122 | 123 | # Gatsby files 124 | 125 | # Comment in the public line in if your project uses Gatsby and not Next.js 126 | 127 | # https://nextjs.org/blog/next-9-1#public-directory-support 128 | 129 | # public 130 | 131 | # vuepress build output 132 | 133 | .vuepress/dist 134 | 135 | # vuepress v2.x temp and cache directory 136 | 137 | .temp 138 | 139 | # Docusaurus cache and generated files 140 | 141 | .docusaurus 142 | 143 | # Serverless directories 144 | 145 | .serverless/ 146 | 147 | # FuseBox cache 148 | 149 | .fusebox/ 150 | 151 | # DynamoDB Local files 152 | 153 | .dynamodb/ 154 | 155 | # TernJS port file 156 | 157 | .tern-port 158 | 159 | # Stores VSCode versions used for testing VSCode extensions 160 | 161 | .vscode-test 162 | 163 | # yarn v2 164 | 165 | .yarn/cache 166 | .yarn/unplugged 167 | .yarn/build-state.yml 168 | .yarn/install-state.gz 169 | .pnp.* 170 | 171 | # IntelliJ based IDEs 172 | .idea 173 | 174 | # Finder (MacOS) folder config 175 | .DS_Store 176 | 177 | .vscode 178 | .aider* 179 | db.sqlite3 180 | .buildtmp 181 | .winterspec 182 | db.backup.sqlite3 183 | .bin 184 | .fly.toml.swp -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | # syntax = docker/dockerfile:1 2 | 3 | # Adjust BUN_VERSION as desired 4 | ARG BUN_VERSION=1.1.32 5 | FROM oven/bun:${BUN_VERSION}-slim as base 6 | 7 | LABEL fly_launch_runtime="Bun" 8 | 9 | # Bun app lives here 10 | WORKDIR /app 11 | 12 | # Set production environment 13 | ENV NODE_ENV="production" 14 | 15 | 16 | # Throw-away build stage to reduce size of final image 17 | FROM base as build 18 | 19 | # Install packages needed to build node modules 20 | RUN apt-get update -qq && \ 21 | apt-get install --no-install-recommends -y build-essential pkg-config python-is-python3 22 | 23 | # Install node modules 24 | COPY bun.lockb package.json ./ 25 | RUN bun install --ci 26 | 27 | # Copy application code 28 | COPY . . 29 | 30 | RUN bun setup 31 | 32 | RUN rm -rf .buildtmp 33 | 34 | 35 | # Final stage for app image 36 | FROM base 37 | 38 | # Copy built application 39 | COPY --from=build /app /app 40 | 41 | # Start the server by default, this can be overwritten at runtime 42 | EXPOSE 3000 43 | CMD [ "bun", "run", "start" ] 44 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2024 tscircuit Inc. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # jlcsearch (in-stock jlcpcb search engine and API) 2 | 3 | [Search for Parts](https://jlcsearch.tscircuit.com) ⋅ [tscircuit](https://github.com/tscircuit/tscircuit) ⋅ [discord](https://tscircuit.com/join) 4 | 5 | This is an in-stock parts search engine for JLCPCB parts. It also 6 | features an easy-to-use API (just add ".json") 7 | 8 | Play with it at [jlcsearch.tscircuit.com](https://jlcsearch.tscircuit.com) 9 | 10 | ![image](https://github.com/user-attachments/assets/bf036e76-f67d-47f6-b1f8-01de0dfe3fd2) 11 | 12 | ## API Usage 13 | 14 | You can go on any page and click "json" in the top right corner to automatically convert whatever filter you've made to a JSON query. 15 | 16 | ```bash 17 | curl https://jlcsearch.tscircuit.com/resistors/list.json?package=&resistance=1k 18 | 19 | # { 20 | # "resistors": [ 21 | # { 22 | # "lcsc": 21190, 23 | # "mfr": "0603WAF1001T5E", 24 | # "package": "0603", 25 | # "resistance": 1000, 26 | # "tolerance_fraction": 0.01, 27 | # "power_watts": 100, 28 | # "stock": 31485061, 29 | # "price1": 0.000814286 30 | # }, 31 | # { 32 | # "lcsc": 11702, 33 | # "mfr": "0402WGF1001TCE", 34 | # "package": "0402", 35 | # "resistance": 1000, 36 | # ... 37 | ``` 38 | 39 | ## Development 40 | 41 | Run `bun i` then `bun run setup` to download the necessary dependencies and vendor data, 42 | you can then run `bun run start` to start the server. 43 | 44 | All the routes are in the `routes` folder. If you want to add a new page/table, 45 | you can do the following: 46 | 47 | 1. Create a new "derived table" inside `lib/db/derivedtables`, reference `docs` 48 | to understand the structure and available properties for different components 49 | 2. Run `bun run scripts/setup-derived-tables.ts --reset led_driver` (if `led_driver` is the name of the table you're adding) 50 | 3. Run `bun run generate:db-types` to generate the new table types 51 | 4. Create a new route inside `routes` to represent the page 52 | 5. Add the new route to the `routes/index.ts` file 53 | 6. Make sure to run `bun run format` 54 | 55 | AI is incredibly good at performing every step in the process above, end to end. 56 | I recommend using [aider](https://www.aider.chat/) and adding docs, lib, routes 57 | and scripts folders to the context. 58 | 59 | ## Acknowledgements 60 | 61 | None of this would be possible without [JLCPCB](https://jlcpcb.com) and the work 62 | [jlcparts](https://github.com/yaqwsx/jlcparts) project. 63 | -------------------------------------------------------------------------------- /biome.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://biomejs.dev/schemas/1.9.3/schema.json", 3 | "organizeImports": { 4 | "enabled": true 5 | }, 6 | "formatter": { 7 | "enabled": true, 8 | "indentStyle": "space" 9 | }, 10 | "files": { 11 | "ignore": [ 12 | "cosmos-export", 13 | "dist", 14 | "package.json", 15 | "*.md", 16 | "lib/db/generated/kysely.ts" 17 | ] 18 | }, 19 | "javascript": { 20 | "formatter": { 21 | "jsxQuoteStyle": "double", 22 | "quoteProperties": "asNeeded", 23 | "trailingCommas": "all", 24 | "semicolons": "asNeeded", 25 | "arrowParentheses": "always", 26 | "bracketSpacing": true, 27 | "bracketSameLine": false 28 | } 29 | }, 30 | "linter": { 31 | "enabled": true, 32 | "rules": { 33 | "recommended": true, 34 | "suspicious": { 35 | "noExplicitAny": "off", 36 | "noArrayIndexKey": "off" 37 | }, 38 | "complexity": { 39 | "noForEach": "info", 40 | "noBannedTypes": "off", 41 | "useLiteralKeys": "off" 42 | }, 43 | "a11y": { 44 | "noLabelWithoutControl": "off" 45 | }, 46 | "style": { 47 | "useImportType": "off", 48 | "noUnusedTemplateLiteral": "off", 49 | "noUselessElse": "off", 50 | "noNonNullAssertion": "off", 51 | "useNumberNamespace": "off", 52 | "useFilenamingConvention": { 53 | "level": "error", 54 | "options": { 55 | "strictCase": true, 56 | "requireAscii": true, 57 | "filenameCases": ["kebab-case", "export"] 58 | } 59 | } 60 | } 61 | } 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /bun.lockb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tscircuit/jlcsearch/720d581a9599051867f50bb3575c9e0a2f14caf0/bun.lockb -------------------------------------------------------------------------------- /docs/generated/analog_ics.md: -------------------------------------------------------------------------------- 1 | # Analog ICs 2 | 3 | ### Digital To Analog Converters (DACs) 4 | 5 | | Key | Ex1 | Ex2 | 6 | | --- | --- | --- | 7 | | lcsc | 108207 | 128601 | 8 | | stock | 9295 | 7792 | 9 | | mfr | MCP4728-E/UN | DAC7311IDCKR | 10 | | package | MSOP-10 | SOT-363-6 | 11 | | joints | 10 | 6 | 12 | | description | 6us I2C 2.7V~5.5V 12 Bits MSOP-10 Digital to Analog Converters (DAC) ROHS | 12us 2V~5.5V 12 Bits SOT-363-6 Digital to Analog Converters (DAC) ROHS | 13 | | min_q_price | 1.94057971 | 0.77826087 | 14 | | extra_title | Microchip Tech MCP4728-E/UN | Texas Instruments DAC7311IDCKR | 15 | | extra.number | C108207 | C128601 | 16 | | extra.package | MSOP-10 | SOT-363-6 | 17 | | extra.attributes["Operating Temperature"] | -40℃~+125℃ | -40℃~+125℃ | 18 | | extra.attributes["Number of Channels"] | 4 | | 19 | | extra.attributes["Output Type"] | Voltage Buffer | Voltage Buffer | 20 | | extra.attributes["Integral nonlinearity"] | ±2LSB;±0.2LSB | ±0.3LSB;±0.2LSB | 21 | | extra.attributes["Supply Voltage"] | 2.7V~5.5V | 2V~5.5V | 22 | | extra.attributes["Settling Time"] | 6us | 12us | 23 | | extra.attributes["Interface"] | I2C | SPI;DSP | 24 | | extra.attributes["Resolution"] | 12 Bits | 12 Bits | 25 | 26 | ### Analog Switches 27 | 28 | | Key | Ex1 | Ex2 | 29 | | --- | --- | --- | 30 | | lcsc | 19618 | 79910 | 31 | | stock | 2873 | 2 | 32 | | mfr | SGM3005XMS/TR | SGM3001XC6/TR | 33 | | package | MSOP-10 | - | 34 | | joints | 10 | 6 | 35 | | description | MSOP-10 Analog Switches, Multiplexers ROHS | Analog Switches, Multiplexers ROHS | 36 | | min_q_price | 0.971014493 | 0.824637681 | 37 | | extra_title | SGMICRO SGM3005XMS/TR | SGMICRO SGM3001XC6/TR | 38 | | extra.number | C19618 | C79910 | 39 | | extra.package | MSOP-10 | - | 40 | | extra.attributes["Switch Circuit"] | - | - | 41 | 42 | ### Analog To Digital Converters (ADCs) 43 | 44 | | Key | Ex1 | Ex2 | 45 | | --- | --- | --- | 46 | | lcsc | 6705483 | 29454 | 47 | | stock | 34446 | 16024 | 48 | | mfr | HX711 | MCP3421A0T-E/CH | 49 | | package | SOP-16 | SOT-23-6 | 50 | | joints | 16 | 6 | 51 | | description | SOP-16 Analog to Digital Converters (ADC) ROHS | 18Bit 2.7V~5.5V 3.75Hz I2C SOT-23-6 Analog to Digital Converters (ADC) ROHS | 52 | | min_q_price | 0.411594203 | 1.744927536 | 53 | | extra_title | Avia Semicon (Xiamen) HX711 | Microchip Tech MCP3421A0T-E/CH | 54 | | extra.number | C6705483 | C29454 | 55 | | extra.package | SOP-16 | SOT-23-6 | 56 | | extra.attributes["Operating Temperature"] | undefined | -40℃~+125℃ | 57 | | extra.attributes["Supply Voltage"] | undefined | 2.7V~5.5V | 58 | | extra.attributes["number of channels"] | undefined | 1 | 59 | | extra.attributes["sampling frequency"] | undefined | 3.75Hz | 60 | | extra.attributes["differential input"] | undefined | Yes | 61 | | extra.attributes["resolution"] | undefined | 18Bit | 62 | | extra.attributes["Interface"] | undefined | I2C | 63 | 64 | -------------------------------------------------------------------------------- /docs/generated/audio_products__vibration_motors.md: -------------------------------------------------------------------------------- 1 | # Audio Products / Vibration Motors 2 | 3 | ### MEMS Microphones 4 | 5 | | Key | Ex1 | Ex2 | 6 | | --- | --- | --- | 7 | | lcsc | 140705 | 5373233 | 8 | | stock | 4981 | 4781 | 9 | | mfr | WMM7037AT2-4/TR | LMA3722T421-OA5 | 10 | | package | LGA-4(3x3.8) | SMD-4P,3.8x2.2mm | 11 | | joints | 4 | 4 | 12 | | description | Omni-directional -42dB 200Ω 59dB LGA-4(3x3.8) MEMS Microphones ROHS | Omni-directional -42dB 300Ω 55dB SMD-4P,3.8x2.2mm MEMS Microphones ROHS | 13 | | min_q_price | 0.286956522 | 0.060144928 | 14 | | extra_title | WILLSEMI(Will Semicon) WMM7037AT2 | LinkMems LMA3722T421-OA5 | 15 | | extra.number | C140705 | C5373233 | 16 | | extra.package | LGA-4(3x3.8) | SMD-4P,3.8x2.2mm | 17 | | extra.attributes["Sensitivity"] | -42dB | -42dB | 18 | | extra.attributes["Supply Voltage"] | 1.5V~3.6V | 1.6V~3.6V | 19 | | extra.attributes["SNR(Signal to Noise Ratio)"] | 59dB | 55dB | 20 | | extra.attributes["Impedance"] | 200Ω | 300Ω | 21 | | extra.attributes["Direction"] | Omnidirectional | Omni-directional | 22 | | extra.attributes["Current Consumption"] | 80uA | 120uA | 23 | 24 | ### Buzzers 25 | 26 | | Key | Ex1 | Ex2 | 27 | | --- | --- | --- | 28 | | lcsc | 96256 | 96102 | 29 | | stock | 78746 | 39686 | 30 | | mfr | QMB-09B-03 | HNB09A03 | 31 | | package | Plugin,D=9mm | Plugin,D=9mm | 32 | | joints | 2 | 2 | 33 | | description | 85dB Passive (external drive) Electromagnetic Type 2.7kHz Plugin,D=9mm Buzzers ROHS | 85dB Active (Built-in Driver Circuit) Electromagnetic Type 3kHz Plugin,D=9mm Buzzers ROHS | 34 | | min_q_price | 0.097681159 | 0.190434783 | 35 | | extra_title | Jiangsu Huaneng Elec QMB-09B-03 | Jiangsu Huaneng Elec HNB09A03 | 36 | | extra.number | C96256 | C96102 | 37 | | extra.package | Plugin,D=9mm | Plugin,D=9mm | 38 | | extra.attributes["Sound Pressure Level (SPL)"] | 85dB@3V,10cm | 85dB@10cm | 39 | | extra.attributes["Technology Type"] | Magnetic | Magnetic | 40 | | extra.attributes["Diameter (φD)"] | 9mm | 9mm | 41 | | extra.attributes["Operating Voltage"] | 2V~5V | 1.5V~4.5V | 42 | | extra.attributes["Oscillator Circuit"] | Externally Driven | Active (driven circuit included) | 43 | | extra.attributes["Frequency"] | 2700Hz | 3kHz | 44 | | extra.attributes["Height"] | 5.7mm | 5.5mm | 45 | | extra.attributes["Rated Voltage"] | 3V | 3V | 46 | | extra.attributes["Operating Temperature"] | undefined | -20℃~+70℃ | 47 | | extra.attributes["Length"] | undefined | - | 48 | | extra.attributes["Width"] | undefined | - | 49 | | extra.attributes["Current Consumption"] | undefined | 30mA | 50 | 51 | ### Vibration Motors 52 | 53 | | Key | Ex1 | Ex2 | 54 | | --- | --- | --- | 55 | | lcsc | 7528806 | 41348533 | 56 | | stock | 3517 | 829 | 57 | | mfr | LCM1027B3605F | LD-SM-430 | 58 | | package | - | - | 59 | | joints | 5 | 3 | 60 | | description | 16000±3500rpm Flat Vibration Motor 3V Vibration Motors ROHS | Vibration Motors ROHS | 61 | | min_q_price | 0.401449275 | 1.015942029 | 62 | | extra_title | | LEADER LD-SM-430 | 63 | | extra.number | | C41348533 | 64 | | extra.package | | - | 65 | 66 | ### Speakers 67 | 68 | | Key | Ex1 | Ex2 | 69 | | --- | --- | --- | 70 | | lcsc | 530539 | 530544 | 71 | | stock | 891 | 739 | 72 | | mfr | GSPK151035PN-8R0.5W-L35-1.25T | GSPK2004PN-8R1W-L100 | 73 | | package | - | - | 74 | | joints | 1 | 5 | 75 | | description | - Speakers ROHS | - Speakers ROHS | 76 | | min_q_price | 0.333333333 | 0.51884058 | 77 | | extra_title | INGHAi GSPK151035PN-8R0.5W-L35-1.25T | INGHAi GSPK2004PN-8R1W-L100 | 78 | | extra.number | C530539 | C530544 | 79 | | extra.package | - | - | 80 | 81 | ### Microphones 82 | 83 | | Key | Ex1 | Ex2 | 84 | | --- | --- | --- | 85 | | lcsc | 233793 | 233939 | 86 | | stock | 8336 | 6153 | 87 | | mfr | B4013AM422-42 | GMI6050P-36db | 88 | | package | - | Plugin,D=6mm | 89 | | joints | 3 | 2 | 90 | | description | - Microphones ROHS | Plugin,D=6mm Microphones ROHS | 91 | | min_q_price | 0.14815942 | 0.148884058 | 92 | | extra_title | Goertek B4013AM422-42 | INGHAi GMI6050P-36db | 93 | | extra.number | C233793 | C233939 | 94 | | extra.package | - | Plugin,D=6mm | 95 | 96 | -------------------------------------------------------------------------------- /docs/generated/audio_productsmicromotors.md: -------------------------------------------------------------------------------- 1 | # audio products/micromotors 2 | 3 | ### MEMS Microphones 4 | 5 | | Key | Ex1 | Ex2 | 6 | | --- | --- | --- | 7 | | lcsc | 140705 | 5373233 | 8 | | stock | 4981 | 4781 | 9 | | mfr | WMM7037AT2-4/TR | LMA3722T421-OA5 | 10 | | package | LGA-4(3x3.8) | SMD-4P,3.8x2.2mm | 11 | | joints | 4 | 4 | 12 | | description | Omni-directional -42dB 200Ω 59dB LGA-4(3x3.8) MEMS Microphones ROHS | Omni-directional -42dB 300Ω 55dB SMD-4P,3.8x2.2mm MEMS Microphones ROHS | 13 | | min_q_price | 0.286956522 | 0.060144928 | 14 | | extra_title | WILLSEMI(Will Semicon) WMM7037AT2 | LinkMems LMA3722T421-OA5 | 15 | | extra.number | C140705 | C5373233 | 16 | | extra.package | LGA-4(3x3.8) | SMD-4P,3.8x2.2mm | 17 | | extra.attributes["Sensitivity"] | -42dB | -42dB | 18 | | extra.attributes["Supply Voltage"] | 1.5V~3.6V | 1.6V~3.6V | 19 | | extra.attributes["SNR(Signal to Noise Ratio)"] | 59dB | 55dB | 20 | | extra.attributes["Impedance"] | 200Ω | 300Ω | 21 | | extra.attributes["Direction"] | Omnidirectional | Omni-directional | 22 | | extra.attributes["Current Consumption"] | 80uA | 120uA | 23 | 24 | ### 25 | 26 | | Key | Ex1 | Ex2 | 27 | | --- | --- | --- | 28 | | lcsc | 5299908 | 5346354 | 29 | | stock | 5570 | 4793 | 30 | | mfr | CH32V003F4U6 | CH32V003J4M6 | 31 | | package | QFN-20(3X3) | SOP-8 | 32 | | joints | 21 | 8 | 33 | | description | 16KB 2KB 18 RISC-V 48MHz QFN-20(3X3) Microcontrollers (MCU/MPU/SOC) ROHS | SOP-8 Microcontrollers (MCU/MPU/SOC) ROHS | 34 | | min_q_price | 0.229130435 | 0.185362319 | 35 | | extra_title | WCH(Jiangsu Qin Heng) CH32V003F4U6 | WCH(Jiangsu Qin Heng) CH32V003J4M6 | 36 | | extra.number | C5299908 | C5346354 | 37 | | extra.package | QFN-20(3X3) | SOP-8 | 38 | | extra.attributes["DAC (Bit)"] | - | | 39 | | extra.attributes["Program Memory Type"] | - | | 40 | | extra.attributes["Peripheral/Function"] | - | | 41 | | extra.attributes["CPU Core"] | RISC-V | | 42 | | extra.attributes["Operating Voltage Range"] | - | | 43 | | extra.attributes["communication protocol"] | - | | 44 | | extra.attributes["Infrared Data Association"] | - | | 45 | | extra.attributes["SPI"] | 1 | | 46 | | extra.attributes["UART/USART"] | 1 | | 47 | | extra.attributes["32Bit Timer"] | - | | 48 | | extra.attributes["Direct Memory Access"] | - | | 49 | | extra.attributes["Universal Serial Bus"] | - | | 50 | | extra.attributes["Low-Voltage Detect"] | - | | 51 | | extra.attributes["Real-Time Clock"] | Yes | | 52 | | extra.attributes["I2C"] | 1 | | 53 | | extra.attributes["Application Area"] | - | | 54 | | extra.attributes["PWM (Bit)"] | - | | 55 | | extra.attributes["LCD Module"] | - | | 56 | | extra.attributes["CCP Capture/Compare"] | - | | 57 | | extra.attributes["LED Module"] | - | | 58 | | extra.attributes["RAM Size"] | 2KB | | 59 | | extra.attributes["Operating Temperature Range"] | - | | 60 | | extra.attributes["Internal Comparator"] | - | | 61 | | extra.attributes["I2S"] | - | | 62 | | extra.attributes["Internal Oscillator"] | - | | 63 | | extra.attributes["GPIO Ports Number"] | 18 | | 64 | | extra.attributes["16Bit Timer"] | - | | 65 | | extra.attributes["EEPROM"] | - | | 66 | | extra.attributes["CPU Maximum Speed"] | 48MHz | | 67 | | extra.attributes["CAN"] | - | | 68 | | extra.attributes["Program Storage Size"] | 16KB | | 69 | | extra.attributes["Watchdog"] | Yes | | 70 | | extra.attributes["8Bit Timer"] | - | | 71 | | extra.attributes["ADC (Bit)"] | - | | 72 | | extra.attributes["Secure Digital Input and Output"] | - | | 73 | 74 | -------------------------------------------------------------------------------- /docs/generated/battery_products.md: -------------------------------------------------------------------------------- 1 | # Battery Products 2 | 3 | ### Battery Holders, Clips & Contacts 4 | 5 | | Key | Ex1 | Ex2 | 6 | | --- | --- | --- | 7 | | lcsc | 5352788 | 2844281 | 8 | | stock | 1001 | 59 | 9 | | mfr | 53 | BQ7695203PFBR | 10 | | package | - | TQFP-48(7x7) | 11 | | joints | 2 | 48 | 12 | | description | - BatteryConnector ROHS | Lithium-ion/Polymer 3~16 TQFP-48(7x7) Battery Management ROHS | 13 | | min_q_price | 0.279710145 | 4.8 | 14 | | extra_title | Keystone 53 | Texas Instruments BQ7695203PFBR | 15 | | extra.number | C5352788 | C2844281 | 16 | | extra.package | - | TQFP-48(7x7) | 17 | | extra.attributes["Operating Temperature"] | undefined | -40℃~+85℃ | 18 | | extra.attributes["Type of Battery"] | undefined | Lithium-ion/Polymer | 19 | | extra.attributes["Number of Cells"] | undefined | 3~16 | 20 | 21 | ### 22 | 23 | | Key | Ex1 | Ex2 | 24 | | --- | --- | --- | 25 | | lcsc | 5299908 | 5346354 | 26 | | stock | 5570 | 4793 | 27 | | mfr | CH32V003F4U6 | CH32V003J4M6 | 28 | | package | QFN-20(3X3) | SOP-8 | 29 | | joints | 21 | 8 | 30 | | description | 16KB 2KB 18 RISC-V 48MHz QFN-20(3X3) Microcontrollers (MCU/MPU/SOC) ROHS | SOP-8 Microcontrollers (MCU/MPU/SOC) ROHS | 31 | | min_q_price | 0.229130435 | 0.185362319 | 32 | | extra_title | WCH(Jiangsu Qin Heng) CH32V003F4U6 | WCH(Jiangsu Qin Heng) CH32V003J4M6 | 33 | | extra.number | C5299908 | C5346354 | 34 | | extra.package | QFN-20(3X3) | SOP-8 | 35 | | extra.attributes["DAC (Bit)"] | - | | 36 | | extra.attributes["Program Memory Type"] | - | | 37 | | extra.attributes["Peripheral/Function"] | - | | 38 | | extra.attributes["CPU Core"] | RISC-V | | 39 | | extra.attributes["Operating Voltage Range"] | - | | 40 | | extra.attributes["communication protocol"] | - | | 41 | | extra.attributes["Infrared Data Association"] | - | | 42 | | extra.attributes["SPI"] | 1 | | 43 | | extra.attributes["UART/USART"] | 1 | | 44 | | extra.attributes["32Bit Timer"] | - | | 45 | | extra.attributes["Direct Memory Access"] | - | | 46 | | extra.attributes["Universal Serial Bus"] | - | | 47 | | extra.attributes["Low-Voltage Detect"] | - | | 48 | | extra.attributes["Real-Time Clock"] | Yes | | 49 | | extra.attributes["I2C"] | 1 | | 50 | | extra.attributes["Application Area"] | - | | 51 | | extra.attributes["PWM (Bit)"] | - | | 52 | | extra.attributes["LCD Module"] | - | | 53 | | extra.attributes["CCP Capture/Compare"] | - | | 54 | | extra.attributes["LED Module"] | - | | 55 | | extra.attributes["RAM Size"] | 2KB | | 56 | | extra.attributes["Operating Temperature Range"] | - | | 57 | | extra.attributes["Internal Comparator"] | - | | 58 | | extra.attributes["I2S"] | - | | 59 | | extra.attributes["Internal Oscillator"] | - | | 60 | | extra.attributes["GPIO Ports Number"] | 18 | | 61 | | extra.attributes["16Bit Timer"] | - | | 62 | | extra.attributes["EEPROM"] | - | | 63 | | extra.attributes["CPU Maximum Speed"] | 48MHz | | 64 | | extra.attributes["CAN"] | - | | 65 | | extra.attributes["Program Storage Size"] | 16KB | | 66 | | extra.attributes["Watchdog"] | Yes | | 67 | | extra.attributes["8Bit Timer"] | - | | 68 | | extra.attributes["ADC (Bit)"] | - | | 69 | | extra.attributes["Secure Digital Input and Output"] | - | | 70 | 71 | -------------------------------------------------------------------------------- /docs/generated/buzzers__speakers__microphones.md: -------------------------------------------------------------------------------- 1 | # Buzzers & Speakers & Microphones 2 | 3 | ### Buzzers 4 | 5 | | Key | Ex1 | Ex2 | 6 | | --- | --- | --- | 7 | | lcsc | 96256 | 96102 | 8 | | stock | 78746 | 39686 | 9 | | mfr | QMB-09B-03 | HNB09A03 | 10 | | package | Plugin,D=9mm | Plugin,D=9mm | 11 | | joints | 2 | 2 | 12 | | description | 85dB Passive (external drive) Electromagnetic Type 2.7kHz Plugin,D=9mm Buzzers ROHS | 85dB Active (Built-in Driver Circuit) Electromagnetic Type 3kHz Plugin,D=9mm Buzzers ROHS | 13 | | min_q_price | 0.097681159 | 0.190434783 | 14 | | extra_title | Jiangsu Huaneng Elec QMB-09B-03 | Jiangsu Huaneng Elec HNB09A03 | 15 | | extra.number | C96256 | C96102 | 16 | | extra.package | Plugin,D=9mm | Plugin,D=9mm | 17 | | extra.attributes["Sound Pressure Level (SPL)"] | 85dB@3V,10cm | 85dB@10cm | 18 | | extra.attributes["Technology Type"] | Magnetic | Magnetic | 19 | | extra.attributes["Diameter (φD)"] | 9mm | 9mm | 20 | | extra.attributes["Operating Voltage"] | 2V~5V | 1.5V~4.5V | 21 | | extra.attributes["Oscillator Circuit"] | Externally Driven | Active (driven circuit included) | 22 | | extra.attributes["Frequency"] | 2700Hz | 3kHz | 23 | | extra.attributes["Height"] | 5.7mm | 5.5mm | 24 | | extra.attributes["Rated Voltage"] | 3V | 3V | 25 | | extra.attributes["Operating Temperature"] | undefined | -20℃~+70℃ | 26 | | extra.attributes["Length"] | undefined | - | 27 | | extra.attributes["Width"] | undefined | - | 28 | | extra.attributes["Current Consumption"] | undefined | 30mA | 29 | 30 | -------------------------------------------------------------------------------- /docs/generated/circuit_protection.md: -------------------------------------------------------------------------------- 1 | # circuit protection 2 | 3 | ### TVS 4 | 5 | | Key | Ex1 | Ex2 | 6 | | --- | --- | --- | 7 | | lcsc | 172440 | 32677 | 8 | | stock | 925333 | 314908 | 9 | | mfr | LTVS16H5.0T5G | PSM712-LF-T7 | 10 | | package | DFN1610-2 | SOT-23 | 11 | | joints | 2 | 3 | 12 | | description | 100A@8/20us 8.5V 6V 5V DFN1610-2 ESD and Surge Protection (TVS/ESD) ROHS | 19V 13.3V 12V SOT-23 ESD and Surge Protection (TVS/ESD) ROHS | 13 | | min_q_price | 0.026231884 | 0.299695652 | 14 | | extra_title | LRC LTVS16H5.0T5G | ProTek Devices PSM712-LF-T7 | 15 | | extra.number | C172440 | C32677 | 16 | | extra.package | DFN1610-2 | SOT-23(TO-236) | 17 | | extra.attributes["Breakdown Voltage"] | 6V | 13.3V | 18 | | extra.attributes["Maximum Clamping Voltage"] | 8.5V | 19V | 19 | | extra.attributes["Reverse Stand-Off Voltage (Vrwm)"] | 5V | 12V | 20 | | extra.attributes["Peak Pulse Current (Ipp)@10/1000us"] | 100A@8/20us | | 21 | 22 | ### Fuses 23 | 24 | | Key | Ex1 | Ex2 | 25 | | --- | --- | --- | 26 | | lcsc | 136354 | 182974 | 27 | | stock | 39926 | 34337 | 28 | | mfr | JFC1206-2100FS | 12B1100B | 29 | | package | 1206 | 1206 | 30 | | joints | 2 | 2 | 31 | | description | 150A SMD Fuse 10A 32V 32V 1206 Disposable fuses ROHS | 50A SMD Fuse 1A 125V 125V 1206 Disposable fuses ROHS | 32 | | min_q_price | 0.055362319 | 0.055942029 | 33 | | extra_title | Shenzhen JDT Fuse JFC1206-2100FS | Shenzhen lanson Elec 12B1100B | 34 | | extra.number | C136354 | C182974 | 35 | | extra.package | 1206 | 1206 | 36 | | extra.attributes["Operating Temperature"] | -55℃~+125℃ | -55℃~+125℃ | 37 | | extra.attributes["Type"] | SMD Fuse | SMD Fuse | 38 | | extra.attributes["Current Rating"] | 10A | 1A | 39 | | extra.attributes["Breaking Capacity"] | 150A | 50A | 40 | | extra.attributes["Voltage Rating (AC)"] | undefined | 125V | 41 | | extra.attributes["Voltage Rating (DC)"] | undefined | 125V | 42 | 43 | -------------------------------------------------------------------------------- /docs/generated/crystalsoscillatorsresonators.md: -------------------------------------------------------------------------------- 1 | # crystals/oscillators/resonators 2 | 3 | ### 4 | 5 | | Key | Ex1 | Ex2 | 6 | | --- | --- | --- | 7 | | lcsc | 5149201 | 962342 | 8 | | stock | 40262 | 4702 | 9 | | mfr | SK6812MINI-E | ES8311 | 10 | | package | SMD | WQFN-20-EP(3x3) | 11 | | joints | 4 | 21 | 12 | | description | SMD RGB LEDs(Built-in IC) ROHS | WQFN-20-EP(3x3) Signal Switches, Multiplexers, Decoders ROHS | 13 | | min_q_price | 0.084347826 | 0.510144928 | 14 | | extra_title | OPSCO Optoelectronics SK6812MINI-E | Everest-semi(Everest Semiconductor) ES8311 | 15 | | extra.number | C5149201 | C962342 | 16 | | extra.package | SMD | QFN-20-EP(3x3) | 17 | 18 | ### Crystals 19 | 20 | | Key | Ex1 | Ex2 | 21 | | --- | --- | --- | 22 | | lcsc | 12674 | 32346 | 23 | | stock | 249381 | 188872 | 24 | | mfr | X49SM8MSD2SC | Q13FC13500004 | 25 | | package | HC-49S-SMD | SMD3215-2P | 26 | | joints | 2 | 2 | 27 | | description | 8MHz Surface Mount Crystal 20pF ±20ppm ±30ppm HC-49S-SMD Crystals ROHS | 32.768kHz Surface Mount Crystal 12.5pF ±20ppm SMD3215-2P Crystals ROHS | 28 | | min_q_price | 0.070869565 | 0.179855072 | 29 | | extra_title | Yangxing Tech X49SM8MSD2SC | Seiko Epson Q13FC1350000400 | 30 | | extra.number | C12674 | C32346 | 31 | | extra.package | HC-49S-SMD | SMD3215-2P | 32 | | extra.attributes["Load Capacitance"] | 20pF | 12.5pF | 33 | | extra.attributes["Crystal Type"] | 49SMD | SMD Crystal Resonator | 34 | | extra.attributes["Frequency Tolerance"] | ±20ppm | ±20ppm | 35 | | extra.attributes["Operating Temperature"] | -20℃~+70℃ | -40℃~+85℃ | 36 | | extra.attributes["Frequency Stability"] | ±30ppm | | 37 | | extra.attributes["Frequency"] | 8MHz | 32.768kHz | 38 | | extra.attributes["Equivalent Series Resistance (ESR)"] | undefined | 70kΩ | 39 | 40 | -------------------------------------------------------------------------------- /docs/generated/display_modules__led_drivers__display_drivers.md: -------------------------------------------------------------------------------- 1 | # display modules / led drivers / display drivers 2 | 3 | ### 4 | 5 | | Key | Ex1 | Ex2 | 6 | | --- | --- | --- | 7 | | lcsc | 5149201 | 962342 | 8 | | stock | 40262 | 4702 | 9 | | mfr | SK6812MINI-E | ES8311 | 10 | | package | SMD | WQFN-20-EP(3x3) | 11 | | joints | 4 | 21 | 12 | | description | SMD RGB LEDs(Built-in IC) ROHS | WQFN-20-EP(3x3) Signal Switches, Multiplexers, Decoders ROHS | 13 | | min_q_price | 0.084347826 | 0.510144928 | 14 | | extra_title | OPSCO Optoelectronics SK6812MINI-E | Everest-semi(Everest Semiconductor) ES8311 | 15 | | extra.number | C5149201 | C962342 | 16 | | extra.package | SMD | QFN-20-EP(3x3) | 17 | 18 | ### LCD Drivers 19 | 20 | | Key | Ex1 | Ex2 | 21 | | --- | --- | --- | 22 | | lcsc | 7873 | 2980111 | 23 | | stock | 31931 | 6213 | 24 | | mfr | HT1621B | TM1621B | 25 | | package | SSOP-48-300mil | LQFP-44(10x10) | 26 | | joints | 48 | 44 | 27 | | description | 60uA 2.4V~5.2V SSOP-48-300mil LCD Drivers ROHS | LQFP-44(10x10) LCD Drivers ROHS | 28 | | min_q_price | 0.450724638 | 0.240724638 | 29 | | extra_title | Holtek Semicon HT1621B | TM(Shenzhen Titan Micro Elec) TM1621B | 30 | | extra.number | C7873 | C2980111 | 31 | | extra.package | SSOP-48-300mil | LQFP-44(10x10) | 32 | | extra.attributes["Operating Temperature"] | -25℃~+75℃ | | 33 | | extra.attributes["Display Configurations"] | 32x4 bit | | 34 | | extra.attributes["Duty cycle"] | 1/2, 1/3, 1/4 | | 35 | | extra.attributes["Bias"] | 1/2, 1/3 | | 36 | | extra.attributes["Operating Voltage"] | 2.4V~5.2V | | 37 | | extra.attributes["Operating Current"] | 60uA | | 38 | | extra.attributes["Interface"] | - | | 39 | 40 | -------------------------------------------------------------------------------- /docs/generated/display_screen.md: -------------------------------------------------------------------------------- 1 | # Display Screen 2 | 3 | ### Liquid Crystal Display Screen 4 | 5 | | Key | Ex1 | Ex2 | 6 | | --- | --- | --- | 7 | | lcsc | 18198250 | 5329586 | 8 | | stock | 85 | 30 | 9 | | mfr | HS1602A-Y | HS20S010B | 10 | | package | - | - | 11 | | joints | 20 | 20 | 12 | | description | 2 SPLC780 - LCD Screen ROHS | 2 320x240 ST7789 - LCD Screen ROHS | 13 | | min_q_price | 1.982608696 | 4.488405797 | 14 | | extra_title | | | 15 | | extra.number | | | 16 | | extra.package | | | 17 | 18 | ### Organic Light Emitting Diode Display Screen 19 | 20 | | Key | Ex1 | Ex2 | 21 | | --- | --- | --- | 22 | | lcsc | 4944144 | 88334 | 23 | | stock | 72 | 1 | 24 | | mfr | X096-2864KLBAG01-H30 | UG-6448KLBEG03 | 25 | | package | - | - | 26 | | joints | 30 | 28 | 27 | | description | SSD1315 128x64 0.96 - OLED Display ROHS | 0.66 OLED Display ROHS | 28 | | min_q_price | 2.11884058 | 1.898550725 | 29 | | extra_title | | | 30 | | extra.number | | | 31 | | extra.package | | | 32 | 33 | ### LED Segment Displays 34 | 35 | | Key | Ex1 | Ex2 | 36 | | --- | --- | --- | 37 | | lcsc | 3291495 | 19272542 | 38 | | stock | 1529 | 421 | 39 | | mfr | MHDC2052SRBW | A551G1-IN B/W | 40 | | package | Plugin | DIP-10 | 41 | | joints | 13 | 10 | 42 | | description | Red 50mW 5 Digits Common Cathode 0.2 Plugin LED Segment Displays ROHS | Yellow-Green 60mW 1 Digit Common Anode 0.56 DIP-10 LED Segment Displays ROHS | 43 | | min_q_price | 0.87826087 | 0.105942029 | 44 | | extra_title | | | 45 | | extra.number | | | 46 | | extra.package | | | 47 | 48 | -------------------------------------------------------------------------------- /docs/generated/displays.md: -------------------------------------------------------------------------------- 1 | # Displays 2 | 3 | ### Liquid Crystal Display Screen 4 | 5 | | Key | Ex1 | Ex2 | 6 | | --- | --- | --- | 7 | | lcsc | 18198250 | 5329586 | 8 | | stock | 85 | 30 | 9 | | mfr | HS1602A-Y | HS20S010B | 10 | | package | - | - | 11 | | joints | 20 | 20 | 12 | | description | 2 SPLC780 - LCD Screen ROHS | 2 320x240 ST7789 - LCD Screen ROHS | 13 | | min_q_price | 1.982608696 | 4.488405797 | 14 | | extra_title | | | 15 | | extra.number | | | 16 | | extra.package | | | 17 | 18 | ### Organic Light Emitting Diode Display Screen 19 | 20 | | Key | Ex1 | Ex2 | 21 | | --- | --- | --- | 22 | | lcsc | 4944144 | 88334 | 23 | | stock | 72 | 1 | 24 | | mfr | X096-2864KLBAG01-H30 | UG-6448KLBEG03 | 25 | | package | - | - | 26 | | joints | 30 | 28 | 27 | | description | SSD1315 128x64 0.96 - OLED Display ROHS | 0.66 OLED Display ROHS | 28 | | min_q_price | 2.11884058 | 1.898550725 | 29 | | extra_title | | | 30 | | extra.number | | | 31 | | extra.package | | | 32 | 33 | ### LED Segment Displays 34 | 35 | | Key | Ex1 | Ex2 | 36 | | --- | --- | --- | 37 | | lcsc | 3291495 | 19272542 | 38 | | stock | 1529 | 421 | 39 | | mfr | MHDC2052SRBW | A551G1-IN B/W | 40 | | package | Plugin | DIP-10 | 41 | | joints | 13 | 10 | 42 | | description | Red 50mW 5 Digits Common Cathode 0.2 Plugin LED Segment Displays ROHS | Yellow-Green 60mW 1 Digit Common Anode 0.56 DIP-10 LED Segment Displays ROHS | 43 | | min_q_price | 0.87826087 | 0.105942029 | 44 | | extra_title | | | 45 | | extra.number | | | 46 | | extra.package | | | 47 | 48 | ### OLED Display 49 | 50 | | Key | Ex1 | Ex2 | 51 | | --- | --- | --- | 52 | | lcsc | 7465997 | 18723026 | 53 | | stock | 48 | 45 | 54 | | mfr | HS13L03W2C01 | X096-2864KSWPG01-H30 | 55 | | package | - | - | 56 | | joints | 4 | 30 | 57 | | description | SH1106 I2C 1.3 OLED Display ROHS | - OLED Display ROHS | 58 | | min_q_price | 4.32173913 | 1.692753623 | 59 | | extra_title | | | 60 | | extra.number | | | 61 | | extra.package | | | 62 | 63 | ### LCD Screen 64 | 65 | | Key | Ex1 | Ex2 | 66 | | --- | --- | --- | 67 | | lcsc | 2939933 | 18198244 | 68 | | stock | 9 | 1 | 69 | | mfr | HS0802 | HS28B02A | 70 | | package | - | - | 71 | | joints | 20 | 34 | 72 | | description | 1.8 SPLC780 LCD Screen ROHS | 2.8 320x240 ST7789 LCD Screen ROHS | 73 | | min_q_price | 1.57826087 | 5.598550725 | 74 | | extra_title | | | 75 | | extra.number | | | 76 | | extra.package | | | 77 | 78 | -------------------------------------------------------------------------------- /docs/generated/driver_ics.md: -------------------------------------------------------------------------------- 1 | # Driver ICs 2 | 3 | ### LED Drivers 4 | 5 | | Key | Ex1 | Ex2 | 6 | | --- | --- | --- | 7 | | lcsc | 114581 | 533883 | 8 | | stock | 131101 | 82437 | 9 | | mfr | WS2811 | BCR 401U E6327 | 10 | | package | SOP-8 | SC-74-6 | 11 | | joints | 8 | 6 | 12 | | description | 20V 3 16.5mA 5V~24V SOP-8 LED Drivers ROHS | SC-74-6 LED Drivers ROHS | 13 | | min_q_price | 0.030724638 | 0.204202899 | 14 | | extra_title | Worldsemi WS2811 | Infineon Technologies BCR 401U E6327 | 15 | | extra.number | C114581 | C533883 | 16 | | extra.package | SOP-8 | SC-74-6 | 17 | | extra.attributes["Type"] | - | | 18 | | extra.attributes["Output Current"] | - | | 19 | | extra.attributes["Features"] | - | | 20 | | extra.attributes["Dimming"] | - | | 21 | | extra.attributes["Input Voltage"] | - | | 22 | | extra.attributes["Topology"] | - | | 23 | | extra.attributes["Input Voltage(VAC)"] | - | | 24 | | extra.attributes["Output Voltage"] | - | | 25 | | extra.attributes["Channels"] | - | | 26 | | extra.attributes["Switch Frequency"] | - | | 27 | | extra.attributes["Operating temperature"] | - | | 28 | 29 | ### Darlington transistor array driver 30 | 31 | | Key | Ex1 | Ex2 | 32 | | --- | --- | --- | 33 | | lcsc | 164883 | 138393 | 34 | | stock | 3058 | 657 | 35 | | mfr | ULN2003AS16-13 | NCV1413BDR2G | 36 | | package | SOIC-16 | SOIC-16 | 37 | | joints | 16 | 16 | 38 | | description | SO-16 Darlington transistor array driver RoHS | TRANSISTOR ARRAY NPN 50V SOIC | 39 | | min_q_price | 0.153144928 | 0.501449275 | 40 | | extra_title | | | 41 | | extra.number | | | 42 | | extra.package | | | 43 | 44 | ### Driver ICs 45 | 46 | | Key | Ex1 | Ex2 | 47 | | --- | --- | --- | 48 | | lcsc | 116578 | 157476 | 49 | | stock | 2410 | 175 | 50 | | mfr | SGM3732YTN6G/TR | AM26C31CDR | 51 | | package | TSOT-23-6 | SOIC-16 | 52 | | joints | 6 | 16 | 53 | | description | TSOT-23-6 LED Drivers ROHS | Driver ICs SOIC-16 RoHS | 54 | | min_q_price | 0.508695652 | 0.952173913 | 55 | | extra_title | SGMICRO SGM3732YTN6G/TR | | 56 | | extra.number | C116578 | | 57 | | extra.package | TSOT-23-6 | | 58 | 59 | ### IGBT 60 | 61 | | Key | Ex1 | Ex2 | 62 | | --- | --- | --- | 63 | | lcsc | 194135 | 60056 | 64 | | stock | 802 | 246 | 65 | | mfr | ACPL-W341-500E | ACPL-W340-500E | 66 | | package | SO-6-6.8mm | SO-6-6.8mm | 67 | | joints | 6 | 6 | 68 | | description | SO-6 IGBT RoHS | SO-6 IGBT RoHS | 69 | | min_q_price | 0.950724638 | 0.789855072 | 70 | | extra_title | | | 71 | | extra.number | | | 72 | | extra.package | | | 73 | 74 | ### MOS Drivers 75 | 76 | | Key | Ex1 | Ex2 | 77 | | --- | --- | --- | 78 | | lcsc | 83516 | 73205 | 79 | | stock | 815 | 67 | 80 | | mfr | A3941KLPTR-T | FDC6324L | 81 | | package | TSSOP-28-EP | SuperSOT-6 | 82 | | joints | 28 | 6 | 83 | | description | 芯片, MOSFET驱动器, 全桥, 28TSSOP | SuperSOT-6 Gate Drivers ROHS | 84 | | min_q_price | 2.114492754 | 0.571014493 | 85 | | extra_title | | | 86 | | extra.number | | | 87 | | extra.package | | | 88 | 89 | ### LCD Drivers 90 | 91 | | Key | Ex1 | Ex2 | 92 | | --- | --- | --- | 93 | | lcsc | 7873 | 2980111 | 94 | | stock | 31931 | 6213 | 95 | | mfr | HT1621B | TM1621B | 96 | | package | SSOP-48-300mil | LQFP-44(10x10) | 97 | | joints | 48 | 44 | 98 | | description | 60uA 2.4V~5.2V SSOP-48-300mil LCD Drivers ROHS | LQFP-44(10x10) LCD Drivers ROHS | 99 | | min_q_price | 0.450724638 | 0.240724638 | 100 | | extra_title | Holtek Semicon HT1621B | TM(Shenzhen Titan Micro Elec) TM1621B | 101 | | extra.number | C7873 | C2980111 | 102 | | extra.package | SSOP-48-300mil | LQFP-44(10x10) | 103 | | extra.attributes["Operating Temperature"] | -25℃~+75℃ | | 104 | | extra.attributes["Display Configurations"] | 32x4 bit | | 105 | | extra.attributes["Duty cycle"] | 1/2, 1/3, 1/4 | | 106 | | extra.attributes["Bias"] | 1/2, 1/3 | | 107 | | extra.attributes["Operating Voltage"] | 2.4V~5.2V | | 108 | | extra.attributes["Operating Current"] | 60uA | | 109 | | extra.attributes["Interface"] | - | | 110 | 111 | -------------------------------------------------------------------------------- /docs/generated/electromechanical_devices__components.md: -------------------------------------------------------------------------------- 1 | # Electromechanical Devices & Components 2 | 3 | ### Power Connectors 4 | 5 | | Key | Ex1 | Ex2 | 6 | | --- | --- | --- | 7 | | lcsc | 111510 | 99101 | 8 | | stock | 17800 | 12509 | 9 | | mfr | 917692-1 | XT30U-M | 10 | | package | - | - | 11 | | joints | 2 | 2 | 12 | | description | - Power Connectors ROHS | - plug ROHS | 13 | | min_q_price | 0.058115942 | 0.240434783 | 14 | | extra_title | | Changzhou Amass Elec XT30U-M | 15 | | extra.number | | C99101 | 16 | | extra.package | | - | 17 | 18 | ### Heat Sinks 19 | 20 | | Key | Ex1 | Ex2 | 21 | | --- | --- | --- | 22 | | lcsc | 13380 | 116600 | 23 | | stock | 32015 | 1089 | 24 | | mfr | TO220 | 15*10.5*21 | 25 | | package | - | - | 26 | | joints | 1 | 1 | 27 | | description | - Other accessories ROHS | 15.5*10.5*21MM 6063-T5 Heat sink/heatsink | 28 | | min_q_price | 0.001463768 | 0.094202899 | 29 | | extra_title | | | 30 | | extra.number | | | 31 | | extra.package | | | 32 | 33 | ### 34 | 35 | | Key | Ex1 | Ex2 | 36 | | --- | --- | --- | 37 | | lcsc | 5299908 | 5346354 | 38 | | stock | 5570 | 4793 | 39 | | mfr | CH32V003F4U6 | CH32V003J4M6 | 40 | | package | QFN-20(3X3) | SOP-8 | 41 | | joints | 21 | 8 | 42 | | description | 16KB 2KB 18 RISC-V 48MHz QFN-20(3X3) Microcontrollers (MCU/MPU/SOC) ROHS | SOP-8 Microcontrollers (MCU/MPU/SOC) ROHS | 43 | | min_q_price | 0.229130435 | 0.185362319 | 44 | | extra_title | WCH(Jiangsu Qin Heng) CH32V003F4U6 | WCH(Jiangsu Qin Heng) CH32V003J4M6 | 45 | | extra.number | C5299908 | C5346354 | 46 | | extra.package | QFN-20(3X3) | SOP-8 | 47 | | extra.attributes["DAC (Bit)"] | - | | 48 | | extra.attributes["Program Memory Type"] | - | | 49 | | extra.attributes["Peripheral/Function"] | - | | 50 | | extra.attributes["CPU Core"] | RISC-V | | 51 | | extra.attributes["Operating Voltage Range"] | - | | 52 | | extra.attributes["communication protocol"] | - | | 53 | | extra.attributes["Infrared Data Association"] | - | | 54 | | extra.attributes["SPI"] | 1 | | 55 | | extra.attributes["UART/USART"] | 1 | | 56 | | extra.attributes["32Bit Timer"] | - | | 57 | | extra.attributes["Direct Memory Access"] | - | | 58 | | extra.attributes["Universal Serial Bus"] | - | | 59 | | extra.attributes["Low-Voltage Detect"] | - | | 60 | | extra.attributes["Real-Time Clock"] | Yes | | 61 | | extra.attributes["I2C"] | 1 | | 62 | | extra.attributes["Application Area"] | - | | 63 | | extra.attributes["PWM (Bit)"] | - | | 64 | | extra.attributes["LCD Module"] | - | | 65 | | extra.attributes["CCP Capture/Compare"] | - | | 66 | | extra.attributes["LED Module"] | - | | 67 | | extra.attributes["RAM Size"] | 2KB | | 68 | | extra.attributes["Operating Temperature Range"] | - | | 69 | | extra.attributes["Internal Comparator"] | - | | 70 | | extra.attributes["I2S"] | - | | 71 | | extra.attributes["Internal Oscillator"] | - | | 72 | | extra.attributes["GPIO Ports Number"] | 18 | | 73 | | extra.attributes["16Bit Timer"] | - | | 74 | | extra.attributes["EEPROM"] | - | | 75 | | extra.attributes["CPU Maximum Speed"] | 48MHz | | 76 | | extra.attributes["CAN"] | - | | 77 | | extra.attributes["Program Storage Size"] | 16KB | | 78 | | extra.attributes["Watchdog"] | Yes | | 79 | | extra.attributes["8Bit Timer"] | - | | 80 | | extra.attributes["ADC (Bit)"] | - | | 81 | | extra.attributes["Secure Digital Input and Output"] | - | | 82 | 83 | -------------------------------------------------------------------------------- /docs/generated/embedded_peripheral_ics.md: -------------------------------------------------------------------------------- 1 | # Embedded Peripheral ICs 2 | 3 | ### Microprocessor & Microcontroller Supervisors 4 | 5 | | Key | Ex1 | Ex2 | 6 | | --- | --- | --- | 7 | | lcsc | 80062 | 143833 | 8 | | stock | 2816 | 2094 | 9 | | mfr | SGM706-SYS8G/TR | APX803S00-29SR-7 | 10 | | package | SOIC-8 | SOT-23 | 11 | | joints | 8 | 3 | 12 | | description | Active Low SOIC-8 Supervisor and Reset ICs ROHS | SOT-23-3 Microprocessor & Microcontroller Supervisors RoHS | 13 | | min_q_price | 0.54057971 | 0.157130435 | 14 | | extra_title | SGMICRO SGM706-SYS8G/TR | | 15 | | extra.number | C80062 | | 16 | | extra.package | SOIC-8 | | 17 | | extra.attributes["ChipType"] | Monitor circuit | | 18 | | extra.attributes["Threshold Voltage"] | 2.93V | | 19 | | extra.attributes["Reset Active Level"] | Active Low | | 20 | 21 | ### Clock Generators, PLLs, Frequency Synthesizers 22 | 23 | | Key | Ex1 | Ex2 | 24 | | --- | --- | --- | 25 | | lcsc | 440388 | 5215031 | 26 | | stock | 439 | 282 | 27 | | mfr | LMX2571NJKR | LMX2820RTCR | 28 | | package | QFN-36-EP(6x6) | VQFN-48(7x7) | 29 | | joints | 37 | 49 | 30 | | description | | VQFN-48(7x7) Clock Generators, PLLs, Frequency Synthesizers ROHS | 31 | | min_q_price | 5.94057971 | 52.405797101 | 32 | | extra_title | | | 33 | | extra.number | | | 34 | | extra.package | | | 35 | 36 | ### 37 | 38 | | Key | Ex1 | Ex2 | 39 | | --- | --- | --- | 40 | | lcsc | 5149201 | 962342 | 41 | | stock | 40262 | 4702 | 42 | | mfr | SK6812MINI-E | ES8311 | 43 | | package | SMD | WQFN-20-EP(3x3) | 44 | | joints | 4 | 21 | 45 | | description | SMD RGB LEDs(Built-in IC) ROHS | WQFN-20-EP(3x3) Signal Switches, Multiplexers, Decoders ROHS | 46 | | min_q_price | 0.084347826 | 0.510144928 | 47 | | extra_title | OPSCO Optoelectronics SK6812MINI-E | Everest-semi(Everest Semiconductor) ES8311 | 48 | | extra.number | C5149201 | C962342 | 49 | | extra.package | SMD | QFN-20-EP(3x3) | 50 | 51 | -------------------------------------------------------------------------------- /docs/generated/filtersemi_optimization.md: -------------------------------------------------------------------------------- 1 | # filters/emi optimization 2 | 3 | ### EMI Filters (LC, RC Networks) 4 | 5 | | Key | Ex1 | Ex2 | 6 | | --- | --- | --- | 7 | | lcsc | 125058 | 125056 | 8 | | stock | 276575 | 11450 | 9 | | mfr | ICMEF112P900MFR | ICMEF212P900MFR | 10 | | package | 1.27x1x0.6mm | SMD | 11 | | joints | 6 | 6 | 12 | | description | 90Ω@100MHz 4Ω 2 1.27x1x0.6mm Common Mode Filters ROHS | 90Ω@100MHz 4Ω 2 SMD Common Mode Filters ROHS | 13 | | min_q_price | 0.044782609 | 0.188985507 | 14 | | extra_title | Moda-Innochips ICMEF112P900MFR | Moda-Innochips ICMEF212P900MFR | 15 | | extra.number | C125058 | C125056 | 16 | | extra.package | 1.27x1x0.6mm | SMD | 17 | | extra.attributes["Operating Temperature"] | -40℃~+85℃ | -40℃~+85℃ | 18 | | extra.attributes["Voltage Rating - DC"] | 5V | 5V | 19 | | extra.attributes["Impedance @ Frequency"] | 90Ω@100MHz | 90Ω@100MHz | 20 | | extra.attributes["Number of Lines"] | 2 | 2 | 21 | | extra.attributes["Current Rating"] | 100mA | 100mA | 22 | | extra.attributes["DC Resistance (DCR)"] | 4Ω | 4Ω | 23 | 24 | -------------------------------------------------------------------------------- /docs/generated/fuses.md: -------------------------------------------------------------------------------- 1 | # Fuses 2 | 3 | ### PTC Resettable Fuses 4 | 5 | | Key | Ex1 | Ex2 | 6 | | --- | --- | --- | 7 | | lcsc | 192524 | 55996 | 8 | | stock | 790 | 4 | 9 | | mfr | 2920L125PR | SMD1812P300TF/16V | 10 | | package | 2920 | 1812 | 11 | | joints | 2 | 2 | 12 | | description | Detailed description is being updated | 16V 3A 100A 5A 1812 Resettable Fuses ROHS | 13 | | min_q_price | 0.453623188 | 0.129130435 | 14 | | extra_title | | RUILON(Shenzhen Ruilongyuan Elec) SMD1812P300TF/16V | 15 | | extra.number | | C55996 | 16 | | extra.package | | 1812 | 17 | | extra.attributes["Trip Current"] | undefined | 5A | 18 | | extra.attributes["Current Rating (Max)"] | undefined | 100A | 19 | | extra.attributes["Operating Voltage (Max)"] | undefined | 16V | 20 | | extra.attributes["Hold Current"] | undefined | 3A | 21 | 22 | ### Surface Mount Fuses 23 | 24 | | Key | Ex1 | Ex2 | 25 | | --- | --- | --- | 26 | | lcsc | 189641 | 95352 | 27 | | stock | 1005 | 326 | 28 | | mfr | 0438.250WR | 0443001.DR | 29 | | package | 0603 | SMD,10.1x3.1mm | 30 | | joints | 2 | 2 | 31 | | description | Detailed description is being updated | 50A SMD Fuse 1A 250V SMD,10.1x3.1mm Disposable fuses ROHS | 32 | | min_q_price | 0.086811594 | 0.657971014 | 33 | | extra_title | | | 34 | | extra.number | | | 35 | | extra.package | | | 36 | 37 | ### 38 | 39 | | Key | Ex1 | Ex2 | 40 | | --- | --- | --- | 41 | | lcsc | 5299908 | 5346354 | 42 | | stock | 5570 | 4793 | 43 | | mfr | CH32V003F4U6 | CH32V003J4M6 | 44 | | package | QFN-20(3X3) | SOP-8 | 45 | | joints | 21 | 8 | 46 | | description | 16KB 2KB 18 RISC-V 48MHz QFN-20(3X3) Microcontrollers (MCU/MPU/SOC) ROHS | SOP-8 Microcontrollers (MCU/MPU/SOC) ROHS | 47 | | min_q_price | 0.229130435 | 0.185362319 | 48 | | extra_title | WCH(Jiangsu Qin Heng) CH32V003F4U6 | WCH(Jiangsu Qin Heng) CH32V003J4M6 | 49 | | extra.number | C5299908 | C5346354 | 50 | | extra.package | QFN-20(3X3) | SOP-8 | 51 | | extra.attributes["DAC (Bit)"] | - | | 52 | | extra.attributes["Program Memory Type"] | - | | 53 | | extra.attributes["Peripheral/Function"] | - | | 54 | | extra.attributes["CPU Core"] | RISC-V | | 55 | | extra.attributes["Operating Voltage Range"] | - | | 56 | | extra.attributes["communication protocol"] | - | | 57 | | extra.attributes["Infrared Data Association"] | - | | 58 | | extra.attributes["SPI"] | 1 | | 59 | | extra.attributes["UART/USART"] | 1 | | 60 | | extra.attributes["32Bit Timer"] | - | | 61 | | extra.attributes["Direct Memory Access"] | - | | 62 | | extra.attributes["Universal Serial Bus"] | - | | 63 | | extra.attributes["Low-Voltage Detect"] | - | | 64 | | extra.attributes["Real-Time Clock"] | Yes | | 65 | | extra.attributes["I2C"] | 1 | | 66 | | extra.attributes["Application Area"] | - | | 67 | | extra.attributes["PWM (Bit)"] | - | | 68 | | extra.attributes["LCD Module"] | - | | 69 | | extra.attributes["CCP Capture/Compare"] | - | | 70 | | extra.attributes["LED Module"] | - | | 71 | | extra.attributes["RAM Size"] | 2KB | | 72 | | extra.attributes["Operating Temperature Range"] | - | | 73 | | extra.attributes["Internal Comparator"] | - | | 74 | | extra.attributes["I2S"] | - | | 75 | | extra.attributes["Internal Oscillator"] | - | | 76 | | extra.attributes["GPIO Ports Number"] | 18 | | 77 | | extra.attributes["16Bit Timer"] | - | | 78 | | extra.attributes["EEPROM"] | - | | 79 | | extra.attributes["CPU Maximum Speed"] | 48MHz | | 80 | | extra.attributes["CAN"] | - | | 81 | | extra.attributes["Program Storage Size"] | 16KB | | 82 | | extra.attributes["Watchdog"] | Yes | | 83 | | extra.attributes["8Bit Timer"] | - | | 84 | | extra.attributes["ADC (Bit)"] | - | | 85 | | extra.attributes["Secure Digital Input and Output"] | - | | 86 | 87 | -------------------------------------------------------------------------------- /docs/generated/gallium_nitride_gan_devices.md: -------------------------------------------------------------------------------- 1 | # Gallium Nitride (GaN) Devices 2 | 3 | ### GaN Transistors(GaN HEMT) 4 | 5 | | Key | Ex1 | Ex2 | 6 | | --- | --- | --- | 7 | | lcsc | 22446733 | 22446734 | 8 | | stock | 920 | 892 | 9 | | mfr | CID18N65D | CID18N65D5 | 10 | | package | DFN-8(8x8) | DFN-8(5x6) | 11 | | joints | 9 | 10 | 12 | | description | DFN-8(8x8) GaN Transistors(GaN HEMT) ROHS | DFN-8(5x6) GaN Transistors(GaN HEMT) ROHS | 13 | | min_q_price | 1.32173913 | 1.34057971 | 14 | | extra_title | | | 15 | | extra.number | | | 16 | | extra.package | | | 17 | 18 | -------------------------------------------------------------------------------- /docs/generated/inductorscoilstransformers.md: -------------------------------------------------------------------------------- 1 | # inductors/coils/transformers 2 | 3 | ### Inductors (SMD) 4 | 5 | | Key | Ex1 | Ex2 | 6 | | --- | --- | --- | 7 | | lcsc | 90209 | 77103 | 8 | | stock | 518488 | 439190 | 9 | | mfr | VHF160808H33NJT | LQG15HS10NJ02D | 10 | | package | 0603 | 0402 | 11 | | joints | 2 | 2 | 12 | | description | 300mA 33nH ±5% 800mΩ 0603 Inductors (SMD) ROHS | 500mA 10nH ±5% 260mΩ 0402 Inductors (SMD) ROHS | 13 | | min_q_price | 0.005782609 | 0.006173913 | 14 | | extra_title | FH (Guangdong Fenghua Advanced Tech) VHF160808H33NJT | Murata Electronics LQG15HS10NJ02D | 15 | | extra.number | C90209 | C77103 | 16 | | extra.package | 0603 | 0402 | 17 | | extra.attributes["Inductance"] | 33nH | 10nH | 18 | | extra.attributes["Q @ Freq"] | - | 8@100MHz | 19 | | extra.attributes["Frequency - Self Resonant"] | - | 3.4GHz | 20 | | extra.attributes["Tolerance"] | ±5% | ±5% | 21 | | extra.attributes["Saturation Current (Isat)"] | - | - | 22 | | extra.attributes["Rated Current"] | 300mA | 500mA | 23 | | extra.attributes["DC Resistance (DCR)"] | 800mΩ | 260mΩ | 24 | | extra.attributes["Ratings"] | - | - | 25 | 26 | -------------------------------------------------------------------------------- /docs/generated/isolators.md: -------------------------------------------------------------------------------- 1 | # Isolators 2 | 3 | ### Digital Isolators 4 | 5 | | Key | Ex1 | Ex2 | 6 | | --- | --- | --- | 7 | | lcsc | 428879 | 87626 | 8 | | stock | 24859 | 14096 | 9 | | mfr | CA-IS3722HS | ADUM1201BRZ-RL7 | 10 | | package | SOIC-8 | SOIC-8 | 11 | | joints | 8 | 8 | 12 | | description | SOIC-8 Digital Isolators ROHS | SOIC-8 Digital Isolators ROHS | 13 | | min_q_price | 0.210289855 | 1.034782609 | 14 | | extra_title | | | 15 | | extra.number | | | 16 | | extra.package | | | 17 | 18 | ### Isolation Amplifiers 19 | 20 | | Key | Ex1 | Ex2 | 21 | | --- | --- | --- | 22 | | lcsc | 39673 | 190273 | 23 | | stock | 24723 | 5796 | 24 | | mfr | AMC1200SDUBR | AMC1301DWVR | 25 | | package | SOP-8 | SOIC-8-300mil | 26 | | joints | 8 | 8 | 27 | | description | SOP-8 Isolation Amplifiers ROHS | SOIC-8-300mil Isolation Amplifiers ROHS | 28 | | min_q_price | 0.7 | 1.085507246 | 29 | | extra_title | Texas Instruments AMC1200SDUBR | Texas Instruments AMC1301DWVR | 30 | | extra.number | C39673 | C190273 | 31 | | extra.package | SOP-8 | SOP-8-300mil | 32 | | extra.attributes["Input Bias Current (Ib)"] | - | 60uA | 33 | | extra.attributes["Operating Temperature"] | -40℃~+105℃ | -40℃~+125℃ | 34 | | extra.attributes["Number of Channels"] | 1 | 1 | 35 | | extra.attributes["Input Offset Voltage (Vos)"] | 200uV | 50uV | 36 | | extra.attributes["Bandwidth (-3dB)"] | 100kHz | - | 37 | | extra.attributes["Gain Bandwidth Product (GBP)"] | undefined | 1MHz | 38 | 39 | ### Isolated ADCs 40 | 41 | | Key | Ex1 | Ex2 | 42 | | --- | --- | --- | 43 | | lcsc | 7422590 | 7422581 | 44 | | stock | 950 | 200 | 45 | | mfr | CA-IS1204W | CA-IS1305AM25W | 46 | | package | SOIC-16-300mil | SOIC-16-300mil | 47 | | joints | 16 | 16 | 48 | | description | SOIC-16-300mil Isolated ADCs ROHS | SOIC-16-300mil Isolated ADCs ROHS | 49 | | min_q_price | 0.844927536 | 0.673913043 | 50 | | extra_title | | | 51 | | extra.number | | | 52 | | extra.package | | | 53 | 54 | ### Digital Isolators With Power 55 | 56 | | Key | Ex1 | Ex2 | 57 | | --- | --- | --- | 58 | | lcsc | 20613349 | 20598866 | 59 | | stock | 485 | 169 | 60 | | mfr | CA-IS3644HW | CA-IS3621LVW | 61 | | package | SOIC-16-WB | SOIC-16-WB | 62 | | joints | 16 | 16 | 63 | | description | SOIC-16-WB Digital Isolators (with Power) ROHS | SOIC-16-WB Digital Isolators (with Power) ROHS | 64 | | min_q_price | 2.127536232 | 1.982608696 | 65 | | extra_title | | | 66 | | extra.number | | | 67 | | extra.package | | | 68 | 69 | ### Isolated RS-485/422 Transceivers 70 | 71 | | Key | Ex1 | Ex2 | 72 | | --- | --- | --- | 73 | | lcsc | 7422548 | 1121858 | 74 | | stock | 2567 | 459 | 75 | | mfr | CA-IS3082WNX | MAX14946EWE+T | 76 | | package | SOIC16-WB(W) | SOIC-16-300mil | 77 | | joints | 16 | 16 | 78 | | description | SOIC16-WB(W) Isolated RS-485/422 Transceivers ROHS | SOIC-16-300mil Isolated RS-485/422 Transceivers ROHS | 79 | | min_q_price | 0.842028986 | 2.810144928 | 80 | | extra_title | | | 81 | | extra.number | | | 82 | | extra.package | | | 83 | 84 | -------------------------------------------------------------------------------- /docs/generated/led_drivers.md: -------------------------------------------------------------------------------- 1 | # LED Drivers 2 | 3 | ### LED Drivers 4 | 5 | | Key | Ex1 | Ex2 | 6 | | --- | --- | --- | 7 | | lcsc | 114581 | 533883 | 8 | | stock | 131101 | 82437 | 9 | | mfr | WS2811 | BCR 401U E6327 | 10 | | package | SOP-8 | SC-74-6 | 11 | | joints | 8 | 6 | 12 | | description | 20V 3 16.5mA 5V~24V SOP-8 LED Drivers ROHS | SC-74-6 LED Drivers ROHS | 13 | | min_q_price | 0.030724638 | 0.204202899 | 14 | | extra_title | Worldsemi WS2811 | Infineon Technologies BCR 401U E6327 | 15 | | extra.number | C114581 | C533883 | 16 | | extra.package | SOP-8 | SC-74-6 | 17 | | extra.attributes["Type"] | - | | 18 | | extra.attributes["Output Current"] | - | | 19 | | extra.attributes["Features"] | - | | 20 | | extra.attributes["Dimming"] | - | | 21 | | extra.attributes["Input Voltage"] | - | | 22 | | extra.attributes["Topology"] | - | | 23 | | extra.attributes["Input Voltage(VAC)"] | - | | 24 | | extra.attributes["Output Voltage"] | - | | 25 | | extra.attributes["Channels"] | - | | 26 | | extra.attributes["Switch Frequency"] | - | | 27 | | extra.attributes["Operating temperature"] | - | | 28 | 29 | ### LCD Drivers 30 | 31 | | Key | Ex1 | Ex2 | 32 | | --- | --- | --- | 33 | | lcsc | 7873 | 2980111 | 34 | | stock | 31931 | 6213 | 35 | | mfr | HT1621B | TM1621B | 36 | | package | SSOP-48-300mil | LQFP-44(10x10) | 37 | | joints | 48 | 44 | 38 | | description | 60uA 2.4V~5.2V SSOP-48-300mil LCD Drivers ROHS | LQFP-44(10x10) LCD Drivers ROHS | 39 | | min_q_price | 0.450724638 | 0.240724638 | 40 | | extra_title | Holtek Semicon HT1621B | TM(Shenzhen Titan Micro Elec) TM1621B | 41 | | extra.number | C7873 | C2980111 | 42 | | extra.package | SSOP-48-300mil | LQFP-44(10x10) | 43 | | extra.attributes["Operating Temperature"] | -25℃~+75℃ | | 44 | | extra.attributes["Display Configurations"] | 32x4 bit | | 45 | | extra.attributes["Duty cycle"] | 1/2, 1/3, 1/4 | | 46 | | extra.attributes["Bias"] | 1/2, 1/3 | | 47 | | extra.attributes["Operating Voltage"] | 2.4V~5.2V | | 48 | | extra.attributes["Operating Current"] | 60uA | | 49 | | extra.attributes["Interface"] | - | | 50 | 51 | ### Digital Tube Drivers 52 | 53 | | Key | Ex1 | Ex2 | 54 | | --- | --- | --- | 55 | | lcsc | 5337165 | 2844295 | 56 | | stock | 2895 | 2325 | 57 | | mfr | TM1624(TA1323C) | FM6565QB | 58 | | package | SOP-24 | QFN-24-EP(4x4) | 59 | | joints | 24 | 25 | 60 | | description | SOP-24 Digital Tube Drivers ROHS | QFN-24-EP(4x4) Digital Tube Drivers ROHS | 61 | | min_q_price | 0.172028986 | 0.174637681 | 62 | | extra_title | | Shenzhen Fuman Elec FM6565QB | 63 | | extra.number | | C2844295 | 64 | | extra.package | | QFN-24-EP(4x4) | 65 | 66 | ### Laser Drivers 67 | 68 | | Key | Ex1 | Ex2 | 69 | | --- | --- | --- | 70 | | lcsc | 2651273 | 2988285 | 71 | | stock | 100 | 82 | 72 | | mfr | ONET1131ECRSMR | MAX3949ETE+T | 73 | | package | VQFN-32(4x4) | WFQFN-16 | 74 | | joints | 5 | 17 | 75 | | description | VQFN-32(4x4) Laser Drivers ROHS | 11.3Gbps 2.95V~3.63V 55mA WFQFN-16 Laser Drivers ROHS | 76 | | min_q_price | 20.191304348 | 3.265217391 | 77 | | extra_title | Texas Instruments ONET1131ECRSMR | Analog Devices Inc./Maxim Integrated MAX3949ETE+T | 78 | | extra.number | C2651273 | C2988285 | 79 | | extra.package | VQFN-32(4x4) | WFQFN-16 | 80 | | extra.attributes["Operating Temperature"] | undefined | -40℃~+95℃ | 81 | | extra.attributes["Number of Channels"] | undefined | 1 | 82 | | extra.attributes["Data Rate"] | undefined | 11.3Gbps | 83 | | extra.attributes["Bias Current"] | undefined | 105mA | 84 | | extra.attributes["Supply Current"] | undefined | 55mA | 85 | | extra.attributes["Supply Voltage"] | undefined | 2.95V~3.63V | 86 | | extra.attributes["Modulated Current"] | undefined | 85mA | 87 | 88 | -------------------------------------------------------------------------------- /docs/generated/magnetic_sensors.md: -------------------------------------------------------------------------------- 1 | # Magnetic Sensors 2 | 3 | ### Current Sensors 4 | 5 | | Key | Ex1 | Ex2 | 6 | | --- | --- | --- | 7 | | lcsc | 10681 | 19673779 | 8 | | stock | 9229 | 9042 | 9 | | mfr | ACS712ELCTR-20A-T | ACS712ELCTR-05B-T-JSM | 10 | | package | SOIC-8 | SOP-8 | 11 | | joints | 8 | 8 | 12 | | description | 20A SOIC-8 Current Sensors ROHS | 5A SOP-8 Current Sensors ROHS | 13 | | min_q_price | 1.076811594 | 0.926086957 | 14 | | extra_title | Allegro MicroSystems, LLC ACS712ELCTR-20A-T | | 15 | | extra.number | C10681 | | 16 | | extra.package | SOP-8 | | 17 | | extra.attributes["Current Range"] | 20A | | 18 | | extra.attributes["Operating Temperature"] | -40℃~+85℃ | | 19 | | extra.attributes["Supply Voltage"] | 5V | | 20 | 21 | ### Hall Switches 22 | 23 | | Key | Ex1 | Ex2 | 24 | | --- | --- | --- | 25 | | lcsc | 5246112 | 22400320 | 26 | | stock | 5750 | 4990 | 27 | | mfr | AH1911-W-7 | HAL2041SO | 28 | | package | SC-59 | SOT-23 | 29 | | joints | 3 | 3 | 30 | | description | SC-59 Hall Switches ROHS | SOT-23 Hall Switches ROHS | 31 | | min_q_price | 0.269565217 | 0.045797101 | 32 | | extra_title | | | 33 | | extra.number | | | 34 | | extra.package | | | 35 | 36 | ### Linear Hall Sensors 37 | 38 | | Key | Ex1 | Ex2 | 39 | | --- | --- | --- | 40 | | lcsc | 5439871 | 6847466 | 41 | | stock | 4166 | 3000 | 42 | | mfr | QMC6309 | MH182KSO | 43 | | package | WLCSP-4(0.8x0.8) | SOT-23 | 44 | | joints | 4 | 5 | 45 | | description | WLCSP-4(0.8x0.8) 3D Magnetic Sensors ROHS | SOT-23 Linear Hall Sensors ROHS | 46 | | min_q_price | 0.279710145 | 0.224057971 | 47 | | extra_title | | | 48 | | extra.number | | | 49 | | extra.package | | | 50 | 51 | ### Magnetic Angle Sensors 52 | 53 | | Key | Ex1 | Ex2 | 54 | | --- | --- | --- | 55 | | lcsc | 25838715 | 25838710 | 56 | | stock | 200 | 100 | 57 | | mfr | KTH5702AQ3QNS | KTH4621AAM-ST6 | 58 | | package | QFN-16L-EP(3x3) | SOT-23-6L | 59 | | joints | 17 | 5 | 60 | | description | QFN-16L-EP(3x3) Magnetic Angle Sensors ROHS | SOT-23-6L Magnetic Angle Sensors ROHS | 61 | | min_q_price | 0.844927536 | 0.417391304 | 62 | | extra_title | | | 63 | | extra.number | | | 64 | | extra.package | | | 65 | 66 | -------------------------------------------------------------------------------- /docs/generated/motor_driver_ics.md: -------------------------------------------------------------------------------- 1 | # Motor Driver ICs 2 | 3 | ### Gate Drivers 4 | 5 | | Key | Ex1 | Ex2 | 6 | | --- | --- | --- | 7 | | lcsc | 18164496 | 19077363 | 8 | | stock | 6940 | 5715 | 9 | | mfr | GR2103 | JSM27517 | 10 | | package | SOP-8 | SOT-23-5 | 11 | | joints | 8 | 5 | 12 | | description | Half Bridge 2 IGBT 600uA 10V~20V 600uA SOP-8 Gate Drivers ROHS | SOT-23-5 Gate Drivers ROHS | 13 | | min_q_price | 0.09115942 | 0.211449275 | 14 | | extra_title | | | 15 | | extra.number | | | 16 | | extra.package | | | 17 | 18 | ### Brushed DC Motor Drivers 19 | 20 | | Key | Ex1 | Ex2 | 21 | | --- | --- | --- | 22 | | lcsc | 22462581 | 17703109 | 23 | | stock | 3805 | 2622 | 24 | | mfr | AT8870-MS | CJDR9111 | 25 | | package | ESOP-8 | SOT-23-6L | 26 | | joints | 9 | 6 | 27 | | description | ESOP-8 Brushed DC Motor Drivers ROHS | SOT-23-6L Brushed DC Motor Drivers ROHS | 28 | | min_q_price | 0.442028986 | 0.067101449 | 29 | | extra_title | | | 30 | | extra.number | | | 31 | | extra.package | | | 32 | 33 | ### Brushless DC (BLDC) Motor Driver 34 | 35 | | Key | Ex1 | Ex2 | 36 | | --- | --- | --- | 37 | | lcsc | 22471069 | 5370899 | 38 | | stock | 9965 | 4097 | 39 | | mfr | FU6812V | SS6343M | 40 | | package | SSOP-24 | QFN3x4-24L | 41 | | joints | 24 | 25 | 42 | | description | SSOP-24 Brushless DC (BLDC) Motor Driver ROHS | QFN3x4-24L Brushless DC (BLDC) Motor Driver ROHS | 43 | | min_q_price | 0.860869565 | 0.38115942 | 44 | | extra_title | | | 45 | | extra.number | | | 46 | | extra.package | | | 47 | 48 | ### Stepper Motor Driver 49 | 50 | | Key | Ex1 | Ex2 | 51 | | --- | --- | --- | 52 | | lcsc | 22396981 | 16197215 | 53 | | stock | 4000 | 3955 | 54 | | mfr | FM TC6803S | GC8548 | 55 | | package | SSOP-24 | SSOP-10 | 56 | | joints | 24 | 10 | 57 | | description | SSOP-24 Stepper Motor Driver ROHS | SSOP-10 Stepper Motor Driver ROHS | 58 | | min_q_price | 0.116231884 | 0.436231884 | 59 | | extra_title | | | 60 | | extra.number | | | 61 | | extra.package | | | 62 | 63 | -------------------------------------------------------------------------------- /docs/generated/optocoupler.md: -------------------------------------------------------------------------------- 1 | # Optocoupler 2 | 3 | ### Transistor Output Optocoupler 4 | 5 | | Key | Ex1 | Ex2 | 6 | | --- | --- | --- | 7 | | lcsc | 20612682 | 20612591 | 8 | | stock | 148340 | 103205 | 9 | | mfr | AT1019-CuH-L | PC817CS | 10 | | package | LSOP-4 | SOP-4 | 11 | | joints | 4 | 4 | 12 | | description | 5kV 50mA 300mV@1mA,10mA 1 6V 1.2V DC SOP-4 Transistor, Photovoltaic Output Optoisolators ROHS | 5kV 50mA 200mV@1mA,20mA 1 6V 1.2V DC SOP-4 Transistor, Photovoltaic Output Optoisolators ROHS | 13 | | min_q_price | 0.050869565 | 0.030434783 | 14 | | extra_title | | | 15 | | extra.number | | | 16 | | extra.package | | | 17 | 18 | ### Thyristor Output Optocoupler 19 | 20 | | Key | Ex1 | Ex2 | 21 | | --- | --- | --- | 22 | | lcsc | 5798515 | 20612763 | 23 | | stock | 38069 | 5119 | 24 | | mfr | TLP265J(TPL,E | ATM3052-CuH-SE | 25 | | package | SOIC-4-175mil | SOP-4 | 26 | | joints | 4 | 4 | 27 | | description | 50mA 600V 1.27V SOIC-4-175mil Triac, SCR Output Optoisolators ROHS | 100mA 60mA 600V 1.23V Two-way thyristor SOP-4 Triac, SCR Output Optoisolators ROHS | 28 | | min_q_price | 0.31884058 | 0.137971014 | 29 | | extra_title | | | 30 | | extra.number | | | 31 | | extra.package | | | 32 | 33 | ### Logic Output Optocoupler 34 | 35 | | Key | Ex1 | Ex2 | 36 | | --- | --- | --- | 37 | | lcsc | 7124390 | 20612601 | 38 | | stock | 2116 | 1678 | 39 | | mfr | TLP5772(TP,E | 6N137S | 40 | | package | SOIC-6-300mil | SOP-8 | 41 | | joints | 6 | 8 | 42 | | description | 150ns 10V~30V 35kV/us DC SOIC-6-300mil Logic Output Optoisolators ROHS | 10Mbit/s 100ns 2.7V~5.5V 10kV DC SOP-8 Logic Output Optoisolators ROHS | 43 | | min_q_price | 0.802898551 | 0.239565217 | 44 | | extra_title | | | 45 | | extra.number | | | 46 | | extra.package | | | 47 | 48 | ### Solid State Relay (MOS Output) 49 | 50 | | Key | Ex1 | Ex2 | 51 | | --- | --- | --- | 52 | | lcsc | 19188473 | 22379858 | 53 | | stock | 10146 | 5960 | 54 | | mfr | ELM406A(TA)-G | KAQY212STLD | 55 | | package | SOP-4 | SOP-4-175mil-2.54mm | 56 | | joints | 4 | 4 | 57 | | description | SOP-4 Solid State Relays (MOS Output) ROHS | SOP-4-175mil-2.54mm Solid State Relays (MOS Output) ROHS | 58 | | min_q_price | 0.471014493 | 0.642028986 | 59 | | extra_title | | | 60 | | extra.number | | | 61 | | extra.package | | | 62 | 63 | ### Gate Drive Optocoupler 64 | 65 | | Key | Ex1 | Ex2 | 66 | | --- | --- | --- | 67 | | lcsc | 22436729 | 19185369 | 68 | | stock | 923 | 875 | 69 | | mfr | TLP155 | HCPL-3150-C5L0 | 70 | | package | SO-6 | SMD-8 | 71 | | joints | 5 | 5 | 72 | | description | SO-6 Gate Drive Optocoupler ROHS | SMD-8 Gate Drive Optocoupler ROHS | 73 | | min_q_price | 0.446376812 | 0.553623188 | 74 | | extra_title | | | 75 | | extra.number | | | 76 | | extra.package | | | 77 | 78 | -------------------------------------------------------------------------------- /docs/generated/optocouplersphotocouplers.md: -------------------------------------------------------------------------------- 1 | # Optocouplers/Photocouplers 2 | 3 | ### Transistor Output Optocoupler 4 | 5 | | Key | Ex1 | Ex2 | 6 | | --- | --- | --- | 7 | | lcsc | 20612682 | 20612591 | 8 | | stock | 148340 | 103205 | 9 | | mfr | AT1019-CuH-L | PC817CS | 10 | | package | LSOP-4 | SOP-4 | 11 | | joints | 4 | 4 | 12 | | description | 5kV 50mA 300mV@1mA,10mA 1 6V 1.2V DC SOP-4 Transistor, Photovoltaic Output Optoisolators ROHS | 5kV 50mA 200mV@1mA,20mA 1 6V 1.2V DC SOP-4 Transistor, Photovoltaic Output Optoisolators ROHS | 13 | | min_q_price | 0.050869565 | 0.030434783 | 14 | | extra_title | | | 15 | | extra.number | | | 16 | | extra.package | | | 17 | 18 | ### Solid State Relay (MOS Output) 19 | 20 | | Key | Ex1 | Ex2 | 21 | | --- | --- | --- | 22 | | lcsc | 19188473 | 22379858 | 23 | | stock | 10146 | 5960 | 24 | | mfr | ELM406A(TA)-G | KAQY212STLD | 25 | | package | SOP-4 | SOP-4-175mil-2.54mm | 26 | | joints | 4 | 4 | 27 | | description | SOP-4 Solid State Relays (MOS Output) ROHS | SOP-4-175mil-2.54mm Solid State Relays (MOS Output) ROHS | 28 | | min_q_price | 0.471014493 | 0.642028986 | 29 | | extra_title | | | 30 | | extra.number | | | 31 | | extra.package | | | 32 | 33 | ### Logic Output Optocoupler 34 | 35 | | Key | Ex1 | Ex2 | 36 | | --- | --- | --- | 37 | | lcsc | 7124390 | 20612601 | 38 | | stock | 2116 | 1678 | 39 | | mfr | TLP5772(TP,E | 6N137S | 40 | | package | SOIC-6-300mil | SOP-8 | 41 | | joints | 6 | 8 | 42 | | description | 150ns 10V~30V 35kV/us DC SOIC-6-300mil Logic Output Optoisolators ROHS | 10Mbit/s 100ns 2.7V~5.5V 10kV DC SOP-8 Logic Output Optoisolators ROHS | 43 | | min_q_price | 0.802898551 | 0.239565217 | 44 | | extra_title | | | 45 | | extra.number | | | 46 | | extra.package | | | 47 | 48 | ### Thyristor Output Optocoupler 49 | 50 | | Key | Ex1 | Ex2 | 51 | | --- | --- | --- | 52 | | lcsc | 5798515 | 20612763 | 53 | | stock | 38069 | 5119 | 54 | | mfr | TLP265J(TPL,E | ATM3052-CuH-SE | 55 | | package | SOIC-4-175mil | SOP-4 | 56 | | joints | 4 | 4 | 57 | | description | 50mA 600V 1.27V SOIC-4-175mil Triac, SCR Output Optoisolators ROHS | 100mA 60mA 600V 1.23V Two-way thyristor SOP-4 Triac, SCR Output Optoisolators ROHS | 58 | | min_q_price | 0.31884058 | 0.137971014 | 59 | | extra_title | | | 60 | | extra.number | | | 61 | | extra.package | | | 62 | 63 | ### Gate Drive Optocoupler 64 | 65 | | Key | Ex1 | Ex2 | 66 | | --- | --- | --- | 67 | | lcsc | 22436729 | 19185369 | 68 | | stock | 923 | 875 | 69 | | mfr | TLP155 | HCPL-3150-C5L0 | 70 | | package | SO-6 | SMD-8 | 71 | | joints | 5 | 5 | 72 | | description | SO-6 Gate Drive Optocoupler ROHS | SMD-8 Gate Drive Optocoupler ROHS | 73 | | min_q_price | 0.446376812 | 0.553623188 | 74 | | extra_title | | | 75 | | extra.number | | | 76 | | extra.package | | | 77 | 78 | ### Transistor, Photovoltaic Output Optoisolators 79 | 80 | | Key | Ex1 | Ex2 | 81 | | --- | --- | --- | 82 | | lcsc | 5360336 | 17193662 | 83 | | stock | 22235 | 19409 | 84 | | mfr | ORPC-817SB-TP-F | TLP291(BL-TP,SE | 85 | | package | SOP-4 | SOIC-4-4.55mm | 86 | | joints | 4 | 4 | 87 | | description | SOP-4 Transistor, Photovoltaic Output Optoisolators ROHS | 3.75kV 50mA 1 1.25V SOIC-4-4.55mm Transistor, Photovoltaic Output Optoisolators ROHS | 88 | | min_q_price | 0.027681159 | 0.148753623 | 89 | | extra_title | | | 90 | | extra.number | | | 91 | | extra.package | | | 92 | 93 | -------------------------------------------------------------------------------- /docs/generated/optoisolators.md: -------------------------------------------------------------------------------- 1 | # Optoisolators 2 | 3 | ### Triac, SCR Output Optoisolators 4 | 5 | | Key | Ex1 | Ex2 | 6 | | --- | --- | --- | 7 | | lcsc | 6171203 | 27636831 | 8 | | stock | 4355 | 3224 | 9 | | mfr | MOC3063M | MOC3083M | 10 | | package | DIP-6 | DIP-6 | 11 | | joints | 6 | 5 | 12 | | description | DIP-6 Triac, SCR Output Optoisolators ROHS | 100mA 60mA 1.23V Two-way thyristor DIP-6 Triac, SCR Output Optoisolators ROHS | 13 | | min_q_price | 0.123333333 | 0.209855072 | 14 | | extra_title | | | 15 | | extra.number | | | 16 | | extra.package | | | 17 | 18 | ### Solid State Relays (Triac Output) 19 | 20 | | Key | Ex1 | Ex2 | 21 | | --- | --- | --- | 22 | | lcsc | 7327477 | 5578997 | 23 | | stock | 17 | 15 | 24 | | mfr | PF240D25R | CPC1718J | 25 | | package | SIP-4 | - | 26 | | joints | 4 | 4 | 27 | | description | 12V~280V 3V~15V 1 Form A (SPST-NO) 25A SIP-4 Solid State Relays (Triac Output) ROHS | 100V 1.2V 6.75A 1 Form A (SPST-NO) - Solid State Relays (Triac Output) ROHS | 28 | | min_q_price | 25.913043478 | 6.395652174 | 29 | | extra_title | | | 30 | | extra.number | | | 31 | | extra.package | | | 32 | 33 | ### Transistor, Photovoltaic Output Optoisolators 34 | 35 | | Key | Ex1 | Ex2 | 36 | | --- | --- | --- | 37 | | lcsc | 5360336 | 17193662 | 38 | | stock | 22235 | 19409 | 39 | | mfr | ORPC-817SB-TP-F | TLP291(BL-TP,SE | 40 | | package | SOP-4 | SOIC-4-4.55mm | 41 | | joints | 4 | 4 | 42 | | description | SOP-4 Transistor, Photovoltaic Output Optoisolators ROHS | 3.75kV 50mA 1 1.25V SOIC-4-4.55mm Transistor, Photovoltaic Output Optoisolators ROHS | 43 | | min_q_price | 0.027681159 | 0.148753623 | 44 | | extra_title | | | 45 | | extra.number | | | 46 | | extra.package | | | 47 | 48 | ### Solid State Relays (MOS Output) 49 | 50 | | Key | Ex1 | Ex2 | 51 | | --- | --- | --- | 52 | | lcsc | 5340394 | 6747780 | 53 | | stock | 3000 | 2455 | 54 | | mfr | G3VM-351VY | ASSR-1218-503E | 55 | | package | SOP-4 | SO-4 | 56 | | joints | 4 | 4 | 57 | | description | SOP-4 Solid State Relays (MOS Output) ROHS | SO-4 Solid State Relays (MOS Output) ROHS | 58 | | min_q_price | 0.947826087 | 1.037681159 | 59 | | extra_title | | | 60 | | extra.number | | | 61 | | extra.package | | | 62 | 63 | ### Logic Output Optoisolators 64 | 65 | | Key | Ex1 | Ex2 | 66 | | --- | --- | --- | 67 | | lcsc | 4153768 | 5370532 | 68 | | stock | 25440 | 3930 | 69 | | mfr | TLP2761(TP,E(T | TLP2768A(D4-TP,E(T | 70 | | package | SOP-6 | SOIC-6 | 71 | | joints | 6 | 6 | 72 | | description | SOP-6 Logic Output Optoisolators ROHS | SOIC-6 Logic Output Optoisolators ROHS | 73 | | min_q_price | 0.562318841 | 0.782608696 | 74 | | extra_title | | | 75 | | extra.number | | | 76 | | extra.package | | | 77 | 78 | ### Gate Drive Optocoupler 79 | 80 | | Key | Ex1 | Ex2 | 81 | | --- | --- | --- | 82 | | lcsc | 22436729 | 19185369 | 83 | | stock | 923 | 875 | 84 | | mfr | TLP155 | HCPL-3150-C5L0 | 85 | | package | SO-6 | SMD-8 | 86 | | joints | 5 | 5 | 87 | | description | SO-6 Gate Drive Optocoupler ROHS | SMD-8 Gate Drive Optocoupler ROHS | 88 | | min_q_price | 0.446376812 | 0.553623188 | 89 | | extra_title | | | 90 | | extra.number | | | 91 | | extra.package | | | 92 | 93 | -------------------------------------------------------------------------------- /docs/generated/power_modules.md: -------------------------------------------------------------------------------- 1 | # Power Modules 2 | 3 | ### DC-DC Power Modules 4 | 5 | | Key | Ex1 | Ex2 | 6 | | --- | --- | --- | 7 | | lcsc | 5369645 | 5377999 | 8 | | stock | 324 | 295 | 9 | | mfr | K7812-500R3 | K7805-500R3 | 10 | | package | SIP | SIP-3 | 11 | | joints | 3 | 3 | 12 | | description | SIP DC-DC Power Modules ROHS | SIP-3 DC-DC Power Modules ROHS | 13 | | min_q_price | undefined | 1.666666667 | 14 | | extra_title | | | 15 | | extra.number | | | 16 | | extra.package | | | 17 | 18 | ### Isolated Power Modules 19 | 20 | | Key | Ex1 | Ex2 | 21 | | --- | --- | --- | 22 | | lcsc | 5369477 | 5369386 | 23 | | stock | 2561 | 1874 | 24 | | mfr | B0524S-2WR3 | A0512S-1WR3 | 25 | | package | SIP-4 | SIP | 26 | | joints | 4 | 5 | 27 | | description | SIP-4 Isolated Power Modules ROHS | SIP Isolated Power Modules ROHS | 28 | | min_q_price | undefined | 1.404347826 | 29 | | extra_title | | | 30 | | extra.number | | | 31 | | extra.package | | | 32 | 33 | ### AC-DC Power Modules 34 | 35 | | Key | Ex1 | Ex2 | 36 | | --- | --- | --- | 37 | | lcsc | 5354760 | 5354759 | 38 | | stock | 77 | 60 | 39 | | mfr | TAS12-5-W2 | TAD5-0503-WVDI | 40 | | package | Plugin,25x39mm | Plugin,19x38mm | 41 | | joints | 4 | 7 | 42 | | description | 5V 2.4A 85VAC~265VAC 100V~370V 12W Step-down type 86% Plugin,25x39mm AC-DC Power Modules ROHS | 85VAC~265VAC 100V~370V 5W Step-down type 80% Plugin,19x38mm AC-DC Power Modules ROHS | 43 | | min_q_price | 3.117391304 | 3.595652174 | 44 | | extra_title | | | 45 | | extra.number | | | 46 | | extra.package | | | 47 | 48 | -------------------------------------------------------------------------------- /docs/generated/relays.md: -------------------------------------------------------------------------------- 1 | # relays 2 | 3 | ### 4 | 5 | | Key | Ex1 | Ex2 | 6 | | --- | --- | --- | 7 | | lcsc | 5299908 | 5346354 | 8 | | stock | 5570 | 4793 | 9 | | mfr | CH32V003F4U6 | CH32V003J4M6 | 10 | | package | QFN-20(3X3) | SOP-8 | 11 | | joints | 21 | 8 | 12 | | description | 16KB 2KB 18 RISC-V 48MHz QFN-20(3X3) Microcontrollers (MCU/MPU/SOC) ROHS | SOP-8 Microcontrollers (MCU/MPU/SOC) ROHS | 13 | | min_q_price | 0.229130435 | 0.185362319 | 14 | | extra_title | WCH(Jiangsu Qin Heng) CH32V003F4U6 | WCH(Jiangsu Qin Heng) CH32V003J4M6 | 15 | | extra.number | C5299908 | C5346354 | 16 | | extra.package | QFN-20(3X3) | SOP-8 | 17 | | extra.attributes["DAC (Bit)"] | - | | 18 | | extra.attributes["Program Memory Type"] | - | | 19 | | extra.attributes["Peripheral/Function"] | - | | 20 | | extra.attributes["CPU Core"] | RISC-V | | 21 | | extra.attributes["Operating Voltage Range"] | - | | 22 | | extra.attributes["communication protocol"] | - | | 23 | | extra.attributes["Infrared Data Association"] | - | | 24 | | extra.attributes["SPI"] | 1 | | 25 | | extra.attributes["UART/USART"] | 1 | | 26 | | extra.attributes["32Bit Timer"] | - | | 27 | | extra.attributes["Direct Memory Access"] | - | | 28 | | extra.attributes["Universal Serial Bus"] | - | | 29 | | extra.attributes["Low-Voltage Detect"] | - | | 30 | | extra.attributes["Real-Time Clock"] | Yes | | 31 | | extra.attributes["I2C"] | 1 | | 32 | | extra.attributes["Application Area"] | - | | 33 | | extra.attributes["PWM (Bit)"] | - | | 34 | | extra.attributes["LCD Module"] | - | | 35 | | extra.attributes["CCP Capture/Compare"] | - | | 36 | | extra.attributes["LED Module"] | - | | 37 | | extra.attributes["RAM Size"] | 2KB | | 38 | | extra.attributes["Operating Temperature Range"] | - | | 39 | | extra.attributes["Internal Comparator"] | - | | 40 | | extra.attributes["I2S"] | - | | 41 | | extra.attributes["Internal Oscillator"] | - | | 42 | | extra.attributes["GPIO Ports Number"] | 18 | | 43 | | extra.attributes["16Bit Timer"] | - | | 44 | | extra.attributes["EEPROM"] | - | | 45 | | extra.attributes["CPU Maximum Speed"] | 48MHz | | 46 | | extra.attributes["CAN"] | - | | 47 | | extra.attributes["Program Storage Size"] | 16KB | | 48 | | extra.attributes["Watchdog"] | Yes | | 49 | | extra.attributes["8Bit Timer"] | - | | 50 | | extra.attributes["ADC (Bit)"] | - | | 51 | | extra.attributes["Secure Digital Input and Output"] | - | | 52 | 53 | ### Power Relays 54 | 55 | | Key | Ex1 | Ex2 | 56 | | --- | --- | --- | 57 | | lcsc | 34758 | 35449 | 58 | | stock | 47282 | 31943 | 59 | | mfr | G5NB-1A-E-24VDC | SRD-05VDC-SL-C | 60 | | package | Plugin,7x20.4mm | Plugin,15.6x19.2mm | 61 | | joints | 4 | 5 | 62 | | description | Plugin,7x20.4mm Power Relays ROHS | 250V@AC 5V 15A One Conversion: 1C (SPDT-Conversion) Plugin,15.6x19.2mm Power Relays ROHS | 63 | | min_q_price | 0.37826087 | 0.288405797 | 64 | | extra_title | Omron Electronics G5NB-1A-E-24VDC | Ningbo Songle Relay SRD-05VDC-SL-C | 65 | | extra.number | C34758 | C35449 | 66 | | extra.package | Plugin,7x20.4mm | Plugin,15.6x19.2mm | 67 | | extra.attributes["Operating Temperature"] | - | | 68 | | extra.attributes["Maximum Switching Voltage"] | - | 250V@AC | 69 | | extra.attributes["Coil Resistance"] | - | 70Ω | 70 | | extra.attributes["Contact Form"] | - | SPDT (1 Form C) | 71 | | extra.attributes["Operate Time"] | - | 10ms | 72 | | extra.attributes["Contact Material"] | - | | 73 | | extra.attributes["Coil Voltage"] | - | 5V | 74 | | extra.attributes["Release Time"] | - | 10ms | 75 | | extra.attributes["Contact Resistance"] | - | 100mΩ | 76 | | extra.attributes["Contact Rating"] | - | - | 77 | | extra.attributes["Coil Type"] | - | Electromagnetic Relay-Single Coil | 78 | | extra.attributes["Maximum Switching Current"] | - | 15A | 79 | | extra.attributes["Pin Number"] | - | 5 | 80 | 81 | -------------------------------------------------------------------------------- /docs/generated/silicon_carbide_sic_devices.md: -------------------------------------------------------------------------------- 1 | # Silicon Carbide (SiC) Devices 2 | 3 | ### SiC Diodes 4 | 5 | | Key | Ex1 | Ex2 | 6 | | --- | --- | --- | 7 | | lcsc | 22373371 | 5373184 | 8 | | stock | 5393 | 2841 | 9 | | mfr | 1SS388,L3F(T | KN3D06065G | 10 | | package | SOD-523 | DFN-5(8x8) | 11 | | joints | 2 | 5 | 12 | | description | SOD-523 SiC Diodes ROHS | 650V Independent Type 1.5V 6A DFN-5(8x8) SiC Diodes ROHS | 13 | | min_q_price | 0.067971014 | 0.902898551 | 14 | | extra_title | | | 15 | | extra.number | | | 16 | | extra.package | | | 17 | 18 | ### SiC MOSFETs 19 | 20 | | Key | Ex1 | Ex2 | 21 | | --- | --- | --- | 22 | | lcsc | 22363608 | 22363605 | 23 | | stock | 451 | 130 | 24 | | mfr | S1M075120H2 | S1M040120H | 25 | | package | TO-247-4L | TO-247-4L | 26 | | joints | 5 | 5 | 27 | | description | TO-247-4L Silicon Carbide Field Effect Transistor (MOSFET) ROHS | TO-247-4L Silicon Carbide Field Effect Transistor (MOSFET) ROHS | 28 | | min_q_price | 6.772463768 | 9.271014493 | 29 | | extra_title | | | 30 | | extra.number | | | 31 | | extra.package | | | 32 | 33 | ### Silicon Carbide Field Effect Transistor (MOSFET) 34 | 35 | | Key | Ex1 | Ex2 | 36 | | --- | --- | --- | 37 | | lcsc | 5364636 | 5713521 | 38 | | stock | 263 | 184 | 39 | | mfr | CI90N120SM | C3M0021120K | 40 | | package | TO-247-3 | TO-247-4 | 41 | | joints | 3 | 4 | 42 | | description | TO-247-3 Silicon Carbide Field Effect Transistor (MOSFET) ROHS | TO-247-4 Silicon Carbide Field Effect Transistor (MOSFET) ROHS | 43 | | min_q_price | 11.275362319 | 24.733333333 | 44 | | extra_title | | | 45 | | extra.number | | | 46 | | extra.package | | | 47 | 48 | -------------------------------------------------------------------------------- /fly.toml: -------------------------------------------------------------------------------- 1 | # fly.toml app configuration file generated for jlcsearch on 2024-11-03T15:35:53-08:00 2 | # 3 | # See https://fly.io/docs/reference/configuration/ for information about how to use this file. 4 | # 5 | 6 | app = 'jlcsearch' 7 | primary_region = 'sjc' 8 | 9 | [build] 10 | 11 | [http_service] 12 | internal_port = 3065 13 | force_https = false 14 | auto_stop_machines = 'stop' 15 | auto_start_machines = true 16 | min_machines_running = 1 17 | max_machines_running = 1 18 | processes = ['app'] 19 | 20 | [[http_service.checks]] 21 | path = "/health" 22 | protocol = "http" 23 | tls_skip_verify = true 24 | interval = "15s" 25 | timeout = "2s" 26 | grace_period = "5s" 27 | 28 | [[vm]] 29 | memory = '2gb' 30 | cpu_kind = 'shared' 31 | cpus = 2 32 | -------------------------------------------------------------------------------- /lib/db/derivedtables/bjt_transistor.ts: -------------------------------------------------------------------------------- 1 | import type { DerivedTableSpec } from "./types" 2 | import type { KyselyDatabaseInstance } from "../kysely-types" 3 | import { BaseComponent } from "./component-base" 4 | import { extractMinQPrice } from "lib/util/extract-min-quantity-price" 5 | import { parseAndConvertSiUnit } from "lib/util/parse-and-convert-si-unit" 6 | 7 | export interface BJTTransistor extends BaseComponent { 8 | package?: string 9 | current_gain?: number 10 | collector_current?: number 11 | collector_emitter_voltage?: number 12 | transition_frequency?: number 13 | power_dissipation?: number 14 | temperature_range?: string 15 | } 16 | 17 | export const bjtTransistorTableSpec: DerivedTableSpec = { 18 | tableName: "bjt_transistor", 19 | extraColumns: [ 20 | { name: "package", type: "text" }, 21 | { name: "current_gain", type: "integer" }, 22 | { name: "collector_current", type: "integer" }, 23 | { name: "collector_emitter_voltage", type: "integer" }, 24 | { name: "transition_frequency", type: "integer" }, 25 | { name: "power_dissipation", type: "integer" }, 26 | { name: "temperature_range", type: "text" }, 27 | ], 28 | listCandidateComponents(db: KyselyDatabaseInstance) { 29 | return db 30 | .selectFrom("components") 31 | .innerJoin("categories", "components.category_id", "categories.id") 32 | .selectAll() 33 | .where((eb) => 34 | eb.or([ 35 | eb("description", "like", "%BJT%"), 36 | eb("description", "like", "%Bipolar Transistor%"), 37 | eb("description", "like", "%Transistor NPN%"), 38 | eb("description", "like", "%Transistor PNP%"), 39 | ]), 40 | ) 41 | }, 42 | mapToTable(components) { 43 | return components.map((c) => { 44 | try { 45 | const attrs = c.extra ? JSON.parse(c.extra)?.attributes || {} : {} 46 | const desc = c.description.toLowerCase() 47 | 48 | const parseValue = (val: string | undefined): number | undefined => { 49 | if (!val) return undefined 50 | const result = parseAndConvertSiUnit(val) 51 | return result?.value || undefined 52 | } 53 | 54 | // Extract values from attributes 55 | const current_gain = parseValue(attrs["Current Gain (hFE)"]) 56 | const collector_current = parseValue(attrs["Collector Current (Ic)"]) 57 | const collector_emitter_voltage = parseValue( 58 | attrs["Collector-Emitter Breakdown Voltage (Vceo)"], 59 | ) 60 | const transition_frequency = parseValue( 61 | attrs["Transition Frequency (fT)"], 62 | ) 63 | const power_dissipation = parseValue(attrs["Power Dissipation (Pd)"]) 64 | const temperature_range = attrs["Operating Temperature"] || undefined 65 | 66 | return { 67 | lcsc: Number(c.lcsc), 68 | mfr: String(c.mfr || ""), 69 | description: String(c.description || ""), 70 | stock: Number(c.stock || 0), 71 | price1: extractMinQPrice(c.price), 72 | in_stock: Boolean((c.stock || 0) > 0), 73 | package: c.package || "", 74 | current_gain: current_gain, 75 | collector_current: collector_current, 76 | collector_emitter_voltage: collector_emitter_voltage, 77 | transition_frequency: transition_frequency, 78 | power_dissipation: power_dissipation, 79 | temperature_range: temperature_range, 80 | attributes: attrs, 81 | } 82 | } catch (e) { 83 | return null 84 | } 85 | }) 86 | }, 87 | } 88 | -------------------------------------------------------------------------------- /lib/db/derivedtables/component-base.ts: -------------------------------------------------------------------------------- 1 | export interface BaseComponent { 2 | lcsc: number 3 | mfr: string 4 | description: string 5 | stock: number 6 | price1: number | null 7 | in_stock: boolean 8 | attributes: Record 9 | } 10 | -------------------------------------------------------------------------------- /lib/db/derivedtables/lcd_display.ts: -------------------------------------------------------------------------------- 1 | import type { DerivedTableSpec } from "./types" 2 | import type { KyselyDatabaseInstance } from "../kysely-types" 3 | import { extractMinQPrice } from "lib/util/extract-min-quantity-price" 4 | import { BaseComponent } from "./component-base" 5 | 6 | export interface LCDDisplay extends BaseComponent { 7 | package?: string 8 | display_size?: string 9 | resolution?: string 10 | display_type?: string 11 | } 12 | 13 | export const lcdDisplayTableSpec: DerivedTableSpec = { 14 | tableName: "lcd_display", 15 | extraColumns: [ 16 | { name: "package", type: "text" }, 17 | { name: "display_size", type: "text" }, 18 | { name: "resolution", type: "text" }, 19 | { name: "display_type", type: "text" }, 20 | ], 21 | listCandidateComponents(db: KyselyDatabaseInstance) { 22 | return db 23 | .selectFrom("components") 24 | .innerJoin("categories", "components.category_id", "categories.id") 25 | .selectAll() 26 | .where((eb) => eb("description", "like", "%LCD%")) 27 | }, 28 | mapToTable(components) { 29 | return components.map((c) => { 30 | try { 31 | const extraData = c.extra ? JSON.parse(c.extra) : {} 32 | const attrs = extraData.attributes || {} 33 | 34 | // Extract display size from description (e.g., "1.8 inch", "2.4\"") 35 | let display_size = undefined 36 | const sizeMatch = c.description.match(/(\d+\.?\d*)["\s]*(inch|"|'')?/) 37 | if (sizeMatch) { 38 | display_size = sizeMatch[1] + '"' 39 | } 40 | 41 | // Extract resolution from description (e.g., "128x64", "240x320") 42 | let resolution = undefined 43 | const resMatch = c.description.match(/(\d+x\d+)/) 44 | if (resMatch) { 45 | resolution = resMatch[1] 46 | } 47 | 48 | // Extract display type from description or attributes 49 | let display_type = attrs.Type || undefined 50 | if (!display_type) { 51 | if (c.description.includes("TFT")) display_type = "TFT" 52 | else if (c.description.includes("STN")) display_type = "STN" 53 | else if (c.description.includes("FSTN")) display_type = "FSTN" 54 | } 55 | 56 | return { 57 | lcsc: Number(c.lcsc), 58 | mfr: String(c.mfr || ""), 59 | description: String(c.description || ""), 60 | stock: Number(c.stock || 0), 61 | price1: extractMinQPrice(c.price), 62 | in_stock: Boolean((c.stock || 0) > 0), 63 | package: String(c.package || ""), 64 | display_size, 65 | resolution, 66 | display_type, 67 | attributes: attrs, 68 | } 69 | } catch (e) { 70 | return null 71 | } 72 | }) 73 | }, 74 | } 75 | -------------------------------------------------------------------------------- /lib/db/derivedtables/led_dot_matrix_display.ts: -------------------------------------------------------------------------------- 1 | import type { DerivedTableSpec } from "./types" 2 | import type { KyselyDatabaseInstance } from "../kysely-types" 3 | import { BaseComponent } from "./component-base" 4 | import { extractMinQPrice } from "lib/util/extract-min-quantity-price" 5 | 6 | export interface LEDDotMatrixDisplay extends BaseComponent { 7 | package?: string 8 | matrix_size?: string 9 | color?: string 10 | } 11 | 12 | export const ledDotMatrixDisplayTableSpec: DerivedTableSpec = 13 | { 14 | tableName: "led_dot_matrix_display", 15 | extraColumns: [ 16 | { name: "package", type: "text" }, 17 | { name: "matrix_size", type: "text" }, 18 | { name: "color", type: "text" }, 19 | ], 20 | listCandidateComponents(db: KyselyDatabaseInstance) { 21 | return db 22 | .selectFrom("components") 23 | .innerJoin("categories", "components.category_id", "categories.id") 24 | .selectAll() 25 | .where((eb) => eb("description", "like", "%LED Dot Matrix%")) 26 | }, 27 | mapToTable(components) { 28 | return components.map((c) => { 29 | try { 30 | const extraData = c.extra ? JSON.parse(c.extra) : {} 31 | const attrs = extraData.attributes || {} 32 | 33 | // Extract matrix size from description (e.g., "8x8", "16x32") 34 | let matrix_size = undefined 35 | const sizeMatch = c.description.match(/(\d+x\d+)/) 36 | if (sizeMatch) { 37 | matrix_size = sizeMatch[1] 38 | } 39 | 40 | // Extract color from description or attributes 41 | let color = attrs.Color || undefined 42 | if (!color) { 43 | if (c.description.includes("Red")) color = "Red" 44 | else if (c.description.includes("Green")) color = "Green" 45 | else if (c.description.includes("Blue")) color = "Blue" 46 | else if (c.description.includes("RGB")) color = "RGB" 47 | } 48 | 49 | return { 50 | lcsc: Number(c.lcsc), 51 | mfr: String(c.mfr || ""), 52 | description: String(c.description || ""), 53 | stock: Number(c.stock || 0), 54 | price1: extractMinQPrice(c.price), 55 | in_stock: Boolean((c.stock || 0) > 0), 56 | package: String(c.package || ""), 57 | matrix_size, 58 | color, 59 | attributes: attrs, 60 | } 61 | } catch (e) { 62 | return null 63 | } 64 | }) 65 | }, 66 | } 67 | -------------------------------------------------------------------------------- /lib/db/derivedtables/led_segment_display.ts: -------------------------------------------------------------------------------- 1 | import type { DerivedTableSpec } from "./types" 2 | import type { KyselyDatabaseInstance } from "../kysely-types" 3 | import { BaseComponent } from "./component-base" 4 | import { extractMinQPrice } from "lib/util/extract-min-quantity-price" 5 | 6 | export interface LEDSegmentDisplay extends BaseComponent { 7 | package?: string 8 | positions?: string 9 | type?: string 10 | size?: string 11 | color?: string 12 | } 13 | 14 | export const ledSegmentDisplayTableSpec: DerivedTableSpec = { 15 | tableName: "led_segment_display", 16 | extraColumns: [ 17 | { name: "package", type: "text" }, 18 | { name: "positions", type: "text" }, 19 | { name: "type", type: "text" }, 20 | { name: "size", type: "text" }, 21 | { name: "color", type: "text" }, 22 | ], 23 | 24 | listCandidateComponents(db: KyselyDatabaseInstance) { 25 | return db 26 | .selectFrom("components") 27 | .innerJoin("categories", "components.category_id", "categories.id") 28 | .selectAll() 29 | .where((eb) => eb("description", "like", "%LED Segment Display%")) 30 | }, 31 | 32 | mapToTable(components) { 33 | return components.map((c) => { 34 | try { 35 | const extraData = c.extra ? JSON.parse(c.extra) : {} 36 | const attrs = extraData.attributes || {} 37 | 38 | let positions = undefined 39 | const posMatch = c.description.match(/(\d+)\s*[Pp]ositions?/) 40 | if (posMatch) { 41 | positions = posMatch[1] 42 | } 43 | 44 | let type = undefined 45 | if (c.description.includes("Common Cathode")) { 46 | type = "Common Cathode" 47 | } else if (c.description.includes("Common Anode")) { 48 | type = "Common Anode" 49 | } 50 | 51 | let size = undefined 52 | const sizeMatch = c.description.match(/(\d+\.\d+)/) 53 | if (sizeMatch) { 54 | size = sizeMatch[1] 55 | } 56 | 57 | let color = undefined 58 | if (c.description.includes("Red")) { 59 | color = "Red" 60 | } 61 | 62 | return { 63 | lcsc: Number(c.lcsc), 64 | mfr: String(c.mfr || ""), 65 | description: String(c.description || ""), 66 | stock: Number(c.stock || 0), 67 | price1: extractMinQPrice(c.price), 68 | in_stock: Boolean((c.stock || 0) > 0), 69 | package: String(c.package || ""), 70 | positions, 71 | type, 72 | size, 73 | color, 74 | attributes: attrs, 75 | } 76 | } catch (e) { 77 | return null 78 | } 79 | }) 80 | }, 81 | } 82 | -------------------------------------------------------------------------------- /lib/db/derivedtables/mosfet.ts: -------------------------------------------------------------------------------- 1 | import type { DerivedTableSpec } from "./types" 2 | import type { SelectQueryBuilder, Generated } from "kysely" 3 | import type { Component } from "../generated/kysely" 4 | import type { KyselyDatabaseInstance } from "../kysely-types" 5 | 6 | type UnwrapGenerated = { 7 | [K in keyof T]: T[K] extends Generated ? U : T[K] 8 | } 9 | import { parseAndConvertSiUnit } from "lib/util/parse-and-convert-si-unit" 10 | import { extractMinQPrice } from "lib/util/extract-min-quantity-price" 11 | import { parseIntOrNull } from "lib/util/parse-int-or-null" 12 | import { BaseComponent } from "./component-base" 13 | 14 | export interface Mosfet extends BaseComponent { 15 | package?: string 16 | drain_source_voltage?: number 17 | continuous_drain_current?: number 18 | gate_threshold_voltage?: number 19 | power_dissipation?: number 20 | operating_temp_min?: number 21 | operating_temp_max?: number 22 | mounting_style?: string 23 | } 24 | 25 | export const mosfetTableSpec: DerivedTableSpec = { 26 | tableName: "mosfet", 27 | extraColumns: [ 28 | { name: "package", type: "text" }, 29 | { name: "drain_source_voltage", type: "real" }, 30 | { name: "continuous_drain_current", type: "real" }, 31 | { name: "gate_threshold_voltage", type: "real" }, 32 | { name: "power_dissipation", type: "real" }, 33 | { name: "operating_temp_min", type: "real" }, 34 | { name: "operating_temp_max", type: "real" }, 35 | { name: "mounting_style", type: "text" }, 36 | ], 37 | listCandidateComponents(db: KyselyDatabaseInstance) { 38 | return db 39 | .selectFrom("components") 40 | .innerJoin("categories", "components.category_id", "categories.id") 41 | .selectAll() 42 | .where((eb) => 43 | eb.or([ 44 | eb("categories.subcategory", "=", "MOSFETs"), 45 | eb("description", "like", "%MOSFET%"), 46 | ]), 47 | ) 48 | }, 49 | mapToTable(components: UnwrapGenerated[]): (Mosfet | null)[] { 50 | return components.map((c) => { 51 | try { 52 | const attrs = c.extra ? JSON.parse(c.extra)?.attributes || {} : {} 53 | 54 | const parseValue = (val: string | undefined): number | undefined => { 55 | if (!val) return undefined 56 | const result = parseAndConvertSiUnit(val) 57 | return result?.value || undefined 58 | } 59 | 60 | return { 61 | lcsc: Number(c.lcsc), 62 | mfr: String(c.mfr || ""), 63 | description: String(c.description || ""), 64 | stock: Number(c.stock || 0), 65 | price1: extractMinQPrice(c.price), 66 | in_stock: Boolean((c.stock || 0) > 0), 67 | package: String(c.package || ""), 68 | drain_source_voltage: parseValue( 69 | attrs["Drain Source Voltage (Vdss)"], 70 | ), 71 | continuous_drain_current: parseValue( 72 | attrs["Continuous Drain Current (Id)"], 73 | ), 74 | gate_threshold_voltage: parseValue( 75 | attrs["Gate Threshold Voltage (Vgs(th)@Id)"], 76 | ), 77 | power_dissipation: parseValue(attrs["Power Dissipation (Pd)"]), 78 | operating_temp_min: parseValue( 79 | attrs["Operating temperature"]?.split("~")[0], 80 | ), 81 | operating_temp_max: parseValue( 82 | attrs["Operating temperature"]?.split("~")[1], 83 | ), 84 | mounting_style: attrs["Mounting Style"], 85 | attributes: attrs, 86 | } 87 | } catch (e) { 88 | return null 89 | } 90 | }) 91 | }, 92 | } 93 | -------------------------------------------------------------------------------- /lib/db/derivedtables/oled_display.ts: -------------------------------------------------------------------------------- 1 | import type { DerivedTableSpec } from "./types" 2 | import type { KyselyDatabaseInstance } from "../kysely-types" 3 | import { BaseComponent } from "./component-base" 4 | import { extractMinQPrice } from "lib/util/extract-min-quantity-price" 5 | 6 | export interface OLEDDisplay extends BaseComponent { 7 | package?: string 8 | protocol?: string 9 | display_width?: string 10 | pixel_resolution?: string 11 | } 12 | 13 | export const oledDisplayTableSpec: DerivedTableSpec = { 14 | tableName: "oled_display", 15 | extraColumns: [ 16 | { name: "package", type: "text" }, 17 | { name: "protocol", type: "text" }, 18 | { name: "display_width", type: "text" }, 19 | { name: "pixel_resolution", type: "text" }, 20 | ], 21 | 22 | listCandidateComponents(db: KyselyDatabaseInstance) { 23 | return db 24 | .selectFrom("components") 25 | .innerJoin("categories", "components.category_id", "categories.id") 26 | .selectAll() 27 | .where((eb) => eb("description", "like", "%OLED Display%")) 28 | }, 29 | 30 | mapToTable(components) { 31 | return components.map((c) => { 32 | try { 33 | const extraData = c.extra ? JSON.parse(c.extra) : {} 34 | const attrs = extraData.attributes || {} 35 | // Extract protocol from description or interface attribute 36 | let protocol 37 | if (c.description.includes("I2C")) { 38 | protocol = "I2C" 39 | } else if (attrs.Interface) { 40 | protocol = attrs.Interface 41 | } 42 | // Extract display_width and resolution from description 43 | let display_width = undefined 44 | let pixel_resolution = undefined 45 | const description = c.description || "" 46 | // Extract resolution (e.g., "128x64") 47 | const resMatch = description.match(/(\d+x\d+)/) 48 | if (resMatch) { 49 | pixel_resolution = resMatch[1] 50 | } 51 | // Extract display_width (e.g., "0.96") 52 | const widthMatch = description.match(/\s(\d+\.\d+)\s/) 53 | if (widthMatch) { 54 | display_width = widthMatch[1] 55 | } 56 | 57 | return { 58 | lcsc: Number(c.lcsc), 59 | mfr: String(c.mfr || ""), 60 | description: String(description), 61 | stock: Number(c.stock || 0), 62 | price1: extractMinQPrice(c.price), 63 | in_stock: Boolean((c.stock || 0) > 0), 64 | package: String(c.package || ""), 65 | protocol: protocol || undefined, 66 | display_width, 67 | pixel_resolution, 68 | attributes: attrs, 69 | } 70 | } catch (e) { 71 | return null 72 | } 73 | }) 74 | }, 75 | } 76 | -------------------------------------------------------------------------------- /lib/db/derivedtables/potentiometer.ts: -------------------------------------------------------------------------------- 1 | import { parseAndConvertSiUnit } from "lib/util/parse-and-convert-si-unit" 2 | import type { DerivedTableSpec } from "./types" 3 | import { extractMinQPrice } from "lib/util/extract-min-quantity-price" 4 | import { BaseComponent } from "./component-base" 5 | 6 | export interface Potentiometer extends BaseComponent { 7 | max_resistance: number 8 | pin_variant: "two_pin" | "three_pin" 9 | package: string 10 | is_surface_mount: boolean 11 | } 12 | 13 | export const potentiometerTableSpec: DerivedTableSpec = { 14 | tableName: "potentiometer", 15 | extraColumns: [ 16 | { name: "max_resistance", type: "real" }, 17 | { name: "pin_variant", type: "text" }, 18 | { name: "package", type: "text" }, 19 | { name: "is_surface_mount", type: "boolean" }, 20 | ], 21 | listCandidateComponents: (db) => 22 | db 23 | .selectFrom("components") 24 | .innerJoin("categories", "components.category_id", "categories.id") 25 | .selectAll() 26 | .where("categories.category", "=", "Resistors") 27 | .where("components.description", "like", "%potentiometer%"), 28 | mapToTable: (components) => { 29 | return components.map((c): Potentiometer | null => { 30 | if (!c.extra) return null 31 | const extra = JSON.parse(c.extra ?? "{}") 32 | if (!extra.attributes) return null 33 | 34 | const rawResistance = extra?.attributes?.["Resistance"] 35 | const maxResistance = parseAndConvertSiUnit(rawResistance).value as number 36 | 37 | // Determine pin variant based on number of pins 38 | const numPins = parseInt(extra?.attributes?.["Number of Pins"]) || 3 39 | const pinVariant = numPins === 2 ? "two_pin" : "three_pin" 40 | 41 | // Determine if surface mount 42 | const isSurfaceMount = 43 | c.package?.toLowerCase().includes("smd") || 44 | !c.package?.toLowerCase().includes("plugin") 45 | 46 | return { 47 | lcsc: c.lcsc, 48 | mfr: c.mfr, 49 | description: c.description, 50 | stock: c.stock, 51 | price1: extractMinQPrice(c.price)!, 52 | in_stock: c.stock > 0, 53 | max_resistance: maxResistance, 54 | pin_variant: pinVariant, 55 | package: c.package || "", 56 | is_surface_mount: isSurfaceMount, 57 | attributes: extra.attributes, 58 | } 59 | }) 60 | }, 61 | } 62 | -------------------------------------------------------------------------------- /lib/db/derivedtables/resistor.ts: -------------------------------------------------------------------------------- 1 | import { parseAndConvertSiUnit } from "lib/util/parse-and-convert-si-unit" 2 | import type { DerivedTableSpec } from "./types" 3 | import { extractMinQPrice } from "lib/util/extract-min-quantity-price" 4 | import { BaseComponent } from "./component-base" 5 | 6 | export interface Resistor extends BaseComponent { 7 | resistance: number 8 | tolerance_fraction: number 9 | power_watts: number 10 | package: string 11 | max_overload_voltage: number | null 12 | number_of_resistors: number | null 13 | number_of_pins: number | null 14 | is_potentiometer: boolean 15 | is_surface_mount: boolean 16 | is_multi_resistor_chip: boolean 17 | } 18 | 19 | export const resistorTableSpec: DerivedTableSpec = { 20 | tableName: "resistor", 21 | extraColumns: [ 22 | { name: "resistance", type: "real" }, 23 | { name: "tolerance_fraction", type: "real" }, 24 | { name: "power_watts", type: "real" }, 25 | { name: "package", type: "text" }, 26 | { name: "max_overload_voltage", type: "real" }, 27 | { name: "number_of_resistors", type: "integer" }, 28 | { name: "number_of_pins", type: "integer" }, 29 | { name: "is_potentiometer", type: "boolean" }, 30 | { name: "is_surface_mount", type: "boolean" }, 31 | { name: "is_multi_resistor_chip", type: "boolean" }, 32 | ], 33 | listCandidateComponents: (db) => 34 | db 35 | .selectFrom("components") 36 | .innerJoin("categories", "components.category_id", "categories.id") 37 | .selectAll() 38 | .where("categories.category", "=", "Resistors"), 39 | mapToTable: (components) => { 40 | return components.map((c): Resistor | null => { 41 | if (!c.extra) return null 42 | const extra = JSON.parse(c.extra ?? "{}") 43 | if (!extra.attributes) return null 44 | const rawResistance = extra?.attributes?.["Resistance"] 45 | const rawTolerance = extra?.attributes?.["Tolerance"] 46 | const rawPower = extra?.attributes?.["Power(Watts)"] 47 | 48 | const resistance = parseAndConvertSiUnit(rawResistance).value as number 49 | const tolerance = parseAndConvertSiUnit(rawTolerance).value as number 50 | const power_watts = parseAndConvertSiUnit(rawPower).value as number 51 | 52 | // Extract additional fields 53 | const maxVoltage = parseAndConvertSiUnit( 54 | extra?.attributes?.["Overload Voltage (Max)"], 55 | ).value as number 56 | const numResistors = 57 | parseInt(extra?.attributes?.["Number of Resistors"]) || null 58 | const numPins = parseInt(extra?.attributes?.["Number of Pins"]) || null 59 | const isPotentiometer = c.description 60 | .toLowerCase() 61 | .includes("potentiometer") 62 | const isSurfaceMount = 63 | c.package?.toLowerCase().includes("smd") || 64 | !c.package?.toLowerCase().includes("plugin") 65 | 66 | // Determine if this is a multi-resistor chip 67 | const isMultiResistorChip = Boolean( 68 | (numResistors && numResistors > 1) || 69 | c.description.toLowerCase().includes("array") || 70 | c.description.toLowerCase().includes("network") || 71 | c.package?.toLowerCase().includes("x"), 72 | ) 73 | 74 | return { 75 | lcsc: c.lcsc, 76 | mfr: c.mfr, 77 | description: c.description, 78 | stock: c.stock, 79 | price1: extractMinQPrice(c.price)!, 80 | in_stock: c.stock > 0, 81 | resistance: resistance, 82 | tolerance_fraction: tolerance, 83 | power_watts, 84 | package: c.package || "", 85 | max_overload_voltage: maxVoltage, 86 | number_of_resistors: numResistors, 87 | number_of_pins: numPins, 88 | is_potentiometer: isPotentiometer, 89 | is_surface_mount: isSurfaceMount, 90 | is_multi_resistor_chip: isMultiResistorChip, 91 | attributes: extra.attributes, 92 | } 93 | }) 94 | }, 95 | } 96 | -------------------------------------------------------------------------------- /lib/db/derivedtables/switch.ts: -------------------------------------------------------------------------------- 1 | import { parseAndConvertSiUnit } from "lib/util/parse-and-convert-si-unit" 2 | import type { DerivedTableSpec } from "./types" 3 | import { extractMinQPrice } from "lib/util/extract-min-quantity-price" 4 | import { BaseComponent } from "./component-base" 5 | 6 | export interface Switch extends BaseComponent { 7 | package: string 8 | switch_type: string 9 | circuit: string | null 10 | current_rating_a: number | null 11 | voltage_rating_v: number | null 12 | mounting_style: string | null 13 | is_latching: boolean | null 14 | operating_temp_min: number | null 15 | operating_temp_max: number | null 16 | pin_count: number | null 17 | } 18 | 19 | export const switchTableSpec: DerivedTableSpec = { 20 | tableName: "switch", 21 | extraColumns: [ 22 | { name: "package", type: "text" }, 23 | { name: "switch_type", type: "text" }, 24 | { name: "circuit", type: "text" }, 25 | { name: "current_rating_a", type: "real" }, 26 | { name: "voltage_rating_v", type: "real" }, 27 | { name: "mounting_style", type: "text" }, 28 | { name: "is_latching", type: "boolean" }, 29 | { name: "operating_temp_min", type: "real" }, 30 | { name: "operating_temp_max", type: "real" }, 31 | { name: "pin_count", type: "integer" }, 32 | ], 33 | listCandidateComponents(db) { 34 | return db 35 | .selectFrom("components") 36 | .innerJoin("categories", "components.category_id", "categories.id") 37 | .selectAll() 38 | .where((eb) => 39 | eb.and([ 40 | eb("categories.category", "like", "%Switch%"), 41 | eb("categories.subcategory", "not like", "%Relay%"), 42 | eb("categories.subcategory", "not like", "%Accessory%"), 43 | ]), 44 | ) 45 | }, 46 | mapToTable(components) { 47 | return components.map((c) => { 48 | if (!c.extra) return null 49 | const extra = JSON.parse(c.extra ?? "{}") 50 | const attrs = extra.attributes || {} 51 | 52 | const parseNum = (val: string | undefined): number | null => { 53 | if (!val) return null 54 | return parseAndConvertSiUnit(val).value as number 55 | } 56 | 57 | let isLatching: boolean | null = null 58 | const lockField = 59 | attrs["Self Lock / No Lock"] || attrs["self lock / no lock"] 60 | if (lockField) { 61 | isLatching = lockField.toLowerCase().includes("latch") ? true : false 62 | } 63 | 64 | const tempRange = attrs["Operating Temperature"] 65 | let tempMin: number | null = null 66 | let tempMax: number | null = null 67 | if (tempRange && tempRange.includes("~")) { 68 | const [min, max] = tempRange.split("~") 69 | tempMin = parseNum(min) 70 | tempMax = parseNum(max) 71 | } 72 | 73 | return { 74 | lcsc: c.lcsc, 75 | mfr: c.mfr, 76 | description: c.description, 77 | stock: c.stock, 78 | price1: extractMinQPrice(c.price)!, 79 | in_stock: c.stock > 0, 80 | package: c.package || "", 81 | switch_type: (c as any).subcategory || "", 82 | circuit: attrs["Circuit"] || null, 83 | current_rating_a: 84 | parseNum(attrs["Current Rating (DC)"] || attrs["Contact Current"]) || 85 | parseNum(attrs["Current Rating (AC)"]), 86 | voltage_rating_v: 87 | parseNum(attrs["Voltage Rating (DC)"]) || 88 | parseNum(attrs["Voltage Rating (AC)"]), 89 | mounting_style: attrs["Mounting Style"] || attrs["Pin Style"] || null, 90 | is_latching: isLatching, 91 | operating_temp_min: tempMin, 92 | operating_temp_max: tempMax, 93 | pin_count: c.joints ?? null, 94 | attributes: attrs, 95 | } 96 | }) 97 | }, 98 | } 99 | -------------------------------------------------------------------------------- /lib/db/derivedtables/types.ts: -------------------------------------------------------------------------------- 1 | import type { SelectQueryBuilder } from "kysely" 2 | import type { Component, Generated } from "../generated/kysely" 3 | import type { KyselyDatabaseInstance } from "../kysely-types" 4 | 5 | type UnwrapGenerated = { 6 | [K in keyof T]: T[K] extends Generated ? U : T[K] 7 | } 8 | 9 | export interface DerivedTableSpec< 10 | Resource extends { 11 | lcsc: number 12 | mfr: string 13 | description: string 14 | stock: number 15 | price1: number | null 16 | in_stock: boolean 17 | }, 18 | > { 19 | tableName: string 20 | extraColumns: Array<{ 21 | name: keyof Resource 22 | type: string 23 | }> 24 | listCandidateComponents: ( 25 | db: KyselyDatabaseInstance, 26 | ) => SelectQueryBuilder 27 | mapToTable: (components: UnwrapGenerated[]) => (Resource | null)[] 28 | } 29 | -------------------------------------------------------------------------------- /lib/db/get-db-client.ts: -------------------------------------------------------------------------------- 1 | import { Database } from "bun:sqlite" 2 | import { Kysely, SqliteDialect } from "kysely" 3 | import Path from "node:path" 4 | import type { DB } from "./generated/kysely" 5 | import { BunSqliteDialect } from "kysely-bun-sqlite" 6 | 7 | export const getDbClient = () => { 8 | return new Kysely({ 9 | dialect: new BunSqliteDialect({ 10 | database: getBunDatabaseClient(), 11 | }), 12 | }) 13 | } 14 | 15 | export const getBunDatabaseClient = () => { 16 | return new Database(Path.join(import.meta.dir, "../../db.sqlite3")) 17 | } 18 | -------------------------------------------------------------------------------- /lib/db/kysely-types.ts: -------------------------------------------------------------------------------- 1 | import type { Kysely } from "kysely" 2 | import type { DB } from "./generated/kysely" 3 | 4 | export type KyselyDatabaseInstance = Kysely 5 | -------------------------------------------------------------------------------- /lib/db/optimizations/component-category-index.ts: -------------------------------------------------------------------------------- 1 | import { sql } from "kysely" 2 | import type { DbOptimizationSpec } from "./types" 3 | import type { KyselyDatabaseInstance } from "../kysely-types" 4 | 5 | export const componentCategoryIndex: DbOptimizationSpec = { 6 | name: "idx_components_category_id", 7 | description: 8 | "Index on components.category_id for faster category-based queries", 9 | 10 | async checkIfAdded(db: KyselyDatabaseInstance) { 11 | const result = await sql` 12 | SELECT name FROM sqlite_master 13 | WHERE type='index' AND name=${this.name} 14 | `.execute(db) 15 | 16 | return result.rows.length > 0 17 | }, 18 | 19 | async execute(db: KyselyDatabaseInstance) { 20 | await db.schema 21 | .createIndex(this.name) 22 | .on("components") 23 | .column("category_id") 24 | .execute() 25 | }, 26 | } 27 | -------------------------------------------------------------------------------- /lib/db/optimizations/component-in-stock-category-index.ts: -------------------------------------------------------------------------------- 1 | import { sql } from "kysely" 2 | import type { DbOptimizationSpec } from "./types" 3 | import type { KyselyDatabaseInstance } from "../kysely-types" 4 | 5 | export const componentInStockCategoryIndex: DbOptimizationSpec = { 6 | name: "idx_components_in_stock_category", 7 | description: 8 | "Compound index on components.in_stock and category_id for faster filtered queries", 9 | 10 | async checkIfAdded(db: KyselyDatabaseInstance) { 11 | const result = await sql` 12 | SELECT name FROM sqlite_master 13 | WHERE type='index' AND name=${this.name} 14 | `.execute(db) 15 | 16 | return result.rows.length > 0 17 | }, 18 | 19 | async execute(db: KyselyDatabaseInstance) { 20 | await db.schema 21 | .createIndex(this.name) 22 | .on("components") 23 | .columns(["in_stock", "category_id"]) 24 | .execute() 25 | }, 26 | } 27 | -------------------------------------------------------------------------------- /lib/db/optimizations/component-in-stock-column.ts: -------------------------------------------------------------------------------- 1 | import { sql } from "kysely" 2 | import type { DbOptimizationSpec } from "./types" 3 | import type { KyselyDatabaseInstance } from "../kysely-types" 4 | 5 | export const componentInStockColumn: DbOptimizationSpec = { 6 | name: "add_components_in_stock_column", 7 | description: 8 | "Adds in_stock boolean column to components table derived from stock > 0", 9 | 10 | async checkIfAdded(db: KyselyDatabaseInstance) { 11 | const { 12 | rows: [ex], 13 | } = await sql` 14 | SELECT * FROM components LIMIT 1 15 | `.execute(db) 16 | 17 | return "in_stock" in ex 18 | }, 19 | 20 | async execute(db: KyselyDatabaseInstance) { 21 | // Add the column 22 | await sql` 23 | ALTER TABLE components 24 | ADD COLUMN in_stock boolean 25 | GENERATED ALWAYS AS (stock > 0) 26 | `.execute(db) 27 | 28 | // Create an index on the new column 29 | await db.schema 30 | .createIndex("idx_components_in_stock") 31 | .on("components") 32 | .column("in_stock") 33 | .execute() 34 | }, 35 | } 36 | -------------------------------------------------------------------------------- /lib/db/optimizations/component-indexes.ts: -------------------------------------------------------------------------------- 1 | import { sql } from "kysely" 2 | import type { DbOptimizationSpec } from "./types" 3 | import type { KyselyDatabaseInstance } from "../kysely-types" 4 | 5 | export const componentPackageIndex: DbOptimizationSpec = { 6 | name: "idx_components_package", 7 | description: "Index on package column for filter performance", 8 | 9 | async checkIfAdded(db: KyselyDatabaseInstance) { 10 | const result = await sql` 11 | SELECT name FROM sqlite_master 12 | WHERE type='index' AND name=${this.name} 13 | `.execute(db) 14 | return result.rows.length > 0 15 | }, 16 | 17 | async execute(db: KyselyDatabaseInstance) { 18 | await db.schema 19 | .createIndex(this.name) 20 | .on("components") 21 | .column("package") 22 | .execute() 23 | }, 24 | } 25 | -------------------------------------------------------------------------------- /lib/db/optimizations/component-search-fts.ts: -------------------------------------------------------------------------------- 1 | import { sql } from "kysely" 2 | import type { DbOptimizationSpec } from "./types" 3 | import type { KyselyDatabaseInstance } from "../kysely-types" 4 | 5 | export const componentSearchFTS: DbOptimizationSpec = { 6 | name: "components_fts", 7 | description: 8 | "FTS5 virtual table for fast component search with case-insensitive and scrambled letter support", 9 | 10 | async checkIfAdded(db: KyselyDatabaseInstance) { 11 | const result = await sql` 12 | SELECT name FROM sqlite_master 13 | WHERE type='table' AND name=${this.name} 14 | `.execute(db) 15 | return result.rows.length > 0 16 | }, 17 | 18 | async execute(db: KyselyDatabaseInstance) { 19 | // Create FTS5 virtual table with mfr_chars for scrambled letter searching 20 | await sql` 21 | CREATE VIRTUAL TABLE components_fts USING fts5( 22 | mfr, 23 | description, 24 | lcsc, 25 | mfr_chars 26 | ) 27 | `.execute(db) 28 | 29 | // Create synchronization triggers 30 | // INSERT trigger: Store fields in lowercase and populate mfr_chars 31 | await sql` 32 | CREATE TRIGGER components_ai AFTER INSERT ON components 33 | BEGIN 34 | INSERT INTO components_fts (rowid, mfr, description, lcsc, mfr_chars) 35 | VALUES ( 36 | new.rowid, 37 | LOWER(new.mfr), 38 | LOWER(new.description), 39 | LOWER(new.lcsc), 40 | REPLACE(LOWER(new.mfr), '', ' ') 41 | ); 42 | END 43 | `.execute(db) 44 | 45 | // UPDATE trigger: Update fields in lowercase and regenerate mfr_chars 46 | await sql` 47 | CREATE TRIGGER components_au AFTER UPDATE ON components 48 | BEGIN 49 | UPDATE components_fts 50 | SET 51 | mfr = LOWER(new.mfr), 52 | description = LOWER(new.description), 53 | lcsc = LOWER(new.lcsc), 54 | mfr_chars = REPLACE(LOWER(new.mfr), '', ' ') 55 | WHERE rowid = old.rowid; 56 | END 57 | `.execute(db) 58 | 59 | // DELETE trigger: Remove corresponding FTS entry 60 | await sql` 61 | CREATE TRIGGER components_ad AFTER DELETE ON components 62 | BEGIN 63 | DELETE FROM components_fts WHERE rowid = old.rowid; 64 | END 65 | `.execute(db) 66 | 67 | // Populate initial data from components table 68 | await sql` 69 | INSERT INTO components_fts (rowid, mfr, description, lcsc, mfr_chars) 70 | SELECT 71 | rowid, 72 | LOWER(mfr), 73 | LOWER(description), 74 | LOWER(lcsc), 75 | REPLACE(LOWER(mfr), '', ' ') 76 | FROM components 77 | `.execute(db) 78 | }, 79 | } 80 | -------------------------------------------------------------------------------- /lib/db/optimizations/component-stock-index.ts: -------------------------------------------------------------------------------- 1 | import { sql } from "kysely" 2 | import type { DbOptimizationSpec } from "./types" 3 | import type { KyselyDatabaseInstance } from "../kysely-types" 4 | 5 | export const componentStockIndex: DbOptimizationSpec = { 6 | name: "idx_components_stock_desc", 7 | description: "Index on components.stock DESC for faster stock-based queries", 8 | 9 | async checkIfAdded(db: KyselyDatabaseInstance) { 10 | const result = await sql` 11 | SELECT name FROM sqlite_master 12 | WHERE type='index' AND name=${this.name} 13 | `.execute(db) 14 | 15 | return result.rows.length > 0 16 | }, 17 | 18 | async execute(db: KyselyDatabaseInstance) { 19 | await db.schema 20 | .createIndex(this.name) 21 | .on("components") 22 | .column("stock desc") 23 | .execute() 24 | }, 25 | } 26 | -------------------------------------------------------------------------------- /lib/db/optimizations/in-stock-column.ts: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tscircuit/jlcsearch/720d581a9599051867f50bb3575c9e0a2f14caf0/lib/db/optimizations/in-stock-column.ts -------------------------------------------------------------------------------- /lib/db/optimizations/remove-stale-components.ts: -------------------------------------------------------------------------------- 1 | import { sql } from "kysely" 2 | import type { DbOptimizationSpec } from "./types" 3 | import type { KyselyDatabaseInstance } from "../kysely-types" 4 | 5 | export const removeStaleComponents: DbOptimizationSpec = { 6 | name: "remove_stale_components", 7 | description: "Removes components that haven't been in stock for over a year", 8 | 9 | async checkIfAdded(db: KyselyDatabaseInstance) { 10 | // Check if any components exist with last_on_stock older than 1 year 11 | const result = await sql<{ count: number }>` 12 | SELECT COUNT(*) as count 13 | FROM components 14 | WHERE last_on_stock < strftime('%s', 'now', '-1 year') 15 | `.execute(db) 16 | 17 | // If no stale components exist, consider this optimization as "added" 18 | return result.rows[0]?.count === 0 19 | }, 20 | 21 | async execute(db: KyselyDatabaseInstance) { 22 | await sql` 23 | DELETE FROM components 24 | WHERE last_on_stock < strftime('%s', 'now', '-1 year') 25 | `.execute(db) 26 | }, 27 | } 28 | -------------------------------------------------------------------------------- /lib/db/optimizations/types.ts: -------------------------------------------------------------------------------- 1 | import type { KyselyDatabaseInstance } from "../kysely-types" 2 | 3 | export interface DbOptimizationSpec { 4 | name: string 5 | description: string 6 | checkIfAdded: (db: KyselyDatabaseInstance) => Promise 7 | execute: (db: KyselyDatabaseInstance) => Promise 8 | } 9 | -------------------------------------------------------------------------------- /lib/middlewares/with-cache-headers.ts: -------------------------------------------------------------------------------- 1 | import type { Middleware } from "winterspec" 2 | 3 | export const withCacheHeaders: Middleware<{}, {}> = async (req, ctx, next) => { 4 | const res = await next(req, ctx) 5 | 6 | if (req.url.includes("tscircuit.com")) { 7 | // Cache for 1 week (604800 seconds) with 1 hour stale-while-revalidate 8 | res.headers.set( 9 | "Cache-Control", 10 | "public, max-age=604800, s-maxage=604800, stale-while-revalidate=3600", 11 | ) 12 | res.headers.set("Vary", "*") 13 | } 14 | 15 | return res 16 | } 17 | -------------------------------------------------------------------------------- /lib/middlewares/with-cors.ts: -------------------------------------------------------------------------------- 1 | import type { Middleware } from "winterspec/middleware" 2 | 3 | export const allowed_headers = [ 4 | "x-csrf-token", 5 | "x-requested-with", 6 | "accept", 7 | "accept-version", 8 | "content-length", 9 | "content-md5", 10 | "content-type", 11 | "date", 12 | "authorization", 13 | "user-agent", 14 | ] 15 | 16 | export const withCors: Middleware<{}, {}> = async (req, ctx, next) => { 17 | const cors_headers = { 18 | "Access-Control-Allow-Origin": req.headers.get("origin") ?? "*", 19 | "Access-Control-Allow-Methods": "GET, POST, PUT, DELETE, OPTIONS", 20 | "Access-Control-Allow-Credentials": "true", 21 | "Access-Control-Allow-Headers": allowed_headers.join(", "), 22 | "Access-Control-Max-Age": "86400", 23 | Vary: "Origin", 24 | } 25 | 26 | if (req.method === "OPTIONS") { 27 | return new Response("", { 28 | headers: cors_headers, 29 | }) 30 | } 31 | const response = await next(req, ctx) 32 | 33 | if (response.headers.set) { 34 | for (const [header, value] of Object.entries(cors_headers)) { 35 | response.headers.set(header, value) 36 | } 37 | } 38 | 39 | return response 40 | } 41 | -------------------------------------------------------------------------------- /lib/middlewares/with-ctx-error.ts: -------------------------------------------------------------------------------- 1 | import { Middleware } from "winterspec/middleware" 2 | 3 | export const withCtxError: Middleware< 4 | {}, 5 | { 6 | error: ( 7 | status: number, 8 | error_payload: { 9 | error_code: string 10 | message: string 11 | }, 12 | ) => Response 13 | } 14 | > = async (req, ctx, next) => { 15 | ctx.error = (status, error_payload) => { 16 | return new Response(JSON.stringify({ error: error_payload }), { 17 | status, 18 | headers: { 19 | "Content-Type": "application/json", 20 | }, 21 | }) 22 | } 23 | return next(req, ctx) 24 | } 25 | -------------------------------------------------------------------------------- /lib/middlewares/with-db.ts: -------------------------------------------------------------------------------- 1 | import type { Middleware } from "winterspec/middleware" 2 | import { getDbClient } from "lib/db/get-db-client" 3 | import type { KyselyDatabaseInstance } from "lib/db/kysely-types" 4 | 5 | export const withDb: Middleware< 6 | {}, 7 | { 8 | db: KyselyDatabaseInstance 9 | } 10 | > = (req, ctx, next) => { 11 | if (!ctx.db) { 12 | ctx.db = getDbClient() 13 | } 14 | return next(req, ctx) 15 | } 16 | -------------------------------------------------------------------------------- /lib/middlewares/with-error-response.ts: -------------------------------------------------------------------------------- 1 | import { Middleware } from "winterspec/middleware" 2 | import kleur from "kleur" 3 | 4 | export const withErrorResponse: Middleware<{}, {}> = async (req, ctx, next) => { 5 | try { 6 | return await next(req, ctx) 7 | } catch (error: any) { 8 | console.error(kleur.red("Intercepted error:"), error) 9 | // If error is a Response, return it 10 | if (error instanceof Response) { 11 | return error 12 | } 13 | return (ctx as any).json( 14 | { 15 | ok: false, 16 | error: { 17 | message: error?.message, 18 | error_code: error?.error_code ?? "internal_server_error", 19 | }, 20 | }, 21 | { status: error?.status || 500 }, 22 | ) 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /lib/middlewares/with-is-api-request.ts: -------------------------------------------------------------------------------- 1 | import type { Middleware } from "winterspec" 2 | 3 | export const withIsApiRequest: Middleware<{}, { isApiRequest: boolean }> = ( 4 | req, 5 | ctx, 6 | next, 7 | ) => { 8 | ctx.isApiRequest = 9 | req.url.includes("json=") || 10 | req.url.includes(".json") || 11 | req.headers.get("content-type") === "application/json" 12 | return next(req, ctx) 13 | } 14 | -------------------------------------------------------------------------------- /lib/middlewares/with-request-logging.ts: -------------------------------------------------------------------------------- 1 | import type { Middleware } from "winterspec/middleware" 2 | import kleur from "kleur" 3 | 4 | // ENABLE COLORS ALWAYS 5 | kleur.enabled = true 6 | 7 | const colorStatus = (status: number) => { 8 | if (status >= 500) { 9 | return kleur.red(status.toString()) 10 | } 11 | if (status >= 400) { 12 | return kleur.yellow(status.toString()) 13 | } 14 | return kleur.green(status.toString()) 15 | } 16 | 17 | export interface Logger { 18 | error: (...args: any[]) => void 19 | info: (...args: any[]) => void 20 | warn: (...args: any[]) => void 21 | debug: (...args: any[]) => void 22 | } 23 | 24 | export const withRequestLogging: Middleware< 25 | {}, 26 | { 27 | logger: Logger 28 | } 29 | > = async (req, ctx, next) => { 30 | if (!ctx.logger) { 31 | ctx.logger = { 32 | error: (...args: any[]) => console.error(...args), 33 | info: (...args: any[]) => console.log(...args), 34 | warn: (...args: any[]) => console.warn(...args), 35 | debug: (...args: any[]) => console.log(...args), 36 | } 37 | } 38 | try { 39 | ctx.logger.info(kleur.blue(`> ${req.method} ${req.url}`)) 40 | const response = await next(req, ctx) 41 | try { 42 | const responseBody = await response.clone().text() 43 | ctx.logger.info( 44 | `< ${colorStatus(response.status)} ${kleur.gray(responseBody.slice(0, 40).replace(/(\r\n|\n|\r)/gm, ""))}`, 45 | ) 46 | } catch (e) { 47 | ctx.logger.info(`< ${colorStatus(response.status)}`) 48 | } 49 | return response 50 | } catch (e: any) { 51 | ctx.logger.info(kleur.red(`< ERROR ${e.toString().slice(0, 50)}...`)) 52 | throw e 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /lib/ui/Table.tsx: -------------------------------------------------------------------------------- 1 | import React from "react" 2 | import { timeAgo } from "./time-ago" 3 | 4 | const pluralize = (resource: string) => { 5 | return resource.endsWith("y") ? `${resource.slice(0, -1)}ies` : `${resource}s` 6 | } 7 | 8 | const removeResourcePrefixes = (resource: string) => { 9 | if (resource.startsWith("creator_")) return resource.slice(8) 10 | if (resource.startsWith("owner_")) return resource.slice(6) 11 | if (resource.startsWith("personal_")) return resource.slice(9) 12 | return resource 13 | } 14 | 15 | const Cell = ({ 16 | row, 17 | columnKey, 18 | cellValue, 19 | timezone, 20 | }: { 21 | row: any 22 | columnKey: string 23 | cellValue: any 24 | timezone: string 25 | }) => { 26 | if (!cellValue) return <> 27 | if (React.isValidElement(cellValue)) return cellValue 28 | if (columnKey === "lcsc") { 29 | return ( 30 | 31 | {cellValue} 32 | 33 | ) 34 | } 35 | if (columnKey.endsWith("_at")) { 36 | return {timeAgo(cellValue, timezone)} 37 | } 38 | return <>{String(cellValue)} 39 | } 40 | 41 | export const Table = ({ 42 | rows, 43 | obj, 44 | timezone, 45 | }: { rows?: object[]; obj?: object; timezone?: string }) => { 46 | if (!timezone) { 47 | timezone = "UTC" //globalThis.timezone ?? "UTC" 48 | } 49 | if (obj) { 50 | const entries = Object.entries(obj) 51 | return ( 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | {entries.map(([key, value], index) => ( 61 | 62 | 63 | 71 | 72 | ))} 73 | 74 |
KeyValue
{key} 64 | 70 |
75 | ) 76 | } 77 | 78 | if (!rows || rows.length === 0) return null 79 | 80 | const keys = Object.keys(rows[0]!) 81 | 82 | return ( 83 | 84 | 85 | 86 | {keys.map((key) => ( 87 | 90 | ))} 91 | 92 | 93 | 94 | {rows.map((row: any, rowIndex) => ( 95 | 96 | {keys.map((key) => ( 97 | 105 | ))} 106 | 107 | ))} 108 | 109 |
88 | {key} 89 |
98 | 104 |
110 | ) 111 | } 112 | -------------------------------------------------------------------------------- /lib/ui/time-ago.tsx: -------------------------------------------------------------------------------- 1 | export function timeAgo(date: Date, timezone = "UTC") { 2 | if (!date) return "" 3 | const now = new Date() 4 | const timeDiff = now.getTime() - date.getTime() 5 | 6 | const formatTime = (date: Date) => { 7 | return new Intl.DateTimeFormat("en-US", { 8 | hour: "numeric", 9 | minute: "numeric", 10 | second: "numeric", 11 | hour12: timezone !== "UTC", 12 | timeZone: timezone, 13 | }).format(date) 14 | } 15 | 16 | const formatDateShort = (date: Date) => { 17 | return new Intl.DateTimeFormat("en-US", { 18 | month: "2-digit", 19 | day: "2-digit", 20 | timeZone: timezone, 21 | }).format(date) 22 | } 23 | 24 | const formatDateFull = (date: Date) => { 25 | return new Intl.DateTimeFormat("en-US", { 26 | year: "numeric", 27 | month: "2-digit", 28 | day: "2-digit", 29 | timeZone: timezone, 30 | }).format(date) 31 | } 32 | 33 | if (timeDiff < 12 * 60 * 60 * 1000) { 34 | // Within the past 12 hours 35 | return formatTime(date) 36 | } 37 | if (date.getUTCFullYear() === now.getUTCFullYear()) { 38 | // More than 12 hours ago, but in the same year 39 | return `${formatDateShort(date)} ${formatTime(date)}` 40 | } 41 | 42 | // Not in the same year 43 | return `${formatDateFull(date)} ${formatTime(date)}` 44 | } 45 | -------------------------------------------------------------------------------- /lib/util/convert-to-possible-footprinter-strings.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Converts a JLCPCB package name to a possible footprinter string. 3 | * 4 | * Example JLCPCB strings: 5 | * - Plugin,P=2.54mm 6 | * - SOD-123 7 | * - Push-Pull,P=2.54mm 8 | * - Plugin,D6.3xL11mm 9 | */ 10 | export const convertToPossibleFootprinterStrings = (jlcPackage: string) => { 11 | // Plugin,P=2.54mm -> plugin_p2.54mm 12 | const v1 = jlcPackage 13 | .toLowerCase() 14 | .replace(/ /g, "") 15 | .replace(/-/g, "_") 16 | .replace(/=/g, "") 17 | .replace(/,/g, "_") 18 | 19 | // SOT_23 -> sot23 20 | const v2 = v1.replace("_", "") 21 | 22 | return [v1, v2] 23 | } 24 | -------------------------------------------------------------------------------- /lib/util/extract-min-quantity-price.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Extracts the minimum quantity price from a price string. 3 | * 4 | * Example string: '[{"qFrom": 1, "qTo": 9, "price": 14.320289855}, {"qFrom": 10, "qTo": 11, "price": 14.320289855}, {"qFrom": 12, "qTo": 199, "price": 14.320289855}, {"qFrom": 200, "qTo": 499, "price": 5.542028986}, {"qFrom": 500, "qTo": 999, "price": 5.347826087}, {"qFrom": 1000, "qTo": null, "price": 5.250724638}]' 5 | */ 6 | export const extractMinQPrice = (price: string) => { 7 | try { 8 | return JSON.parse(price)[0].price as number 9 | } catch (e) { 10 | return null 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /lib/util/format-price.ts: -------------------------------------------------------------------------------- 1 | export const formatPrice = (price: number | null) => { 2 | if (!price) return "" 3 | return price.toLocaleString("en-US", { 4 | style: "currency", 5 | currency: "USD", 6 | }) 7 | } 8 | -------------------------------------------------------------------------------- /lib/util/format-si-unit.ts: -------------------------------------------------------------------------------- 1 | const SI_PREFIXES = [ 2 | { value: 1e12, symbol: "T" }, 3 | { value: 1e9, symbol: "G" }, 4 | { value: 1e6, symbol: "M" }, 5 | { value: 1e3, symbol: "k" }, 6 | { value: 1, symbol: "" }, 7 | { value: 1e-3, symbol: "m" }, 8 | { value: 1e-6, symbol: "µ" }, 9 | { value: 1e-9, symbol: "n" }, 10 | { value: 1e-12, symbol: "p" }, 11 | ] 12 | 13 | export function formatSiUnit(value?: number | null): string { 14 | if (value == null) return "" 15 | if (value === 0) return "0" 16 | 17 | const prefix = 18 | SI_PREFIXES.find((p) => Math.abs(value) >= p.value) || 19 | SI_PREFIXES[SI_PREFIXES.length - 1] 20 | const scaled = value / prefix.value 21 | 22 | // Format number to at most 3 significant digits 23 | const formatted = scaled.toPrecision(3).replace(/\.0+$/, "") 24 | 25 | return `${formatted}${prefix.symbol}` 26 | } 27 | -------------------------------------------------------------------------------- /lib/util/parse-int-or-null.ts: -------------------------------------------------------------------------------- 1 | export const parseIntOrNull = ( 2 | value: string | number | null, 3 | ): number | null => { 4 | if (value === null) return null 5 | const parsed = Number(value) 6 | return Number.isNaN(parsed) ? null : parsed 7 | } 8 | -------------------------------------------------------------------------------- /lib/with-winter-spec.ts: -------------------------------------------------------------------------------- 1 | import { withCtxError } from "lib/middlewares/with-ctx-error" 2 | import { withDb } from "lib/middlewares/with-db" 3 | import { withErrorResponse } from "lib/middlewares/with-error-response" 4 | import { withCtxReact } from "./middlewares/with-ctx-react" 5 | import { createWithWinterSpec } from "winterspec" 6 | import { withRequestLogging } from "./middlewares/with-request-logging" 7 | import { withCacheHeaders } from "./middlewares/with-cache-headers" 8 | import { withIsApiRequest } from "./middlewares/with-is-api-request" 9 | import { withCors } from "./middlewares/with-cors" 10 | 11 | export const withWinterSpec = createWithWinterSpec({ 12 | authMiddleware: {}, 13 | 14 | beforeAuthMiddleware: [ 15 | withErrorResponse, 16 | withCtxError, 17 | withCtxReact, 18 | withDb, 19 | withRequestLogging, 20 | withCacheHeaders, 21 | withIsApiRequest, 22 | withCors, 23 | ], 24 | 25 | apiName: "tscircuit JLC Search", 26 | productionServerUrl: "https://jlcsearch.tscircuit.com", 27 | addOkStatus: true, 28 | 29 | shouldValidateGetRequestBody: true, 30 | shouldValidateResponses: true, 31 | }) 32 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "jlcpcb-parts-engine", 3 | "module": "index.ts", 4 | "devDependencies": { 5 | "@biomejs/biome": "^1.9.4", 6 | "@flydotio/dockerfile": "^0.5.9", 7 | "@types/bun": "^1.2.15", 8 | "@types/react": "^18.3.12", 9 | "@types/react-dom": "^18.3.1", 10 | "better-sqlite3": "^11.7.0", 11 | "kysely": "^0.27.4", 12 | "kysely-codegen": "^0.17.0", 13 | "winterspec": "^0.0.96" 14 | }, 15 | "peerDependencies": { 16 | "typescript": "^5.0.0" 17 | }, 18 | "scripts": { 19 | "start": "bun run --hot scripts/start-server.ts", 20 | "generate:db-types": "bunx kysely-codegen --out-file ./lib/db/generated/kysely.ts --singular --dialect bun-sqlite --url ./db.sqlite3", 21 | "setup": "bun run setup:7z && bun run setup:download-cache-fragments && bun run setup:extract-db && bun run setup:replace-db-file && bun run setup:optimize-db && bun run setup:derived-tables", 22 | "setup:7z": "bun run scripts/setup-7z.ts", 23 | "setup:download-cache-fragments": "bun scripts/download-cache-fragments.ts", 24 | "setup:extract-db": ".bin/7zz x .buildtmp/cache.zip", 25 | "setup:replace-db-file": "rm -f ./db.sqlite3 && mv ./cache.sqlite3 ./db.sqlite3", 26 | "setup:optimize-db": "bun run scripts/setup-db-optimizations.ts", 27 | "setup:derived-tables": "bun run scripts/setup-derived-tables.ts", 28 | "setup:download": "curl -o db.sqlite \"https://jlcsearch.fly.dev/database/$DATABASE_DOWNLOAD_TOKEN\"", 29 | "format": "biome format --write .", 30 | "format:check": "biome format ." 31 | }, 32 | "type": "module", 33 | "dependencies": { 34 | "@tscircuit/footprinter": "^0.0.143", 35 | "kysely-bun-sqlite": "^0.3.2", 36 | "react": "^18.3.1", 37 | "react-dom": "^18.3.1", 38 | "redaxios": "^0.5.1" 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /routes/[...anyroute].ts: -------------------------------------------------------------------------------- 1 | import { withWinterSpec } from "lib/with-winter-spec" 2 | import { z } from "zod" 3 | import React from "react" 4 | 5 | export default withWinterSpec({ 6 | auth: "none", 7 | methods: ["GET", "POST"], 8 | jsonResponse: z.object({ 9 | error_code: z.string(), 10 | message: z.string(), 11 | }), 12 | } as const)(async (req, ctx) => { 13 | if (ctx.isApiRequest) { 14 | return ctx.error(404, { 15 | error_code: "not_found", 16 | message: "Not Found", 17 | }) 18 | } 19 | 20 | return ctx.react( 21 | React.createElement( 22 | "div", 23 | { className: "p-8" }, 24 | React.createElement( 25 | "h1", 26 | { className: "text-2xl font-bold mb-4" }, 27 | "404 - Not Found", 28 | ), 29 | React.createElement("p", null, "The requested page could not be found."), 30 | ), 31 | "404 Not Found", 32 | ) 33 | }) 34 | -------------------------------------------------------------------------------- /routes/accelerometers/list.json.tsx: -------------------------------------------------------------------------------- 1 | import list from "./list" 2 | export default list 3 | -------------------------------------------------------------------------------- /routes/adcs/list.json.tsx: -------------------------------------------------------------------------------- 1 | import list from "./list" 2 | export default list 3 | -------------------------------------------------------------------------------- /routes/admin/index.tsx: -------------------------------------------------------------------------------- 1 | import { withWinterSpec } from "lib/with-winter-spec" 2 | import { z } from "zod" 3 | 4 | export default withWinterSpec({ 5 | auth: "none", 6 | methods: ["HEAD", "GET", "POST"], 7 | jsonResponse: z.any(), 8 | } as const)(async (req, ctx) => { 9 | if (req.method === "HEAD") { 10 | return new Response(null, { status: 200 }) 11 | } 12 | 13 | return ctx.react( 14 |
15 | Categories 16 |
, 17 | ) 18 | }) 19 | -------------------------------------------------------------------------------- /routes/admin/system/create-indexes.tsx: -------------------------------------------------------------------------------- 1 | import { Table } from "lib/ui/Table" 2 | import { withWinterSpec } from "lib/with-winter-spec" 3 | import { z } from "zod" 4 | import { componentStockIndex } from "lib/db/optimizations/component-stock-index" 5 | import { removeStaleComponents } from "lib/db/optimizations/remove-stale-components" 6 | import { componentInStockCategoryIndex } from "lib/db/optimizations/component-in-stock-category-index" 7 | import type { DbOptimizationSpec } from "lib/db/optimizations/types" 8 | 9 | const OPTIMIZATIONS: DbOptimizationSpec[] = [ 10 | componentStockIndex, 11 | removeStaleComponents, 12 | componentInStockCategoryIndex, 13 | ] 14 | 15 | export default withWinterSpec({ 16 | auth: "none", 17 | methods: ["GET", "POST"], 18 | jsonResponse: z.any(), 19 | } as const)(async (req, ctx) => { 20 | // Handle POST request to add optimization 21 | if (req.method === "POST") { 22 | const formData = await req.formData() 23 | const optName = formData.get("optimization_name") 24 | const optimization = OPTIMIZATIONS.find((opt) => opt.name === optName) 25 | 26 | if (optimization) { 27 | await optimization.execute(ctx.db) 28 | } 29 | 30 | return Response.redirect(req.url) 31 | } 32 | 33 | // Check which optimizations exist 34 | const optimizationStates = await Promise.all( 35 | OPTIMIZATIONS.map(async (opt) => ({ 36 | name: opt.name, 37 | description: opt.description, 38 | enabled: await opt.checkIfAdded(ctx.db), 39 | })), 40 | ) 41 | 42 | return ctx.react( 43 |
44 |

Database Optimizations

45 | ({ 47 | name: opt.name, 48 | description: opt.description, 49 | enabled: opt.enabled ? "Yes" : "No", 50 | actions: !opt.enabled ? ( 51 | 55 | 56 | 62 | 63 | ) : null, 64 | }))} 65 | /> 66 | , 67 | ) 68 | }) 69 | -------------------------------------------------------------------------------- /routes/analog_multiplexers/list.json.tsx: -------------------------------------------------------------------------------- 1 | import list from "./list" 2 | export default list 3 | -------------------------------------------------------------------------------- /routes/api/search.tsx: -------------------------------------------------------------------------------- 1 | import { sql } from "kysely" 2 | import { withWinterSpec } from "lib/with-winter-spec" 3 | import { z } from "zod" 4 | 5 | const extractSmallQuantityPrice = (price: string | null): string => { 6 | if (!price) return "" 7 | try { 8 | const priceObj = JSON.parse(price) 9 | return priceObj[0]?.price || "" 10 | } catch { 11 | return "" 12 | } 13 | } 14 | 15 | export default withWinterSpec({ 16 | auth: "none", 17 | methods: ["GET"], 18 | queryParams: z.object({ 19 | package: z.string().optional(), 20 | full: z.boolean().optional(), 21 | q: z.string().optional(), 22 | limit: z.string().optional(), 23 | }), 24 | jsonResponse: z.any(), 25 | } as const)(async (req, ctx) => { 26 | const limit = parseInt(req.query.limit ?? "100", 10) || 100 27 | 28 | let query = ctx.db 29 | .selectFrom("components") 30 | .selectAll() 31 | .limit(limit) 32 | .orderBy("stock", "desc") 33 | .where("stock", ">", 0) 34 | 35 | if (req.query.package) { 36 | query = query.where("package", "=", req.query.package) 37 | } 38 | 39 | if (req.query.q) { 40 | const searchTerm = req.query.q.trim().toLowerCase() 41 | const searchPattern = `%${searchTerm}%` 42 | 43 | // Full-text search query for mfr and other fields 44 | const mfrFtsQuery = `mfr:${searchTerm}*` 45 | const generalFtsQuery = `${searchTerm}*` 46 | const combinedFtsQuery = `${mfrFtsQuery} OR ${generalFtsQuery}` 47 | query = query.where((eb) => 48 | eb("mfr", "like", searchPattern) 49 | .or("description", "like", searchPattern) 50 | .or(sql`lcsc IN ( 51 | SELECT CAST(lcsc AS INTEGER) 52 | FROM components_fts 53 | WHERE components_fts MATCH ${combinedFtsQuery} 54 | ORDER BY rank 55 | )`), 56 | ) 57 | } 58 | 59 | const fullComponents = await query.execute() 60 | 61 | const components = fullComponents.map((c) => ({ 62 | lcsc: c.lcsc, 63 | mfr: c.mfr, 64 | package: c.package, 65 | description: c.description, 66 | stock: c.stock, 67 | price: extractSmallQuantityPrice(c.price), 68 | })) 69 | 70 | return ctx.json({ 71 | components: req.query.full ? fullComponents : components, 72 | }) 73 | }) 74 | -------------------------------------------------------------------------------- /routes/bjt_transistors/list.json.tsx: -------------------------------------------------------------------------------- 1 | import list from "./list" 2 | export default list 3 | -------------------------------------------------------------------------------- /routes/boost_converters/list.json.tsx: -------------------------------------------------------------------------------- 1 | import list from "./list" 2 | export default list 3 | -------------------------------------------------------------------------------- /routes/capacitors/list.json.tsx: -------------------------------------------------------------------------------- 1 | import list from "./list" 2 | export default list 3 | -------------------------------------------------------------------------------- /routes/categories/list.json.tsx: -------------------------------------------------------------------------------- 1 | import list from "./list" 2 | export default list 3 | -------------------------------------------------------------------------------- /routes/categories/list.tsx: -------------------------------------------------------------------------------- 1 | import { Table } from "lib/ui/Table" 2 | import { withWinterSpec } from "lib/with-winter-spec" 3 | import { z } from "zod" 4 | 5 | export default withWinterSpec({ 6 | auth: "none", 7 | methods: ["GET", "POST"], 8 | queryParams: z.object({ 9 | category_name: z.string().optional(), 10 | }), 11 | jsonResponse: z.any(), 12 | } as const)(async (req, ctx) => { 13 | let categories: Array<{ category: string; subcategory?: string }> = 14 | await ctx.db.selectFrom("categories").selectAll().execute() 15 | 16 | if (req.query.category_name) { 17 | categories = categories.filter( 18 | (c: { category: string }) => c.category === req.query.category_name, 19 | ) 20 | } else { 21 | // Group categories and their subcategories 22 | const categoryMap = categories.reduce( 23 | (acc: Map>, c) => { 24 | if (!acc.has(c.category)) { 25 | acc.set(c.category, new Set()) 26 | } 27 | if (c.subcategory) { 28 | acc.get(c.category)!.add(c.subcategory) 29 | } 30 | return acc 31 | }, 32 | new Map>(), 33 | ) 34 | 35 | categories = Array.from(categoryMap.entries()).map( 36 | ([category, subcategories]) => ({ 37 | category, 38 | subcategory: Array.from(subcategories)[0] as string | undefined, 39 | }), 40 | ) 41 | } 42 | 43 | if (ctx.isApiRequest) { 44 | return ctx.json({ 45 | categories: categories.map((c) => ({ 46 | category: c.category, 47 | subcategory: c.subcategory, 48 | })), 49 | }) 50 | } 51 | 52 | return ctx.react( 53 |
54 |

Categories

55 |
Click for subcategories
56 |
({ 58 | category: ( 59 | 60 | {c.category} 61 | 62 | ), 63 | subcategory: ( 64 | 65 | {c.subcategory} 66 | 67 | ), 68 | }))} 69 | /> 70 | , 71 | "JLCPCB Component Categories", 72 | ) 73 | }) 74 | -------------------------------------------------------------------------------- /routes/components/list.json.tsx: -------------------------------------------------------------------------------- 1 | import list from "./list" 2 | export default list 3 | -------------------------------------------------------------------------------- /routes/components/list.tsx: -------------------------------------------------------------------------------- 1 | import { sql } from "kysely" 2 | import { Table } from "lib/ui/Table" 3 | import { ExpressionBuilder } from "kysely" 4 | import { withWinterSpec } from "lib/with-winter-spec" 5 | import { z } from "zod" 6 | 7 | const extractSmallQuantityPrice = (price: string | null) => { 8 | try { 9 | const priceObj = JSON.parse(price!) 10 | return priceObj[0].price 11 | } catch (e) { 12 | return "" 13 | } 14 | } 15 | 16 | export default withWinterSpec({ 17 | auth: "none", 18 | methods: ["GET"], 19 | queryParams: z.object({ 20 | subcategory_name: z.string().optional(), 21 | package: z.string().optional(), 22 | full: z.boolean().optional(), 23 | search: z.string().optional(), 24 | }), 25 | jsonResponse: z.any(), 26 | } as const)(async (req, ctx) => { 27 | const limit = 100 28 | 29 | let query = ctx.db 30 | .selectFrom("v_components") 31 | .select([ 32 | "lcsc", 33 | "mfr", 34 | "package", 35 | "description", 36 | "stock", 37 | "price", 38 | "extra", 39 | ]) 40 | .limit(limit) 41 | .orderBy("stock", "desc") 42 | .where("stock", ">", 0) 43 | 44 | if (req.query.subcategory_name) { 45 | query = query.where("subcategory", "=", req.query.subcategory_name) 46 | } 47 | 48 | if (req.query.package) { 49 | query = query.where("package", "=", req.query.package) 50 | } 51 | 52 | if (req.query.search) { 53 | const search = req.query.search // TypeScript now knows this is defined within this block 54 | const searchPattern = `%${search}%` 55 | query = query.where((eb) => 56 | eb("description", "like", searchPattern) 57 | .or("mfr", "like", searchPattern) 58 | // For lcsc, we'll search it as a number if it's numeric, otherwise skip it 59 | .or( 60 | search.match(/^\d+$/) 61 | ? eb("lcsc", "=", parseInt(search)) 62 | : eb("description", "like", searchPattern), // Fallback to description if not numeric 63 | ), 64 | ) 65 | } 66 | 67 | const fullComponents = await query.execute() 68 | 69 | const components = fullComponents.map((c) => ({ 70 | lcsc: c.lcsc, 71 | mfr: c.mfr, 72 | package: c.package, 73 | description: c.description, 74 | stock: c.stock, 75 | price: extractSmallQuantityPrice(c.price), 76 | })) 77 | 78 | if (ctx.isApiRequest) { 79 | return ctx.json({ 80 | components: req.query.full ? fullComponents : components, 81 | }) 82 | } 83 | 84 | return ctx.react( 85 |
86 |

Components

87 | {req.query.subcategory_name && ( 88 |
Filtering by subcategory: {req.query.subcategory_name}
89 | )} 90 |
91 | , 92 | req.query.search 93 | ? `${req.query.search} - JLCPCB Component Search` 94 | : "JLCPCB Component Search", 95 | ) 96 | }) 97 | -------------------------------------------------------------------------------- /routes/dacs/list.json.tsx: -------------------------------------------------------------------------------- 1 | import list from "./list" 2 | export default list 3 | -------------------------------------------------------------------------------- /routes/diodes/list.json.tsx: -------------------------------------------------------------------------------- 1 | import list from "./list" 2 | export default list 3 | -------------------------------------------------------------------------------- /routes/footprint_index/list.tsx: -------------------------------------------------------------------------------- 1 | import { Table } from "lib/ui/Table" 2 | import { withWinterSpec } from "lib/with-winter-spec" 3 | import { z } from "zod" 4 | import { fp } from "@tscircuit/footprinter" 5 | import { convertToPossibleFootprinterStrings } from "lib/util/convert-to-possible-footprinter-strings" 6 | 7 | export default withWinterSpec({ 8 | auth: "none", 9 | methods: ["GET"], 10 | jsonResponse: z.any(), 11 | })(async (req, ctx) => { 12 | // Query distinct package values with the count of components for each package 13 | const result = await ctx.db 14 | .selectFrom("components") 15 | .select("package") 16 | .select((eb) => eb.fn.count("lcsc").as("count")) 17 | .groupBy("package") 18 | .orderBy("count", "desc") 19 | .having((eb) => eb.fn.count("lcsc"), ">", 10) 20 | .execute() 21 | 22 | const footprints = result.map((row) => { 23 | const footprinterStrings = convertToPossibleFootprinterStrings(row.package) 24 | let validFootprinterString: string | null = null 25 | for (const footprinterString of footprinterStrings) { 26 | try { 27 | const result = fp.string(footprinterString).circuitJson() 28 | if (result.length > 0) { 29 | validFootprinterString = footprinterString 30 | break 31 | } 32 | } catch (e) { 33 | // Do nothing 34 | } 35 | } 36 | 37 | return { 38 | package: row.package, 39 | num_components: row.count, 40 | footprinter_string: validFootprinterString, 41 | tscircuit_accepts: Boolean(validFootprinterString), 42 | } 43 | }) 44 | 45 | if (ctx.isApiRequest) { 46 | return ctx.json({ footprints }) 47 | } 48 | 49 | return ctx.react( 50 |
51 |

Package Index

52 |
53 | Percentage tscircuit accepts w/ string:{" "} 54 | {( 55 | (footprints.filter((row) => row.tscircuit_accepts).length / 56 | footprints.length) * 57 | 100 58 | ).toFixed(2)} 59 | % 60 |
61 |
({ 63 | ...row, 64 | package: ( 65 | 68 | {row.package} 69 | 70 | ), 71 | tscircuit_accepts: row.tscircuit_accepts ? "✓" : "", 72 | report: row.tscircuit_accepts ? ( 73 | "" 74 | ) : ( 75 | // Title: "Implement " 76 | // Description: 77 | // Here's are components on JLCPCB with this footprint: > 78 | // There may be reference dimensions/designs on the [kicad viewer](https://tscircuit.github.io/kicad-viewer) 79 | // This issue may be eligible for a $10 bounty from the TSCircuit team (please review!) 80 | 83 | Create issue ($10) 84 | 85 | ), 86 | }))} 87 | /> 88 | , 89 | ) 90 | }) 91 | -------------------------------------------------------------------------------- /routes/fuses/list.json.tsx: -------------------------------------------------------------------------------- 1 | import list from "./list" 2 | export default list 3 | -------------------------------------------------------------------------------- /routes/gas_sensors/list.json.tsx: -------------------------------------------------------------------------------- 1 | import list from "./list" 2 | export default list 3 | -------------------------------------------------------------------------------- /routes/gyroscopes/list.json.tsx: -------------------------------------------------------------------------------- 1 | import list from "./list" 2 | export default list 3 | -------------------------------------------------------------------------------- /routes/headers/list.json.ts: -------------------------------------------------------------------------------- 1 | import list from "./list" 2 | export default list 3 | -------------------------------------------------------------------------------- /routes/health.ts: -------------------------------------------------------------------------------- 1 | import { withWinterSpec } from "lib/with-winter-spec" 2 | import { z } from "zod" 3 | 4 | export default withWinterSpec({ 5 | auth: "none", 6 | methods: ["GET", "POST"], 7 | jsonResponse: z.object({ 8 | ok: z.boolean(), 9 | }), 10 | } as const)(async (req, ctx) => { 11 | return ctx.json({ ok: true }) 12 | }) 13 | -------------------------------------------------------------------------------- /routes/index.tsx: -------------------------------------------------------------------------------- 1 | import { withWinterSpec } from "lib/with-winter-spec" 2 | import { z } from "zod" 3 | 4 | export default withWinterSpec({ 5 | auth: "none", 6 | methods: ["HEAD", "GET", "POST"], 7 | jsonResponse: z.any(), 8 | } as const)(async (req, ctx) => { 9 | if (req.method === "HEAD") { 10 | return new Response(null, { status: 200 }) 11 | } 12 | 13 | return ctx.react( 14 | , 49 | ) 50 | }) 51 | -------------------------------------------------------------------------------- /routes/io_expanders/list.json.tsx: -------------------------------------------------------------------------------- 1 | import list from "./list" 2 | export default list 3 | -------------------------------------------------------------------------------- /routes/lcd_display/list.json.tsx: -------------------------------------------------------------------------------- 1 | import list from "./list" 2 | export default list 3 | -------------------------------------------------------------------------------- /routes/led_dot_matrix_display/list.json.tsx: -------------------------------------------------------------------------------- 1 | import list from "./list" 2 | export default list 3 | -------------------------------------------------------------------------------- /routes/led_drivers/list.json.tsx: -------------------------------------------------------------------------------- 1 | import list from "./list" 2 | export default list 3 | -------------------------------------------------------------------------------- /routes/led_segment_display/list.json.tsx: -------------------------------------------------------------------------------- 1 | import list from "./list" 2 | export default list 3 | -------------------------------------------------------------------------------- /routes/led_with_ic/list.json.tsx: -------------------------------------------------------------------------------- 1 | import list from "./list" 2 | export default list 3 | -------------------------------------------------------------------------------- /routes/leds/list.json.tsx: -------------------------------------------------------------------------------- 1 | import list from "./list" 2 | export default list 3 | -------------------------------------------------------------------------------- /routes/microcontrollers/list.json.tsx: -------------------------------------------------------------------------------- 1 | import list from "./list" 2 | export default list 3 | -------------------------------------------------------------------------------- /routes/mosfets/list.json.tsx: -------------------------------------------------------------------------------- 1 | import list from "./list" 2 | export default list 3 | -------------------------------------------------------------------------------- /routes/oled_display/list.json.tsx: -------------------------------------------------------------------------------- 1 | import list from "./list" 2 | export default list 3 | -------------------------------------------------------------------------------- /routes/potentiometers/list.json.tsx: -------------------------------------------------------------------------------- 1 | import list from "./list" 2 | export default list 3 | -------------------------------------------------------------------------------- /routes/resistors/list.json.tsx: -------------------------------------------------------------------------------- 1 | import list from "./list" 2 | export default list 3 | -------------------------------------------------------------------------------- /routes/switches/list.json.tsx: -------------------------------------------------------------------------------- 1 | import list from "./list" 2 | export default list 3 | -------------------------------------------------------------------------------- /routes/voltage_regulators/list.json.tsx: -------------------------------------------------------------------------------- 1 | import list from "./list" 2 | export default list 3 | -------------------------------------------------------------------------------- /routes/wifi_modules/list.json.tsx: -------------------------------------------------------------------------------- 1 | import list from "./list" 2 | export default list 3 | -------------------------------------------------------------------------------- /scripts/download-cache-fragments.ts: -------------------------------------------------------------------------------- 1 | import { mkdir } from "node:fs/promises" 2 | import { existsSync } from "node:fs" 3 | 4 | const BASE_URL = "https://yaqwsx.github.io/jlcparts/data" 5 | const OUTPUT_DIR = ".buildtmp" 6 | 7 | async function downloadFile(url: string, outputPath: string): Promise { 8 | try { 9 | const response = await fetch(url) 10 | if (!response.ok) { 11 | if (response.status === 404) { 12 | return false 13 | } 14 | throw new Error(`HTTP error! status: ${response.status}`) 15 | } 16 | const fileData = await response.arrayBuffer() 17 | await Bun.write(outputPath, fileData) 18 | console.log(`Downloaded: ${url}`) 19 | return true 20 | } catch (error) { 21 | console.error(`Error downloading ${url}:`, error) 22 | return false 23 | } 24 | } 25 | 26 | async function main() { 27 | // Create output directory if it doesn't exist 28 | if (!existsSync(OUTPUT_DIR)) { 29 | await mkdir(OUTPUT_DIR) 30 | } 31 | 32 | console.log(`Downloading into ${OUTPUT_DIR}`) 33 | // Download initial cache.zip 34 | await downloadFile(`${BASE_URL}/cache.zip`, `${OUTPUT_DIR}/cache.zip`) 35 | 36 | // Download fragments until we get a 404 37 | let index = 1 38 | while (true) { 39 | const paddedIndex = index.toString().padStart(2, "0") 40 | const success = await downloadFile( 41 | `${BASE_URL}/cache.z${paddedIndex}`, 42 | `${OUTPUT_DIR}/cache.z${paddedIndex}`, 43 | ) 44 | 45 | if (!success) { 46 | console.log(`Stopped at index ${paddedIndex} (404 encountered)`) 47 | break 48 | } 49 | index++ 50 | } 51 | } 52 | 53 | main().catch(console.error) 54 | -------------------------------------------------------------------------------- /scripts/setup-7z.ts: -------------------------------------------------------------------------------- 1 | import { mkdir, chmod } from "node:fs/promises" 2 | import { existsSync } from "node:fs" 3 | import { platform, arch } from "node:os" 4 | 5 | const BINARY_DIR = ".bin" 6 | const BINARY_NAME = "7zz" 7 | 8 | // Map of platform-arch combinations to download URLs 9 | const BINARY_URLS: Record = { 10 | "linux-x64": "https://7-zip.org/a/7z2408-linux-x64.tar.xz", 11 | "linux-arm64": "https://7-zip.org/a/7z2408-linux-arm64.tar.xz", 12 | "darwin-x64": "https://7-zip.org/a/7z2408-mac.tar.xz", 13 | "darwin-arm64": "https://7-zip.org/a/7z2408-mac.tar.xz", 14 | } 15 | 16 | async function downloadAndExtract7z() { 17 | const currentPlatform = platform() 18 | const currentArch = arch() 19 | const platformKey = `${currentPlatform}-${currentArch}` 20 | 21 | const downloadUrl = BINARY_URLS[platformKey] 22 | if (!downloadUrl) { 23 | throw new Error(`Unsupported platform: ${platformKey}`) 24 | } 25 | 26 | // Create binary directory if it doesn't exist 27 | if (!existsSync(BINARY_DIR)) { 28 | await mkdir(BINARY_DIR) 29 | } 30 | 31 | const binaryPath = `${BINARY_DIR}/${BINARY_NAME}` 32 | 33 | // Skip if binary already exists 34 | if (existsSync(binaryPath)) { 35 | console.log("7z binary already exists") 36 | return 37 | } 38 | 39 | console.log("Downloading 7z...") 40 | const response = await fetch(downloadUrl) 41 | if (!response.ok) { 42 | throw new Error(`Failed to download: ${response.statusText}`) 43 | } 44 | 45 | // Save the tar.xz file 46 | const tempFile = "7z-temp.tar.xz" 47 | await Bun.write(tempFile, await response.arrayBuffer()) 48 | 49 | // Extract the tar.xz file 50 | console.log("Extracting 7z binary...") 51 | await Bun.spawn(["tar", "xf", tempFile]).exited 52 | 53 | // Move the binary to the right location 54 | await Bun.spawn(["mv", "7zz", binaryPath]).exited 55 | 56 | // Make the binary executable 57 | await chmod(binaryPath, 0o755) 58 | 59 | // Cleanup 60 | await Bun.spawn(["rm", tempFile]).exited 61 | 62 | console.log("7z binary setup complete") 63 | } 64 | 65 | await downloadAndExtract7z() 66 | -------------------------------------------------------------------------------- /scripts/setup-db-optimizations.ts: -------------------------------------------------------------------------------- 1 | import { getBunDatabaseClient, getDbClient } from "lib/db/get-db-client" 2 | import { componentStockIndex } from "lib/db/optimizations/component-stock-index" 3 | import { componentInStockColumn } from "lib/db/optimizations/component-in-stock-column" 4 | import { removeStaleComponents } from "lib/db/optimizations/remove-stale-components" 5 | import { componentCategoryIndex } from "lib/db/optimizations/component-category-index" 6 | import { componentInStockCategoryIndex } from "lib/db/optimizations/component-in-stock-category-index" 7 | import type { DbOptimizationSpec } from "lib/db/optimizations/types" 8 | import { componentSearchFTS } from "lib/db/optimizations/component-search-fts" 9 | import { componentPackageIndex } from "lib/db/optimizations/component-indexes" 10 | 11 | const OPTIMIZATIONS: DbOptimizationSpec[] = [ 12 | componentSearchFTS, 13 | componentPackageIndex, 14 | removeStaleComponents, 15 | componentStockIndex, 16 | componentInStockColumn, 17 | componentCategoryIndex, 18 | componentInStockCategoryIndex, 19 | ] 20 | 21 | async function main() { 22 | const db = getDbClient() 23 | 24 | for (const optimization of OPTIMIZATIONS) { 25 | const isAdded = await optimization.checkIfAdded(db) 26 | 27 | if (!isAdded) { 28 | console.log(`Adding optimization: ${optimization.name}`) 29 | console.log(`Description: ${optimization.description}`) 30 | await optimization.execute(db) 31 | console.log("Successfully added optimization") 32 | } else { 33 | console.log(`Optimization already exists: ${optimization.name}`) 34 | } 35 | } 36 | 37 | await db.destroy() 38 | 39 | const bunDb = getBunDatabaseClient() 40 | console.log("Running VACUUM to optimize database...") 41 | await bunDb.exec("VACUUM") 42 | console.log("VACUUM completed") 43 | bunDb.close() 44 | } 45 | 46 | main().catch(console.error) 47 | -------------------------------------------------------------------------------- /scripts/start-server.ts: -------------------------------------------------------------------------------- 1 | import { createWinterSpecBundleFromDir } from "winterspec/adapters/node" 2 | import {} from "winterspec" 3 | import * as Path from "node:path" 4 | 5 | console.log(`Loading API routes from "./routes"...`) 6 | const winterspecBundle = await createWinterSpecBundleFromDir( 7 | Path.join(import.meta.dir, "../routes"), 8 | ) 9 | 10 | console.log("Starting server on port http://localhost:3065 ...") 11 | Bun.serve({ 12 | fetch: (req) => { 13 | const response = winterspecBundle.makeRequest(req) 14 | return response 15 | }, 16 | routes: { 17 | [`/database/${process.env.DATABASE_DOWNLOAD_TOKEN}`]: () => 18 | new Response(Bun.file("./db.sqlite3")), 19 | }, 20 | port: 3065, 21 | }) 22 | -------------------------------------------------------------------------------- /tests/fixtures/get-test-server.ts: -------------------------------------------------------------------------------- 1 | import { afterEach } from "bun:test" 2 | import defaultAxios from "redaxios" 3 | import type { KyselyDatabaseInstance } from "lib/db/kysely-types" 4 | import * as Path from "node:path" 5 | import { createWinterSpecBundleFromDir } from "winterspec/adapters/node" 6 | 7 | interface TestFixture { 8 | url: string 9 | db: KyselyDatabaseInstance 10 | server: any 11 | axios: typeof defaultAxios 12 | // seed: Awaited> 13 | jane_axios: typeof defaultAxios 14 | } 15 | 16 | const winterspecBundle = await createWinterSpecBundleFromDir( 17 | Path.join(import.meta.dir, "../../routes"), 18 | ) 19 | 20 | export const getTestServer = async ( 21 | options: { env?: Record } = {}, 22 | ): Promise => { 23 | const port = 3001 + Math.floor(Math.random() * 999) 24 | const testInstanceId = Math.random().toString(36).substring(2, 15) 25 | 26 | const fixture = {} as TestFixture 27 | 28 | const server = Bun.serve({ 29 | port, 30 | fetch: (req) => { 31 | const response = winterspecBundle.makeRequest(req) 32 | return response 33 | }, 34 | }) 35 | 36 | const url = `http://127.0.0.1:${port}` 37 | const axios = defaultAxios.create({ 38 | baseURL: url, 39 | }) 40 | 41 | fixture.axios = axios 42 | fixture.url = url 43 | fixture.server = server 44 | 45 | fixture.jane_axios = defaultAxios.create({ 46 | baseURL: url, 47 | headers: {}, 48 | }) 49 | 50 | afterEach(async () => { 51 | await server.stop() 52 | }) 53 | 54 | return fixture 55 | } 56 | -------------------------------------------------------------------------------- /tests/routes/[...anyroute].test.ts: -------------------------------------------------------------------------------- 1 | import { test, expect } from "bun:test" 2 | import { getTestServer } from "tests/fixtures/get-test-server" 3 | 4 | test("GET /not-found", async () => { 5 | const { axios } = await getTestServer() 6 | 7 | try { 8 | await axios.get("/not-found/list?json=true") 9 | } catch (error: any) { 10 | expect(error.status).toBe(404) 11 | expect(error.headers.get("content-type")).toBe("application/json") 12 | expect(error.data.error.error_code).toBe("not_found") 13 | expect(error.data.error.message).toBe("Not Found") 14 | } 15 | }) 16 | -------------------------------------------------------------------------------- /tests/routes/accelerometers/list.test.ts: -------------------------------------------------------------------------------- 1 | import { test, expect } from "bun:test" 2 | import { getTestServer } from "../../fixtures/get-test-server" 3 | 4 | test("GET /accelerometers/list with json param returns accelerometer data", async () => { 5 | const { axios } = await getTestServer() 6 | const res = await axios.get("/accelerometers/list?json=true") 7 | expect(res.data).toHaveProperty("accelerometers") 8 | expect(Array.isArray(res.data.accelerometers)).toBe(true) 9 | if (res.data.accelerometers.length > 0) { 10 | const accel = res.data.accelerometers[0] 11 | expect(accel).toHaveProperty("lcsc") 12 | expect(accel).toHaveProperty("mfr") 13 | expect(accel).toHaveProperty("package") 14 | expect(accel).toHaveProperty("has_spi") 15 | expect(typeof accel.lcsc).toBe("number") 16 | expect(typeof accel.has_spi).toBe("boolean") 17 | expect(typeof accel.has_i2c).toBe("boolean") 18 | } 19 | }) 20 | -------------------------------------------------------------------------------- /tests/routes/analog_multiplexers/list.test.ts: -------------------------------------------------------------------------------- 1 | import { test, expect } from "bun:test" 2 | import { getTestServer } from "tests/fixtures/get-test-server" 3 | 4 | test("GET /analog_multiplexers/list with json param returns multiplexer data", async () => { 5 | const { axios } = await getTestServer() 6 | const res = await axios.get("/analog_multiplexers/list?json=true") 7 | expect(res.data).toHaveProperty("multiplexers") 8 | expect(Array.isArray(res.data.multiplexers)).toBe(true) 9 | if (res.data.multiplexers.length > 0) { 10 | const mux = res.data.multiplexers[0] 11 | expect(mux).toHaveProperty("lcsc") 12 | expect(mux).toHaveProperty("mfr") 13 | expect(mux).toHaveProperty("package") 14 | expect(mux).toHaveProperty("num_channels") 15 | expect(mux).toHaveProperty("has_spi") 16 | expect(typeof mux.lcsc).toBe("number") 17 | expect(typeof mux.has_spi).toBe("boolean") 18 | expect(typeof mux.has_i2c).toBe("boolean") 19 | } 20 | }) 21 | -------------------------------------------------------------------------------- /tests/routes/api/search.test.ts: -------------------------------------------------------------------------------- 1 | import { test, expect } from "bun:test" 2 | import { getTestServer } from "tests/fixtures/get-test-server" 3 | 4 | test("GET /api/search with search query 'ARG05FTC1234N' returns expected components", async () => { 5 | const { axios } = await getTestServer() 6 | const res = await axios.get("/api/search?q=ARG05FTC1234N") 7 | 8 | expect(res.data).toHaveProperty("components") 9 | expect(Array.isArray(res.data.components)).toBe(true) 10 | expect(res.data.components.length).toBeGreaterThan(0) 11 | 12 | // Check for required fields in the first component 13 | const component = res.data.components[0] 14 | expect(component).toHaveProperty("description") 15 | expect(component).toHaveProperty("lcsc") 16 | expect(component).toHaveProperty("mfr") 17 | expect(component.mfr).toContain("ARG05FTC1234N") // More specific check 18 | expect(component).toHaveProperty("package") 19 | expect(component).toHaveProperty("price") 20 | expect(component).toHaveProperty("stock") 21 | }) 22 | 23 | test("GET /api/search with search query '555 Timer' returns expected components", async () => { 24 | const { axios } = await getTestServer() 25 | const res = await axios.get("/api/search?limit=1&q=555%20Timer") 26 | 27 | expect(res.data).toHaveProperty("components") 28 | expect(Array.isArray(res.data.components)).toBe(true) 29 | expect(res.data.components.length).toBeGreaterThan(0) 30 | 31 | // Check for required fields and some basic validation 32 | const component = res.data.components[0] 33 | expect(component).toHaveProperty("description") 34 | expect(component.description.toLowerCase()).toContain("555") 35 | expect(component).toHaveProperty("lcsc") 36 | expect(component).toHaveProperty("mfr") 37 | expect(component).toHaveProperty("package") 38 | expect(component).toHaveProperty("price") 39 | expect(component).toHaveProperty("stock") 40 | }) 41 | 42 | test("GET /api/search with search query 'red led' returns expected components", async () => { 43 | const { axios } = await getTestServer() 44 | const res = await axios.get("/api/search?limit=1&q=red%20led") 45 | 46 | expect(res.data).toHaveProperty("components") 47 | expect(Array.isArray(res.data.components)).toBe(true) 48 | expect(res.data.components.length).toBeGreaterThan(0) 49 | 50 | // Check for required fields and some basic validation 51 | const component = res.data.components[0] 52 | expect(component).toHaveProperty("description") 53 | expect(component.description.toLowerCase()).toContain("red") 54 | expect(component.description.toLowerCase()).toContain("led") 55 | expect(component).toHaveProperty("lcsc") 56 | expect(component).toHaveProperty("mfr") 57 | expect(component).toHaveProperty("package") 58 | expect(component).toHaveProperty("price") 59 | expect(component).toHaveProperty("stock") 60 | }) 61 | -------------------------------------------------------------------------------- /tests/routes/bjt_transistors/list.test.ts: -------------------------------------------------------------------------------- 1 | import { test, expect } from "bun:test" 2 | import { getTestServer } from "../../fixtures/get-test-server" 3 | 4 | test("GET /bjt_transistors/list with json param returns BJT transistor data", async () => { 5 | const { axios } = await getTestServer() 6 | 7 | const res = await axios.get("/bjt_transistors/list?json=true") 8 | 9 | expect(res.data).toHaveProperty("bjt_transistors") 10 | expect(Array.isArray(res.data.bjt_transistors)).toBe(true) 11 | 12 | // Check structure of first BJT transistor if array not empty 13 | if (res.data.bjt_transistors.length > 0) { 14 | const bjt = res.data.bjt_transistors[0] 15 | 16 | // Required fields 17 | expect(bjt).toHaveProperty("lcsc") 18 | expect(bjt).toHaveProperty("mfr") 19 | expect(bjt).toHaveProperty("description") 20 | expect(bjt).toHaveProperty("stock") 21 | expect(bjt).toHaveProperty("price1") 22 | expect(bjt).toHaveProperty("in_stock") 23 | expect(bjt).toHaveProperty("package") 24 | 25 | // BJT specific fields 26 | expect(bjt).toHaveProperty("current_gain") 27 | expect(bjt).toHaveProperty("collector_current") 28 | expect(bjt).toHaveProperty("collector_emitter_voltage") 29 | expect(bjt).toHaveProperty("transition_frequency") 30 | expect(bjt).toHaveProperty("power_dissipation") 31 | expect(bjt).toHaveProperty("temperature_range") 32 | 33 | // Check types 34 | expect(typeof bjt.lcsc).toBe("number") 35 | expect(typeof bjt.mfr).toBe("string") 36 | expect(typeof bjt.description).toBe("string") 37 | expect(typeof bjt.stock).toBe("number") 38 | expect(bjt.price1 === null || typeof bjt.price1 === "number").toBe(true) 39 | expect(typeof bjt.in_stock).toBe("boolean") 40 | expect(typeof bjt.package).toBe("string") 41 | } 42 | }) 43 | 44 | test("GET /bjt_transistors/list with package filter returns filtered data", async () => { 45 | const { axios } = await getTestServer() 46 | 47 | // Test with package filter 48 | const res = await axios.get("/bjt_transistors/list?json=true&package=SOT-23") 49 | 50 | expect(res.data).toHaveProperty("bjt_transistors") 51 | expect(Array.isArray(res.data.bjt_transistors)).toBe(true) 52 | 53 | // Verify all returned BJTs have the specified package 54 | for (const bjt of res.data.bjt_transistors) { 55 | expect(bjt.package).toBe("SOT-23") 56 | } 57 | }) 58 | 59 | test("GET /bjt_transistors/list with current and voltage filters returns filtered data", async () => { 60 | const { axios } = await getTestServer() 61 | 62 | // Test with current and voltage range filters 63 | const res = await axios.get( 64 | "/bjt_transistors/list?json=true&collector_current_min=1&collector_emitter_voltage_min=20", 65 | ) 66 | 67 | expect(res.data).toHaveProperty("bjt_transistors") 68 | expect(Array.isArray(res.data.bjt_transistors)).toBe(true) 69 | 70 | // Verify all returned BJTs meet the criteria 71 | for (const bjt of res.data.bjt_transistors) { 72 | if (bjt.collector_current !== null) { 73 | expect(bjt.collector_current).toBeGreaterThanOrEqual(1) 74 | } 75 | if (bjt.collector_emitter_voltage !== null) { 76 | expect(bjt.collector_emitter_voltage).toBeGreaterThanOrEqual(20) 77 | } 78 | } 79 | }) 80 | -------------------------------------------------------------------------------- /tests/routes/boost_converters/list.test.ts: -------------------------------------------------------------------------------- 1 | import { test, expect } from "bun:test" 2 | import { getTestServer } from "../../fixtures/get-test-server" 3 | 4 | test("GET /boost_converters/list with json param returns converter data", async () => { 5 | const { axios } = await getTestServer() 6 | 7 | const res = await axios.get("/boost_converters/list?json=true") 8 | 9 | expect(res.data).toHaveProperty("boost_converters") 10 | expect(Array.isArray(res.data.boost_converters)).toBe(true) 11 | 12 | if (res.data.boost_converters.length > 0) { 13 | const conv = res.data.boost_converters[0] 14 | expect(conv).toHaveProperty("lcsc") 15 | expect(conv).toHaveProperty("mfr") 16 | expect(conv).toHaveProperty("package") 17 | expect(typeof conv.lcsc).toBe("number") 18 | } 19 | }) 20 | 21 | test("GET /boost_converters/list with package filter returns filtered data", async () => { 22 | const { axios } = await getTestServer() 23 | 24 | const res = await axios.get( 25 | "/boost_converters/list?json=true&package=SOT-23-6", 26 | ) 27 | expect(res.data).toHaveProperty("boost_converters") 28 | for (const conv of res.data.boost_converters) { 29 | expect(conv.package).toBe("SOT-23-6") 30 | } 31 | }) 32 | -------------------------------------------------------------------------------- /tests/routes/capacitors/list.test.ts: -------------------------------------------------------------------------------- 1 | import { test, expect } from "bun:test" 2 | import { getTestServer } from "tests/fixtures/get-test-server" 3 | 4 | test("GET /capacitors/list with json param returns capacitor data", async () => { 5 | const { axios } = await getTestServer() 6 | 7 | const res = await axios.get("/capacitors/list?json=true") 8 | 9 | expect(res.data).toHaveProperty("capacitors") 10 | expect(Array.isArray(res.data.capacitors)).toBe(true) 11 | 12 | // Check structure of first capacitor if array not empty 13 | if (res.data.capacitors.length > 0) { 14 | const capacitor = res.data.capacitors[0] 15 | expect(capacitor).toHaveProperty("lcsc") 16 | expect(capacitor).toHaveProperty("mfr") 17 | expect(capacitor).toHaveProperty("package") 18 | expect(capacitor).toHaveProperty("capacitance") 19 | expect(typeof capacitor.lcsc).toBe("number") 20 | } 21 | }) 22 | 23 | test("GET /capacitors/list with filters returns filtered data", async () => { 24 | const { axios } = await getTestServer() 25 | 26 | // Test with package filter 27 | const res = await axios.get("/capacitors/list?json=true&package=0603") 28 | 29 | expect(res.data).toHaveProperty("capacitors") 30 | expect(Array.isArray(res.data.capacitors)).toBe(true) 31 | 32 | // Verify all returned capacitors have the specified package 33 | for (const capacitor of res.data.capacitors) { 34 | expect(capacitor.package).toBe("0603") 35 | } 36 | }) 37 | 38 | test("GET /capacitors/list with capacitance filter allows small rounding error", async () => { 39 | const { axios } = await getTestServer() 40 | 41 | const res = await axios.get("/capacitors/list?json=true&capacitance=10u") 42 | 43 | expect(res.data).toHaveProperty("capacitors") 44 | expect(Array.isArray(res.data.capacitors)).toBe(true) 45 | 46 | for (const capacitor of res.data.capacitors) { 47 | const delta = Math.abs(capacitor.capacitance - 10e-6) 48 | expect(delta).toBeLessThanOrEqual(10e-6 * 0.0001 + 1e-12) 49 | } 50 | }) 51 | -------------------------------------------------------------------------------- /tests/routes/categories/list.test.ts: -------------------------------------------------------------------------------- 1 | import { test, expect } from "bun:test" 2 | import { getTestServer } from "tests/fixtures/get-test-server" 3 | 4 | test("GET /categories/list with json param returns category data", async () => { 5 | const { axios } = await getTestServer() 6 | const res = await axios.get("/categories/list?json=true") 7 | expect(res.data).toHaveProperty("categories") 8 | expect(Array.isArray(res.data.categories)).toBe(true) 9 | if (res.data.categories.length > 0) { 10 | const category = res.data.categories[0] 11 | expect(category).toHaveProperty("category") 12 | expect(category).toHaveProperty("subcategory") 13 | expect(typeof category.category).toBe("string") 14 | expect(typeof category.subcategory).toBe("string") 15 | } 16 | }) 17 | -------------------------------------------------------------------------------- /tests/routes/components/list.test.ts: -------------------------------------------------------------------------------- 1 | import { test, expect } from "bun:test" 2 | import { getTestServer } from "tests/fixtures/get-test-server" 3 | 4 | test("GET /components/list with json param returns component data", async () => { 5 | const { axios } = await getTestServer() 6 | const res = await axios.get("/components/list?json=true") 7 | expect(res.data).toHaveProperty("components") 8 | expect(Array.isArray(res.data.components)).toBe(true) 9 | }) 10 | -------------------------------------------------------------------------------- /tests/routes/diodes/list.test.ts: -------------------------------------------------------------------------------- 1 | import { test, expect } from "bun:test" 2 | import { getTestServer } from "tests/fixtures/get-test-server" 3 | 4 | test("GET /diodes/list with json param returns diode data", async () => { 5 | const { axios } = await getTestServer() 6 | 7 | const res = await axios.get("/diodes/list?json=true") 8 | 9 | expect(res.data).toHaveProperty("diodes") 10 | expect(Array.isArray(res.data.diodes)).toBe(true) 11 | 12 | // Check structure of first diode if array not empty 13 | if (res.data.diodes.length > 0) { 14 | const diode = res.data.diodes[0] 15 | expect(diode).toHaveProperty("lcsc") 16 | expect(diode).toHaveProperty("mfr") 17 | expect(diode).toHaveProperty("package") 18 | expect(diode).toHaveProperty("diode_type") 19 | expect(typeof diode.lcsc).toBe("number") 20 | } 21 | }) 22 | 23 | test("GET /diodes/list with filters returns filtered data", async () => { 24 | const { axios } = await getTestServer() 25 | 26 | // Test with package filter 27 | const res = await axios.get("/diodes/list?json=true&package=SOD-123") 28 | 29 | expect(res.data).toHaveProperty("diodes") 30 | expect(Array.isArray(res.data.diodes)).toBe(true) 31 | 32 | // Verify all returned diodes have the specified package 33 | for (const diode of res.data.diodes) { 34 | expect(diode.package).toBe("SOD-123") 35 | } 36 | }) 37 | -------------------------------------------------------------------------------- /tests/routes/fuses/list.test.ts: -------------------------------------------------------------------------------- 1 | import { test, expect } from "bun:test" 2 | import { getTestServer } from "../../fixtures/get-test-server" 3 | 4 | test("GET /fuses/list.json with json param returns fuse data", async () => { 5 | const { axios } = await getTestServer() 6 | const res = await axios.get("/fuses/list.json?json=true") 7 | 8 | expect(res.data).toHaveProperty("fuses") 9 | expect(Array.isArray(res.data.fuses)).toBe(true) 10 | 11 | // check structure of first fuse if array not empty 12 | if (res.data.fuses.length > 0) { 13 | const fuse = res.data.fuses[0] 14 | expect(fuse).toHaveProperty("lcsc") 15 | expect(fuse).toHaveProperty("mfr") 16 | expect(fuse).toHaveProperty("package") 17 | expect(fuse).toHaveProperty("description") 18 | expect(fuse).toHaveProperty("stock") 19 | expect(fuse).toHaveProperty("price1") 20 | expect(fuse).toHaveProperty("current_rating") 21 | expect(fuse).toHaveProperty("voltage_rating") 22 | expect(fuse).toHaveProperty("response_time") 23 | expect(fuse).toHaveProperty("is_surface_mount") 24 | expect(fuse).toHaveProperty("is_glass_encased") 25 | expect(fuse).toHaveProperty("is_resettable") 26 | 27 | expect(typeof fuse.lcsc).toBe("number") 28 | expect(typeof fuse.mfr).toBe("string") 29 | expect(typeof fuse.package).toBe("string") 30 | expect(typeof fuse.description).toBe("string") 31 | expect(typeof fuse.stock).toBe("number") 32 | expect(typeof fuse.price1).toBe("number") 33 | expect(typeof fuse.current_rating).toBe("number") 34 | expect(typeof fuse.voltage_rating).toBe("number") 35 | expect(typeof fuse.response_time).toBe("string") 36 | expect(typeof fuse.is_surface_mount).toBe("boolean") 37 | expect(typeof fuse.is_glass_encased).toBe("boolean") 38 | expect(typeof fuse.is_resettable).toBe("boolean") 39 | } 40 | }) 41 | 42 | test("GET /fuses/list.json with filters returns filtered data", async () => { 43 | const { axios } = await getTestServer() 44 | 45 | // Test with package filter 46 | const res = await axios.get("/fuses/list.json?json=true&package=AXIAL") 47 | expect(res.data).toHaveProperty("fuses") 48 | expect(Array.isArray(res.data.fuses)).toBe(true) 49 | 50 | // Verify all returned fuses have the specified package 51 | for (const fuse of res.data.fuses) { 52 | expect(fuse.package).toBe("AXIAL") 53 | } 54 | 55 | // Test with current rating filter 56 | const currentRes = await axios.get( 57 | "/fuses/list.json?json=true¤t_rating=1", 58 | ) 59 | expect(currentRes.data).toHaveProperty("fuses") 60 | expect(Array.isArray(currentRes.data.fuses)).toBe(true) 61 | 62 | // Verify all returned fuses have the specified current rating 63 | for (const fuse of currentRes.data.fuses) { 64 | expect(fuse.current_rating).toBe(1) 65 | } 66 | 67 | // Test with response time filter 68 | const timeRes = await axios.get( 69 | "/fuses/list.json?json=true&response_time=Fast", 70 | ) 71 | expect(timeRes.data).toHaveProperty("fuses") 72 | expect(Array.isArray(timeRes.data.fuses)).toBe(true) 73 | 74 | // Verify all returned fuses have the specified response time 75 | for (const fuse of timeRes.data.fuses) { 76 | expect(fuse.response_time).toBe("Fast") 77 | } 78 | }) 79 | -------------------------------------------------------------------------------- /tests/routes/gas_sensors/list.test.ts: -------------------------------------------------------------------------------- 1 | import { test, expect } from "bun:test" 2 | import { getTestServer } from "../../fixtures/get-test-server" 3 | 4 | test("GET /gas_sensors/list with json param returns gas sensor data", async () => { 5 | const { axios } = await getTestServer() 6 | const res = await axios.get("/gas_sensors/list?json=true") 7 | expect(res.data).toHaveProperty("gas_sensors") 8 | expect(Array.isArray(res.data.gas_sensors)).toBe(true) 9 | if (res.data.gas_sensors.length > 0) { 10 | const sensor = res.data.gas_sensors[0] 11 | expect(sensor).toHaveProperty("lcsc") 12 | expect(sensor).toHaveProperty("mfr") 13 | expect(sensor).toHaveProperty("package") 14 | expect(sensor).toHaveProperty("measures_oxygen") 15 | expect(typeof sensor.measures_oxygen).toBe("boolean") 16 | } 17 | }) 18 | 19 | test("GET /gas_sensors/list with measurement filter returns filtered data", async () => { 20 | const { axios } = await getTestServer() 21 | const res = await axios.get("/gas_sensors/list", { 22 | params: { 23 | json: true, 24 | measurement: "oxygen", 25 | }, 26 | }) 27 | 28 | expect(res.data).toHaveProperty("gas_sensors") 29 | expect(Array.isArray(res.data.gas_sensors)).toBe(true) 30 | 31 | for (const sensor of res.data.gas_sensors) { 32 | expect(sensor.measures_oxygen).toBe(true) 33 | } 34 | }) 35 | -------------------------------------------------------------------------------- /tests/routes/gyroscopes/list.test.ts: -------------------------------------------------------------------------------- 1 | import { test, expect } from "bun:test" 2 | import { getTestServer } from "../../fixtures/get-test-server" 3 | 4 | test("GET /gyroscopes/list with json param returns gyroscope data", async () => { 5 | const { axios } = await getTestServer() 6 | const res = await axios.get("/gyroscopes/list?json=true") 7 | expect(res.data).toHaveProperty("gyroscopes") 8 | expect(Array.isArray(res.data.gyroscopes)).toBe(true) 9 | if (res.data.gyroscopes.length > 0) { 10 | const gyro = res.data.gyroscopes[0] 11 | expect(gyro).toHaveProperty("lcsc") 12 | expect(gyro).toHaveProperty("mfr") 13 | expect(gyro).toHaveProperty("package") 14 | expect(gyro).toHaveProperty("has_spi") 15 | expect(typeof gyro.lcsc).toBe("number") 16 | expect(typeof gyro.has_spi).toBe("boolean") 17 | expect(typeof gyro.has_i2c).toBe("boolean") 18 | } 19 | }) 20 | -------------------------------------------------------------------------------- /tests/routes/headers/list.test.ts: -------------------------------------------------------------------------------- 1 | import { test, expect } from "bun:test" 2 | import { getTestServer } from "tests/fixtures/get-test-server" 3 | 4 | test("GET /headers/list with json param returns header data", async () => { 5 | const { axios } = await getTestServer() 6 | 7 | const res = await axios.get("/headers/list", { 8 | params: { 9 | json: true, 10 | }, 11 | }) 12 | 13 | expect(res.data).toHaveProperty("headers") 14 | expect(Array.isArray(res.data.headers)).toBe(true) 15 | 16 | // Check structure of first header if array not empty 17 | if (res.data.headers.length > 0) { 18 | const header = res.data.headers[0] 19 | expect(header).toHaveProperty("lcsc") 20 | expect(header).toHaveProperty("mfr") 21 | expect(header).toHaveProperty("package") 22 | expect(header).toHaveProperty("pitch_mm") 23 | expect(typeof header.lcsc).toBe("number") 24 | } 25 | }) 26 | 27 | test("GET /headers/list with filters returns filtered data", async () => { 28 | const { axios } = await getTestServer() 29 | 30 | // Test with gender filter 31 | const res = await axios.get("/headers/list", { 32 | params: { 33 | json: true, 34 | gender: "male", 35 | }, 36 | }) 37 | 38 | expect(res.data).toHaveProperty("headers") 39 | expect(Array.isArray(res.data.headers)).toBe(true) 40 | 41 | // Verify all returned headers have the specified gender 42 | for (const header of res.data.headers) { 43 | expect(header.gender).toBe("male") 44 | } 45 | }) 46 | -------------------------------------------------------------------------------- /tests/routes/health.test.ts: -------------------------------------------------------------------------------- 1 | import { test, expect } from "bun:test" 2 | import { getTestServer } from "tests/fixtures/get-test-server" 3 | 4 | test("GET /health", async () => { 5 | const { axios, server } = await getTestServer() 6 | 7 | const res = await axios.get("/health") 8 | 9 | expect(res.data.ok).toBe(true) 10 | }) 11 | -------------------------------------------------------------------------------- /tests/routes/lcd_display/list.test.ts: -------------------------------------------------------------------------------- 1 | import { test, expect } from "bun:test" 2 | import { getTestServer } from "../../fixtures/get-test-server" 3 | 4 | test("GET /lcd_display/list.json with json param returns LCD Display data", async () => { 5 | const { axios } = await getTestServer() 6 | const res = await axios.get("/lcd_display/list.json?json=true") 7 | 8 | expect(res.data).toHaveProperty("lcd_displays") 9 | expect(Array.isArray(res.data.lcd_displays)).toBe(true) 10 | 11 | // check structure of first LCD Display if array not empty 12 | if (res.data.lcd_displays.length > 0) { 13 | const lcdDisplay = res.data.lcd_displays[0] 14 | expect(lcdDisplay).toHaveProperty("lcsc") 15 | expect(lcdDisplay).toHaveProperty("mfr") 16 | expect(lcdDisplay).toHaveProperty("package") 17 | expect(lcdDisplay).toHaveProperty("description") 18 | expect(lcdDisplay).toHaveProperty("stock") 19 | expect(lcdDisplay).toHaveProperty("price1") 20 | expect(lcdDisplay).toHaveProperty("display_size") 21 | 22 | expect(typeof lcdDisplay.lcsc).toBe("number") 23 | expect(typeof lcdDisplay.mfr).toBe("string") 24 | expect(typeof lcdDisplay.package).toBe("string") 25 | expect(typeof lcdDisplay.description).toBe("string") 26 | expect(typeof lcdDisplay.stock).toBe("number") 27 | expect(typeof lcdDisplay.price1).toBe("number") 28 | 29 | if (lcdDisplay.display_size) { 30 | expect(typeof lcdDisplay.display_size).toBe("string") 31 | } 32 | if (lcdDisplay.resolution) { 33 | expect(typeof lcdDisplay.resolution).toBe("string") 34 | } 35 | if (lcdDisplay.display_type) { 36 | expect(typeof lcdDisplay.display_type).toBe("string") 37 | } 38 | } 39 | }) 40 | 41 | test("GET /lcd_display/list.json with filters returns filtered data", async () => { 42 | const { axios } = await getTestServer() 43 | 44 | // Test with package filter 45 | const res = await axios.get("/lcd_display/list.json?json=true&package=COB") 46 | expect(res.data).toHaveProperty("lcd_displays") 47 | expect(Array.isArray(res.data.lcd_displays)).toBe(true) 48 | 49 | // Verify all returned LCD Displays have the specified package 50 | for (const lcdDisplay of res.data.lcd_displays) { 51 | expect(lcdDisplay.package).toBe("COB") 52 | } 53 | 54 | // Test with display type filter 55 | const typeRes = await axios.get( 56 | "/lcd_display/list.json?json=true&display_type=TFT", 57 | ) 58 | expect(typeRes.data).toHaveProperty("lcd_displays") 59 | expect(Array.isArray(typeRes.data.lcd_displays)).toBe(true) 60 | 61 | // Verify all returned LCD Displays have the specified display type 62 | for (const lcdDisplay of typeRes.data.lcd_displays) { 63 | expect(lcdDisplay.display_type).toBe("TFT") 64 | } 65 | }) 66 | -------------------------------------------------------------------------------- /tests/routes/led_dot_matrix_display/list.test.ts: -------------------------------------------------------------------------------- 1 | import { test, expect } from "bun:test" 2 | import { getTestServer } from "../../fixtures/get-test-server" 3 | 4 | test("GET /led_dot_matrix_display/list.json with json param returns LED Dot Matrix data", async () => { 5 | const { axios } = await getTestServer() 6 | const res = await axios.get("/led_dot_matrix_display/list.json?json=true") 7 | 8 | expect(res.data).toHaveProperty("led_dot_matrix_displays") 9 | expect(Array.isArray(res.data.led_dot_matrix_displays)).toBe(true) 10 | 11 | // check structure of first LED Matrix if array not empty 12 | if (res.data.led_dot_matrix_displays.length > 0) { 13 | const ledMatrix = res.data.led_dot_matrix_displays[0] 14 | expect(ledMatrix).toHaveProperty("lcsc") 15 | expect(ledMatrix).toHaveProperty("mfr") 16 | expect(ledMatrix).toHaveProperty("package") 17 | expect(ledMatrix).toHaveProperty("description") 18 | expect(ledMatrix).toHaveProperty("stock") 19 | expect(ledMatrix).toHaveProperty("price1") 20 | expect(ledMatrix).toHaveProperty("matrix_size") 21 | 22 | expect(typeof ledMatrix.lcsc).toBe("number") 23 | expect(typeof ledMatrix.mfr).toBe("string") 24 | expect(typeof ledMatrix.package).toBe("string") 25 | expect(typeof ledMatrix.description).toBe("string") 26 | expect(typeof ledMatrix.stock).toBe("number") 27 | expect(typeof ledMatrix.price1).toBe("number") 28 | 29 | if (ledMatrix.matrix_size) { 30 | expect(typeof ledMatrix.matrix_size).toBe("string") 31 | } 32 | if (ledMatrix.color) { 33 | expect(typeof ledMatrix.color).toBe("string") 34 | } 35 | } 36 | }) 37 | 38 | test("GET /led_dot_matrix_display/list.json with filters returns filtered data", async () => { 39 | const { axios } = await getTestServer() 40 | 41 | // Test with package filter 42 | const res = await axios.get( 43 | "/led_dot_matrix_display/list.json?json=true&package=DIP", 44 | ) 45 | expect(res.data).toHaveProperty("led_dot_matrix_displays") 46 | expect(Array.isArray(res.data.led_dot_matrix_displays)).toBe(true) 47 | 48 | // Verify all returned LED Matrices have the specified package 49 | for (const ledMatrix of res.data.led_dot_matrix_displays) { 50 | expect(ledMatrix.package).toBe("DIP") 51 | } 52 | 53 | // Test with color filter 54 | const colorRes = await axios.get( 55 | "/led_dot_matrix_display/list.json?json=true&color=Red", 56 | ) 57 | expect(colorRes.data).toHaveProperty("led_dot_matrix_displays") 58 | expect(Array.isArray(colorRes.data.led_dot_matrix_displays)).toBe(true) 59 | 60 | // Verify all returned LED Matrices have the specified color 61 | for (const ledMatrix of colorRes.data.led_dot_matrix_displays) { 62 | expect(ledMatrix.color).toBe("Red") 63 | } 64 | }) 65 | -------------------------------------------------------------------------------- /tests/routes/led_drivers/list.test.ts: -------------------------------------------------------------------------------- 1 | import { test, expect } from "bun:test" 2 | import { getTestServer } from "../../fixtures/get-test-server" 3 | 4 | test("GET /led_drivers/list with json param returns LED driver data", async () => { 5 | const { axios } = await getTestServer() 6 | 7 | const res = await axios.get("/led_drivers/list?json=true") 8 | 9 | expect(res.data).toHaveProperty("led_drivers") 10 | expect(Array.isArray(res.data.led_drivers)).toBe(true) 11 | 12 | // Check structure of first LED driver if array not empty 13 | if (res.data.led_drivers.length > 0) { 14 | const driver = res.data.led_drivers[0] 15 | expect(driver).toHaveProperty("lcsc") 16 | expect(driver).toHaveProperty("mfr") 17 | expect(driver).toHaveProperty("description") 18 | expect(driver).toHaveProperty("stock") 19 | expect(driver).toHaveProperty("price1") 20 | expect(driver).toHaveProperty("in_stock") 21 | expect(driver).toHaveProperty("package") 22 | expect(driver).toHaveProperty("supply_voltage_min") 23 | expect(driver).toHaveProperty("supply_voltage_max") 24 | expect(driver).toHaveProperty("output_current_max") 25 | expect(driver).toHaveProperty("channel_count") 26 | expect(driver).toHaveProperty("dimming_method") 27 | expect(driver).toHaveProperty("efficiency_percent") 28 | expect(typeof driver.lcsc).toBe("number") 29 | } 30 | }) 31 | 32 | test("GET /led_drivers/list with filters returns filtered data", async () => { 33 | const { axios } = await getTestServer() 34 | 35 | // Test with package filter 36 | const res = await axios.get("/led_drivers/list?json=true&package=SOP-8") 37 | 38 | expect(res.data).toHaveProperty("led_drivers") 39 | expect(Array.isArray(res.data.led_drivers)).toBe(true) 40 | 41 | // Verify all returned LED drivers have the specified package 42 | for (const driver of res.data.led_drivers) { 43 | expect(driver.package).toBe("SOP-8") 44 | } 45 | }) 46 | 47 | test("GET /led_drivers/list with voltage filter returns filtered data", async () => { 48 | const { axios } = await getTestServer() 49 | 50 | // Test with voltage range filter 51 | const res = await axios.get( 52 | "/led_drivers/list?json=true&supply_voltage_min=3.3&supply_voltage_max=5", 53 | ) 54 | 55 | expect(res.data).toHaveProperty("led_drivers") 56 | expect(Array.isArray(res.data.led_drivers)).toBe(true) 57 | 58 | // Verify all returned LED drivers are within voltage range 59 | for (const driver of res.data.led_drivers) { 60 | if ( 61 | driver.supply_voltage_min !== null && 62 | driver.supply_voltage_max !== null 63 | ) { 64 | expect(driver.supply_voltage_min).toBeGreaterThanOrEqual(3.3) 65 | expect(driver.supply_voltage_max).toBeLessThanOrEqual(5) 66 | } 67 | } 68 | }) 69 | -------------------------------------------------------------------------------- /tests/routes/led_segment_display/list.test.ts: -------------------------------------------------------------------------------- 1 | import { test, expect } from "bun:test" 2 | import { getTestServer } from "../../fixtures/get-test-server" 3 | 4 | test("GET /led_segment_display/list.json with json param returns LED Segment data", async () => { 5 | const { axios } = await getTestServer() 6 | const res = await axios.get("/led_segment_display/list.json?json=true") 7 | 8 | expect(res.data).toHaveProperty("led_segment_displays") 9 | expect(Array.isArray(res.data.led_segment_displays)).toBe(true) 10 | 11 | // Check structure of first LED Segment if array not empty 12 | if (res.data.led_segment_displays.length > 0) { 13 | const ledSegment = res.data.led_segment_displays[0] 14 | expect(ledSegment).toHaveProperty("lcsc") 15 | expect(ledSegment).toHaveProperty("mfr") 16 | expect(ledSegment).toHaveProperty("package") 17 | expect(ledSegment).toHaveProperty("description") 18 | expect(ledSegment).toHaveProperty("stock") 19 | expect(ledSegment).toHaveProperty("price1") 20 | expect(typeof ledSegment.lcsc).toBe("number") 21 | expect(typeof ledSegment.mfr).toBe("string") 22 | expect(typeof ledSegment.package).toBe("string") 23 | expect(typeof ledSegment.description).toBe("string") 24 | expect(typeof ledSegment.stock).toBe("number") 25 | expect(typeof ledSegment.price1).toBe("number") 26 | 27 | // Check optional properties if they exist 28 | if ("positions" in ledSegment) { 29 | expect(typeof ledSegment.positions).toBe("string") 30 | } 31 | if ("type" in ledSegment) { 32 | expect(typeof ledSegment.type).toBe("string") 33 | } 34 | } 35 | }) 36 | 37 | test("GET /led_segment_display/list.json with filters returns filtered data", async () => { 38 | const { axios } = await getTestServer() 39 | 40 | // Test with package filter 41 | const res = await axios.get( 42 | "/led_segment_display/list.json?json=true&package=Plugin", 43 | ) 44 | expect(res.data).toHaveProperty("led_segment_displays") 45 | expect(Array.isArray(res.data.led_segment_displays)).toBe(true) 46 | 47 | // Verify all returned LED Segments have the specified package 48 | for (const ledSegment of res.data.led_segment_displays) { 49 | expect(ledSegment.package).toBe("Plugin") 50 | } 51 | 52 | // Test with type filter 53 | const typeRes = await axios.get( 54 | "/led_segment_display/list.json?json=true&type=Common Cathode", 55 | ) 56 | expect(typeRes.data).toHaveProperty("led_segment_displays") 57 | expect(Array.isArray(typeRes.data.led_segment_displays)).toBe(true) 58 | 59 | // Verify all returned LED Segments have the specified type 60 | for (const ledSegment of typeRes.data.led_segment_displays) { 61 | expect(ledSegment.type).toBe("Common Cathode") 62 | } 63 | }) 64 | -------------------------------------------------------------------------------- /tests/routes/led_with_ic/list.test.ts: -------------------------------------------------------------------------------- 1 | import { test, expect } from "bun:test" 2 | import { getTestServer } from "../../fixtures/get-test-server" 3 | 4 | test("GET /led_with_ic/list.json with json param returns LED with IC data", async () => { 5 | const { axios } = await getTestServer() 6 | 7 | const res = await axios.get("/led_with_ic/list.json?json=true") 8 | 9 | expect(res.data).toHaveProperty("leds_with_ic") 10 | expect(Array.isArray(res.data.leds_with_ic)).toBe(true) 11 | 12 | // Check structure of first LED with IC if array not empty 13 | if (res.data.leds_with_ic.length > 0) { 14 | const ledWithIC = res.data.leds_with_ic[0] 15 | expect(ledWithIC).toHaveProperty("lcsc") 16 | expect(ledWithIC).toHaveProperty("mfr") 17 | expect(ledWithIC).toHaveProperty("package") 18 | expect(ledWithIC).toHaveProperty("description") 19 | expect(ledWithIC).toHaveProperty("stock") 20 | expect(ledWithIC).toHaveProperty("price1") 21 | 22 | expect(typeof ledWithIC.lcsc).toBe("number") 23 | expect(typeof ledWithIC.mfr).toBe("string") 24 | expect(typeof ledWithIC.package).toBe("string") 25 | expect(typeof ledWithIC.description).toBe("string") 26 | expect(typeof ledWithIC.stock).toBe("number") 27 | expect(typeof ledWithIC.price1).toBe("number") 28 | } 29 | }) 30 | 31 | test("GET /led_with_ic/list.json with filters returns filtered data", async () => { 32 | const { axios } = await getTestServer() 33 | 34 | // Test with package filter 35 | const res = await axios.get("/led_with_ic/list.json?json=true&package=0603") 36 | 37 | expect(res.data).toHaveProperty("leds_with_ic") 38 | expect(Array.isArray(res.data.leds_with_ic)).toBe(true) 39 | 40 | // Verify all returned LEDs with IC have the specified package 41 | for (const ledWithIC of res.data.leds_with_ic) { 42 | expect(ledWithIC.package).toBe("0603") 43 | } 44 | 45 | // Test with color filter 46 | const colorRes = await axios.get("/led_with_ic/list.json?json=true&color=RED") 47 | 48 | expect(colorRes.data).toHaveProperty("leds_with_ic") 49 | expect(Array.isArray(colorRes.data.leds_with_ic)).toBe(true) 50 | 51 | // Verify all returned LEDs with IC have the specified color 52 | for (const ledWithIC of colorRes.data.leds_with_ic) { 53 | expect(ledWithIC.color).toBe("RED") 54 | } 55 | }) 56 | -------------------------------------------------------------------------------- /tests/routes/leds/list.test.ts: -------------------------------------------------------------------------------- 1 | import { test, expect } from "bun:test" 2 | import { getTestServer } from "tests/fixtures/get-test-server" 3 | 4 | test("GET /leds/list with json param returns LED data", async () => { 5 | const { axios } = await getTestServer() 6 | 7 | const res = await axios.get("/leds/list?json=true") 8 | 9 | expect(res.data).toHaveProperty("leds") 10 | expect(Array.isArray(res.data.leds)).toBe(true) 11 | 12 | // Check structure of first LED if array not empty 13 | if (res.data.leds.length > 0) { 14 | const led = res.data.leds[0] 15 | expect(led).toHaveProperty("lcsc") 16 | expect(led).toHaveProperty("mfr") 17 | expect(led).toHaveProperty("package") 18 | expect(led).toHaveProperty("color") 19 | expect(typeof led.lcsc).toBe("number") 20 | } 21 | }) 22 | 23 | test("GET /leds/list with filters returns filtered data", async () => { 24 | const { axios } = await getTestServer() 25 | 26 | // Test with package filter 27 | const res = await axios.get("/leds/list?json=true&package=0603") 28 | 29 | expect(res.data).toHaveProperty("leds") 30 | expect(Array.isArray(res.data.leds)).toBe(true) 31 | 32 | // Verify all returned LEDs have the specified package 33 | for (const led of res.data.leds) { 34 | expect(led.package).toBe("0603") 35 | } 36 | }) 37 | -------------------------------------------------------------------------------- /tests/routes/microcontrollers/list.test.ts: -------------------------------------------------------------------------------- 1 | import { test, expect } from "bun:test" 2 | import { getTestServer } from "tests/fixtures/get-test-server" 3 | 4 | test("GET /microcontrollers/list with json param returns microcontroller data", async () => { 5 | const { axios } = await getTestServer() 6 | const res = await axios.get("/microcontrollers/list?json=true") 7 | expect(res.data).toHaveProperty("microcontrollers") 8 | expect(Array.isArray(res.data.microcontrollers)).toBe(true) 9 | if (res.data.microcontrollers.length > 0) { 10 | const mcu = res.data.microcontrollers[0] 11 | expect(mcu).toHaveProperty("lcsc") 12 | expect(mcu).toHaveProperty("mfr") 13 | expect(mcu).toHaveProperty("package") 14 | expect(mcu).toHaveProperty("cpu_core") 15 | expect(mcu).toHaveProperty("cpu_speed_hz") 16 | expect(mcu).toHaveProperty("has_uart") 17 | expect(typeof mcu.lcsc).toBe("number") 18 | expect(typeof mcu.has_uart).toBe("boolean") 19 | expect(typeof mcu.has_i2c).toBe("boolean") 20 | } 21 | }) 22 | -------------------------------------------------------------------------------- /tests/routes/mosfets/list.test.ts: -------------------------------------------------------------------------------- 1 | import { test, expect } from "bun:test" 2 | import { getTestServer } from "../../fixtures/get-test-server" 3 | 4 | test("GET /mosfets/list with json param returns MOSFET data", async () => { 5 | const { axios } = await getTestServer() 6 | 7 | const res = await axios.get("/mosfets/list?json=true") 8 | 9 | expect(res.data).toHaveProperty("mosfets") 10 | expect(Array.isArray(res.data.mosfets)).toBe(true) 11 | 12 | // Check structure of first MOSFET if array not empty 13 | if (res.data.mosfets.length > 0) { 14 | const mosfet = res.data.mosfets[0] 15 | expect(mosfet).toHaveProperty("lcsc") 16 | expect(mosfet).toHaveProperty("mfr") 17 | expect(mosfet).toHaveProperty("description") 18 | expect(mosfet).toHaveProperty("stock") 19 | expect(mosfet).toHaveProperty("price1") 20 | expect(mosfet).toHaveProperty("in_stock") 21 | expect(mosfet).toHaveProperty("package") 22 | expect(mosfet).toHaveProperty("drain_source_voltage") 23 | expect(mosfet).toHaveProperty("continuous_drain_current") 24 | expect(mosfet).toHaveProperty("gate_threshold_voltage") 25 | expect(mosfet).toHaveProperty("power_dissipation") 26 | expect(typeof mosfet.lcsc).toBe("number") 27 | } 28 | }) 29 | 30 | test("GET /mosfets/list with filters returns filtered data", async () => { 31 | const { axios } = await getTestServer() 32 | 33 | // Test with package filter 34 | const res = await axios.get("/mosfets/list?json=true&package=SOT-23") 35 | 36 | expect(res.data).toHaveProperty("mosfets") 37 | expect(Array.isArray(res.data.mosfets)).toBe(true) 38 | 39 | // Verify all returned MOSFETs have the specified package 40 | for (const mosfet of res.data.mosfets) { 41 | expect(mosfet.package).toBe("SOT-23") 42 | } 43 | }) 44 | 45 | test("GET /mosfets/list with voltage filter returns filtered data", async () => { 46 | const { axios } = await getTestServer() 47 | 48 | // Test with voltage range filter 49 | const res = await axios.get( 50 | "/mosfets/list?json=true&drain_source_voltage_min=20&drain_source_voltage_max=60", 51 | ) 52 | 53 | expect(res.data).toHaveProperty("mosfets") 54 | expect(Array.isArray(res.data.mosfets)).toBe(true) 55 | 56 | // Verify all returned MOSFETs are within voltage range 57 | for (const mosfet of res.data.mosfets) { 58 | if (mosfet.drain_source_voltage !== null) { 59 | expect(mosfet.drain_source_voltage).toBeGreaterThanOrEqual(20) 60 | expect(mosfet.drain_source_voltage).toBeLessThanOrEqual(60) 61 | } 62 | } 63 | }) 64 | -------------------------------------------------------------------------------- /tests/routes/oled_display/list.test.ts: -------------------------------------------------------------------------------- 1 | import { test, expect } from "bun:test" 2 | import { getTestServer } from "../../fixtures/get-test-server" 3 | 4 | test("GET /oled_display/list.json with json param returns OLED Display data", async () => { 5 | const { axios } = await getTestServer() 6 | 7 | const res = await axios.get("/oled_display/list.json?json=true") 8 | 9 | expect(res.data).toHaveProperty("oled_displays") 10 | expect(Array.isArray(res.data.oled_displays)).toBe(true) 11 | 12 | // check structure of first OLED Display if array not empty 13 | if (res.data.oled_displays.length > 0) { 14 | const oledDisplay = res.data.oled_displays[0] 15 | expect(oledDisplay).toHaveProperty("lcsc") 16 | expect(oledDisplay).toHaveProperty("mfr") 17 | expect(oledDisplay).toHaveProperty("package") 18 | expect(oledDisplay).toHaveProperty("description") 19 | expect(oledDisplay).toHaveProperty("stock") 20 | expect(oledDisplay).toHaveProperty("price1") 21 | expect(oledDisplay).toHaveProperty("protocol") 22 | 23 | expect(typeof oledDisplay.lcsc).toBe("number") 24 | expect(typeof oledDisplay.mfr).toBe("string") 25 | expect(typeof oledDisplay.package).toBe("string") 26 | expect(typeof oledDisplay.description).toBe("string") 27 | expect(typeof oledDisplay.stock).toBe("number") 28 | expect(typeof oledDisplay.price1).toBe("number") 29 | if (oledDisplay.protocol) { 30 | expect(typeof oledDisplay.protocol).toBe("string") 31 | } 32 | } 33 | }) 34 | 35 | test("GET /oled_display/list.json with filters returns filtered data", async () => { 36 | const { axios } = await getTestServer() 37 | 38 | // Test with package filter 39 | const res = await axios.get("/oled_display/list.json?json=true&package=QFN32") 40 | 41 | expect(res.data).toHaveProperty("oled_displays") 42 | expect(Array.isArray(res.data.oled_displays)).toBe(true) 43 | 44 | // Verify all returned OLED Displays have the specified package 45 | for (const oledDisplay of res.data.oled_displays) { 46 | expect(oledDisplay.package).toBe("QFN32") 47 | } 48 | 49 | // Test with protocol filter 50 | const protocolRes = await axios.get( 51 | "/oled_display/list.json?json=true&protocol=I2C", 52 | ) 53 | 54 | expect(protocolRes.data).toHaveProperty("oled_displays") 55 | expect(Array.isArray(protocolRes.data.oled_displays)).toBe(true) 56 | 57 | // Verify all returned OLED Displays have the specified protocol 58 | for (const oledDisplay of protocolRes.data.oled_displays) { 59 | expect(oledDisplay.protocol).toBe("I2C") 60 | } 61 | }) 62 | -------------------------------------------------------------------------------- /tests/routes/resistors/list.test.ts: -------------------------------------------------------------------------------- 1 | import { test, expect } from "bun:test" 2 | import { getTestServer } from "tests/fixtures/get-test-server" 3 | 4 | test("GET /resistors/list with json param returns resistor data", async () => { 5 | const { axios } = await getTestServer() 6 | 7 | const res = await axios.get("/resistors/list?json=true") 8 | 9 | expect(res.data).toHaveProperty("resistors") 10 | expect(Array.isArray(res.data.resistors)).toBe(true) 11 | 12 | // Check structure of first resistor if array not empty 13 | if (res.data.resistors.length > 0) { 14 | const resistor = res.data.resistors[0] 15 | expect(resistor).toHaveProperty("lcsc") 16 | expect(resistor).toHaveProperty("mfr") 17 | expect(resistor).toHaveProperty("package") 18 | expect(resistor).toHaveProperty("resistance") 19 | expect(typeof resistor.lcsc).toBe("number") 20 | } 21 | }) 22 | 23 | test("GET /resistors/list with filters returns filtered data", async () => { 24 | const { axios } = await getTestServer() 25 | 26 | // Test with package filter 27 | const res = await axios.get("/resistors/list?json=true&package=0603") 28 | 29 | expect(res.data).toHaveProperty("resistors") 30 | expect(Array.isArray(res.data.resistors)).toBe(true) 31 | 32 | // Verify all returned resistors have the specified package 33 | for (const resistor of res.data.resistors) { 34 | expect(resistor.package).toBe("0603") 35 | } 36 | }) 37 | 38 | test("GET /resistors/list with resistance filter allows small rounding error", async () => { 39 | const { axios } = await getTestServer() 40 | 41 | const res = await axios.get("/resistors/list?json=true&resistance=1k") 42 | 43 | expect(res.data).toHaveProperty("resistors") 44 | expect(Array.isArray(res.data.resistors)).toBe(true) 45 | 46 | for (const resistor of res.data.resistors) { 47 | const delta = Math.abs(resistor.resistance - 1000) 48 | expect(delta).toBeLessThanOrEqual(1000 * 0.0001 + 1e-9) 49 | } 50 | }) 51 | -------------------------------------------------------------------------------- /tests/routes/switches/list.test.ts: -------------------------------------------------------------------------------- 1 | import { test, expect } from "bun:test" 2 | import { getTestServer } from "tests/fixtures/get-test-server" 3 | 4 | test("GET /switches/list with json param returns switch data", async () => { 5 | const { axios } = await getTestServer() 6 | 7 | const res = await axios.get("/switches/list?json=true") 8 | 9 | expect(res.data).toHaveProperty("switches") 10 | expect(Array.isArray(res.data.switches)).toBe(true) 11 | 12 | if (res.data.switches.length > 0) { 13 | const sw = res.data.switches[0] 14 | expect(sw).toHaveProperty("lcsc") 15 | expect(sw).toHaveProperty("mfr") 16 | expect(sw).toHaveProperty("package") 17 | expect(sw).toHaveProperty("pin_count") 18 | expect(sw).toHaveProperty("switch_type") 19 | expect(typeof sw.lcsc).toBe("number") 20 | } 21 | }) 22 | 23 | test("GET /switches/list with filters returns filtered data", async () => { 24 | const { axios } = await getTestServer() 25 | 26 | const res = await axios.get( 27 | "/switches/list?json=true&circuit=SPDT&package=SMD&pin_count=2", 28 | ) 29 | 30 | expect(res.data).toHaveProperty("switches") 31 | expect(Array.isArray(res.data.switches)).toBe(true) 32 | 33 | for (const sw of res.data.switches) { 34 | if (sw.circuit) { 35 | expect(sw.circuit).toBe("SPDT") 36 | } 37 | if (sw.package) { 38 | expect(sw.package).toBe("SMD") 39 | } 40 | if (sw.pin_count) { 41 | expect(sw.pin_count).toBe(2) 42 | } 43 | } 44 | }) 45 | -------------------------------------------------------------------------------- /tests/routes/voltage_regulators/list.test.ts: -------------------------------------------------------------------------------- 1 | import { test, expect } from "bun:test" 2 | import { getTestServer } from "tests/fixtures/get-test-server" 3 | 4 | test("GET /voltage_regulators/list with json param returns regulator data", async () => { 5 | const { axios } = await getTestServer() 6 | const res = await axios.get("/voltage_regulators/list?json=true") 7 | expect(res.data).toHaveProperty("regulators") 8 | expect(Array.isArray(res.data.regulators)).toBe(true) 9 | if (res.data.regulators.length > 0) { 10 | const regulator = res.data.regulators[0] 11 | expect(regulator).toHaveProperty("lcsc") 12 | expect(regulator).toHaveProperty("mfr") 13 | expect(regulator).toHaveProperty("package") 14 | expect(regulator).toHaveProperty("output_type") 15 | expect(regulator).toHaveProperty("is_low_dropout") 16 | expect(regulator).toHaveProperty("is_positive") 17 | expect(typeof regulator.lcsc).toBe("number") 18 | expect(typeof regulator.is_low_dropout).toBe("boolean") 19 | expect(typeof regulator.is_positive).toBe("boolean") 20 | } 21 | }) 22 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | // Enable latest features 4 | "lib": ["ESNext", "DOM"], 5 | "target": "ESNext", 6 | "module": "ESNext", 7 | "moduleDetection": "force", 8 | "jsx": "react-jsx", 9 | "allowJs": true, 10 | 11 | "paths": { 12 | "lib/*": ["./lib/*"], 13 | "tests/*": ["./tests/*"] 14 | }, 15 | 16 | // Bundler mode 17 | "moduleResolution": "bundler", 18 | "allowImportingTsExtensions": true, 19 | "verbatimModuleSyntax": false, 20 | "noEmit": true, 21 | 22 | // Best practices 23 | "strict": true, 24 | "skipLibCheck": true, 25 | "noFallthroughCasesInSwitch": true, 26 | 27 | // Some stricter flags (disabled by default) 28 | "noUnusedLocals": false, 29 | "noUnusedParameters": false, 30 | "noPropertyAccessFromIndexSignature": false 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /winterspec.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from "winterspec" 2 | 3 | export default defineConfig({ 4 | routesDirectory: "./routes", 5 | platform: "node", 6 | }) 7 | --------------------------------------------------------------------------------