npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@tscircuit/autorouting-cache-engine

v0.0.8

Published

Generate a cache key(s) to enable re-using previous autorouting results.

Readme

autorouting-cache-engine

Generate a cache key(s) to enable re-using previous autorouting results.

import { generateCacheKey, normalizePcbTraces, denormalizeTraces } from "@tscircuit/autorouting-cache-engine"
import circuitJson from "./circuit.json"

// Generate cache key and get normalization transform
const { cacheKey, normalizationTransform } = generateCacheKey(circuitJson)

console.log(cacheKey) 
// 938c2cc0dcc05f2b68c4287040cfcf71

// ------------- USAGE WITH CACHE -------------------
import myCachedTraces from "./cached-traces"

const cachedTraces = myCachedTraces.get(cacheKey)

if (!cachedTraces) {
  // Route and store normalized traces
  const newlyRoutedTraces = autoroute(circuitJson)
  
  // Normalize traces for caching
  const normalizedTraces = normalizePcbTraces({
    normalizationTransform,
    circuitJson,
    pcbTraceIds: newlyRoutedTraces.map(t => t.pcb_trace_id!)
  })
  
  myCachedTraces.set(cacheKey, normalizedTraces)
  const circuitJsonWithTraces = circuitJson.concat(newlyRoutedTraces)
} else {
  // Denormalize cached traces back to original space
  const traces = denormalizeTraces({
    normalizationTransform,
    circuitJson,
    normalizedTraces: cachedTraces
  })

  const circuitJsonWithTraces = circuitJson.concat(traces)
}

You can now use this cacheKey to see if you've already routed this subcircuit, and re-use the results!

The cacheKeyTransform represents how you need to transform the cached traces to or from the normalized space

Visual Overview

flowchart TD
    CJ[Circuit JSON] --> NAJ[Normalized Autorouting JSON]
    NAJ --> |Deterministic JSON Stringify| LS[Long String]
    LS --> |MD5 Hash| CK[Cache Key]
    NAJ --> |Store Transform| TF[Transform Functions]

    subgraph "Cache Key Generation"
        NAJ
        LS
        CK
        TF
    end

    subgraph "Cache Usage"
        CK --> |Cache Lookup| CR{Cache Result}
        CR -->|Hit| CT[Cached Traces]
        CR -->|Miss| AR[Autoroute]

        CT --> TFR[Transform From Normalized Space]
        AR --> TTC[Transform To Normalized Space]

        TTC --> |Store| Cache[(Cache)]
        TTC --> TFR

        TFR --> FT[Final Traces]
    end

Internals

NormalizedAutoroutingJson

To generate a cache key, we first generate a NormalizedAutoroutingJson. A NormalizedAutoroutingJson is a JSON object that contains a version of all the obstacles/traces with rounded numbers. Serializing two different circuits that have the same autorouting result should have the same NormalizedAutoroutingJson

Here's an example NormalizedAutoroutingJson:

{
  "allowed_layers": 2,
  "nets_to_route": [1],
  "sorted_normalized_objects": [
    {
      "net": 1,
      "x": "0.00",
      "y": "0.00",
      "layers": [1],
      "width": "0.25",
      "height": "0.25"
    },
    {
      "type": "rect",
      "x": "3.00",
      "y": "3.00",
      "width": "1.00",
      "height": "2.00",
      "net": null
    },
    {
      "net": 1,
      "x": "6.00",
      "y": "6.00",
      "layers": [1],
      "width": "0.25",
      "height": "0.25"
    }
  ]
}

There are rules to make sure that NormalizedAutoroutingJson is always the same for the same autorouting problem, these are the rules:

  • Traces and obstacles are converted into sorted_normalized_objects
  • All mm units are converted into strings with 2 decimal points
  • All objects are sorted by layers, x, y, width, height in that order (asc)
  • All connectivity nets (traces, nets etc.) are converted into a net number
    • The net numbers increment by their order in sorted_normalized_objects
    • If an object is in the same net as a previous object, use the previous net number
  • Obstacles that are not connected to any trace should be given "net": null
  • nets_to_route is a sorted array of integers indicating the nets to route
  • allowed_layers indicates the layers that the autorouting is allowed to use for the solution
  • The normalized objects are translated to be centered about the "region of interest" which is the smallest bounding box that contains all the nets to connect
  • When creating NormalizedAutoroutingJson, you can specify a marginOutsideOfRegionOfInterest which indicates how far outside the region of interest to include obstacles. If an obstacle is outside the region of interest plus the marginOutsideOfRegionOfInterest, it will be ignored (it will not be included in the NormalizedAutoroutingJson)

LongString

The LongString is a predictable JSON serialization to ensure that the NormalizedAutoroutingJson is always turned into the same string.

To do predictable serialization, we mandate the following rules:

  • All keys must be sorted when serializing
  • No whitespace is allowed

You can use the json-stringify-deterministic library to create a LongString from NormalizedAutoroutingJson

import deterministicStringify from "json-stringify-deterministic"

deterministicStringify(normalizedAutoroutingJson)
// { "nets_to_route": [ ....

CacheKey1

The CacheKey1 is an md5-encoded hash of the LongString. It can be used to see if this autorouting problem has ever previously been solved against a cache.

md5 was selected for it's speed and popularity for checksums. There is not a major security risk since this is used for caching, not password security.

import { createHash } from "crypto"

const longString = deterministicStringify(normalizedAutoroutingJson)
const cacheKey1 = createHash("md5").update(longString).digest("hex")
// "5d41402abc4b2a76b9719d911017c592"