<script lang="ts">
import { TanStackDevtools } from '@tanstack/svelte-devtools'
import { pacerDevtoolsPlugin } from '@tanstack/svelte-pacer-devtools'
import { rateLimit } from '@tanstack/svelte-pacer/rate-limiter'
let counterWindowType = $state<'fixed' | 'sliding'>('fixed')
let instantCount = $state(0)
let rateLimitedCount = $state(0)
const rateLimitedSetCount = $derived.by(() =>
rateLimit((value: typeof rateLimitedCount) => (rateLimitedCount = value), {
limit: 5,
window: 5000,
windowType: counterWindowType,
onReject: (rateLimiter) =>
console.log(
'Rejected by rate limiter',
rateLimiter.getMsUntilNextWindow(),
),
}),
)
function increment() {
instantCount = ((c) => {
const newInstantCount = c + 1
rateLimitedSetCount(newInstantCount)
return newInstantCount
})(instantCount)
}
let rangeWindowType = $state<'fixed' | 'sliding'>('fixed')
let currentValue = $state(50)
let rateLimitedValue = $state(50)
const rateLimitedSetValue = $derived.by(() =>
rateLimit((value: typeof rateLimitedValue) => (rateLimitedValue = value), {
limit: 30,
window: 2000,
windowType: rangeWindowType,
onReject: (rateLimiter) =>
console.log(
'Rejected by rate limiter',
rateLimiter.getMsUntilNextWindow(),
),
}),
)
function handleRangeChange(e: Event) {
const newValue = parseInt((e.target as HTMLInputElement).value, 10)
currentValue = newValue
rateLimitedSetValue(newValue)
}
let searchWindowType = $state<'fixed' | 'sliding'>('fixed')
let text = $state('')
let rateLimitedText = $state('')
const rateLimitedSetText = $derived.by(() =>
rateLimit((value: typeof rateLimitedText) => (rateLimitedText = value), {
limit: 5,
window: 5000,
windowType: searchWindowType,
onReject: (rateLimiter) =>
console.log(
'Rejected by rate limiter',
rateLimiter.getMsUntilNextWindow(),
),
}),
)
function handleTextChange(e: Event) {
const newValue = (e.target as HTMLInputElement).value
text = newValue
rateLimitedSetText(newValue)
}
</script>
<div>
<div>
<h1>TanStack Pacer rateLimit Example 1</h1>
<div style="display: grid; gap: 0.5rem; margin-bottom: 1rem">
<label
><input
type="radio"
name="counterWindowType"
value="fixed"
checked={counterWindowType === 'fixed'}
oninput={() => (counterWindowType = 'fixed')}
/>Fixed Window</label
><label
><input
type="radio"
name="counterWindowType"
value="sliding"
checked={counterWindowType === 'sliding'}
oninput={() => (counterWindowType = 'sliding')}
/>Sliding Window</label
>
</div>
<table>
<tbody
><tr><td>Instant Count:</td><td>{instantCount}</td></tr><tr
><td>Rate Limited Count:</td><td>{rateLimitedCount}</td></tr
></tbody
>
</table>
<div><button onclick={increment}>Increment</button></div>
</div>
<hr />
<div>
<h1>TanStack Pacer rateLimit Example 2</h1>
<div style="display: grid; gap: 0.5rem; margin-bottom: 1rem">
<label
><input
type="radio"
name="windowType2"
value="fixed"
checked={searchWindowType === 'fixed'}
oninput={() => (searchWindowType = 'fixed')}
/>Fixed Window</label
><label
><input
type="radio"
name="windowType2"
value="sliding"
checked={searchWindowType === 'sliding'}
oninput={() => (searchWindowType = 'sliding')}
/>Sliding Window</label
>
</div>
<div>
<input
type="search"
value={text}
oninput={handleTextChange}
placeholder="Type text (rate limited to 5 updates per 5 seconds)..."
style="width: 100%"
/>
</div>
<table>
<tbody
><tr><td>Instant Text:</td><td>{text}</td></tr><tr
><td>Rate Limited Text:</td><td>{rateLimitedText}</td></tr
></tbody
>
</table>
</div>
<hr />
<div>
<h1>TanStack Pacer rateLimit Example 3</h1>
<div style="display: grid; gap: 0.5rem; margin-bottom: 1rem">
<label
><input
type="radio"
name="windowType3"
value="fixed"
checked={rangeWindowType === 'fixed'}
oninput={() => (rangeWindowType = 'fixed')}
/>Fixed Window</label
><label
><input
type="radio"
name="windowType3"
value="sliding"
checked={rangeWindowType === 'sliding'}
oninput={() => (rangeWindowType = 'sliding')}
/>Sliding Window</label
>
</div>
<div style="margin-bottom: 20px">
<label
>Current Range:<input
type="range"
min="0"
max="100"
value={currentValue}
oninput={handleRangeChange}
style="width: 100%"
/><span>{currentValue}</span></label
>
</div>
<div style="margin-bottom: 20px">
<label
>Rate Limited Range (Readonly):<input
type="range"
min="0"
max="100"
value={rateLimitedValue}
disabled
style="width: 100%"
/><span>{rateLimitedValue}</span></label
>
</div>
<div style="color: #666; font-size: 0.9em">
<p>Rate limited to 30 updates per 2000ms window</p>
</div>
</div>
</div>
{#if import.meta.env.DEV}<TanStackDevtools
plugins={[pacerDevtoolsPlugin()]}
/>{/if}