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 🙏

© 2025 – Pkg Stats / Ryan Hefner

@opensky/remotes

v0.0.3

Published

SvelteKit remotes helper utilities

Readme

@opensky/remotes

Provides two helpers createValidation and createEnhancedForm that improve the behaviors and experience working with remote form functions.

createValidation

Use this to achieve better user experience around validation issues. The logic for showing issues on fields is: issues only appear when you leave a field (onblur events) but they are cleared on input. This way you don't see issues appear as you type, but if the field shows an issue, as you type, the issue will go away as soon as you modify it to be valid.

This follows the same validation as superforms did and is inspired by several articles. (todo: links)

Usage

import { createValidation } from '@opensky/remotes'

const valid = createValidation(remoteForm)

Returns an object with:

  • fields(path: string) - Returns onblur and oninput handlers for a field path
  • issues(path: string) - Returns validation issues for a field path
  • allIssues() - Returns all validation issues
  • addIssue(path: string, issue: string) - Adds a custom validation error to a field
  • reset() - Clears all validation issues
  • validateAll() - Validates all registered fields (with server)
  • updateIssues() - Updates issues for all registered fields (populates from issues)

Use .fields() to add the fields you want validated. Use string access like 'address.state' to reference the fields.

Then use .issues() to get issues by field path the same way. This returns an array of strings or null. So you can easily use it as a check for styling like class:border-red-500={valid.issues('address.state')}

<input
  {...remoteForm.fields.address.state.as('text')}
  {...valid.fields('address.state')}
  class:border-red-500={valid.issues('address.state')}
/>

{#if valid.issues('address.state')}
  {#each valid.issues('address.state') as issue}
    <p>{issue}</p>
  {/each}
{/if}

Details

There is currently a lot of change with svelte's remote functions and with form validation. We use a very newly added preflightOnly flag for validation calls to avoid making calls to the server to validate on every keystroke however there seem to be bugs in the current implementation including that we don't get server issues until you submit the form (we should be getting them on blur).

We also have some buggy behavior after a submit if the server sends back validation issues (and doesn't run the remote function), we do show those issues, however they currently all get cleared when you mutate the form. This is not desired. We want to clear only the issues for the field that mutates after server sends back issues.

For these to update you need to call valid.updateIssues() in your form enhance handler when there is no error but also no result. And you need to call valid.validateAll() in your catch block. (Or use alongside createEnhancedForm to get this automatically).

createEnhancedForm

Creates tracked state for the remote form and also semantic callbacks for stages of the request.

This allows you to add callbacks a little more easily (more like superforms) and allows this utility to take care of some things for you. It also exposes state of the form including delayed and timeout. And you can pass in your validation instance from createValidation for the proper calls be added in the callbacks.

Usage

import { createEnhancedForm } from '@opensky/remotes'

const form = createEnhancedForm(remoteForm, {
  validation: valid,
  delayMs: 500,
  timeoutMs: 3500
})

Returns an object with:

  • enhance(params, callbacks) - Form enhancement handler
  • reset() - Resets the form state back to 'idle'
  • state - Current form state (type-safe based on creation options)
  • idle, pending, issues, error, result - Boolean getters (always available)
  • delayed - Boolean getter (only available if delayMs was provided)
  • timeout - Boolean getter (only available if timeoutMs was provided)

Creation Options:

  • validation? - Optional validation instance from createValidation
  • delayMs? - Milliseconds to wait before transitioning to 'delayed' state
  • timeoutMs? - Milliseconds to wait before transitioning to 'timeout' state

Callbacks (all optional):

  • onSubmit - Called when form submission begins. Receives cancel() and updates() functions:
    • cancel(state?) - Cancel submission and set state to 'idle' (default), 'error', or 'issues'
    • updates(...queries) - Provide queries/overrides for optimistic updates via submit().updates(...)
  • onDelay - Called when delayed state is reached (only allowed if delayMs is set)
  • onTimeout - Called when timeout state is reached (only allowed if timeoutMs is set)
  • onReturn - Called when form submission returns successfully
  • onIssues - Called when form submission returns with validation issues
  • onError - Called when form submission encounters an error

Use with the remote form's enhance method:

<form {...remoteForm.preflight(schema).enhance(opts =>
  form.enhance(opts, {
    onSubmit: ({ cancel, updates, data }) => {
      // Custom client-side checks before submission
      if (!customValidationCheck(data)) {
        valid.addIssue('fieldName', 'Custom validation failed')
        cancel('issues') // Cancel and set state to 'issues'
        return
      }

      // Optimistic updates
      updates(getPosts().withOverride((posts) => [newPost, ...posts]))
    },
    onDelay: () => {},      // Only allowed if delayMs was set at creation
    onTimeout: () => {},    // Only allowed if timeoutMs was set at creation
    onReturn: ({ result }) => {},
    onIssues: () => {},
    onError: ({ error }) => {}
  })
)}>
  <!-- form fields -->

  <button disabled={form.pending || form.delayed}>
    {form.delayed ? 'Loading...' : 'Submit'}
  </button>
</form>

{#if form.timeout}
  <p>Request timed out</p>
{/if}

Example

Example of usage of both createValidation and createEnhancedForm

<script lang="ts">
  import { createValidation, createEnhancedForm } from '@opensky/remotes'
  import { myForm } from './myForm.remote'
  import { z } from 'zod'

  const schema = z.object({
    name: z.string().min(4, 'Too short').max(10, 'Too long'),
    address: z.object({
      state: z.string()
    })
  })

  const valid = createValidation(myForm)
  const form = createEnhancedForm(myForm, {
    validation: valid,
    delayMs: 500,
    timeoutMs: 3500
  })
</script>

<p>State: {form.state}</p>

<form {...myForm.preflight(schema).enhance(opts =>
  form.enhance(opts, {
    onDelay: () => console.log('showing loader'),
    onTimeout: () => console.log('request timeout'),
    onReturn: ({ result }) => console.log('success', result)
  })
)}>
  <input
    {...myForm.fields.name.as('text')}
    {...valid.fields('name')}
    class:error={valid.issues('name')}
  />

  {#if valid.issues('name')}
    {#each valid.issues('name') as issue}
      <p class="error">{issue}</p>
    {/each}
  {/if}

  <input
    {...myForm.fields.address.state.as('text')}
    {...valid.fields('address.state')}
    class:error={valid.issues('address.state')}
  />

  <button disabled={form.pending || form.delayed}>
    {form.delayed ? 'Loading...' : 'Submit'}
  </button>
</form>

{#if form.timeout}
  <p>Request timed out</p>
{/if}