@deijose/nix-js 2.2.0 → 2.2.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,2 +1,2 @@
1
- export { Signal, signal, effect, computed, batch, watch, untrack, nextTick, html, repeat, ref, showWhen, portal, createPortalOutlet, portalOutlet, provideOutlet, injectOutlet, createErrorBoundary, transition, mount, NixComponent, createStore, createRouter, RouterView, Link, nixRouter, RouterKey, suspend, lazy, provide, inject, createInjectionKey, nixField, nixFieldArray, createForm, required, minLength, maxLength, email, pattern, min, max, createValidator, validators, extendValidators, } from "./nix";
2
- export type { WatchOptions, NixTemplate, NixMountHandle, MountOptions, KeyedList, NixRef, PortalOutlet, ErrorFallback, TransitionOptions, TransitionContent, Store, StoreSignals, Router, NamedRouteLocation, RouteLocation, RouteRecord, RouterOptions, NavigationGuard, NavigationGuardResult, AfterEachHook, ResolvedRoute, ScrollPosition, ScrollBehavior, RouterMode, SuspenseOptions, InjectionKey, Validator, ValidateOn, FieldState, FieldArrayState, FieldErrors, FormState, FormOptions, ValidatorsBase, NixChildren, } from "./nix";
1
+ export { Signal, signal, effect, computed, batch, watch, untrack, nextTick, html, repeat, ref, showWhen, portal, createPortalOutlet, portalOutlet, provideOutlet, injectOutlet, createErrorBoundary, transition, mount, NixComponent, createStore, persistPlugin, loggerPlugin, guardPlugin, bridgePlugin, createRouter, RouterView, Link, nixRouter, RouterKey, suspend, lazy, provide, inject, createInjectionKey, nixField, nixFieldArray, createForm, required, minLength, maxLength, email, pattern, min, max, createValidator, validators, extendValidators, } from "./nix";
2
+ export type { WatchOptions, NixTemplate, NixMountHandle, MountOptions, KeyedList, NixRef, PortalOutlet, ErrorFallback, TransitionOptions, TransitionContent, Store, StoreSignals, NixPlugin, Router, NamedRouteLocation, RouteLocation, RouteRecord, RouterOptions, NavigationGuard, NavigationGuardResult, AfterEachHook, ResolvedRoute, ScrollPosition, ScrollBehavior, RouterMode, SuspenseOptions, InjectionKey, Validator, ValidateOn, FieldState, FieldArrayState, FieldErrors, FormState, FormOptions, ValidatorsBase, NixChildren, } from "./nix";
@@ -7,7 +7,8 @@ export type { MountOptions } from "./component";
7
7
  export { NixComponent } from "./lifecycle";
8
8
  export type { NixChildren } from "./lifecycle";
9
9
  export { createStore } from "./store";
10
- export type { Store, StoreSignals } from "./store";
10
+ export type { Store, StoreSignals, NixPlugin } from "./store";
11
+ export { persistPlugin, loggerPlugin, guardPlugin, bridgePlugin } from "./plugins";
11
12
  export { createRouter, RouterView, Link, nixRouter, RouterKey } from "./router";
12
13
  export type { Router, NamedRouteLocation, RouteLocation, RouteRecord, RouterOptions, NavigationGuard, NavigationGuardResult, AfterEachHook, ResolvedRoute, ScrollPosition, ScrollBehavior, RouterMode, } from "./router";
13
14
  export { suspend, lazy } from "./async";
