Core concepts

Configuration

Sensible defaults, absolute configuration.

That statement is at the core of our design decisions when it comes to Workertown.

We feel very strongly that creating a Workertown service should be as simple as importing and calling a function - however, we all know that the real world can be far more complex than that.


Setting configuration options

In each Workertown package, every aspect of how your service functions is exposed via an optional options argument. This is how you configure a Workertown service to best suite your needs.

import { search } from "@workertown/search";

export default search({
  // Options go here...
})

Universal options

All Workertown services have a common set of options that are available to be set when creating the service.

access

The access object allows you to configure access level protections for your service. Currently, it has a two properties, access.ip and access.rateLimit

access.ip

acces.ip allows you to specify an array of IP addresses/CIDR blocks that are allowed to access your service.

This is disabled by default, meaning that your service can be accessed from any IP address.

import { search } from "@workertown/search";

export default search({
  access: {
    ip: [
      "10.0.0.0",
      "11.0.0.0/24",
      "2001:4860:8006::62",
      "2001:db8::/24",
    ],
  },
});

The values passed in to the access.ip array can either be an IPv4/v6 string, or an IPv4/v6 CIDR block describing an IP range to allow.

Any requests that do not originate from an IP address whitelisted in the access.ip array will be rejected with a 403 Forbidden response.

access.rateLimit

access.rateLimit allows you to specify a rate limit for your service. By default, this is powered by Cloudflare Workers KV, but can be configured to use the built in Upstash Redis rate limiter or a custom rate limiter class. Requests are limited by their IP address in a sliding window of time.

This is disabled by default, meaning that your service can be accessed from an IP address with no rate limiting.

import { search } from "@workertown/search";

export default search({
  access: {
    rateLimit: {
      env: {
        kv: "RATE_LIMIT_KV", // The environment variable to read the KV binding from
      },
      limit: 10, // The maximum number of requests to allow in the window
      window: 60, // The window (in seconds) to allow the requests in
    }
  },
});
import { search } from "@workertown/search";
import { UpstashRedisRateLimiter } from "@workertown/search/rate-limit/upstash-redis";

export default search({
  access: {
    rateLimit: {
      rateLimiter: new UpstashRedisRateLimiter({
        url: "...",
        token: "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
      }),
    }
  },
});
import { search } from "@workertown/search";
import { RateLimiter } from "@workertown/search/rate-limit";

class CustomRateLimiter extends RateLimiter {
  //...
}

export default search({
  access: {
    rateLimit: {
      rateLimiter: new CustomRateLimiter(),
    }
  },
});

auth

See the Authentication documentation.

basePath

The basePath property allows you to specify a base path for your service's API. By default this is set to /, meaning that your service will be available from the root of your service's domain.

import { search } from "@workertown/search";

export default search({
  basePath: "/search", // The API will be exposed from `/search/*`
});

cors

If you would like to expose any Workertown service to a web-based front-end client, you will likely need to enable CORS.

By default, CORS is disabled. To enable it, simply set the cors property.

import { search } from "@workertown/search";

export default search({
  cors: {
    origin: "https://example.com", // The origin to allow requests from
    allowMethods: ["GET", "POST", "PUT", "DELETE", "OPTIONS"], // The HTTP methods to allow
    allowHeaders: ["Content-Type", "Authorization"], // The HTTP headers to allow
    maxAge: 86400, // The maximum age (in seconds) to cache preflight requests
    credentials: true, // Whether or not to allow credentials (cookies, etc)
    exposeHeaders: ["Content-Length"], // The HTTP headers to expose
  }
});

The cors.origin property can be a string, an array of strings, or a function that is passed the origin of the incoming request and returns the allowed CORS origin as a string (or undefined/null if the origin is not allowed).

import { search } from "@workertown/search";

export default search({
  cors: {
    origin: (origin) => {
      if (origin === "https://example.com") {
        return origin;
      }
    },
  },
});

endpoints

To see how the endpoints option works in general, see routing.

getEnv

By default, a Workertown service will read environment variables from either the env argument passed to the service function (in Cloudflare Workers), or from process.env.

You can customise this behaviour by passing in a getEnv function that takes whatever has been parsed from the environment as an env object argument and returns an object of environment variables. This will override any environment variables set via env/process.env, so ensure to include any variables you need from the passed in env object.

import { search } from "@workertown/search";

export default search({
  getEnv: (env) => ({
    ...env,
    db: "SEARCH_DB",
  }),
});

logger

By default, all Workertown services log to console.log in the format:

<METHOD> <URL PATH> <STATUS CODE> <RESPONSE TIME>ms

This logger functionality can be customised by passing in a logger function that takes the method, URL path, status, and elapsed time as arguments that returns void or Promise<void>.

import { search } from "@workertown/search";

export defult search({
  logger: (method: string, path: string, status: number, elapsed: string) => {
    console.log(status, method, path, elapsed);
  },
});

It can be disabled entirely by passing in false instead.

import { search } from "@workertown/search";

export defult search({
  logger: false,
});

runtime

All Workertown services expose the ability to customise the runtime options to allow support for different environments. By default, every Workertown package assumes it is running within a Cloudflare Worker (and therefore makes some assumptions about bindings that are available).

Workertown comes with four out-of-the-box runtimes:

  • cloudflare-workers
  • edge
  • node
  • test

They are all pretty self explanatory - it goes without saying that the test runtime is only intended to be used in test environments, and is not suitable for production.

While the available runtime options differ between services, customising them follows the same simple API.

import { serve } from "@workertown/node";
import { search } from "@workertown/search";
import { runtime } from "@workertown/search/node";

serve(search({ runtime }));

console.log("Server running at http://localhost:3000");

The runtime option accepts either an object (in the shape of the expected runtime - this differs between packages) or a function that returns the expected runtime. The function option receives two arguments, the options set for the service and an env object that contains the environment variables/bindings available within the environment (the env object in a Cloudflare Worker, to the process.env object in Node, for example).

import { serve } from "@workertown/node";
import { search } from "@workertown/search";
import { SqliteStorageAdapter } from "@workertown/search/storage/sqlite";

serve(
  search({
    runtime: (options, env) => ({
      cache: false,
      storage: new SqliteStorageAdapter({
        db: config.env.db,
      }),
    })
  })
);

console.log("Server running at http://localhost:3000");

Check the docs!

Be sure to check the documentation for the particular service you are using to see what runtime options are available.

sentry

All Workertown services support Sentry error reporting at the edge (via Toucan.js). This is disabled by default - to enable Sentry error reporting, simply set the sentry property.

import { search } from "@workertown/search";

export default search({
  sentry: {
    dsn: "xxxxxxxxxxxxxxxxxxxx", // Your Sentry DSN
    allowedCookies: ["__session"], // The cookies to allow
    allowedSearchParams: ["q"], // The search params to allow
    attachStacktrace: true, // Whether or not to attach a stacktrace to errors
    debug: true, // Whether or not to enable debug mode
    environment: "production", // The environment to report errors as
    maxBreadcrumbs: 100, // The maximum number of breadcrumbs to report
    pkg: {
      name: "search", // The name of your service
      version: "1.0.0", // The version of your service
    }, // The package.json values of your service
    release: "1.0.0", // The release version of your service
  },
});
Previous
Introduction Tutorials
Next
Core conceptsRouting

See a problem with this page? Submit an issue