Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
8 changes: 6 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,9 @@ jobs:
run: bun install --frozen-lockfile

- name: Verify public safety
run: bun run verify:public-safety
run: |
node --test scripts/verify-public-safety.test.mjs
bun run verify:public-safety

- name: Install Vale
run: |
Expand All @@ -44,7 +46,9 @@ jobs:
vale --version

- name: Verify prose style
run: bun run verify:prose
run: |
node --test scripts/openapi-prose-scope.test.mjs
bun run verify:prose

- name: Check types and templates
run: bun run check
Expand Down
6 changes: 4 additions & 2 deletions .vale.ini
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,9 @@ BlockIgnores = (?m)^(?:import|export)\s.+$, (?m)^<[A-Z][A-Za-z]*[^>]*/>$

; Inline component props and template placeholders, plus the one sanctioned
; fixed phrase from the monorepo vocabulary registry: "OAuth access token"
; (protocol vocabulary, not the product credential).
TokenIgnores = (\{[^}\n]+\}), (<[A-Z][A-Za-z]*[^>]*/>), (OAuth access tokens?)
; (protocol vocabulary, not the product credential). Quoted API enum identifiers
; remain identifiers even when the source description doesn't backtick them.
TokenIgnores = (\{[^}\n]+\}), (<[A-Z][A-Za-z]*[^>]*/>), (OAuth access tokens?), ("(?:asc|dt)")

