Skip to content

Runtime API

The API endpoint is /proxy/api/runtime. This endpoint allows arbitrary Javascript scripts to run within the runtime of the Go code that queries the Open Street Map data.

The runtime is a sandboxed custom environment, with the following restrictions:

  • No network access
  • No file access
  • No npm packages -- no import or require
  • Timeout 10 seconds

It supports the following:

Functions

This is the list of functions that are available to use in the javascript runtime.

declare const assert: Assert;
declare const colors: Colors;
declare const geo: Geo;
declare const params: Params;
declare const query: Query;

interface Properties {
  [key: string]: string | number | boolean;
}

interface Feature {
  type: string;
  properties: Properties;
  geometry: unknown;
}

interface Assert {
  geoJSON(payload: unknown): void;
  eq(value: boolean, message: string): void;
}

interface Colors {
  pick(number): string;
}

interface Bound {
  extend(number): Bound;
  center(): Point;
  intersects(bound: Bound): boolean;
}

interface BoundArray extends Array<Bound> {
  asFeature(properties?: Properties): Feature;
  asBound(): Bound;
}

interface Point {
  asFeature(properties?: Properties): Feature;
  asBound(): Bound;
  lat(): number;
  lon(): number;
}

interface Prefix {
  name: string;
  fullName: string;
  minLat: number;
  minLon: number;
  maxLat: number;
  maxLon: number;
}

interface Geo {
  asPoint(lat: number, lon: number): Point;
  asResults(...results: Result[]): ResultArray;
  asBounds(...bounds: Bound[]): BoundArray;
  rtree(): Tree;
}

interface Result {
  asFeature(properties?: Properties): Feature;
  name: string;
  id: number;
  minLat: number;
  minLon: number;
  maxLat: number;
  maxLon: number;
  tags: { [key: string]: string };
  bound(): Bound;
}

interface Tree {
  nearby(Bound, number): ResultArray;
  within(Bound): ResultArray;
  insert(Result): void;
}

interface ResultArray extends Array<Result> {
  asTree(depth: number): Tree;
  cluster(number): ResultArray;
  overlap(
    results: ResultArray,
    originRadius: number,
    neighborRadius: number,
    count: number,
  ): ResultArray[];
}

interface Query {
  union(...string): ResultArray;
  execute(string): ResultArray;
  areas(): Prefix[];
  fromAddress(address: string): ResultArray;
}

interface Params {
  [key: string]: string;
}

Examples

List of counties (via curl)

The following script will return all the counties, their state, and center point of a the bounding box.

/// <reference path="../global.d.ts" />

const areas = query.areas();

const counties = areas.flatMap((area) => {
  const results = query.execute(
    `nwr[admin_level=6][boundary=administrative][name](area=${area.name})`,
  );
  return results.map((county) => {
    const center = county.bound().center();

    return {
      name: county.tags.name,
      lat: center.lat(),
      lon: center.lon(),
      state: area.name,
    };
  });
});

export { counties as payload };

This script can be applied via two methods a source parameter in the query string or the request body. If using the query string, Cloudflare will cache it for 25 minutes (1500 seconds).

The above script can be used in a curl command doing the following:

# create `script.js` of the above javascript
curl -X GET --data-urlencode "[email protected]" 'https://knowhere.live/proxy/api/runtime'

This will return a JSON payload in the format of:

[
  {
    "lat": 34.80427,
    "lon": -85.484545,
    "name": "Dade County",
    "state": "alabama"
  }
]

This entire payload could be used for an auto complete client side. Rather that off loading all auto complete filtering to server side.

Find universities nearby each other

Let's find unique university campuses near each other.

/// <reference path="../global.d.ts" />

const areas = query.areas();

// find all the universities country wide
const allUnis = geo.asResults(
  ...areas.flatMap((area) => {
    return query.execute(
      `wr[amenity=university][name](area=${area.name})`,
    );
  }),
);

const radius = 500; // meters
const overlap = 3000; // meters

// find multiple marked universities near each other
// helpful when there are lots of buildings on the campus
// `cluster` always returns the largest area
const clustered = allUnis.cluster(radius);

// find clustered items that overlap each other
// this should find campuses that are near each other
const grouped = clustered.overlap(clustered, overlap, 0, 3);

// lets generate the GeoJSON
const payload = {
  type: "FeatureCollection",
  features: grouped.flatMap((entries, index) => {
    const features = entries.flatMap((entry) => {
      const feature = entry.asFeature({
        "marker-color": colors.pick(index),
        index: index,
      });

      return feature;
    });

    const bounds = geo.asBounds(
      ...entries.map((entry) => entry.bound().extend(overlap)),
    );

    return features.concat(
      [
        bounds.asFeature({
          "fill": colors.pick(index),
          "fill-opacity": 0.2,
        }),
      ],
    );
  }),
};

export { payload };

Find neighborhood areas near areas

This finds neighborhoods within Colorado that are within driving distance of Costco and walking distance from a highschool and coffee shop.

/// <reference path="../global.d.ts" />

const keywords = [
  {
    radius: 5000,
    results: query.execute(`nwr[name=~Costco](area=colorado)`),
  },
  {
    radius: 1000,
    results: query.execute(
      `nwr[amenity=cafe][name][name!~Starbucks](area=colorado)`,
    ),
  },
  {
    radius: 5000,
    results: query.execute(`nwr[amenity=school][name](area=colorado)`),
  },
];

keywords.sort((a, b) => a.results.length - b.results.length);

const neighbors = new Map<number, Map<number, Result>>();
const cluster = keywords[0].results.cluster(500);
cluster.forEach((entry) => {
  neighbors.set(entry.id, new Map());
});

const expectedNeighbors = 2;

keywords.slice(1).forEach((keyword) => {
  const grouped = cluster.overlap(
    keyword.results,
    keywords[0].radius,
    keyword.radius,
    expectedNeighbors - 1,
  );
  grouped.forEach((values) => {
    values.forEach((value) =>
      neighbors.get(values[0].id)?.set(value.id, value)
    );
  });
});

const payload = {
  type: "FeatureCollection",
  features: [...neighbors.values()].flatMap((set, index) => {
    const entries = [...set.values()];

    if (entries.length !== keywords.length) {
      return;
    }

    const features = entries.flatMap((entry, index) => {
      const color = colors.pick(index);

      const feature = entry.asFeature({
        "marker-color": color,
        index: index,
      });

      return feature;
    });

    const bounds = geo.asBounds(
      ...entries.map((entry, index) =>
        entry.bound().extend(keywords[index].radius)
      ),
    );

    return features.concat(
      [
        bounds.asFeature({
          "fill": colors.pick(index),
          "fill-opacity": 0.5,
        }),
      ],
    );
  }).filter(Boolean),
};

assert.geoJSON(payload);

export { payload };