@@ -0,0 +1,52 @@
1
+ import { type NixPlugin, type Store } from "./store";
2
+ /**
3
+ * Minimal interface that any storage adapter must implement.
4
+ * Compatible with localStorage, sessionStorage, AsyncStorage, IndexedDB, etc.
5
+ */
6
+ interface StorageAdapter {
7
+ /** Retrieves an item from storage. Returns null if not found. */
8
+ getItem(key: string): string | null | Promise<string | null>;
9
+ /** Stores an item in storage. */
10
+ setItem(key: string, value: string): void | Promise<void>;
11
+ /** Optional: Removes an item from storage. */
12
+ removeItem?(key: string): void | Promise<void>;
13
+ }
14
+ /**
15
+ * Persists the store state to a storage medium (defaults to localStorage).
16
+ * Automatically hydrates on initialization and saves changes on every reactive flush.
17
+ */
18
+ export declare function persistPlugin<T extends Record<string, unknown>>(storageKey: string, opts?: {
19
+ /** Storage adapter to use. Defaults to localStorage. */
20
+ storage?: StorageAdapter;
21
+ /** Properties to exclude from persistence. */
22
+ exclude?: Array<keyof T>;
23
+ /** Custom serialization function. Defaults to JSON.stringify. */
24
+ serialize?: (state: T) => string;
25
+ /** Custom deserialization function. Defaults to JSON.parse. */
26
+ deserialize?: (raw: string) => Partial<T>;
27
+ /** Debounce interval in milliseconds for batching writes. Defaults to 0 (immediate). */
28
+ debounce?: number;
29
+ }): NixPlugin<T>;
30
+ /**
31
+ * Logs state transitions to the console.
32
+ * Calculates property-level diffs and groups output by store ID.
33
+ */
34
+ export declare function loggerPlugin<T extends Record<string, unknown>>(opts?: {
35
+ /** Whether the console group should be collapsed by default. */
36
+ collapsed?: boolean;
37
+ /** Optional filter to skip logging for specific changes. */
38
+ filter?: (diff: Partial<T>) => boolean;
39
+ }): NixPlugin<T>;
40
+ /**
41
+ * Function type for mutation guards.
42
+ */
43
+ type GuardFn<T extends Record<string, unknown>> = (next: Partial<T>, current: T) => Partial<T> | void;
44
+ /**
45
+ * Intercepts $patch and $reset calls to validate or transform state before it is applied.
46
+ */
47
+ export declare function guardPlugin<T extends Record<string, unknown>>(guards: GuardFn<T>[]): NixPlugin<T>;
48
+ /**
49
+ * Synchronizes data between two stores by watching one and patching the other.
50
+ */
51
+ export declare function bridgePlugin<TA extends Record<string, unknown>, TB extends Record<string, unknown>>(sourceStore: Store<TB>, sync: (sourceState: TB, targetStore: Store<TA>) => void): NixPlugin<TA>;
52
+ export {};
@@ -2,10 +2,10 @@ import { Signal, type WatchOptions } from "./reactivity";
2
2
  export type StoreSignals<T extends Record<string, unknown>> = {
3
3
  readonly [K in keyof T]: Signal<T[K]>;
4
4
  };
5
- export type ReadonlySignal<T> = Omit<Signal<T>, "value" | "update" | "dispose"> & {
6
- readonly value: T;
7
- readonly dispose: never;
8
- };
5
+ export declare class ReadonlySignal<T> extends Signal<T> {
6
+ private readonly label;
7
+ constructor(source: Signal<T>, label?: string);
8
+ }
9
9
  export type StoreGetters<G extends Record<string, Signal<unknown>>> = {
10
10
  readonly [K in keyof G]: ReadonlySignal<G[K] extends Signal<infer V> ? V : never>;
11
11
  };
@@ -48,7 +48,13 @@ export type Store<T extends Record<string, unknown>, A extends Record<string, un
48
48
  */
49
49
  export type NixPlugin<T extends Record<string, unknown>, A extends Record<string, unknown> = Record<never, never>, G extends Record<string, Signal<unknown>> = Record<never, never>> = (store: Store<T, A, G>) => (() => void) | void;
50
50
  export interface CreateStoreOptions<T extends Record<string, unknown>, A extends Record<string, unknown> = Record<never, never>, G extends Record<string, Signal<unknown>> = Record<never, never>> {
51
+ /** Display name for the store. Used in error messages and devtools. */
51
52
  name?: string;
53
+ /** Factory that receives the raw signals and returns action methods. */
54
+ actions?: (signals: StoreSignals<T>) => A;
55
+ /** Factory that receives the raw signals and returns computed getters. */
56
+ getters?: (signals: StoreSignals<T>) => G;
57
+ /** Plugins to extend the store. Each receives the assembled store. */
52
58
  plugins?: NixPlugin<T, A, G>[];
53
59
  }
