Skip to content

Latest commit

 

History

History
344 lines (255 loc) · 9.96 KB

File metadata and controls

344 lines (255 loc) · 9.96 KB

Replane Svelte SDK

Dynamic configuration for Svelte and SvelteKit applications.

npm License Community

Replane Screenshot

Replane is a dynamic configuration manager that lets you tweak your software without running scripts or building your own admin panel. Store feature flags, rate limits, UI text, log level, rollout percentage, and more. Delegate editing to teammates and share config across services. No redeploys needed.

Why Dynamic Configuration?

  • Feature flags – toggle features, run A/B tests, roll out to user segments
  • Operational tuning – adjust limits, TTLs, and timeouts without redeploying
  • Per-environment settings – different values for production, staging, dev
  • Incident response – instantly revert to a known-good version
  • Cross-service configuration – share settings with realtime sync
  • Non-engineer access – safe editing with schema validation

Installation

npm install @replanejs/svelte

Quick Start

<script>
  import { ReplaneContext, config } from '@replanejs/svelte';
  import { Replane } from '@replanejs/svelte';

  const replane = new Replane();
  await replane.connect({
    baseUrl: 'https://replane.example.com',
    sdkKey: 'your-sdk-key',
  });
</script>

<ReplaneContext client={replane}>
  <MyComponent />
</ReplaneContext>
<!-- MyComponent.svelte -->
<script>
  import { config } from '@replanejs/svelte';

  const feature = config<boolean>('feature-flag-name');
</script>

