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

@startupkit-app/jobs

v0.1.1

Published

Typed, zero-dependency fetch client for Kit's (startupkit.app) public hiring API — list published jobs and submit applications from your own job site.

Readme

@startupkit-app/jobs

Typed, zero-dependency JavaScript/TypeScript client for Kit's public hiring API. List your published jobs and accept applications from your own careers site — Node, browsers, edge runtimes, any framework.

  • Zero runtime dependencies — native fetch only
  • ESM + CJS, fully typed, tree-shakeable
  • snake_case wire format preserved — what the API returns is what you get
  • Node >= 18.17

Install

npm install @startupkit-app/jobs

Keys

Create API keys in Kit under Hiring → Settings → API. There are two kinds:

| Key | Prefix | Where | CORS | | --- | --- | --- | --- | | Publishable | pk_… | Browsers | Only from Origins you allowlist | | Secret | sk_… | Servers only | No CORS — never ship to a browser |

Pass exactly one to createClient. The SDK throws if you pass both, and throws if it detects a secretKey being used in a browser.

Quickstart (server-side, sk_…)

import { createClient } from "@startupkit-app/jobs";

const kit = createClient({ secretKey: process.env.KIT_SECRET_KEY });

// One page at a time
const page = await kit.listJobs({ department: "Engineering", remote: true });
for (const job of page.data) {
  console.log(job.title, job.location, job.url);
}
if (page.hasNextPage) {
  const next = await page.nextPage()!;
}

// Or iterate everything
for await (const job of kit.allJobs()) {
  console.log(job.id, job.title);
}

// Full detail: description, stages, and the application form definition
const job = await kit.getJob(page.data[0].id);
console.log(job.description_html, job.accepting_applications);

Quickstart (browser, pk_… + Turnstile)

Publishable keys are safe to embed in frontend code. If the job's application_form.turnstile.required is true, render the Cloudflare Turnstile widget with application_form.turnstile.sitekey and pass the resulting token through to apply:

import { createClient } from "@startupkit-app/jobs";

const kit = createClient({ publishableKey: "pk_live_…" });

const job = await kit.getJob("tok_abc123");
// Render job.application_form.fields and job.application_form.questions,
// show job.application_form.consent_disclosure_html near the submit button.

const result = await kit.apply(
  job.id,
  {
    email: "[email protected]",
    first_name: "Jane",
    last_name: "Doe",
    responses: { motivation: "…" }, // keyed by Question.key
  },
  { turnstileToken } // from the Turnstile widget callback
);

console.log(result.id, result.status); // "app_…", "submitted"

Resume upload flow

uploadFile does the whole direct-upload dance for you: it computes the base64 MD5 checksum, registers the blob, PUTs the bytes straight to storage, and hands back the signed_id to attach to the application.

const file = fileInput.files[0]; // or a Blob in Node

// Optional client-side validation against the job's constraints:
const { content_types, max_byte_size } = job.application_form.resume;

const { signed_id } = await kit.uploadFile(file);

await kit.apply(job.id, {
  email: "[email protected]",
  resume_signed_id: signed_id,
});

Need lower-level control? createUpload(meta) registers the blob and returns the direct_upload.url + direct_upload.headers so you can run the PUT yourself.

Error handling

Non-2xx API responses throw KitApiError; failures that never reach the API (network, DNS, the direct-upload PUT) throw KitNetworkError.

import { KitApiError, KitNetworkError } from "@startupkit-app/jobs";

try {
  await kit.apply(job.id, { email });
} catch (error) {
  if (error instanceof KitApiError) {
    switch (error.code) {
      case "already_applied": // 409
        break;
      case "validation_failed": // 422 — see error.fields
        console.log(error.fields); // { email: ["is invalid"], … }
        break;
      case "turnstile_failed": // 422 — refresh the widget and retry
        break;
      default:
        console.error(error.status, error.code, error.message);
    }
  } else if (error instanceof KitNetworkError) {
    // retry / offline UI
  }
}

Error codes: invalid_key (401), origin_not_allowed (403), not_found (404), already_applied (409), validation_failed / turnstile_failed / invalid_content_type / file_too_large (422), parameter_missing (400).

API

createClient({ publishableKey?, secretKey?, baseUrl? }): KitJobsClient

client.listJobs(params?): Promise<Page<Job>>
client.allJobs(params?): AsyncIterable<Job>
client.getJob(publicToken): Promise<JobDetail>
client.createUpload(meta): Promise<UploadTicket>
client.uploadFile(file, meta?): Promise<{ signed_id: string }>
client.apply(publicToken, input, opts?): Promise<ApplicationResult>

All request/response types (Job, JobDetail, ApplicationInput, ApplicationResult, Page, FormField, Question, …) are exported.

Examples

Releasing (maintainers)

Releases publish to npm via GitHub Actions + npm Trusted Publishing (OIDC) — no NPM_TOKEN secret, provenance attached automatically.

  1. Bump the version (npm version patch|minor|major) and merge to main.
  2. The Release workflow publishes the new version via OIDC.

The workflow is idempotent — it only publishes when package.json's version isn't already on the registry, and is gated behind the repo variable NPM_PUBLISH_ENABLED. The initial 0.1.0 was published locally (npm requires a package to exist before a Trusted Publisher can be configured); every release after is CI-only.

License

MIT