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

@farthershore/product

v0.5.0

Published

Farther Shore product-as-code SDK — declare your software product in TypeScript

Readme

@farthershore/product

Product-as-Code SDK for Farther Shore. Builder repos use this package from product/product.config.ts to declare product contracts in TypeScript. Builders author and export a Product; Farther Shore compiles that program to backend-owned IR, validates it, and applies it through Core. The Product SDK describes the sellable software product: its business logic origin, surfaces, plans, capabilities, meters, and lifecycle. Every product is created with a GitHub repo that contains the editable frontend/ starter and the Product SDK entrypoint; connecting GitHub is a product-creation precondition.

Install

pnpm add @farthershore/product

Builder repos generated by Farther Shore already pin this dependency in product/package.json.

Repo Layout

product/
  package.json
  product.config.ts
  meters.ts
  plans/
    free.ts
    pro.ts
  routes/
    api.ts
frontend/
  ...

product/ is authored Product SDK code and may be split into any imported files the builder wants. frontend/ is the generated editable starter app and is built by the frontend pipeline only. Runtime state, accepted specs, compilation records, deployment runs, and compiled IR are not checked into the builder repo; Farther Shore stores them in Core.

Example

import { fs } from "@farthershore/product";
import { configureMeters } from "./meters.js";
import { configureCronRoutes } from "./routes/cron.js";
import { configurePlans } from "./plans/index.js";

const product = fs.product("croncloud", {
  origin: "https://app.example.com",
  displayName: "CronCloud",
  description: "Managed cron jobs",
});

product.surface("frontend");
product.surface("api");
product.use(configureMeters, configureCronRoutes, configurePlans);

export default product;

Modules are plain synchronous functions:

import { fs, type ProductModule } from "@farthershore/product";

export const configureMeters: ProductModule = (product) => {
  product.requests();

  const tokens = product.meter("tokens_used", {
    unit: "token",
    estimate: 500,
  });

  product.feature("runs").route("POST /v1/runs", {
    reports: tokens,
  });
};

export const configurePlans: ProductModule = (product) => {
  product.plan("starter", {
    name: "Starter",
    price: fs.price.monthly(29),
    limits: [
      {
        dimension: "requests",
        window: { type: "named", name: "minute" },
        capacity: 600,
        enforcement: "enforce",
      },
    ],
  });
};

Metering

product.requests() declares the platform-managed request meter and applies requests = 1 to every metered route. Builders do not need backend code for plain request counting.

const product = fs.product("croncloud", {
  origin: "https://app.croncloud.com",
});

product.requests();

const tokens = product.meter("tokens_used", {
  unit: "token",
  estimate: 500,
});

product.feature("runs").route("POST /v1/runs", {
  reports: tokens,
});

Route metering is explicit:

  • omitted route metering inherits product defaults such as requests = 1
  • reports declares dynamic meters the upstream may report with @farthershore/metering
  • costs declares gateway-known fixed usage values for a route
  • estimates overrides reusable meter estimates for admission checks
  • unmetered: true clears all inherited and explicit route metering
  • inheritDefaultMeters: false disables inherited defaults only
const credits = product.meter("api_credits", { unit: "credit" });

product.defaultMeters(credits.fixed(1));

product.feature("exports").route("POST /v1/bulk-export", {
  costs: credits.fixed(10),
});

product.feature("health").route("GET /healthz", {
  unmetered: true,
});

Lifecycle apply paths

Generated product repos use GitHub as the required automation and frontend workspace:

  1. Loads product/product.config.ts.
  2. Requires the default export to be the Product returned by fs.product(...).
  3. Executes imported modules and compiles the product into deterministic Manifest IR.
  4. Validates the result against the deployed platform contract.
  5. Publishes the accepted release through Core so edge artifacts propagate.

The same IR can be built locally with farthershore build; accepted lifecycle state is validated and applied by the GitHub bot after product/** changes are committed and pushed. The repo remains the required frontend customization workspace because frontend/ is where the starter UI and all custom React code live.

The bundled farthershore-manifest-build binary is shared by the bot, build-runner, and CLI. It emits the deterministic Manifest IR envelope that Core accepts; Core, not the user repo, remains the lifecycle authority.

Public API

  • fs.product(name, options) — create the product builder. options.origin is required and is the business logic origin Farther Shore calls for customer-facing actions.
  • product.use(...modules) — compose Product SDK modules from any files under product/.
  • product.surface(...) — declare the product surfaces customers interact with (frontend, api, docs, widget, webhook, worker, or agent).
  • product.entitlement(...) — group capabilities, feature gates, limits, and meters into reusable access metadata.
  • product.offering.plan(...) — declare a subscription plan through the generalized offering namespace. product.plan(...) remains the direct plan helper.
  • product.meter(...) — declare billable or enforceable dimensions.
  • product.requests() — declare and inherit the platform-managed successful request meter.
  • product.defaultMeters(...) — apply reusable fixed costs to metered routes.
  • product.resource(...) — declare counted resources for resource-count constraints.
  • product.capability(...) — declare capability bundles and plan grants.
  • product.feature(...) / product.api.route(...) — declare gateway routes, static costs, dynamic reports, estimates, and action metadata.
  • product.policy(...) — declare policy files in code.
  • product.plan(...) — declare plan pricing, limits, grants, and lifecycle behavior.
  • product.lifecycle.* — declare migrations.
  • product.raw.* — escape hatches for platform-schema JSON when the typed SDK does not yet have sugar.

Determinism

product/product.config.ts and everything it imports must be deterministic: no dates, randomness, network calls, or process state. Sorted collections produce stable output, while route order remains semantic because the gateway matcher is first-match-wins.

The GitHub bot runs the build twice and rejects the push if the two generated hashes differ.

Release

@farthershore/product publishes to public npm through the GitHub workflow .github/workflows/publish-product-sdk.yml.

Release sequence:

  1. Bump packages/product/package.json version.
  2. Run the package checks:
    pnpm --filter @farthershore/product run lint
    pnpm --filter @farthershore/product run test
    pnpm --filter @farthershore/product run build
    pnpm --filter @farthershore/product run pack:check
  3. Commit, push, and merge through the normal PR flow.
  4. Tag from main with the exact package version:
    git tag product-v<version>
    git push origin product-v<version>

The publish workflow verifies that the tag equals product-v<packages/product/package.json version>, builds/tests the package and its dependencies, runs pack:check, then publishes with NPM_PUBLISH_TOKEN.