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

@spacefast/domain-sdk

v0.8.0

Published

Spacefast provider for domain-sdk: attach, verify, monitor, and remove customer domains on a Space.

Readme

@spacefast/domain-sdk

The Spacefast provider for domain-sdk. Attach, verify, monitor, and remove the custom domains on one Space through the same typed API you use for Vercel, Cloudflare, or Netlify — so a product that lets its customers bring a domain does not have to learn Spacefast's domain endpoints to do it.

Install

npm install @spacefast/domain-sdk @opencoredev/domain-sdk

@opencoredev/domain-sdk is a peer dependency: this package supplies the Spacefast provider, that package supplies the client that drives it.

Quick start

import { createDomainClient } from "@opencoredev/domain-sdk";
import { spacefast } from "@spacefast/domain-sdk";

export const domains = createDomainClient({
  provider: spacefast({
    token: process.env.SPACEFAST_TOKEN!,
    spaceId: process.env.SPACEFAST_SPACE_ID!,
  }),
});

const domain = await domains.add("app.customer.com");
console.log(domain.status, domain.records);

Scope the token to the Space your product serves customer sites from. apiUrl is the only other option, and only matters when you point the adapter at a Spacefast API that is not production.

This is a server-side package. The token can add and delete domains on your Space — keep it out of a browser bundle.

Scope

The adapter manages the custom domains attached to one Space. It does not publish versions, edit customer DNS, register domains, or move a domain between Spaces.

The Space's own *.space.fast (or legacy *.view.fast) hostname comes back from the API as a managed row. The adapter hides it from get(), list(), and remove(), so it can never be mistaken for a customer domain or deleted through this client.

Apex and www are one attachment

Spacefast attaches customer.com and www.customer.com together. One attachment serves both names and returns the DNS records for both, so get("customer.com") and get("www.customer.com") resolve to the same Domain.id and each returns the hostname you asked for. Adding the twin of a hostname you already attached returns the current state instead of creating a second attachment.

Every other subdomain is its own attachment. Wildcard hostnames are not supported.

What maps to what

| domain-sdk call | Spacefast | | ------------------ | ---------------------------------------------------------------------------- | | add(hostname) | POST /v1/spaces/{spaceId}/domains, after a lookup that makes it idempotent | | get(hostname) | the Space's attachments, plus that attachment's live diagnostics | | list() | the same attachments, paged with an offset cursor | | verify(hostname) | POST .../domains/{id}/verify, then a fresh get() | | remove(hostname) | DELETE .../domains/{id}, and a no-op when nothing is attached |

Routing, ownership, and certificate records come from the attachment's required records; their live status comes from the Space's domain diagnostics. Spacefast routes a hostname on two A records and judges the zone by whether what it observes lands in its own address range, rather than by matching one exact value. So an A or AAAA record reads as valid once Spacefast observes its value, or once the hostname resolves into Spacefast's range; invalid when the zone answers with addresses that are neither; pending while nothing resolves. A TXT record reads as valid once Spacefast confirms the challenge. Records read as unknown when diagnostics are unavailable — never as valid.

customer.com and www.customer.com share one attachment but are two hostnames, each with its own records and its own certificate. The adapter answers about the hostname you asked for: get("www.customer.com") reports the www certificate and the www issues, even when the apex is the attachment's configured hostname.

Most domains need no ownership proof and go straight from DNS to a certificate. Spacefast requires a TXT record when another Space already serves the hostname; that record arrives as an ownership record and the domain reports pending_verification until it resolves. verify() queues a provider check and returns the refreshed domain — it does not block until the check finishes, so poll with waitUntilActive() or call get() again.

Certificates are managed by Spacefast. A domain reaches active only once ownership is settled and the certificate is issued.

| Reported status | What Spacefast is telling you | | ---------------------- | ---------------------------------------------------------------- | | unknown | Diagnostics could not be read, so nothing has been observed | | pending | The attachment exists and this hostname has no diagnostics entry | | pending_verification | An ownership TXT record is required and has not resolved | | pending_dns | The records do not point at Spacefast yet | | pending_certificate | The records resolve and the certificate is still being issued | | active | Ownership is settled and the certificate is live | | failed | Verification failed, or certificate issuance is broken |

A broken certificate adds one retryable CERTIFICATE_FAILED issue carrying Spacefast's reason. A hostname resolving through a proxy adds one DNS_PROXY_DETECTED issue: Spacefast cannot see the records behind the proxy, so it cannot validate the domain. Verification problems Spacefast reports as errors arrive as issues keyed by their own code.

list() is the expensive one

list() reads the Space's whole domain set, pages it with an offset cursor, and then makes one live DNS and certificate diagnostics read per row on the page. Those reads query public DNS and Spacefast's certificate store, so a page of 50 is 50 round trips behind one call. Keep pages small, pass a signal you can cancel, and use get() when you want the state of one domain.

Errors

Spacefast returns RFC 9457 problem documents, and the adapter maps their stable code rather than their prose or their status. The original code is kept in error.details.providerCode.

| Spacefast | DomainSdkError.code | | ----------------------------------------------- | --------------------------------- | | 401 | AUTHENTICATION_FAILED | | 403 | PERMISSION_DENIED | | A spaceId the token cannot read | INVALID_CONFIGURATION | | A hostname this Space does not hold | DOMAIN_NOT_FOUND | | domain_in_use, domain_quota_exceeded | DOMAIN_CONFLICT | | invalid_domain_name, domain_reserved_suffix | INVALID_HOSTNAME | | 429 | RATE_LIMITED, with retryAfter | | 5xx, or an origin that never answered | PROVIDER_UNAVAILABLE |

A Space Spacefast cannot read is INVALID_CONFIGURATION, not DOMAIN_NOT_FOUND — the adapter is pointed at a Space that does not exist, which is not the same as a customer domain that was never attached. A rejected hostname arrives as a 422, so that mapping keys on the code, not the status.

add() is safe to retry. When a concurrent attach wins the race and Spacefast answers 409, the adapter re-reads the Space and returns the attachment that landed; a hostname some other Space holds still raises DOMAIN_CONFLICT.

Diagnostics are advisory. When they fail in a way worth retrying — a server error, a rate limit, or an origin that never answered — the adapter still returns the attachment, with status: "unknown", record statuses of unknown, and an unknown certificate, rather than hiding a domain that exists or reporting a verified domain as pending. Cancelling still cancels.

Not in here

  • Domain Connect. The adapter hands you the records to publish; it does not drive a registrar's one-click DNS flow, and nothing here claims Domain Connect support.
  • Wildcards, domain registration, managed DNS, and moving a domain between Spaces. Those live in the Spacefast API and the sf CLI, not in this provider.

More: custom domains and the API reference.