Skip to content

Repository files navigation

sv

Everything you need to build a Svelte project, powered by sv.

Creating a project

If you're seeing this, you've probably already done this step. Congrats!

# create a new project in the current directory
npx sv create

# create a new project in my-app
npx sv create my-app

Developing

Once you've created a project and installed dependencies with npm install (or pnpm install or yarn), start a development server:

npm run dev

# or start the server and open the app in a new browser tab
npm run dev -- --open

Admin contact access

Copy src/routes/(centered)/contact/contact-info.server.example.toml to contact-info.server.toml in the same directory, then replace the redacted values. The private file is ignored by Git. Development falls back to the redacted example when the private file is absent.

Production deployments should store the complete contents of the private TOML as the CONTACT_INFO_TOML runtime secret. Do not commit the private file or put its values directly in wrangler.toml.

For Cloudflare Workers:

pnpm exec wrangler secret put CONTACT_INFO_TOML \
  < 'src/routes/(centered)/contact/contact-info.server.toml'

For Vercel production:

vercel env add CONTACT_INFO_TOML production \
  < 'src/routes/(centered)/contact/contact-info.server.toml'

Add the Vercel variable separately for preview when preview deployments need the real profile. Redeploy after adding or changing the secret.

The admin controls live at /contact/admin. Generate an access key, an admin-session signing secret, and a separate visitor-grant signing secret:

The login form accepts the generated admin_... access key. It does not accept the SHA-256 digest or either signing secret stored in .env.

node <<'NODE'
const { createHash, randomBytes } = require('node:crypto')

const accessKey = `admin_${randomBytes(24).toString('base64url')}`
const accessKeyDigest = createHash('sha256').update(accessKey).digest('hex')
const sessionSecret = randomBytes(32).toString('base64url')
const grantSecret = randomBytes(32).toString('base64url')

console.log('\n=== ADMIN ACCESS KEY: SAVE THIS AND ENTER IT IN THE LOGIN FORM ===\n')
console.log(accessKey)
console.log('\n=== COPY THESE VALUES TO .env ===\n')
console.log(`CONTACT_ADMIN_KEY_SHA256=${accessKeyDigest}`)
console.log(`CONTACT_ADMIN_SESSION_SECRET=${sessionSecret}`)
console.log('CONTACT_ADMIN_SESSION_VERSION=1')
console.log(`CONTACT_GRANT_SECRET=${grantSecret}`)
console.log('\nRestart the development server after updating .env.\n')
NODE

The access key is printed once. Store it in a password manager. Keep both signing secrets separate from the access key and from each other, and do not commit any of them. Rotating CONTACT_GRANT_SECRET immediately invalidates outstanding visitor links and visitor cookies. Generate and deploy a new value with the same command when the secret may be exposed, then create fresh links for recipients who still need access. Admin sessions use their separate secret and are not affected.

Restart the development server after updating .env, then follow the small "Admin" link at the bottom of /contact or open /contact/admin directly.

Building

To create a production version of your app:

npm run build

You can preview the production build with npm run preview.

To deploy your app, you may need to install an adapter for your target environment.

Releases

Packages

Used by

Contributors

Languages