@nativelayer.dev/restate 0.2.0 → 0.2.1
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.
- package/README.md +27 -62
- package/dist/plugin/async.cjs.min.js +1 -1
- package/dist/plugin/async.esm.min.js +1 -1
- package/dist/plugin/history.cjs.min.js +1 -1
- package/dist/plugin/history.esm.min.js +1 -1
- package/dist/plugin/immutable.cjs.min.js +1 -1
- package/dist/plugin/immutable.esm.min.js +1 -1
- package/dist/plugin/persistence.cjs.min.js +1 -1
- package/dist/plugin/persistence.esm.min.js +1 -1
- package/dist/plugin/validate.cjs.min.js +1 -1
- package/dist/plugin/validate.esm.min.js +1 -1
- package/dist/restate.cjs.min.js +1 -1
- package/dist/restate.esm.min.js +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
|
|
7
7
|
# restate
|
|
8
8
|
|
|
9
|
-
version `0.2.
|
|
9
|
+
version `0.2.1`
|
|
10
10
|
|
|
11
11
|
A minimal, framework-agnostic reactive state management library built on ES6 proxies. `restate` provides:
|
|
12
12
|
|
|
@@ -25,19 +25,19 @@ Import directly in a browser or module bundler:
|
|
|
25
25
|
|
|
26
26
|
```js
|
|
27
27
|
// ESM (recommended)
|
|
28
|
-
import { restate } from './dist/
|
|
28
|
+
import { restate } from './dist/restate.esm.min.js';
|
|
29
29
|
|
|
30
30
|
// CommonJS (Node.js)
|
|
31
|
-
const { restate } = require('./dist/
|
|
31
|
+
const { restate } = require('./dist/restate.cjs.min.js');
|
|
32
32
|
```
|
|
33
33
|
|
|
34
34
|
### Which format should I use?
|
|
35
35
|
|
|
36
36
|
| Your setup | Use this |
|
|
37
37
|
|------------|----------|
|
|
38
|
-
| Vite, esbuild, modern bundler | `dist/esm
|
|
39
|
-
| Node.js with `require()` | `dist/cjs
|
|
40
|
-
| Node.js with `"type": "module"` | `dist/esm
|
|
38
|
+
| Vite, esbuild, modern bundler | `dist/restate.esm.min.js` (recommended) |
|
|
39
|
+
| Node.js with `require()` | `dist/restate.cjs.min.js` |
|
|
40
|
+
| Node.js with `"type": "module"` | `dist/restate.esm.min.js` |
|
|
41
41
|
|
|
42
42
|
## Basic Usage
|
|
43
43
|
|
|
@@ -202,7 +202,7 @@ state.count = 7; // Throws or no-op
|
|
|
202
202
|
Define reactive computed properties with automatic dependency tracking:
|
|
203
203
|
|
|
204
204
|
```js
|
|
205
|
-
import { restate } from './dist/
|
|
205
|
+
import { restate } from './dist/restate.esm.min.js';
|
|
206
206
|
|
|
207
207
|
// Initialize state - $computed is built-in, no plugin needed
|
|
208
208
|
const state = restate({ a: 1, b: 2 });
|
|
@@ -232,7 +232,7 @@ console.log(state.double); // logs no 'computing sum' but recomputes double: out
|
|
|
232
232
|
Chaining computed values:
|
|
233
233
|
|
|
234
234
|
```js
|
|
235
|
-
import { restate } from './dist/
|
|
235
|
+
import { restate } from './dist/restate.esm.min.js';
|
|
236
236
|
|
|
237
237
|
// No plugin needed - $computed is built-in
|
|
238
238
|
const state = restate({ a: 2, b: 3 });
|
|
@@ -376,9 +376,9 @@ Plugins hook into `restate`'s lifecycle events (like `beforeSet`, `afterSet`, `b
|
|
|
376
376
|
Chain optional plugins for additional features:
|
|
377
377
|
|
|
378
378
|
```js
|
|
379
|
-
import { restate } from './dist/
|
|
380
|
-
import { PersistencePlugin } from './dist/
|
|
381
|
-
import { ImmutablePlugin } from './dist/
|
|
379
|
+
import { restate } from './dist/restate.esm.min.js';
|
|
380
|
+
import { PersistencePlugin } from './dist/plugin/persistence.esm.min.js';
|
|
381
|
+
import { ImmutablePlugin } from './dist/plugin/immutable.esm.min.js';
|
|
382
382
|
|
|
383
383
|
// Chainable registration:
|
|
384
384
|
const state = restate({ count: 0, items: [] })
|
|
@@ -533,7 +533,7 @@ state.use(ImmutablePlugin, {
|
|
|
533
533
|
By setting `strict: false`, direct property mutations are allowed without throwing:
|
|
534
534
|
|
|
535
535
|
```js
|
|
536
|
-
import { ImmutablePlugin } from './dist/
|
|
536
|
+
import { ImmutablePlugin } from './dist/plugin/immutable.esm.min.js';
|
|
537
537
|
const state = restate({ count: 0, user: { name: 'Alice' } })
|
|
538
538
|
.use(ImmutablePlugin, { strict: false });
|
|
539
539
|
|
|
@@ -561,7 +561,7 @@ state.count = 3; // works without error
|
|
|
561
561
|
With `strict: true`, direct property mutations throw errors, but you can still apply updates using `$set`:
|
|
562
562
|
|
|
563
563
|
```js
|
|
564
|
-
import { ImmutablePlugin } from './dist/
|
|
564
|
+
import { ImmutablePlugin } from './dist/plugin/immutable.esm.min.js';
|
|
565
565
|
const state = restate({ count: 0 })
|
|
566
566
|
.use(ImmutablePlugin, { strict: true });
|
|
567
567
|
|
|
@@ -578,8 +578,8 @@ console.log(state.count); // 1
|
|
|
578
578
|
You can register custom mutation methods under strict immutability by using `$set` within your methods:
|
|
579
579
|
|
|
580
580
|
```js
|
|
581
|
-
import { restate } from './dist/
|
|
582
|
-
import { ImmutablePlugin } from './dist/
|
|
581
|
+
import { restate } from './dist/restate.esm.min.js';
|
|
582
|
+
import { ImmutablePlugin } from './dist/plugin/immutable.esm.min.js';
|
|
583
583
|
|
|
584
584
|
const state = restate({ count: 0 })
|
|
585
585
|
.use(ImmutablePlugin, { strict: true });
|
|
@@ -635,8 +635,8 @@ Hooks:
|
|
|
635
635
|
- `onDestroy` → clear history
|
|
636
636
|
|
|
637
637
|
```js
|
|
638
|
-
import { restate } from './dist/
|
|
639
|
-
import { HistoryPlugin } from './dist/
|
|
638
|
+
import { restate } from './dist/restate.esm.min.js';
|
|
639
|
+
import { HistoryPlugin } from './dist/plugin/history.esm.min.js';
|
|
640
640
|
|
|
641
641
|
// Initialize state with history tracking
|
|
642
642
|
const state = restate({ count: 0 })
|
|
@@ -812,8 +812,8 @@ Validate types or values on state updates using custom validator functions.
|
|
|
812
812
|
Usage:
|
|
813
813
|
|
|
814
814
|
```js
|
|
815
|
-
import { restate } from './dist/
|
|
816
|
-
import { ValidatePlugin } from './dist/
|
|
815
|
+
import { restate } from './dist/restate.esm.min.js';
|
|
816
|
+
import { ValidatePlugin } from './dist/plugin/validate.esm.min.js';
|
|
817
817
|
|
|
818
818
|
const state = restate({ age: 0, name: '' })
|
|
819
819
|
.use(ValidatePlugin({
|
|
@@ -905,8 +905,8 @@ listState.items = ['a','b','c']; // throws TypeError
|
|
|
905
905
|
### Simple Persistence + Methods
|
|
906
906
|
|
|
907
907
|
```js
|
|
908
|
-
import { restate } from './dist/
|
|
909
|
-
import { PersistencePlugin } from './dist/
|
|
908
|
+
import { restate } from './dist/restate.esm.min.js';
|
|
909
|
+
import { PersistencePlugin } from './dist/plugin/persistence.esm.min.js';
|
|
910
910
|
|
|
911
911
|
// Initialize with persistence ($methods is built-in, no plugin needed)
|
|
912
912
|
const state = restate({ count: 0, items: [] })
|
|
@@ -1303,47 +1303,12 @@ All libraries have different trade-offs: `restate` provides fine-grained change
|
|
|
1303
1303
|
|
|
1304
1304
|
## License
|
|
1305
1305
|
|
|
1306
|
-
`restate` is
|
|
1306
|
+
`restate` is licensed under the **[PolyForm Noncommercial License 1.0.0](./LICENSE)**.
|
|
1307
1307
|
|
|
1308
|
-
|
|
1308
|
+
- ✅ Free for personal, educational, research, and non-commercial use
|
|
1309
|
+
- ✅ Non-profit organizations and public institutions
|
|
1310
|
+
- ❌ Commercial use requires a separate license
|
|
1309
1311
|
|
|
1310
|
-
|
|
1312
|
+
See [LICENSE](./LICENSE) for full terms: https://polyformproject.org/licenses/noncommercial/1.0.0
|
|
1311
1313
|
|
|
1312
|
-
|
|
1313
|
-
- ✅ Personal projects and non-revenue generating applications
|
|
1314
|
-
- ✅ Educational purposes and academic research
|
|
1315
|
-
- ✅ Non-profit organizations
|
|
1316
|
-
- ✅ Internal company tools (non-revenue generating)
|
|
1317
|
-
- ✅ Prototypes and MVPs
|
|
1318
|
-
|
|
1319
|
-
See [LICENSE](./LICENSE) and [LICENSE-NONCOMMERCIAL.md](./LICENSE-NONCOMMERCIAL.md) for full details.
|
|
1320
|
-
|
|
1321
|
-
---
|
|
1322
|
-
|
|
1323
|
-
### Commercial Use
|
|
1324
|
-
|
|
1325
|
-
A **commercial license** is required for:
|
|
1326
|
-
|
|
1327
|
-
- ❌ Proprietary software and closed-source commercial applications
|
|
1328
|
-
- ❌ SaaS products and revenue-generating applications
|
|
1329
|
-
- ❌ Enterprise deployments and large-scale corporate use
|
|
1330
|
-
- ❌ White-label products sold or licensed to third parties
|
|
1331
|
-
|
|
1332
|
-
**Commercial licenses include:**
|
|
1333
|
-
|
|
1334
|
-
- Legal protection and indemnification
|
|
1335
|
-
- Priority support and SLA
|
|
1336
|
-
- Updates and bug fixes during license term
|
|
1337
|
-
- Custom licensing terms for enterprise needs
|
|
1338
|
-
|
|
1339
|
-
See [EULA-COMMERCIAL.md](./EULA-COMMERCIAL.md) for commercial licensing terms.
|
|
1340
|
-
|
|
1341
|
-
---
|
|
1342
|
-
|
|
1343
|
-
### Licensing Inquiries
|
|
1344
|
-
|
|
1345
|
-
**For commercial licensing, pricing, or questions:**
|
|
1346
|
-
|
|
1347
|
-
> ynck.chrl@protonmail.com
|
|
1348
|
-
|
|
1349
|
-
I'll be happy to discuss licensing options that fit your needs.
|
|
1314
|
+
**For commercial licensing:** info@nativelayer.dev
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/*! plugin/async v0.2.
|
|
1
|
+
/*! plugin/async v0.2.1 | Copyright (c) 2025 Yannick J.A. Charlery (https://github.com/ynck-chrl/restate) | PolyForm Noncommercial 1.0.0 | https://polyformproject.org/licenses/noncommercial/1.0.0 | Commercial: info@nativelayer.dev */
|
|
2
2
|
"use strict";
|
|
3
3
|
/*!
|
|
4
4
|
* restate AsyncPlugin v1.0.0
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/*! plugin/async v0.2.
|
|
1
|
+
/*! plugin/async v0.2.1 | Copyright (c) 2025 Yannick J.A. Charlery (https://github.com/ynck-chrl/restate) | PolyForm Noncommercial 1.0.0 | https://polyformproject.org/licenses/noncommercial/1.0.0 | Commercial: info@nativelayer.dev */
|
|
2
2
|
/*!
|
|
3
3
|
* restate AsyncPlugin v1.0.0
|
|
4
4
|
* restate Async Plugin
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/*! plugin/history v0.2.
|
|
1
|
+
/*! plugin/history v0.2.1 | Copyright (c) 2025 Yannick J.A. Charlery (https://github.com/ynck-chrl/restate) | PolyForm Noncommercial 1.0.0 | https://polyformproject.org/licenses/noncommercial/1.0.0 | Commercial: info@nativelayer.dev */
|
|
2
2
|
"use strict";
|
|
3
3
|
/*!
|
|
4
4
|
* restate HistoryPlugin v1.0.0
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/*! plugin/history v0.2.
|
|
1
|
+
/*! plugin/history v0.2.1 | Copyright (c) 2025 Yannick J.A. Charlery (https://github.com/ynck-chrl/restate) | PolyForm Noncommercial 1.0.0 | https://polyformproject.org/licenses/noncommercial/1.0.0 | Commercial: info@nativelayer.dev */
|
|
2
2
|
/*!
|
|
3
3
|
* restate HistoryPlugin v1.0.0
|
|
4
4
|
* History Plugin for restate (closure-based)
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/*! plugin/immutable v0.2.
|
|
1
|
+
/*! plugin/immutable v0.2.1 | Copyright (c) 2025 Yannick J.A. Charlery (https://github.com/ynck-chrl/restate) | PolyForm Noncommercial 1.0.0 | https://polyformproject.org/licenses/noncommercial/1.0.0 | Commercial: info@nativelayer.dev */
|
|
2
2
|
"use strict";
|
|
3
3
|
/*!
|
|
4
4
|
* restate ImmutablePlugin v1.0.0
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/*! plugin/immutable v0.2.
|
|
1
|
+
/*! plugin/immutable v0.2.1 | Copyright (c) 2025 Yannick J.A. Charlery (https://github.com/ynck-chrl/restate) | PolyForm Noncommercial 1.0.0 | https://polyformproject.org/licenses/noncommercial/1.0.0 | Commercial: info@nativelayer.dev */
|
|
2
2
|
/*!
|
|
3
3
|
* restate ImmutablePlugin v1.0.0
|
|
4
4
|
* Immutable Plugin for restate (hook-based, no double proxy)
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/*! plugin/persistence v0.2.
|
|
1
|
+
/*! plugin/persistence v0.2.1 | Copyright (c) 2025 Yannick J.A. Charlery (https://github.com/ynck-chrl/restate) | PolyForm Noncommercial 1.0.0 | https://polyformproject.org/licenses/noncommercial/1.0.0 | Commercial: info@nativelayer.dev */
|
|
2
2
|
"use strict";
|
|
3
3
|
/*!
|
|
4
4
|
* restate PersistencePlugin v1.0.0
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/*! plugin/persistence v0.2.
|
|
1
|
+
/*! plugin/persistence v0.2.1 | Copyright (c) 2025 Yannick J.A. Charlery (https://github.com/ynck-chrl/restate) | PolyForm Noncommercial 1.0.0 | https://polyformproject.org/licenses/noncommercial/1.0.0 | Commercial: info@nativelayer.dev */
|
|
2
2
|
/*!
|
|
3
3
|
* restate PersistencePlugin v1.0.0
|
|
4
4
|
* Persistence Plugin for restate (closure-based)
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/*! plugin/validate v0.2.
|
|
1
|
+
/*! plugin/validate v0.2.1 | Copyright (c) 2025 Yannick J.A. Charlery (https://github.com/ynck-chrl/restate) | PolyForm Noncommercial 1.0.0 | https://polyformproject.org/licenses/noncommercial/1.0.0 | Commercial: info@nativelayer.dev */
|
|
2
2
|
"use strict";
|
|
3
3
|
/*!
|
|
4
4
|
* restate ValidatePlugin v1.0.0
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/*! plugin/validate v0.2.
|
|
1
|
+
/*! plugin/validate v0.2.1 | Copyright (c) 2025 Yannick J.A. Charlery (https://github.com/ynck-chrl/restate) | PolyForm Noncommercial 1.0.0 | https://polyformproject.org/licenses/noncommercial/1.0.0 | Commercial: info@nativelayer.dev */
|
|
2
2
|
/*!
|
|
3
3
|
* restate ValidatePlugin v1.0.0
|
|
4
4
|
* Plugin to validate types or values on set operations
|
package/dist/restate.cjs.min.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
/*! restate v0.2.
|
|
1
|
+
/*! restate v0.2.1 | Copyright (c) 2025 Yannick J.A. Charlery (https://github.com/ynck-chrl/restate) | PolyForm Noncommercial 1.0.0 | https://polyformproject.org/licenses/noncommercial/1.0.0 | Commercial: info@nativelayer.dev */
|
|
2
2
|
"use strict";const e=["$onChange","$watch","$unwatch","$set","$computed","$dependencies","$methods","$destroy","$registry","use"],t=["_"];class s{constructor(e={},t={}){this._state=e,this._exactWatchers=new Map,this._shallowWildcards=new Map,this._deepWildcards=new Map,this._proxyCache=new WeakMap,this._computed={},this._computedDependencies=new Map,this._computedCache=new Map,this._tracking=!1,this._currentComputedKey=null,this._accessedPaths=new Set,this._maxDepth=t.maxDepth||100,this._onChange=null,this._isDestroyed=!1,this._bulkMode=!1,this._bulkChanges=new Map,this._plugins=new Map,this._pluginLoadOrder=[],this._pluginHooks={beforeNotify:[],afterNotify:[],beforeSet:[],afterSet:[],beforeBulk:[],afterBulk:[],onDestroy:[]},this._methodRegistry=new Map,this._proxy=this._wrap(e,[],!0),this._setupProxyMethods(),t.plugins&&t.plugins.forEach(e=>this.use(e))}_registerMethod(e,t,s=!1,r=null){this._methodRegistry.set(e,{source:t,configurable:s,originalFn:r})}_isReservedPrefix(e){return t.some(t=>e.startsWith(t))}_checkMethodCollision(t,s,r=!1){if(this._isReservedPrefix(t))return{error:`Plugin '${s}' cannot define method '${t}': names starting with '_' are reserved for internal use`};const i=this._methodRegistry.get(t);if(!i)return null;if(e.includes(t))return{error:`Plugin '${s}' cannot override core method '${t}'`};if(!r){const e=this._pluginLoadOrder,r=i.source.startsWith("plugin:")?e.indexOf(i.source.replace("plugin:",""))+1:0,o=e.indexOf(s)+1;return{error:`Method collision: '${t}'\n - First defined by: ${i.source}${r?` (loaded #${r})`:""}\n - Attempted by: plugin '${s}'${o?` (loaded #${o})`:""}\n Consider renaming the method or using 'overrides: ["${t}"]' in the plugin definition.`}}return i.configurable?null:{error:`Plugin '${s}' cannot override '${t}': method is not configurable (defined by ${i.source})`}}use(e){if("function"==typeof e&&(e=e(this)),!e.name)throw new Error("Plugin must have a name");if(this._plugins.has(e.name))throw new Error(`Plugin '${e.name}' is already registered`);if(this._pluginLoadOrder.push(e.name),this._plugins.set(e.name,e),e.hooks&&Object.keys(e.hooks).forEach(t=>{this._pluginHooks[t]&&this._pluginHooks[t].push(e.hooks[t])}),e.wrap&&Object.keys(e.wrap).forEach(t=>{const s=e.wrap[t],r=this._methodRegistry.get(t);if(!r)throw new Error(`Plugin '${e.name}' attempted to wrap '${t}', but it doesn't exist.\n Available methods: ${Array.from(this._methodRegistry.keys()).join(", ")}`);if("function"!=typeof s)throw new Error(`Plugin '${e.name}': wrap['${t}'] must be a function`);const i=this._proxy[t];if("function"!=typeof i)throw new Error(`Plugin '${e.name}': cannot wrap '${t}' - it's not a function`);const o=s(i.bind(this._proxy));Object.defineProperty(this._proxy,t,{value:o.bind(this),enumerable:!1,configurable:!0,writable:!0}),this._methodRegistry.set(t,{...r,wrappedBy:e.name,originalFn:i})}),e.methods){const t=e.overrides||[];Object.keys(e.methods).forEach(s=>{const r=t.includes(s),i=this._checkMethodCollision(s,e.name,r);if(i)throw new Error(i.error);if(r&&this._methodRegistry.has(s)){const t=this._methodRegistry.get(s);console.warn(`restate: Plugin '${e.name}' is overriding method '${s}' (previously defined by ${t.source})`)}Object.defineProperty(this._proxy,s,{value:e.methods[s].bind(this),enumerable:!1,configurable:!0,writable:!0}),this._registerMethod(s,`plugin:${e.name}`,!0)})}return e.install&&e.install.call(this),this}_notify(e,t,s){this._isDestroyed||(this._runHooks("beforeNotify",e,t,s),this._bulkMode?this._bulkChanges.set(e,t):this._notifyImmediate(e,t,s))}_notifyImmediate(e,t,s){if(this._isDestroyed)return;if("function"==typeof this._onChange)try{this._onChange(e,t,s)}catch(e){console.error("restate: Error in onChange handler:",e)}const r=this._exactWatchers.get(e);if(r)try{r(e,t,s)}catch(t){console.error(`restate: Error in watcher for '${e}':`,t)}const i=e.split(".");if(i.length>=2){const r=i.slice(0,-1).join("."),o=this._shallowWildcards.get(r);if(o)for(const i of o)try{i(e,t,s)}catch(e){console.error(`restate: Error in watcher for '${r}.*':`,e)}}let o="";for(let r=0;r<i.length-1;r++){o=0===r?i[0]:o+"."+i[r];const n=this._deepWildcards.get(o);if(n)for(const r of n)try{r(e,t,s)}catch(e){console.error(`restate: Error in watcher for '${o}.**':`,e)}}this._runHooks("afterNotify",e,t,s)}_runHooks(e,...t){const s="beforeSet"===e;this._pluginHooks[e].forEach(r=>{if(s)r.call(this,...t);else try{r.call(this,...t)}catch(t){console.error(`restate: Error in ${e} hook:`,t)}})}_bulk(e){if(!this._isDestroyed){if(this._bulkMode)return e(this._proxy);this._runHooks("beforeBulk"),this._bulkMode=!0;try{const t=e(this._proxy);return this._flushBulkChanges(),t}finally{this._bulkMode=!1,this._runHooks("afterBulk")}}}_flushBulkChanges(){if(0!==this._bulkChanges.size){if("function"==typeof this._onChange)try{this._onChange("bulk",Array.from(this._bulkChanges.entries()))}catch(e){console.error("restate: Error in onChange during bulk:",e)}for(const[e,t]of this._bulkChanges){const s=this._exactWatchers.get(e);if(s)try{s(e,t)}catch(t){console.error(`restate: Error in watcher for '${e}':`,t)}const r=e.split(".");if(r.length>=2){const s=r.slice(0,-1).join("."),i=this._shallowWildcards.get(s);if(i)for(const r of i)try{r(e,t)}catch(e){console.error(`restate: Error in watcher for '${s}.*':`,e)}}let i="";for(let s=0;s<r.length-1;s++){i=0===s?r[0]:i+"."+r[s];const o=this._deepWildcards.get(i);if(o)for(const s of o)try{s(e,t)}catch(e){console.error(`restate: Error in watcher for '${i}.**':`,e)}}}this._bulkChanges.clear()}}_getComputedValue(e,t){if(this._computedCache.has(e))return this._computedCache.get(e);if(this._computedCallStack||(this._computedCallStack=new Set),this._computedCallStack.has(e))return void console.error(`restate: Circular dependency detected in computed property '${e}'`);this._computedCallStack.add(e);const s=this._tracking,r=this._currentComputedKey,i=s?[...this._accessedPaths]:null;let o;this._tracking=!0,this._currentComputedKey=e,this._accessedPaths.clear();try{o=t(this._proxy)}catch(t){console.error(`restate: Error computing '${e}':`,t),o=void 0}if(this._computedDependencies.set(e,new Set(this._accessedPaths)),this._computedCache.set(e,o),this._computedCallStack.delete(e),this._tracking=s,this._currentComputedKey=r,i){this._accessedPaths.clear();for(const e of i)this._accessedPaths.add(e)}return o}_invalidateComputed(e){const t=new Set,s=[e];for(;s.length>0;){const e=s.shift(),r=[];for(const[s,i]of this._computedDependencies)i.has(e)&&!t.has(s)&&r.push(s);for(const e of r)this._computedCache.delete(e),this._computedDependencies.delete(e),t.add(e),s.push(e)}}_wrap(e,t=[],s=!1){if(this._isDestroyed)return e;if("object"!=typeof e||null===e)return e;if(t.length>this._maxDepth)return e;if(!s&&this._proxyCache.has(e))return this._proxyCache.get(e);if(Array.isArray(e))return this._wrapArray(e,t);const r=new Proxy(e,{get:(e,r)=>{if(this._isDestroyed)return e[r];const i=String(r);if(s&&i in this._computed)return this._tracking&&this._currentComputedKey&&this._currentComputedKey!==i&&this._accessedPaths.add(i),this._getComputedValue(i,this._computed[i]);if(this._tracking&&this._currentComputedKey){const e=t.length>0?t.concat(r).join("."):i;this._accessedPaths.add(e)}const o=e[r];return"object"==typeof o&&null!==o?this._wrap(o,t.concat(r)):o},set:(e,s,r)=>{if(this._isDestroyed)return!1;this._runHooks("beforeSet",e,s,r,t);const i=e[s];if(i!==r){"object"==typeof i&&null!==i&&this._proxyCache.delete(i),e[s]=r;const o=t.concat(s).join(".");this._invalidateComputed(String(s)),t.length>0&&this._invalidateComputed(o),this._notify(o,r,i)}return this._runHooks("afterSet",e,s,r,t),!0},has:(e,t)=>{const r=String(t);return!(!s||!(r in this._computed))||t in e},ownKeys:e=>{const t=Reflect.ownKeys(e);if(s){const e=Object.keys(this._computed);for(const s of e)t.includes(s)||t.push(s)}return t},getOwnPropertyDescriptor:(e,t)=>{const r=String(t);return s&&r in this._computed?{configurable:!0,enumerable:!0,value:this._getComputedValue(r,this._computed[r])}:Object.getOwnPropertyDescriptor(e,t)}});return s||this._proxyCache.set(e,r),r}_wrapArray(e,t){if(t.length>this._maxDepth)return e;if(this._proxyCache.has(e))return this._proxyCache.get(e);const s=new Proxy(e,{get:(e,s)=>{if(this._isDestroyed)return e[s];if(this._tracking&&this._currentComputedKey){const e=t.concat(s).join(".");this._accessedPaths.add(e)}if("function"==typeof e[s])return this._wrapArrayMethod(e,s,t);const r=e[s];return"object"==typeof r&&null!==r?this._wrap(r,t.concat(s)):r},set:(e,s,r)=>{if(this._isDestroyed)return!1;const i=e[s];if(i!==r&&("object"==typeof i&&null!==i&&this._proxyCache.delete(i),e[s]=r,!isNaN(s))){const i=t.concat(s).join(".");this._invalidateComputed(i),this._notify(i,r),this._notify(t.concat("length").join("."),e.length)}return!0}});return this._proxyCache.set(e,s),s}_wrapArrayMethod(e,t,s){const r=e[t],i=["push","pop","shift","unshift","splice","sort","reverse","fill","copyWithin"];return function(...o){if(this._isDestroyed)return r.apply(e,o);const n=e.length,h=r.apply(e,o);if(i.includes(t)){const t=s.join(".");this._invalidateComputed(t),this._notify(t,e),e.length!==n&&this._notify(s.concat("length").join("."),e.length)}return h}.bind(this)}_addWatcher(e,t){if(e.endsWith(".**")){const s=e.slice(0,-3);this._deepWildcards.has(s)||this._deepWildcards.set(s,new Set),this._deepWildcards.get(s).add(t)}else if(e.endsWith(".*")){const s=e.slice(0,-2);this._shallowWildcards.has(s)||this._shallowWildcards.set(s,new Set),this._shallowWildcards.get(s).add(t)}else this._exactWatchers.set(e,t)}_removeWatcher(e){if(e.endsWith(".**")){const t=e.slice(0,-3);this._deepWildcards.delete(t)}else if(e.endsWith(".*")){const t=e.slice(0,-2);this._shallowWildcards.delete(t)}else this._exactWatchers.delete(e)}_clearAllWatchers(){this._exactWatchers.clear(),this._shallowWildcards.clear(),this._deepWildcards.clear()}_setupProxyMethods(){const t=(e,t)=>{Object.defineProperty(this._proxy,e,{value:t,enumerable:!1,configurable:!1,writable:!1}),this._registerMethod(e,"core",!1)};t("$onChange",e=>(this._onChange=e,this._proxy)),t("$watch",(e,t)=>"function"==typeof t?(this._addWatcher(e,t),()=>this._proxy.$unwatch(e)):this._proxy),t("$unwatch",e=>(this._removeWatcher(e),this._proxy)),t("$set",e=>"function"==typeof e?this._bulk(e):this._bulk(t=>{this._applyUpdates(t,e)})),t("$computed",e=>{const t=["__proto__","constructor","prototype"];for(const[s,r]of Object.entries(e))t.includes(s)?console.warn(`restate: Skipping reserved computed key '${s}'`):"function"==typeof r?this._computed[s]=r:console.warn(`restate: Computed property '${s}' must be a function`);return this._proxy}),t("$dependencies",()=>{const e={};for(const[t,s]of this._computedDependencies)e[t]=Array.from(s);return e}),t("$methods",t=>(Object.entries(t).forEach(([t,s])=>{if("function"!=typeof s)throw new Error(`restate: Method '${t}' must be a function`);if(e.includes(t))throw new Error(`restate: Cannot define method '${t}' - it's a reserved core method`);if(this._isReservedPrefix(t))throw new Error(`restate: Cannot define method '${t}' - names starting with '_' are reserved`);const r=this._methodRegistry.get(t);r&&r.source.startsWith("plugin:")&&console.warn(`restate: $methods() is overriding '${t}' (previously defined by ${r.source})`),Object.defineProperty(this._proxy,t,{value:s.bind(this._proxy),enumerable:!1,writable:!0,configurable:!0}),this._registerMethod(t,"user",!0)}),this._proxy)),t("$registry",()=>{const e={};for(const[t,s]of this._methodRegistry)e[t]={...s},delete e[t].originalFn;return e}),t("$destroy",()=>(this._runHooks("onDestroy"),this._isDestroyed=!0,this._clearAllWatchers(),this._onChange=null,this._plugins.clear(),this._pluginLoadOrder=[],this._methodRegistry.clear(),this._proxyCache=new WeakMap,this._computed={},this._computedDependencies.clear(),this._computedCache.clear(),this._computedCallStack&&this._computedCallStack.clear(),this._proxy))}_applyUpdates(e,t,s=[]){if(this._isDestroyed)return;const r=["__proto__","constructor","prototype"];for(const[i,o]of Object.entries(t))r.includes(i)||("object"!=typeof o||null===o||Array.isArray(o)?e[i]=o:(e[i]&&"object"==typeof e[i]||(e[i]={}),this._applyUpdates(e[i],o,s.concat(i))))}}exports.restate=function(e={}){const t=new s(e,{plugins:[]}),r=t._proxy;return r.use=function(e,s){const r="function"==typeof e?e(t):e;return t.use(r),t._proxy},r};
|
package/dist/restate.esm.min.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
/*! restate v0.2.
|
|
1
|
+
/*! restate v0.2.1 | Copyright (c) 2025 Yannick J.A. Charlery (https://github.com/ynck-chrl/restate) | PolyForm Noncommercial 1.0.0 | https://polyformproject.org/licenses/noncommercial/1.0.0 | Commercial: info@nativelayer.dev */
|
|
2
2
|
const e=["$onChange","$watch","$unwatch","$set","$computed","$dependencies","$methods","$destroy","$registry","use"],t=["_"];class s{constructor(e={},t={}){this._state=e,this._exactWatchers=new Map,this._shallowWildcards=new Map,this._deepWildcards=new Map,this._proxyCache=new WeakMap,this._computed={},this._computedDependencies=new Map,this._computedCache=new Map,this._tracking=!1,this._currentComputedKey=null,this._accessedPaths=new Set,this._maxDepth=t.maxDepth||100,this._onChange=null,this._isDestroyed=!1,this._bulkMode=!1,this._bulkChanges=new Map,this._plugins=new Map,this._pluginLoadOrder=[],this._pluginHooks={beforeNotify:[],afterNotify:[],beforeSet:[],afterSet:[],beforeBulk:[],afterBulk:[],onDestroy:[]},this._methodRegistry=new Map,this._proxy=this._wrap(e,[],!0),this._setupProxyMethods(),t.plugins&&t.plugins.forEach(e=>this.use(e))}_registerMethod(e,t,s=!1,r=null){this._methodRegistry.set(e,{source:t,configurable:s,originalFn:r})}_isReservedPrefix(e){return t.some(t=>e.startsWith(t))}_checkMethodCollision(t,s,r=!1){if(this._isReservedPrefix(t))return{error:`Plugin '${s}' cannot define method '${t}': names starting with '_' are reserved for internal use`};const i=this._methodRegistry.get(t);if(!i)return null;if(e.includes(t))return{error:`Plugin '${s}' cannot override core method '${t}'`};if(!r){const e=this._pluginLoadOrder,r=i.source.startsWith("plugin:")?e.indexOf(i.source.replace("plugin:",""))+1:0,o=e.indexOf(s)+1;return{error:`Method collision: '${t}'\n - First defined by: ${i.source}${r?` (loaded #${r})`:""}\n - Attempted by: plugin '${s}'${o?` (loaded #${o})`:""}\n Consider renaming the method or using 'overrides: ["${t}"]' in the plugin definition.`}}return i.configurable?null:{error:`Plugin '${s}' cannot override '${t}': method is not configurable (defined by ${i.source})`}}use(e){if("function"==typeof e&&(e=e(this)),!e.name)throw new Error("Plugin must have a name");if(this._plugins.has(e.name))throw new Error(`Plugin '${e.name}' is already registered`);if(this._pluginLoadOrder.push(e.name),this._plugins.set(e.name,e),e.hooks&&Object.keys(e.hooks).forEach(t=>{this._pluginHooks[t]&&this._pluginHooks[t].push(e.hooks[t])}),e.wrap&&Object.keys(e.wrap).forEach(t=>{const s=e.wrap[t],r=this._methodRegistry.get(t);if(!r)throw new Error(`Plugin '${e.name}' attempted to wrap '${t}', but it doesn't exist.\n Available methods: ${Array.from(this._methodRegistry.keys()).join(", ")}`);if("function"!=typeof s)throw new Error(`Plugin '${e.name}': wrap['${t}'] must be a function`);const i=this._proxy[t];if("function"!=typeof i)throw new Error(`Plugin '${e.name}': cannot wrap '${t}' - it's not a function`);const o=s(i.bind(this._proxy));Object.defineProperty(this._proxy,t,{value:o.bind(this),enumerable:!1,configurable:!0,writable:!0}),this._methodRegistry.set(t,{...r,wrappedBy:e.name,originalFn:i})}),e.methods){const t=e.overrides||[];Object.keys(e.methods).forEach(s=>{const r=t.includes(s),i=this._checkMethodCollision(s,e.name,r);if(i)throw new Error(i.error);if(r&&this._methodRegistry.has(s)){const t=this._methodRegistry.get(s);console.warn(`restate: Plugin '${e.name}' is overriding method '${s}' (previously defined by ${t.source})`)}Object.defineProperty(this._proxy,s,{value:e.methods[s].bind(this),enumerable:!1,configurable:!0,writable:!0}),this._registerMethod(s,`plugin:${e.name}`,!0)})}return e.install&&e.install.call(this),this}_notify(e,t,s){this._isDestroyed||(this._runHooks("beforeNotify",e,t,s),this._bulkMode?this._bulkChanges.set(e,t):this._notifyImmediate(e,t,s))}_notifyImmediate(e,t,s){if(this._isDestroyed)return;if("function"==typeof this._onChange)try{this._onChange(e,t,s)}catch(e){console.error("restate: Error in onChange handler:",e)}const r=this._exactWatchers.get(e);if(r)try{r(e,t,s)}catch(t){console.error(`restate: Error in watcher for '${e}':`,t)}const i=e.split(".");if(i.length>=2){const r=i.slice(0,-1).join("."),o=this._shallowWildcards.get(r);if(o)for(const i of o)try{i(e,t,s)}catch(e){console.error(`restate: Error in watcher for '${r}.*':`,e)}}let o="";for(let r=0;r<i.length-1;r++){o=0===r?i[0]:o+"."+i[r];const n=this._deepWildcards.get(o);if(n)for(const r of n)try{r(e,t,s)}catch(e){console.error(`restate: Error in watcher for '${o}.**':`,e)}}this._runHooks("afterNotify",e,t,s)}_runHooks(e,...t){const s="beforeSet"===e;this._pluginHooks[e].forEach(r=>{if(s)r.call(this,...t);else try{r.call(this,...t)}catch(t){console.error(`restate: Error in ${e} hook:`,t)}})}_bulk(e){if(!this._isDestroyed){if(this._bulkMode)return e(this._proxy);this._runHooks("beforeBulk"),this._bulkMode=!0;try{const t=e(this._proxy);return this._flushBulkChanges(),t}finally{this._bulkMode=!1,this._runHooks("afterBulk")}}}_flushBulkChanges(){if(0!==this._bulkChanges.size){if("function"==typeof this._onChange)try{this._onChange("bulk",Array.from(this._bulkChanges.entries()))}catch(e){console.error("restate: Error in onChange during bulk:",e)}for(const[e,t]of this._bulkChanges){const s=this._exactWatchers.get(e);if(s)try{s(e,t)}catch(t){console.error(`restate: Error in watcher for '${e}':`,t)}const r=e.split(".");if(r.length>=2){const s=r.slice(0,-1).join("."),i=this._shallowWildcards.get(s);if(i)for(const r of i)try{r(e,t)}catch(e){console.error(`restate: Error in watcher for '${s}.*':`,e)}}let i="";for(let s=0;s<r.length-1;s++){i=0===s?r[0]:i+"."+r[s];const o=this._deepWildcards.get(i);if(o)for(const s of o)try{s(e,t)}catch(e){console.error(`restate: Error in watcher for '${i}.**':`,e)}}}this._bulkChanges.clear()}}_getComputedValue(e,t){if(this._computedCache.has(e))return this._computedCache.get(e);if(this._computedCallStack||(this._computedCallStack=new Set),this._computedCallStack.has(e))return void console.error(`restate: Circular dependency detected in computed property '${e}'`);this._computedCallStack.add(e);const s=this._tracking,r=this._currentComputedKey,i=s?[...this._accessedPaths]:null;let o;this._tracking=!0,this._currentComputedKey=e,this._accessedPaths.clear();try{o=t(this._proxy)}catch(t){console.error(`restate: Error computing '${e}':`,t),o=void 0}if(this._computedDependencies.set(e,new Set(this._accessedPaths)),this._computedCache.set(e,o),this._computedCallStack.delete(e),this._tracking=s,this._currentComputedKey=r,i){this._accessedPaths.clear();for(const e of i)this._accessedPaths.add(e)}return o}_invalidateComputed(e){const t=new Set,s=[e];for(;s.length>0;){const e=s.shift(),r=[];for(const[s,i]of this._computedDependencies)i.has(e)&&!t.has(s)&&r.push(s);for(const e of r)this._computedCache.delete(e),this._computedDependencies.delete(e),t.add(e),s.push(e)}}_wrap(e,t=[],s=!1){if(this._isDestroyed)return e;if("object"!=typeof e||null===e)return e;if(t.length>this._maxDepth)return e;if(!s&&this._proxyCache.has(e))return this._proxyCache.get(e);if(Array.isArray(e))return this._wrapArray(e,t);const r=new Proxy(e,{get:(e,r)=>{if(this._isDestroyed)return e[r];const i=String(r);if(s&&i in this._computed)return this._tracking&&this._currentComputedKey&&this._currentComputedKey!==i&&this._accessedPaths.add(i),this._getComputedValue(i,this._computed[i]);if(this._tracking&&this._currentComputedKey){const e=t.length>0?t.concat(r).join("."):i;this._accessedPaths.add(e)}const o=e[r];return"object"==typeof o&&null!==o?this._wrap(o,t.concat(r)):o},set:(e,s,r)=>{if(this._isDestroyed)return!1;this._runHooks("beforeSet",e,s,r,t);const i=e[s];if(i!==r){"object"==typeof i&&null!==i&&this._proxyCache.delete(i),e[s]=r;const o=t.concat(s).join(".");this._invalidateComputed(String(s)),t.length>0&&this._invalidateComputed(o),this._notify(o,r,i)}return this._runHooks("afterSet",e,s,r,t),!0},has:(e,t)=>{const r=String(t);return!(!s||!(r in this._computed))||t in e},ownKeys:e=>{const t=Reflect.ownKeys(e);if(s){const e=Object.keys(this._computed);for(const s of e)t.includes(s)||t.push(s)}return t},getOwnPropertyDescriptor:(e,t)=>{const r=String(t);return s&&r in this._computed?{configurable:!0,enumerable:!0,value:this._getComputedValue(r,this._computed[r])}:Object.getOwnPropertyDescriptor(e,t)}});return s||this._proxyCache.set(e,r),r}_wrapArray(e,t){if(t.length>this._maxDepth)return e;if(this._proxyCache.has(e))return this._proxyCache.get(e);const s=new Proxy(e,{get:(e,s)=>{if(this._isDestroyed)return e[s];if(this._tracking&&this._currentComputedKey){const e=t.concat(s).join(".");this._accessedPaths.add(e)}if("function"==typeof e[s])return this._wrapArrayMethod(e,s,t);const r=e[s];return"object"==typeof r&&null!==r?this._wrap(r,t.concat(s)):r},set:(e,s,r)=>{if(this._isDestroyed)return!1;const i=e[s];if(i!==r&&("object"==typeof i&&null!==i&&this._proxyCache.delete(i),e[s]=r,!isNaN(s))){const i=t.concat(s).join(".");this._invalidateComputed(i),this._notify(i,r),this._notify(t.concat("length").join("."),e.length)}return!0}});return this._proxyCache.set(e,s),s}_wrapArrayMethod(e,t,s){const r=e[t],i=["push","pop","shift","unshift","splice","sort","reverse","fill","copyWithin"];return function(...o){if(this._isDestroyed)return r.apply(e,o);const n=e.length,h=r.apply(e,o);if(i.includes(t)){const t=s.join(".");this._invalidateComputed(t),this._notify(t,e),e.length!==n&&this._notify(s.concat("length").join("."),e.length)}return h}.bind(this)}_addWatcher(e,t){if(e.endsWith(".**")){const s=e.slice(0,-3);this._deepWildcards.has(s)||this._deepWildcards.set(s,new Set),this._deepWildcards.get(s).add(t)}else if(e.endsWith(".*")){const s=e.slice(0,-2);this._shallowWildcards.has(s)||this._shallowWildcards.set(s,new Set),this._shallowWildcards.get(s).add(t)}else this._exactWatchers.set(e,t)}_removeWatcher(e){if(e.endsWith(".**")){const t=e.slice(0,-3);this._deepWildcards.delete(t)}else if(e.endsWith(".*")){const t=e.slice(0,-2);this._shallowWildcards.delete(t)}else this._exactWatchers.delete(e)}_clearAllWatchers(){this._exactWatchers.clear(),this._shallowWildcards.clear(),this._deepWildcards.clear()}_setupProxyMethods(){const t=(e,t)=>{Object.defineProperty(this._proxy,e,{value:t,enumerable:!1,configurable:!1,writable:!1}),this._registerMethod(e,"core",!1)};t("$onChange",e=>(this._onChange=e,this._proxy)),t("$watch",(e,t)=>"function"==typeof t?(this._addWatcher(e,t),()=>this._proxy.$unwatch(e)):this._proxy),t("$unwatch",e=>(this._removeWatcher(e),this._proxy)),t("$set",e=>"function"==typeof e?this._bulk(e):this._bulk(t=>{this._applyUpdates(t,e)})),t("$computed",e=>{const t=["__proto__","constructor","prototype"];for(const[s,r]of Object.entries(e))t.includes(s)?console.warn(`restate: Skipping reserved computed key '${s}'`):"function"==typeof r?this._computed[s]=r:console.warn(`restate: Computed property '${s}' must be a function`);return this._proxy}),t("$dependencies",()=>{const e={};for(const[t,s]of this._computedDependencies)e[t]=Array.from(s);return e}),t("$methods",t=>(Object.entries(t).forEach(([t,s])=>{if("function"!=typeof s)throw new Error(`restate: Method '${t}' must be a function`);if(e.includes(t))throw new Error(`restate: Cannot define method '${t}' - it's a reserved core method`);if(this._isReservedPrefix(t))throw new Error(`restate: Cannot define method '${t}' - names starting with '_' are reserved`);const r=this._methodRegistry.get(t);r&&r.source.startsWith("plugin:")&&console.warn(`restate: $methods() is overriding '${t}' (previously defined by ${r.source})`),Object.defineProperty(this._proxy,t,{value:s.bind(this._proxy),enumerable:!1,writable:!0,configurable:!0}),this._registerMethod(t,"user",!0)}),this._proxy)),t("$registry",()=>{const e={};for(const[t,s]of this._methodRegistry)e[t]={...s},delete e[t].originalFn;return e}),t("$destroy",()=>(this._runHooks("onDestroy"),this._isDestroyed=!0,this._clearAllWatchers(),this._onChange=null,this._plugins.clear(),this._pluginLoadOrder=[],this._methodRegistry.clear(),this._proxyCache=new WeakMap,this._computed={},this._computedDependencies.clear(),this._computedCache.clear(),this._computedCallStack&&this._computedCallStack.clear(),this._proxy))}_applyUpdates(e,t,s=[]){if(this._isDestroyed)return;const r=["__proto__","constructor","prototype"];for(const[i,o]of Object.entries(t))r.includes(i)||("object"!=typeof o||null===o||Array.isArray(o)?e[i]=o:(e[i]&&"object"==typeof e[i]||(e[i]={}),this._applyUpdates(e[i],o,s.concat(i))))}}function restate(e={}){const t=new s(e,{plugins:[]}),r=t._proxy;return r.use=function(e,s){const r="function"==typeof e?e(t):e;return t.use(r),t._proxy},r}export{restate};
|
package/package.json
CHANGED