54
- export declare function createStore<T extends Record<string, unknown>, A extends Record<string, unknown> = Record<never, never>, G extends Record<string, Signal<unknown>> = Record<never, never>>(initialState: T, actionsFactory?: (signals: StoreSignals<T>) => A, gettersFactory?: (signals: StoreSignals<T>) => G, options?: CreateStoreOptions<T, A, G>): Store<T, A, G>;
60
+ export declare function createStore<T extends Record<string, unknown>, A extends Record<string, unknown> = Record<never, never>, G extends Record<string, Signal<unknown>> = Record<never, never>>(initialState: T, options?: CreateStoreOptions<T, A, G>): Store<T, A, G>;
@@ -1 +1 @@
1
- Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e=require("./signals.cjs"),t=require("./template2.cjs"),n=require("./lifecycle.cjs"),r=require("./context.cjs"),i=require("./router.cjs"),a=require("./component.cjs"),o=require("./store.cjs"),s=require("./async.cjs"),c=require("./form.cjs");exports.Link=i.Link,exports.NixComponent=n.NixComponent,exports.RouterKey=i.RouterKey,exports.RouterView=i.RouterView,exports.Signal=e.Signal,exports.batch=e.batch,exports.computed=e.computed,exports.createErrorBoundary=t.t,exports.createForm=c.createForm,exports.createInjectionKey=r.createInjectionKey,exports.createPortalOutlet=t.n,exports.createRouter=i.createRouter,exports.createStore=o.createStore,exports.createValidator=c.createValidator,exports.effect=e.effect,exports.email=c.email,exports.extendValidators=c.extendValidators,exports.html=t.l,exports.inject=r.inject,exports.injectOutlet=t.r,exports.lazy=s.lazy,exports.max=c.max,exports.maxLength=c.maxLength,exports.min=c.min,exports.minLength=c.minLength,exports.mount=a.mount,exports.nextTick=e.nextTick,exports.nixField=c.nixField,exports.nixFieldArray=c.nixFieldArray,exports.nixRouter=i.nixRouter,exports.pattern=c.pattern,exports.portal=t.i,exports.portalOutlet=t.a,exports.provide=r.provide,exports.provideOutlet=t.o,exports.ref=t.h,exports.repeat=t.d,exports.required=c.required,exports.showWhen=t.u,exports.signal=e.signal,exports.suspend=s.suspend,exports.transition=t.s,exports.untrack=e.untrack,exports.validators=c.validators,exports.watch=e.watch;
1
+ Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e=require("./signals.cjs"),t=require("./template2.cjs"),n=require("./lifecycle.cjs"),r=require("./context.cjs"),i=require("./router.cjs"),a=require("./component.cjs"),o=require("./store.cjs"),s=require("./plugins.cjs"),c=require("./async.cjs"),l=require("./form.cjs");exports.Link=i.Link,exports.NixComponent=n.NixComponent,exports.RouterKey=i.RouterKey,exports.RouterView=i.RouterView,exports.Signal=e.Signal,exports.batch=e.batch,exports.bridgePlugin=s.bridgePlugin,exports.computed=e.computed,exports.createErrorBoundary=t.t,exports.createForm=l.createForm,exports.createInjectionKey=r.createInjectionKey,exports.createPortalOutlet=t.n,exports.createRouter=i.createRouter,exports.createStore=o.createStore,exports.createValidator=l.createValidator,exports.effect=e.effect,exports.email=l.email,exports.extendValidators=l.extendValidators,exports.guardPlugin=s.guardPlugin,exports.html=t.l,exports.inject=r.inject,exports.injectOutlet=t.r,exports.lazy=c.lazy,exports.loggerPlugin=s.loggerPlugin,exports.max=l.max,exports.maxLength=l.maxLength,exports.min=l.min,exports.minLength=l.minLength,exports.mount=a.mount,exports.nextTick=e.nextTick,exports.nixField=l.nixField,exports.nixFieldArray=l.nixFieldArray,exports.nixRouter=i.nixRouter,exports.pattern=l.pattern,exports.persistPlugin=s.persistPlugin,exports.portal=t.i,exports.portalOutlet=t.a,exports.provide=r.provide,exports.provideOutlet=t.o,exports.ref=t.h,exports.repeat=t.d,exports.required=l.required,exports.showWhen=t.u,exports.signal=e.signal,exports.suspend=c.suspend,exports.transition=t.s,exports.untrack=e.untrack,exports.validators=l.validators,exports.watch=e.watch;
@@ -1 +1 @@
1
- import{Signal as e,batch as t,computed as n,effect as r,nextTick as i,signal as a,untrack as o,watch as s}from"./signals.js";import{a as c,d as l,h as u,i as d,l as f,n as p,o as m,r as h,s as g,t as _,u as v}from"./template2.js";import{NixComponent as y}from"./lifecycle.js";import{createInjectionKey as b,inject as x,provide as S}from"./context.js";import{Link as C,RouterKey as w,RouterView as T,createRouter as E,nixRouter as D}from"./router.js";import{mount as O}from"./component.js";import{createStore as k}from"./store.js";import{lazy as A,suspend as j}from"./async.js";import{createForm as M,createValidator as N,email as P,extendValidators as F,max as I,maxLength as L,min as R,minLength as z,nixField as B,nixFieldArray as V,pattern as H,required as U,validators as W}from"./form.js";export{C as Link,y as NixComponent,w as RouterKey,T as RouterView,e as Signal,t as batch,n as computed,_ as createErrorBoundary,M as createForm,b as createInjectionKey,p as createPortalOutlet,E as createRouter,k as createStore,N as createValidator,r as effect,P as email,F as extendValidators,f as html,x as inject,h as injectOutlet,A as lazy,I as max,L as maxLength,R as min,z as minLength,O as mount,i as nextTick,B as nixField,V as nixFieldArray,D as nixRouter,H as pattern,d as portal,c as portalOutlet,S as provide,m as provideOutlet,u as ref,l as repeat,U as required,v as showWhen,a as signal,j as suspend,g as transition,o as untrack,W as validators,s as watch};
1
+ import{Signal as e,batch as t,computed as n,effect as r,nextTick as i,signal as a,untrack as o,watch as s}from"./signals.js";import{a as c,d as l,h as u,i as d,l as f,n as p,o as m,r as h,s as g,t as _,u as v}from"./template2.js";import{NixComponent as y}from"./lifecycle.js";import{createInjectionKey as b,inject as x,provide as S}from"./context.js";import{Link as C,RouterKey as w,RouterView as T,createRouter as E,nixRouter as D}from"./router.js";import{mount as O}from"./component.js";import{createStore as k}from"./store.js";import{bridgePlugin as A,guardPlugin as j,loggerPlugin as M,persistPlugin as N}from"./plugins.js";import{lazy as P,suspend as F}from"./async.js";import{createForm as I,createValidator as L,email as R,extendValidators as z,max as B,maxLength as V,min as H,minLength as U,nixField as W,nixFieldArray as G,pattern as K,required as q,validators as J}from"./form.js";export{C as Link,y as NixComponent,w as RouterKey,T as RouterView,e as Signal,t as batch,A as bridgePlugin,n as computed,_ as createErrorBoundary,I as createForm,b as createInjectionKey,p as createPortalOutlet,E as createRouter,k as createStore,L as createValidator,r as effect,R as email,z as extendValidators,j as guardPlugin,f as html,x as inject,h as injectOutlet,P as lazy,M as loggerPlugin,B as max,V as maxLength,H as min,U as minLength,O as mount,i as nextTick,W as nixField,G as nixFieldArray,D as nixRouter,K as pattern,N as persistPlugin,d as portal,c as portalOutlet,S as provide,m as provideOutlet,u as ref,l as repeat,q as required,v as showWhen,a as signal,F as suspend,g as transition,o as untrack,J as validators,s as watch};
@@ -0,0 +1 @@
1
+ Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e=require("./signals.cjs");function t(t,r={}){let{storage:n=localStorage,exclude:o=[],serialize:l=JSON.stringify,deserialize:i=JSON.parse,debounce:c=0}=r;return r=>{let s;return e.untrack(async()=>{try{let e=await n.getItem(t);if(!e)return;let l=i(e),c={};for(let e of Object.keys(l))e in r.$state&&!o.includes(e)&&(c[e]=l[e]);Object.keys(c).length>0&&r.$patch(c)}catch{}}),e.watch(r.$stateSignal,e=>{let r=()=>{try{let r=0===o.length?e:Object.fromEntries(Object.entries(e).filter(([e])=>!o.includes(e)));n.setItem(t,l(r))}catch{}};c>0?(clearTimeout(s),s=setTimeout(r,c)):r()})}}function n(t={}){let{collapsed:r=!0,filter:n}=t;return t=>{let o=r?console.groupCollapsed:console.group;return e.watch(t.$stateSignal,(e,r)=>{if(!r)return;let l={};for(let t of Object.keys(e))Object.is(e[t],r[t])||(l[t]=e[t]);0!==Object.keys(l).length&&(n&&!n(l)||(o(`%c[nix:${t.$id}]%c ${Object.keys(l).join(", ")}`,"color:#7F77DD;font-weight:500","color:inherit;font-weight:400"),console.log("prev →",r),console.log("next →",e),console.log("diff →",l),console.groupEnd()))},{immediate:!0})}}function r(t){return r=>{let n=r.$patch.bind(r),o=r.$reset.bind(r);return r.$patch=function(o){let l=o,i=e.untrack(()=>r.$state);for(let e of t){let t=e(l,i);void 0!==t&&(l=t)}n(l)},r.$reset=function(){let n=e.untrack(()=>r.$state);for(let e of t)e(n,n);o()},()=>{r.$patch=n,r.$reset=o}}}function i(t,r){return n=>e.watch(t.$stateSignal,e=>{r(e,n)})}exports.bridgePlugin=i,exports.guardPlugin=r,exports.loggerPlugin=n,exports.persistPlugin=t;
@@ -0,0 +1 @@
1
+ import{untrack as e,watch as t}from"./signals.js";function n(n,r={}){let{storage:l=localStorage,exclude:o=[],serialize:i=JSON.stringify,deserialize:s=JSON.parse,debounce:c=0}=r;return r=>{let a;return e(async()=>{try{let e=await l.getItem(n);if(!e)return;let t=s(e),i={};for(let e of Object.keys(t))e in r.$state&&!o.includes(e)&&(i[e]=t[e]);Object.keys(i).length>0&&r.$patch(i)}catch{}}),t(r.$stateSignal,e=>{let t=()=>{try{let t=0===o.length?e:Object.fromEntries(Object.entries(e).filter(([e])=>!o.includes(e)));l.setItem(n,i(t))}catch{}};c>0?(clearTimeout(a),a=setTimeout(t,c)):t()})}}function r(e={}){let{collapsed:n=!0,filter:r}=e;return e=>{let l=n?console.groupCollapsed:console.group;return t(e.$stateSignal,(t,n)=>{if(!n)return;let o={};for(let e of Object.keys(t))Object.is(t[e],n[e])||(o[e]=t[e]);0!==Object.keys(o).length&&(r&&!r(o)||(l(`%c[nix:${e.$id}]%c ${Object.keys(o).join(", ")}`,"color:#7F77DD;font-weight:500","color:inherit;font-weight:400"),console.log("prev →",n),console.log("next →",t),console.log("diff →",o),console.groupEnd()))},{immediate:!0})}}function i(t){return n=>{let r=n.$patch.bind(n),l=n.$reset.bind(n);return n.$patch=function(l){let o=l,i=e(()=>n.$state);for(let e of t){let t=e(o,i);void 0!==t&&(o=t)}r(o)},n.$reset=function(){let r=e(()=>n.$state);for(let e of t)e(r,r);l()},()=>{n.$patch=r,n.$reset=l}}}function a(e,n){return r=>t(e.$stateSignal,e=>{n(e,r)})}export{a as bridgePlugin,i as guardPlugin,r as loggerPlugin,n as persistPlugin};
@@ -1 +1 @@
1
- Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e=require("./signals.cjs");var t=new Set(["$id","$state","$stateSignal","$reset","$patch","$watch","$dispose"]);function n(e){if("__proto__"===e||"constructor"===e||"prototype"===e)throw Error(`[Nix] Store key "${e}" is not allowed for security reasons.`);if(t.has(e))throw Error(`[Nix] Store key "${e}" is reserved.`)}function r(e,r){return!t.has(e)||(console.warn(`[Nix] Store ${r} "${e}" is reserved and will be ignored.`),!1)}function i(e,t){let r=Object.create(e);return Object.defineProperty(r,"dispose",{value:()=>{throw Error(`[Nix] Cannot dispose readonly getter "${t}". Dispose the store instead with store.$dispose().`)},writable:!1,configurable:!1}),Object.defineProperty(r,"value",{get:()=>e.value,set(){throw Error(`[Nix] "${t}" is read-only.`)},configurable:!1}),Object.defineProperty(r,"update",{value:()=>{throw Error(`[Nix] "${t}" is read-only.`)},writable:!1,configurable:!1}),r}function a(o,a,l,s={}){let{name:c="store",plugins:f=[]}=s,u=Object.keys(o),d={};for(let t of u)n(t),d[t]=e.signal(o[t]);let b,$=d,g=e.computed(()=>{let e={};for(let t of u)e[t]=d[t].value;return e}),p=i(g,`store "${c}".$stateSignal`);try{b=structuredClone(o)}catch(e){throw Error(`[Nix] Store "${c}" initialState contains non-serializable data (functions, DOM nodes, Symbols, or WeakRefs). Remove these before creating the store. Original error: ${e}`)}let h=Object.assign(Object.create(null),$,{$reset:function(){e.batch(()=>{for(let e of u)d[e].value=b[e]})},$patch:function(t){e.batch(()=>{for(let e of Object.keys(t))Object.prototype.hasOwnProperty.call(d,e)&&(d[e].value=t[e])})},$watch:function(t,r){return e.watch(g,t,r)}});Object.defineProperty(h,"$id",{value:c,writable:!1,enumerable:!1,configurable:!1}),Object.defineProperty(h,"$state",{get:()=>g.value,enumerable:!0,configurable:!1}),Object.defineProperty(h,"$stateSignal",{value:p,writable:!1,enumerable:!1,configurable:!1});let w=new Set([...u,...Array.from(t)]);if(a){let e=a($);for(let t of Object.keys(e))if(r(t,"action")){if(w.has(t)){console.warn(`[Nix] Store "${c}": action "${t}" collides with an existing signal or getter and will be ignored.`);continue}w.add(t),h[t]=e[t]}}if(l){let t=l($);for(let o of Object.keys(t)){if(!r(o,"getter"))continue;if(w.has(o)){console.warn(`[Nix] Store "${c}": getter "${o}" collides with an existing signal or action and will be ignored.`);continue}let n=t[o];if(!(n instanceof e.Signal))throw TypeError(`[Nix] Store "${c}": getter "${o}" must return a Signal (wrap it with computed()). Got: ${typeof n}`);w.add(o),h[o]=i(n,`getter "${o}" in store "${c}"`)}}let y=[()=>g.dispose()];for(let e of f)try{let t=e(h);"function"==typeof t&&y.push(t)}catch(e){console.error(`[Nix] Plugin initialization failed for store "${c}":`,e)}return h.$dispose=()=>{for(let e of y)e()},h}exports.createStore=a;
1
+ Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e=require("./signals.cjs");var t=class extends e.Signal{label;constructor(e,t="ReadonlySignal"){super(e.peek()),this.label=t,Object.defineProperty(this,"value",{get:()=>e.value,set:()=>{throw Error(`[Nix] "${this.label}" is read-only.`)},configurable:!1}),this.update=()=>{throw Error(`[Nix] "${this.label}" is read-only.`)},this.dispose=()=>{throw Error(`[Nix] Cannot dispose "${this.label}" directly.`)}}},n=new Set(["$id","$state","$stateSignal","$reset","$patch","$watch","$dispose"]);function r(e){if("__proto__"===e||"constructor"===e||"prototype"===e)throw Error(`[Nix] Store key "${e}" is not allowed for security reasons.`);if(n.has(e))throw Error(`[Nix] Store key "${e}" is reserved.`)}function i(e,t){return!n.has(e)||(console.warn(`[Nix] Store ${t} "${e}" is reserved and will be ignored.`),!1)}function a(e,r){return new t(e,r)}function o(t,o={}){let{name:l="store",actions:s,getters:c,plugins:f=[]}=o,u=Object.keys(t),d={};for(let o of u)r(o),d[o]=e.signal(t[o]);let g,b=d,$=e.computed(()=>{let e={};for(let t of u)e[t]=d[t].value;return e}),h=a($,`store "${l}".$stateSignal`);try{g=structuredClone(t)}catch(e){throw Error(`[Nix] Store "${l}" initialState contains non-serializable data (functions, DOM nodes, Symbols, or WeakRefs). Remove these before creating the store. Original error: ${e}`)}let p=Object.assign(Object.create(null),b,{$reset:function(){e.batch(()=>{for(let e of u)d[e].value=g[e]})},$patch:function(t){e.batch(()=>{for(let e of Object.keys(t))Object.prototype.hasOwnProperty.call(d,e)&&(d[e].value=t[e])})},$watch:function(t,r){return e.watch($,t,r)}});Object.defineProperty(p,"$id",{value:l,writable:!1,enumerable:!1,configurable:!1}),Object.defineProperty(p,"$state",{get:()=>$.value,enumerable:!0,configurable:!1}),Object.defineProperty(p,"$stateSignal",{value:h,writable:!1,enumerable:!1,configurable:!1});let y=new Set([...u,...Array.from(n)]);if(s){let e=s(b);for(let t of Object.keys(e))if(i(t,"action")){if(y.has(t)){console.warn(`[Nix] Store "${l}": action "${t}" collides with an existing signal or getter and will be ignored.`);continue}y.add(t),p[t]=e[t]}}if(c){let t=c(b);for(let r of Object.keys(t)){if(!i(r,"getter"))continue;if(y.has(r)){console.warn(`[Nix] Store "${l}": getter "${r}" collides with an existing signal or action and will be ignored.`);continue}let o=t[r];if(!(o instanceof e.Signal))throw TypeError(`[Nix] Store "${l}": getter "${r}" must return a Signal (wrap it with computed()). Got: ${typeof o}`);y.add(r),p[r]=a(o,`getter "${r}" in store "${l}"`)}}let w=[()=>$.dispose()];for(let e of f)try{let t=e(p);"function"==typeof t&&w.push(t)}catch(e){console.error(`[Nix] Plugin initialization failed for store "${l}":`,e)}return p.$dispose=()=>{for(let e of w)e()},p}exports.ReadonlySignal=t,exports.createStore=o;
package/dist/lib/store.js CHANGED
@@ -1 +1 @@
1
- import{Signal as e,batch as t,computed as n,signal as r,watch as i}from"./signals.js";var a=new Set(["$id","$state","$stateSignal","$reset","$patch","$watch","$dispose"]);function o(e){if("__proto__"===e||"constructor"===e||"prototype"===e)throw Error(`[Nix] Store key "${e}" is not allowed for security reasons.`);if(a.has(e))throw Error(`[Nix] Store key "${e}" is reserved.`)}function s(e,t){return!a.has(e)||(console.warn(`[Nix] Store ${t} "${e}" is reserved and will be ignored.`),!1)}function c(e,t){let r=Object.create(e);return Object.defineProperty(r,"dispose",{value:()=>{throw Error(`[Nix] Cannot dispose readonly getter "${t}". Dispose the store instead with store.$dispose().`)},writable:!1,configurable:!1}),Object.defineProperty(r,"value",{get:()=>e.value,set(){throw Error(`[Nix] "${t}" is read-only.`)},configurable:!1}),Object.defineProperty(r,"update",{value:()=>{throw Error(`[Nix] "${t}" is read-only.`)},writable:!1,configurable:!1}),r}function l(l,f,u,d={}){let{name:$="store",plugins:b=[]}=d,g=Object.keys(l),p={};for(let e of g)o(e),p[e]=r(l[e]);let w,h=p,y=n(()=>{let e={};for(let t of g)e[t]=p[t].value;return e}),O=c(y,`store "${$}".$stateSignal`);try{w=structuredClone(l)}catch(e){throw Error(`[Nix] Store "${$}" initialState contains non-serializable data (functions, DOM nodes, Symbols, or WeakRefs). Remove these before creating the store. Original error: ${e}`)}let S=Object.assign(Object.create(null),h,{$reset:function(){t(()=>{for(let e of g)p[e].value=w[e]})},$patch:function(e){t(()=>{for(let t of Object.keys(e))Object.prototype.hasOwnProperty.call(p,t)&&(p[t].value=e[t])})},$watch:function(e,t){return i(y,e,t)}});Object.defineProperty(S,"$id",{value:$,writable:!1,enumerable:!1,configurable:!1}),Object.defineProperty(S,"$state",{get:()=>y.value,enumerable:!0,configurable:!1}),Object.defineProperty(S,"$stateSignal",{value:O,writable:!1,enumerable:!1,configurable:!1});let j=new Set([...g,...Array.from(a)]);if(f){let e=f(h);for(let t of Object.keys(e))if(s(t,"action")){if(j.has(t)){console.warn(`[Nix] Store "${$}": action "${t}" collides with an existing signal or getter and will be ignored.`);continue}j.add(t),S[t]=e[t]}}if(u){let t=u(h);for(let r of Object.keys(t)){if(!s(r,"getter"))continue;if(j.has(r)){console.warn(`[Nix] Store "${$}": getter "${r}" collides with an existing signal or action and will be ignored.`);continue}let o=t[r];if(!(o instanceof e))throw TypeError(`[Nix] Store "${$}": getter "${r}" must return a Signal (wrap it with computed()). Got: ${typeof o}`);j.add(r),S[r]=c(o,`getter "${r}" in store "${$}"`)}}let v=[()=>y.dispose()];for(let e of b)try{let t=e(S);"function"==typeof t&&v.push(t)}catch(e){console.error(`[Nix] Plugin initialization failed for store "${$}":`,e)}return S.$dispose=()=>{for(let e of v)e()},S}export{l as createStore};
1
+ import{Signal as e,batch as t,computed as n,signal as r,watch as i}from"./signals.js";var a=class extends e{label;constructor(e,t="ReadonlySignal"){super(e.peek()),this.label=t,Object.defineProperty(this,"value",{get:()=>e.value,set:()=>{throw Error(`[Nix] "${this.label}" is read-only.`)},configurable:!1}),this.update=()=>{throw Error(`[Nix] "${this.label}" is read-only.`)},this.dispose=()=>{throw Error(`[Nix] Cannot dispose "${this.label}" directly.`)}}},o=new Set(["$id","$state","$stateSignal","$reset","$patch","$watch","$dispose"]);function s(e){if("__proto__"===e||"constructor"===e||"prototype"===e)throw Error(`[Nix] Store key "${e}" is not allowed for security reasons.`);if(o.has(e))throw Error(`[Nix] Store key "${e}" is reserved.`)}function c(e,t){return!o.has(e)||(console.warn(`[Nix] Store ${t} "${e}" is reserved and will be ignored.`),!1)}function l(e,t){return new a(e,t)}function u(a,f={}){let{name:u="store",actions:d,getters:$,plugins:g=[]}=f,h=Object.keys(a),b={};for(let e of h)s(e),b[e]=r(a[e]);let p,w=b,y=n(()=>{let e={};for(let t of h)e[t]=b[t].value;return e}),S=l(y,`store "${u}".$stateSignal`);try{p=structuredClone(a)}catch(e){throw Error(`[Nix] Store "${u}" initialState contains non-serializable data (functions, DOM nodes, Symbols, or WeakRefs). Remove these before creating the store. Original error: ${e}`)}let x=Object.assign(Object.create(null),w,{$reset:function(){t(()=>{for(let e of h)b[e].value=p[e]})},$patch:function(e){t(()=>{for(let t of Object.keys(e))Object.prototype.hasOwnProperty.call(b,t)&&(b[t].value=e[t])})},$watch:function(e,t){return i(y,e,t)}});Object.defineProperty(x,"$id",{value:u,writable:!1,enumerable:!1,configurable:!1}),Object.defineProperty(x,"$state",{get:()=>y.value,enumerable:!0,configurable:!1}),Object.defineProperty(x,"$stateSignal",{value:S,writable:!1,enumerable:!1,configurable:!1});let O=new Set([...h,...Array.from(o)]);if(d){let e=d(w);for(let t of Object.keys(e))if(c(t,"action")){if(O.has(t)){console.warn(`[Nix] Store "${u}": action "${t}" collides with an existing signal or getter and will be ignored.`);continue}O.add(t),x[t]=e[t]}}if($){let t=$(w);for(let r of Object.keys(t)){if(!c(r,"getter"))continue;if(O.has(r)){console.warn(`[Nix] Store "${u}": getter "${r}" collides with an existing signal or action and will be ignored.`);continue}let o=t[r];if(!(o instanceof e))throw TypeError(`[Nix] Store "${u}": getter "${r}" must return a Signal (wrap it with computed()). Got: ${typeof o}`);O.add(r),x[r]=l(o,`getter "${r}" in store "${u}"`)}}let j=[()=>y.dispose()];for(let e of g)try{let t=e(x);"function"==typeof t&&j.push(t)}catch(e){console.error(`[Nix] Plugin initialization failed for store "${u}":`,e)}return x.$dispose=()=>{for(let e of j)e()},x}export{a as ReadonlySignal,u as createStore};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@deijose/nix-js",
3
- "version": "2.2.0",
3
+ "version": "2.2.2",
4
4
  "description": "A lightweight, fully reactive micro-framework — no virtual DOM, no compiler, just signals and tagged templates.",
5
5
  "license": "MIT",
6
6
  "author": "Deiver Vasquez",