{#if $feature}
  <p>Feature is enabled!</p>
{:else}
  <p>Feature is disabled</p>
{/if}

Provider Props

Prop Type Required Description
connection ConnectOptions | null Yes Connection options (see below), or null to skip connection
defaults Record<string, unknown> No Default values if server is unavailable
context Record<string, unknown> No Default context for override evaluations
snapshot ReplaneSnapshot No Snapshot for SSR hydration
logger ReplaneLogger No Custom logger (default: console)
loader Snippet No Snippet to show while loading
async boolean No Connect asynchronously (renders immediately with defaults)

Connection Options

The connection prop accepts the following options:

Option Type Required Description
baseUrl string Yes Replane server URL
sdkKey string Yes SDK key for authentication
connectTimeoutMs number No SDK connection timeout (default: 5000)
requestTimeoutMs number No Timeout for SSE requests (default: 2000)
retryDelayMs number No Base delay between retries (default: 200)
inactivityTimeoutMs number No SSE inactivity timeout (default: 30000)
fetchFn typeof fetch No Custom fetch implementation

See @replanejs/sdk documentation for more details.

API

config

Create a reactive store for a specific config value. Similar to readable() or derived().

<script>
  import { config } from '@replanejs/svelte';

  // Returns a Svelte readable store
  const featureEnabled = config<boolean>('featureEnabled');

  // With evaluation context
  const greeting = config<string>('greeting', {
    context: { userId: '123', isPremium: true }
  });
</script>

{#if $featureEnabled}
  <p>{$greeting}</p>
{/if}

getReplane

Get direct access to the Replane client from context.

<script>
  import { getReplane } from '@replanejs/svelte';

  const replane = getReplane();

  function handleClick() {
    const value = replane.get('some-config');
    console.log(value);
  }
</script>

<button onclick={handleClick}>Get Config</button>

configFrom

Create a reactive store from a client directly (without context). Type-safe with full autocomplete for config names.

<script>
  import { configFrom } from '@replanejs/svelte';
  import { replane } from './replane-client';

  // Config name is validated against TConfigs, return type is inferred
  const featureEnabled = configFrom(replane, 'featureEnabled');
</script>

{#if $featureEnabled}
  <p>Feature is enabled!</p>
{/if}

ReplaneContext

Context component that makes the Replane client available to your component tree.

Can be used in several ways:

1. With a pre-created client:

<script>
  import { ReplaneContext, Replane } from '@replanejs/svelte';

  const replane = new Replane();
  await replane.connect({
    baseUrl: 'https://replane.example.com',
    sdkKey: 'your-sdk-key',
  });
</script>

<ReplaneContext client={replane}>
  <App />
</ReplaneContext>

2. With connection (client managed internally):

<script>
  import { ReplaneContext } from '@replanejs/svelte';

  const connection = {
    baseUrl: 'https://your-replane-server.com',
    sdkKey: 'your-sdk-key',
  };
</script>

<svelte:boundary onerror={(e) => console.error(e)}>
  <ReplaneContext {connection}>
    <App />

    {#snippet loader()}
      <p>Loading...</p>
    {/snippet}
  </ReplaneContext>

  {#snippet failed(error)}
    <p>Error: {error.message}</p>
  {/snippet}
</svelte:boundary>

3. With async mode:

Connect in the background while rendering immediately with defaults:

<script>
  import { ReplaneContext } from '@replanejs/svelte';

  const connection = {
    baseUrl: 'https://your-replane-server.com',
    sdkKey: 'your-sdk-key',
  };

  const defaults = {
    featureEnabled: false,
  };
</script>

<ReplaneContext {connection} {defaults} async>
  <App />
</ReplaneContext>

4. With a snapshot (for SSR/hydration):

<script>
  import { ReplaneContext } from '@replanejs/svelte';

  let { data, children } = $props();

  const connection = {
    baseUrl: import.meta.env.VITE_REPLANE_BASE_URL,
    sdkKey: import.meta.env.VITE_REPLANE_SDK_KEY,
  };
</script>

<ReplaneContext {connection} snapshot={data.replaneSnapshot}>
  {@render children()}
</ReplaneContext>

Typed Stores

For better type safety, create typed versions of the store functions:

// $lib/replane/index.ts
import { createTypedConfig, createTypedReplane } from "@replanejs/svelte";

interface AppConfigs {
  theme: { darkMode: boolean; primaryColor: string };
  features: { betaEnabled: boolean };
}

export const appConfig = createTypedConfig<AppConfigs>();
export const getAppReplane = createTypedReplane<AppConfigs>();
<script lang="ts">
  import { appConfig, getAppReplane } from '$lib/replane';

  // Config names autocomplete, values are fully typed
  const theme = appConfig("theme");
  // $theme is { darkMode: boolean; primaryColor: string }

  // Direct client access
  const replane = getAppReplane();
  const features = replane.get("features"); // fully typed
</script>

<div style:color={$theme.primaryColor}>
  {$theme.darkMode ? "Dark" : "Light"}
</div>

SSR / SvelteKit

For server-side rendering, fetch configs on the server and restore on the client:

// src/routes/+layout.server.ts
import { getReplaneSnapshot } from "@replanejs/svelte";

export async function load() {
  const snapshot = await getReplaneSnapshot({
    connection: {
      baseUrl: import.meta.env.REPLANE_BASE_URL,
      sdkKey: import.meta.env.REPLANE_SDK_KEY,
    },
  });

  return { replaneSnapshot: snapshot };
}
<!-- src/routes/+layout.svelte -->
<script lang="ts">
  import { ReplaneContext } from '@replanejs/svelte';

  let { data, children } = $props();

  const connection = {
    baseUrl: import.meta.env.VITE_REPLANE_BASE_URL,
    sdkKey: import.meta.env.VITE_REPLANE_SDK_KEY,
  };
</script>

<ReplaneContext {connection} snapshot={data.replaneSnapshot}>
  {@render children()}
</ReplaneContext>

Realtime Updates

All stores automatically subscribe to realtime updates via SSE. When a config changes on the server, the store updates automatically.

<script>
  import { config } from '@replanejs/svelte';

  const maintenanceMode = config<boolean>('maintenance-mode');
</script>

{#if $maintenanceMode}
  <MaintenanceBanner />
{/if}

Community

Have questions or want to discuss Replane? Join the conversation in GitHub Discussions.

License

MIT