GitHub package.json versionTypeScriptNPM
GitHub package.json versionTypeScriptNPM
Latest

Getting Started

Svelte Eagle Eye is an independent state manager, which once created, can be passed as an argument to any function and/or deployed at any location within an application without further ado.
npm install --save @webkrafters/svelte-eagleeye
Four (4) module functions are provided for integrating this context within the Svelte application environment. Namely:
allKeysIn: lists keys of all Svelte Eagle Eye instance assigned to a request.

Note: Each Svelte Eagle Eye instance is mapped to at most one single request identified by its requestToken. Where no requestToken is assigned, such as in the browser environment, the instance is directly assigned to the application

Note: A server request is identified by an arbitrary requestToken object holding unique string _id value. While requestToken may be used on the browser environment, it is unnecessary.

createEagleEye: creates an Svelte Eagle Eye instance matching an arbitrary key [and optional arbitrary requestToken (a server request requirement)]. It returns the instance along with its identifying information.

Note: The requestToken object and its _id property must be unique in the appilcation. The key for each Svelte Eagle Eye created under each requestToken must be unique within the request.

Note: When an instance whose creation payload matching the current payload exists, that instance is returned instead of creating a duplicate instance. It also returns this instance along with its identifying information.

discardEagleEye: closes and removes from an application the Svelte Eagle Eye instance matching its assigned key [and, if assigned, its requestToken object].

Note: Once called, any useEagleEye attempts on this requestToken-key combination return null. Accessing it using the Svelte getContext(...) will produce and Svelte Eagle Eye instance whose closed property is set.

useEagleEye: returns the Svelte Eagle Eye instance matching its assigned key [and, if assigned, its requestToken object].

Note: This function makes an Svelte Eagle Eye instance accessible throughout the application. While in a Svelte component script, it is more effective to capture the Svelte Eagle Eye instance within the Svelte context and easily access it through out a component tree section that way.

Creating the Svelte Eagle Eye store