; The changelog is a historical record: shipped release notes keep their
; wording, but public-safety and brand casing still apply retroactively.
Expand All @@ -28,3 +29,4 @@ Spacefast.AISpeak = NO
Spacefast.Hype = NO
Spacefast.Wordiness = NO
Spacefast.Condescension = NO
Spacefast.ApiKey = NO
2 changes: 1 addition & 1 deletion content/(concepts)/spaces.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ Check before you commit with [`getSlugAvailability`](/api/reference/spaces/getsl

## The default hostname

Every Space answers at `https://<slug>.view.fast/` from the moment it exists, and keeps that hostname for life. Adding a custom domain never retires it. Version and branch hostnames, the live URL rule, and what a rename does to each are on [URLs and hostnames](/urls).
New Spaces use `https://<label>.space.fast/`. Existing Spaces on `view.fast` keep their domain, including after a publish or slug rename. Adding a custom domain never retires the managed hostname. Version and branch hostnames, the live URL rule, and what a rename does to each are on [URLs and hostnames](/urls).

## Who owns a Space

Expand Down
4 changes: 2 additions & 2 deletions content/(concepts)/versions.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -99,12 +99,12 @@ An explicit promote is never held by a manual policy. That hold only applies to
Every version that reaches ready gets a permanent hostname of its own, computed once and stored:

```text
https://v7--my-site.view.fast/
https://my-site--v7.space.fast/
```

It serves that exact snapshot no matter what is live, and it survives a rename, a transfer, and any number of rollbacks. The API reports it as `immutableUrl`, with `immutableUrlStatus` of `pending` until the hostname is routable.

A version published from a connected Git branch also gets a branch hostname, `https://br-<alias>--my-site.view.fast/`, which follows the branch rather than the snapshot. The dashboard shows it on the version page as **Branch preview URL**. Full hostname rules are on [URLs and hostnames](/urls).
A version published from a connected Git branch also gets a branch hostname, `https://my-site--br-<alias>.space.fast/`, which follows the branch rather than the snapshot. The dashboard shows it on the version page as **Branch preview URL**. Existing Spaces stay on `view.fast`, and existing version and branch URLs retain their format. Full hostname rules are on [URLs and hostnames](/urls).

## Drafts expire in 24 hours

Expand Down
4 changes: 2 additions & 2 deletions content/(publish)/anonymous-and-claim.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ What comes back is a `claim` block. Four fields:

```text
sfc_Kd2mQ7xR4tYb9wLp1sVn3F
https://swift-otter-4821.view.fast/__/sfc_Kd2mQ7xR4tYb9wLp1sVn3F
https://swift-otter-4821.space.fast/__/sfc_Kd2mQ7xR4tYb9wLp1sVn3F
https://my.spacefast.com/claim#sfc_Kd2mQ7xR4tYb9wLp1sVn3F
```

Expand Down Expand Up @@ -105,7 +105,7 @@ After the claim lands the page says **&lt;space&gt; is yours.** and offers a **C
| Thing | Before | After |
| --- | --- | --- |
| Owner | The space key | The team you picked |
| Hostname | `<slug>.view.fast` | Unchanged |
| Hostname | The Space's managed hostname | Unchanged |
| Version URLs | Live | Unchanged |
| Expiry | 33 hours and 20 minutes after the latest publish that changes files | Gone. The Space has no anonymous expiry deadline |
| Served content types | Restricted allowlist | Everything |
Expand Down
6 changes: 3 additions & 3 deletions content/(publish)/recipes/astro.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -29,10 +29,10 @@ sf publish ./dist --prebuilt
## What the receipt shows

```text
Published: https://quiet-harbor.view.fast
Published: https://quiet-harbor.space.fast

Live URL https://quiet-harbor.view.fast
Version URL https://v2--quiet-harbor.view.fast
Live URL https://quiet-harbor.space.fast
Version URL https://quiet-harbor--v2.space.fast
Version v2 (ready)
Files 64
```
Expand Down
6 changes: 3 additions & 3 deletions content/(publish)/recipes/eleventy.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -29,10 +29,10 @@ sf publish ./_site --prebuilt
## What the receipt shows

```text
Published: https://quiet-harbor.view.fast
Published: https://quiet-harbor.space.fast

Live URL https://quiet-harbor.view.fast
Version URL https://v4--quiet-harbor.view.fast
Live URL https://quiet-harbor.space.fast
Version URL https://quiet-harbor--v4.space.fast
Version v4 (ready)
Files 88
```
Expand Down
8 changes: 4 additions & 4 deletions content/(publish)/recipes/html.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -32,11 +32,11 @@ A single file works too. `sf publish ./index.html` sends one file and serves it
## What the receipt shows

```text
Published: https://quiet-harbor.view.fast
Published: https://quiet-harbor.space.fast

Open https://quiet-harbor.view.fast
Live URL https://quiet-harbor.view.fast
Version URL https://v1--quiet-harbor.view.fast
Open https://quiet-harbor.space.fast
Live URL https://quiet-harbor.space.fast
Version URL https://quiet-harbor--v1.space.fast
Version v1 (ready)
Files 4
```
Expand Down
6 changes: 3 additions & 3 deletions content/(publish)/recipes/next.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,10 @@ sf publish
## What the receipt shows

```text
Published: https://quiet-harbor.view.fast
Published: https://quiet-harbor.space.fast

Live URL https://quiet-harbor.view.fast
Version URL https://v3--quiet-harbor.view.fast
Live URL https://quiet-harbor.space.fast
Version URL https://quiet-harbor--v3.space.fast
Version v3 (ready)
Files 212
```
Expand Down
6 changes: 3 additions & 3 deletions content/(publish)/recipes/vite.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,10 @@ sf publish
## What the receipt shows

```text
Published: https://quiet-harbor.view.fast
Published: https://quiet-harbor.space.fast

Live URL https://quiet-harbor.view.fast
Version URL https://v1--quiet-harbor.view.fast
Live URL https://quiet-harbor.space.fast
Version URL https://quiet-harbor--v1.space.fast
Version v1 (ready)
Files 31
```
Expand Down
2 changes: 1 addition & 1 deletion content/(serve)/domains.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -200,7 +200,7 @@ www.example.com purpose=www dns=not_configured txt=missing ssl=missing
| `invalid_domain_name` | 400 | Not a hostname: no dot, an IP literal, over 253 characters, or not convertible to ASCII. |
| `domain_wildcard_label` | 400 | A label contained `*`. Add the apex or the concrete hostname instead. |
| `domain_reserved_suffix` | 400 | The hostname ends in a Spacefast-managed suffix. |
| `managed_domain_protected` | 400 | You passed the id of a built-in `view.fast` hostname. |
| `managed_domain_protected` | 400 | You passed the id of a built-in `space.fast` or `view.fast` hostname. |
| `domain_already_exists` | 409 | The team already has that hostname. |
| `domain_quota_exceeded` | 409 | The plan's external domain group limit is reached. |
| `domain_in_use` | 409 | Another verified claim serves it, or it is still assigned to a Space. |
Expand Down
30 changes: 19 additions & 11 deletions content/(serve)/urls.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -8,27 +8,33 @@ After this page you know every hostname a Space answers on, which one the CLI an

## The default hostname

Every Space gets one hostname the moment it exists:
Every new Space gets one hostname the moment it exists:

```text
https://{label}.view.fast/
https://{label}.space.fast/
```

The label comes from the Space slug, lowercased, with every character outside `a-z`, `0-9` and `-` replaced by `-`, runs of hyphens collapsed, and a 63-character cap. A Space with slug `my-site` serves at `https://my-site.view.fast/`.
The label comes from the Space slug, lowercased, with every character outside `a-z`, `0-9` and `-` replaced by `-`, runs of hyphens collapsed, and a 63-character cap. A new Space with slug `my-site` serves at `https://my-site.space.fast/`.

The default hostname keeps serving for the life of the Space. Adding a custom domain never retires it.

Existing Spaces on `view.fast` keep that domain. Publishing again, renaming the slug, or creating a version or branch preview keeps the Space on its original domain. Existing version URLs and share links keep working.

A hostname label stays taken across both domains. If `my-site.view.fast` belongs to a Space, another Space cannot take `my-site.space.fast`.

A slug cannot contain `--`, because `--` is the separator between a version or branch label and the Space label in the hostnames below.

## Version URLs

Every version that reaches ready gets a permanent hostname of its own:

```text
https://v{number}--{label}.view.fast/
https://{label}--v{number}.{apex}/
```

Version 7 of `my-site` is `https://v7--my-site.view.fast/`. The URL is computed once when the version turns ready and stored on the version row, so it survives a slug rename and keeps serving that exact build no matter what is live now.
The apex is the Space's original domain, either `space.fast` or `view.fast`. Version 7 of a new Space named `my-site` is `https://my-site--v7.space.fast/`. The URL is computed once when the version turns ready and stored on the version row, so it survives a slug rename and keeps serving that exact build no matter what is live now.

Existing URLs such as `https://v7--my-site.view.fast/` retain their format. Use the returned `immutableUrl` rather than composing a version URL yourself.

The API and the CLI report it as `immutableUrl`, with an `immutableUrlStatus` of `pending` until the hostname is routable.

Expand All @@ -39,9 +45,11 @@ Version hostnames always carry `X-Robots-Tag: noindex, nofollow`, and their `/ro
A version published from a connected Git branch also gets a branch hostname:

```text
https://br-{alias}--{label}.view.fast/
https://{label}--br-{alias}.{apex}/
```

The apex stays the same as the Space's default hostname. Existing branch URLs such as `https://br-preview--my-site.view.fast/` retain their format.

The alias is clamped to 16 characters. Branch hostnames follow the branch: pushing again repoints the same URL at the newer version. They are noindex for the same reason version hostnames are.

## What the live URL points at
Expand All @@ -50,23 +58,23 @@ The alias is clamped to 16 characters. Branch hostnames follow the branch: pushi

| Space state | `liveUrl` |
| --- | --- |
| No custom domain | `https://{label}.view.fast/` |
| No custom domain | The Space's default hostname |
| Primary domain, state `active` | `https://{primary hostname}/` |
| Primary domain still verifying, or blocked | `https://{label}.view.fast/` |
| Primary domain still verifying, or blocked | The Space's default hostname |

It is always `https`, always with a trailing slash on the root, so the same host produces a byte-identical URL everywhere. A primary domain that has not reached `active` does not displace the default hostname, which is why a half-configured domain never publishes a link nobody can load.

## After a custom domain becomes primary

Both hostnames serve. The default hostname stays in the Space's serving set permanently, and requests to it keep returning content, not a redirect. What changes is the URL Spacefast reports for the Space.

If you want the `view.fast` hostname to stop answering with content, there is no switch for it. Point people at the custom domain instead.
If you want the managed hostname to stop answering with content, there is no switch for it. Point people at the custom domain instead.

The apex and `www` pair is different. When one of them serves, the other gets an automatic 308 to it. See [Custom domains](/domains).

## Renaming a Space

Renaming the slug moves the default hostname to the new label. The old hostname keeps a temporary 307 to the new one, preserving path and query, so links you already handed out still land. Branch hostnames under the old label get the same 307.
Renaming the slug moves the default hostname to the new label on the same domain. A `view.fast` Space stays on `view.fast`. A `space.fast` Space stays on `space.fast`. The old hostname keeps a temporary 307 to the new one, preserving path and query, so links you already handed out still land. Branch hostnames under the old label get the same 307.

Version URLs do not change on a rename. They were computed once and stay put.

Expand All @@ -82,7 +90,7 @@ One request returns that page. There is no redirect and no interstitial, so `cur

## Hostnames you cannot claim

Any hostname ending in `.view.fast` is refused as a custom domain with `domain_reserved_suffix`. Default hostnames pass DNS verification automatically, so allowing them as custom domains would let one team claim an address owned by another team.
Any hostname ending in `.space.fast` or `.view.fast` is refused as a custom domain with `domain_reserved_suffix`. Default hostnames pass DNS verification automatically, so allowing them as custom domains would let one team claim an address owned by another team.

## Hostnames that do not serve

Expand Down
2 changes: 1 addition & 1 deletion content/api/index.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ The receipt names what to do next:
```json
{
"data": {
"space": { "id": "spc_4a7f...", "slug": "marketing-site", "liveUrl": "https://marketing-site.view.fast" },
"space": { "id": "spc_4a7f...", "slug": "marketing-site", "liveUrl": "https://marketing-site.space.fast" },
"version": { "id": "ver_8c1d...", "status": "finalizing", "number": 7, "immutableUrl": null },
"next": { "action": "poll", "url": "/v1/operations/op_2f6a...", "retryAfter": 1 },
"operation": { "id": "op_2f6a...", "kind": "version_finalize", "status": "running" }
Expand Down
8 changes: 4 additions & 4 deletions content/cli/publish.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -197,11 +197,11 @@ Ignored 3
Mode website
Auth anonymous

Published: https://<slug>.view.fast
Published: https://<slug>.space.fast

Open https://<slug>.view.fast
Live URL https://<slug>.view.fast
Version URL https://v1--<slug>.view.fast
Open https://<slug>.space.fast
Live URL https://<slug>.space.fast
Version URL https://<slug>--v1.space.fast
Space spc_…
Version v1 (ready)
Version ID ver_…
Expand Down
6 changes: 3 additions & 3 deletions content/index.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,10 @@ sf publish ./dist
No account needed for the first publish. The CLI creates a Space, uploads the files, and prints a live URL plus a claim link. Sign in later to keep it.

```text
Published: https://quiet-harbor.view.fast
Published: https://quiet-harbor.space.fast

Open https://quiet-harbor.view.fast
Version URL https://v1--quiet-harbor.view.fast
Open https://quiet-harbor.space.fast
Version URL https://quiet-harbor--v1.space.fast
Version v1 (ready)
Files 12
Duration 3.2s
Expand Down
12 changes: 6 additions & 6 deletions content/quickstart.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ sidebar:
order: 1
---

By the end of this page you have a site live on a `view.fast` hostname, a second version you can roll back to, and a custom domain pointed at it.
By the end of this page you have a site live on a `space.fast` hostname, a second version you can roll back to, and a custom domain pointed at it. Existing Spaces on `view.fast` keep their URLs. See [URLs and hostnames](/urls).

## Before you start

Expand Down Expand Up @@ -46,11 +46,11 @@ You need Node.js 20.3 or newer and a folder of built static files. Any framework
The CLI creates a Space, uploads the folder, and prints the URLs:

```text
Published: https://quiet-harbor.view.fast
Published: https://quiet-harbor.space.fast

Open https://quiet-harbor.view.fast
Live URL https://quiet-harbor.view.fast
Version URL https://v1--quiet-harbor.view.fast
Open https://quiet-harbor.space.fast
Live URL https://quiet-harbor.space.fast
Version URL https://quiet-harbor--v1.space.fast
Space spc_…
Version v1 (ready)
Files 12
Expand Down Expand Up @@ -86,7 +86,7 @@ You need Node.js 20.3 or newer and a folder of built static files. Any framework
sf domains check example.com
```

Once the domain is `active`, the Live URL switches to `https://example.com`. The `view.fast` hostname keeps working. Details, states, and troubleshooting are in [Custom domains](/domains).
Once the domain is `active`, the Live URL switches to `https://example.com`. The `space.fast` hostname keeps working. Details, states, and troubleshooting are in [Custom domains](/domains).

</Step>
</Steps>
Expand Down
2 changes: 1 addition & 1 deletion content/troubleshooting.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ Claude Code on the web and mobile, Codex cloud, and similar hosted sandboxes blo

1. **Add the Spacefast connector to Claude.** [Open the connector form](https://claude.ai/customize/connectors?modal=add-custom-connector&connectorName=Spacefast&connectorUrl=https%3A%2F%2Fmcp.spacefast.com), choose **Connect**, approve, and enable it for the session. Connector traffic goes through Anthropic rather than the sandbox, so publishing works with no network changes, including from the mobile app.
2. **Push to a connected GitHub repository.** Sandboxes can push to GitHub, and Spacefast builds the push itself. Connect the repository once from the Space's **Builds** page; see [Connect a GitHub repository](/git#connect-a-github-repository). Claude Code on the web pushes a working branch, which builds a preview; merge the pull request to go live.
3. **Allow the hosts.** Add `spacefast.com`, `*.spacefast.com`, and `*.view.fast` to the environment's allowlist. In Claude Code that is **Network access → Custom → Allowed domains**; keep **Also include default list of common package managers** checked, or npm, and with it the CLI, is blocked too. In Codex cloud, turn on **Agent internet access**, add the domains, and leave HTTP methods unrestricted, since uploads use `PUT` and `POST`. Allowing only `api.spacefast.com` is not enough: uploads go to `*.view.fast`.
3. **Allow the hosts.** Add `spacefast.com`, `*.spacefast.com`, `*.space.fast`, and `*.view.fast` to the environment's allowlist. In Claude Code that is **Network access → Custom → Allowed domains**; keep **Also include default list of common package managers** checked, or npm, and with it the CLI, is blocked too. In Codex cloud, turn on **Agent internet access**, add the domains, and leave HTTP methods unrestricted, since uploads use `PUT` and `POST`. Allowing only `api.spacefast.com` is not enough: uploads go to managed Space hostnames. New Spaces use `*.space.fast`, and existing Spaces can still use `*.view.fast`.

### An agent gets 403 on one tool

Expand Down
2 changes: 1 addition & 1 deletion evals.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ questions:
routes: /cli
- id: default-hostname
question: What hostname does a new Space get, and what does a single version's URL look like?
expected: ["<slug>.view.fast", "v<number>--<slug>.view.fast"]
expected: ["<label>.space.fast", "<label>--v<number>.space.fast", "existing Spaces keep their original managed apex: space.fast or view.fast"]
routes: /urls
- id: device-login-lifetime
question: How long is the code shown by `sf login` valid, and how long does the resulting credential last?
Expand Down
38 changes: 38 additions & 0 deletions generated/changelog/packages/adapter-kit.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,44 @@ description: "Release history for @spacefast/adapter-kit on npm."

Published as [`@spacefast/adapter-kit`](https://www.npmjs.com/package/@spacefast/adapter-kit) on npm.

## 0.6.0

#### Patch Changes

- @spacefast/routing@0.6.0
- @spacefast/build-output@0.6.0

## 0.5.1

#### Patch Changes

- @spacefast/build-output@0.5.1
- @spacefast/routing@0.5.1

## 0.5.0

#### Patch Changes

- Updated dependencies
- @spacefast/routing@0.5.0
- @spacefast/build-output@0.5.0
- @spacefast/routing@0.5.0
- @spacefast/build-output@0.5.0

## 0.4.1

#### Patch Changes

- @spacefast/routing@0.4.1
- @spacefast/build-output@0.4.1

## 0.4.0

#### Patch Changes

- @spacefast/build-output@0.4.0
- @spacefast/routing@0.4.0

## 0.3.0

#### Patch Changes
Expand Down
Loading
Loading