To obtain a fresh context store, just call the createEagleEye(...) function. Though, how this is achieved depends largely on the runtime environment, as will be demonstrated shortly:
Env: SSR - Universal App example (.svelte & .ts)
src/demo-context-artifacts.ts
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 export const initState = { a: { b: { c: null, x: { v: false, y: { z: [ 2022 ] } } } } }; export type DemoState = typeof initState; export const ContextKey = 'My Demo Context'; export const pageSelectorMap = { active: 'a.b.x.v', year: 'a.b.x.y.z[0]' };
src/hooks.server.ts
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 import type { Handle } from '@sveltejs/kit'; import { FULL_STATE_SELECTOR, type RequestToken useEagleEye } from '@webkrafters/svelte-eagleeye'; import { ContextKey } from './demo-context-artifacts.ts'; export const handle : Handle = async ({ event, resolve }) => { event.locals.requestToken = { // immediately create and share a unique ID for this incoming request _id: crypto.randomUUID() } as RequestToken; const response = await resolve( event ); // layouts, pages and components are processed and resolved here. const ctx = useEagleEye({ // using `useEagleEye(...)` as svelte getContext is not accessible from here key: ContextKey, requestToken: event.locals.requestToken }); console.log( ctx.store.getState([ FULL_STATE_SELECTOR ]); // log final state of this EagleEye context data return response; };
src/routes/+layout.server.ts
1 2 3 4 5 6 7 8 9 10 import { initState } from '../demo-context-artifacts.ts'; let demoCtxValue = { ...initState }; /* build up `demoCtxValue` with request dependent operations as needed. */ export const load = async ({ locals }) => ({ demoCtxValue, requestToken: locals.requestToken });
src/routes/+layout.svelte
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 <script lang="ts" module> import { ContextKey, type DemoState } from '../demo-context-artifacts.ts'; export const CTX_KEY = ContextKey; </script> <script lang="ts"> import { setContext, untrack } from 'svelte'; import { createEagleEye } from '@webkrafters/svelte-eagleeye'; const { data, children } = $props(); const { requestToken, value } = untrack( () => data ); const { value: ctx } = createEagleEye<DemoState>({ key: CTX_KEY, prehooks?, requestToken, value, storage? }); // can tie this instance to component tree making it easier to obtain in the component environment by: setContext( CTX_KEY, ctx ); // does not have to be CTX_KEY but assures naming consistency ... </script> {@render children()}
src/routes/+page.svelte
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 <script lang="ts"> import { getContext } from 'svelte'; import { pageSelectorMap } from './demo-context-artifacts.ts'; import { CTX_KEY } from './+layout.svelte'; const ctx = getContext( CTX_KEY ); const { data, // this will never be subject to loss of reactivity setState } = ctx.stream( 'MY INDEX PAGE', pageSelectorMap ); const CTA = $derived( data.active ? 'deactivate' : 'activate' ); const toggleStatus = () => setState({ a: { b: { x: { v: !data.active } } } }); ... </script> <div>{ JSON.stringify( data, null, 2 ) }</div> <button onclick={ toggleStatus }>{ CTA }</button>

Joining the Svelte Eagle Eye change stream

Svelte Eagle Eye change stream is a reactive store whose data are automatically changing to reflect most recent changes affecting them.
It embodies the "set-it-and-forget-it" paradigm. Just set up a list of property paths to state slices to observe (see Selector Map). The context takes care of the rest.
The following shows how to join the Svelte Eagle Eye stream.
We use the context's stream(...) property to obtain an active store exposing the context change stream to our consumer component.
src/components/Client1.svelte
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 <script lang="ts"> import { type SvelteEagleEye } from '@webkrafters/svelte-eagleeye'; import { ContextKey, type DemoState, pageSelectorMap } from './demo-context-artifacts.ts'; const { data } = getContext<SvelteEagleEye<DemoState>>( ContextKey ) .stream( 'MY CONTAINER I', { year: pageSelectorMap.year } ); </script> <div>Year: { data.year }</div>;
src/components/Client2.svelte
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 <script lang="ts"> import { type SvelteEagleEye } from '@webkrafters/svelte-eagleeye'; import { ContextKey, type DemoState, pageSelectorMap } from './demo-context-artifacts.ts'; const { stream } = getContext<SvelteEagleEye<DemoState>>( ContextKey ); const { data, resetState, setState } = stream( 'MY CONTAINER II', { year: pageSelectorMap.year }); const onChange = e => setState({ a: { b: { x: { y: { z: { 0: e.target.value } } } } } } as DemoState ); $effect(() => data.year > 2049 && resetState([ 'a.b.c' ]); </script> <div>Year: <input type="number" onchange={ onChange } /></div>
src/components/Ui.svelte
1 2 3 4 5 6 <script lang="ts"> import Client1 from './Client1.svelte'; import Client2 from './Client2.svelte'; </script> <Client1 /> <Client2 />

Discarding a Svelte Eagle Eye context instance

The Svelte Eagle Eye runs decoupled from its embodying application, simply providing an active place for the application to accumulate, access, update and delete its various states as needed in ways that maintain immutability and integrity of state data. The discardEagleEye function removes it from the application, making it immediately GC eligible, as long as there no local references to it. The following is a contrived snippet to demonstrate.
Discarding the instance in a purely server .ts script or a CSR-only application script is fairly straight-forward for the following reasons:
  1. in a purely server .ts script, the requestToken object is readily available.
  2. in a CSR-only application, the requestToken object is not needed to create an Svelte Eagle Eye instance. Even when a requestToken was applied, it remained at the component level.
Discarding the instance in a universal application from a componenent script can be a complex task. It requires sharing the requestToken object between the server scripts and the Svelte component for the following reasons:
  1. the requestToken object is not readily available. The server script must assign this per server request and shared with the component.
  2. the requestToken object, once in the componeent script, is not accessible throughout the component tree. Immediately captture this object in a Svelte context to be retrieved from any part of the component tree requiring the discardEagleEye call.
src/routes/+layout.svelte
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 <script lang="ts" module> import { ContextKey, type DemoState } from '../demo-context-artifacts.ts'; export const CTX_KEY = ContextKey; </script> <script lang="ts"> import { setContext, untrack } from 'svelte'; import { createEagleEye } from '@webkrafters/svelte-eagleeye'; const { data, children } = $props(); // from the server load function const { requestToken, value } = untrack( () => data ); const { value: ctx } = createEagleEye<DemoState>({ key: CTX_KEY, prehooks?, requestToken, value, storage? }); setContext( CTX_KEY, { ctx, requestToken } ); // <----- ... </script> {@render children()}
src/components/DiscardContext.svelte
1 2 3 4 5 6 7 8 9 10 11 <script lang="ts"> import { getContext, onDestroy } from 'svelte'; import { discardEagleEye } from '@webkrafters/svelte-eagleeye'; import { CTX_KEY } from './+layout.svelte'; const { requestToken } = getContext( CTX_KEY ); onDestroy(() => discardEagleEye({ key: CTX_KEY, requestToken })); </script>