storion 0.6.0 → 0.7.0
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 +217 -17
- package/dist/async/async.d.ts +49 -0
- package/dist/async/async.d.ts.map +1 -1
- package/dist/async/index.js +50 -0
- package/dist/core/effect.d.ts +20 -0
- package/dist/core/effect.d.ts.map +1 -1
- package/dist/core/storeContext.d.ts.map +1 -1
- package/dist/devtools/index.js +2 -1
- package/dist/effect-DPAYSuW3.js +294 -0
- package/dist/emitter-BA44OHdL.js +228 -0
- package/dist/react/index.js +23 -20
- package/dist/{store-DS-4XdM6.js → store-BroaE7p4.js} +19 -235
- package/dist/storion.js +17 -287
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -385,6 +385,60 @@ export const syncStore = store({
|
|
|
385
385
|
});
|
|
386
386
|
```
|
|
387
387
|
|
|
388
|
+
### Effect Re-run
|
|
389
|
+
|
|
390
|
+
Effects automatically re-run when their tracked state changes. There are three ways an effect can be triggered to re-run:
|
|
391
|
+
|
|
392
|
+
**1. Tracked state changes** — The most common case. When any state property read during the effect's execution changes, the effect re-runs automatically.
|
|
393
|
+
|
|
394
|
+
```ts
|
|
395
|
+
effect(() => {
|
|
396
|
+
// This effect tracks `state.count` and re-runs when it changes
|
|
397
|
+
console.log("Count is:", state.count);
|
|
398
|
+
});
|
|
399
|
+
```
|
|
400
|
+
|
|
401
|
+
**2. Calling `ctx.refresh()` asynchronously** — You can manually trigger a re-run from async code (promises, setTimeout, event handlers).
|
|
402
|
+
|
|
403
|
+
```ts
|
|
404
|
+
effect((ctx) => {
|
|
405
|
+
// Schedule a refresh after some async work
|
|
406
|
+
ctx.safe(fetchData()).then(() => {
|
|
407
|
+
ctx.refresh(); // Re-runs the effect
|
|
408
|
+
});
|
|
409
|
+
|
|
410
|
+
// Or from a setTimeout
|
|
411
|
+
setTimeout(() => {
|
|
412
|
+
ctx.refresh();
|
|
413
|
+
}, 1000);
|
|
414
|
+
});
|
|
415
|
+
```
|
|
416
|
+
|
|
417
|
+
**3. Returning `ctx.refresh`** — For synchronous refresh requests, return `ctx.refresh` from the effect. The effect will re-run after the current execution completes.
|
|
418
|
+
|
|
419
|
+
```ts
|
|
420
|
+
effect((ctx) => {
|
|
421
|
+
const data = async.wait(state.asyncData); // May throw a promise
|
|
422
|
+
// If we get here, data is available
|
|
423
|
+
state.result = transform(data);
|
|
424
|
+
|
|
425
|
+
// Return ctx.refresh to request a re-run after this execution
|
|
426
|
+
if (needsAnotherRun) {
|
|
427
|
+
return ctx.refresh;
|
|
428
|
+
}
|
|
429
|
+
});
|
|
430
|
+
```
|
|
431
|
+
|
|
432
|
+
> **Important:** Effects cannot re-run while already executing. Calling `ctx.refresh()` synchronously during effect execution throws an error:
|
|
433
|
+
>
|
|
434
|
+
> ```ts
|
|
435
|
+
> effect((ctx) => {
|
|
436
|
+
> ctx.refresh(); // ❌ Error: Effect is already running, cannot refresh
|
|
437
|
+
> });
|
|
438
|
+
> ```
|
|
439
|
+
>
|
|
440
|
+
> This prevents infinite loops and ensures predictable execution. Use the return pattern or async scheduling instead.
|
|
441
|
+
|
|
388
442
|
### Effect with Safe Async
|
|
389
443
|
|
|
390
444
|
**The problem:** When an effect re-runs before an async operation completes, you get stale data or "state update on unmounted component" warnings. Managing this manually is error-prone.
|
|
@@ -743,17 +797,14 @@ function Dashboard() {
|
|
|
743
797
|
|
|
744
798
|
// 3c. With custom deps - refetch when deps change
|
|
745
799
|
function UserById({ userId }: { userId: string }) {
|
|
746
|
-
const { user } = useStore(
|
|
747
|
-
|
|
748
|
-
const [state, actions] = get(userStore);
|
|
800
|
+
const { user } = useStore(({ get, trigger }) => {
|
|
801
|
+
const [state, actions] = get(userStore);
|
|
749
802
|
|
|
750
|
-
|
|
751
|
-
|
|
803
|
+
// Refetch when userId prop changes
|
|
804
|
+
trigger(actions.currentUser.dispatch, [userId]);
|
|
752
805
|
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
[userId] // selector deps for proper tracking
|
|
756
|
-
);
|
|
806
|
+
return { user: state.currentUser };
|
|
807
|
+
});
|
|
757
808
|
|
|
758
809
|
return <div>{user.data?.name}</div>;
|
|
759
810
|
}
|
|
@@ -822,7 +873,7 @@ function SearchBox() {
|
|
|
822
873
|
│ │ │
|
|
823
874
|
│ ├── Once ever? ────► trigger(fn, []) │
|
|
824
875
|
│ │ │
|
|
825
|
-
│ ├── Every visit? ──► trigger(fn, [id])
|
|
876
|
+
│ ├── Every visit? ──► trigger(fn, [context.id]) │
|
|
826
877
|
│ │ │
|
|
827
878
|
│ └── When deps change? ► trigger(fn, [dep1, dep2]) │
|
|
828
879
|
│ │
|
|
@@ -886,9 +937,9 @@ function Dashboard() {
|
|
|
886
937
|
const [postState, postActions] = get(postStore);
|
|
887
938
|
const [commentState, commentActions] = get(commentStore);
|
|
888
939
|
|
|
889
|
-
trigger(userActions.fetch
|
|
890
|
-
trigger(postActions.fetch
|
|
891
|
-
trigger(commentActions.fetch
|
|
940
|
+
trigger(userActions.fetch);
|
|
941
|
+
trigger(postActions.fetch);
|
|
942
|
+
trigger(commentActions.fetch);
|
|
892
943
|
|
|
893
944
|
// Wait for ALL async states - suspends until all are ready
|
|
894
945
|
const [user, posts, comments] = async.all(
|
|
@@ -917,10 +968,8 @@ function FastestResult() {
|
|
|
917
968
|
const { result } = useStore(({ get, trigger }) => {
|
|
918
969
|
const [state, actions] = get(searchStore);
|
|
919
970
|
|
|
920
|
-
trigger(
|
|
921
|
-
|
|
922
|
-
actions.searchAPI2(query);
|
|
923
|
-
}, [query]);
|
|
971
|
+
trigger(actions.searchAPI1, [], query);
|
|
972
|
+
trigger(actions.searchAPI2, [], query);
|
|
924
973
|
|
|
925
974
|
// Returns whichever finishes first
|
|
926
975
|
return {
|
|
@@ -944,6 +993,156 @@ function FastestResult() {
|
|
|
944
993
|
| `async.isLoading(state)` | `boolean` | Loading indicator |
|
|
945
994
|
| `async.isError(state)` | `boolean` | Error check |
|
|
946
995
|
|
|
996
|
+
### Derived Async State with `async.derive()`
|
|
997
|
+
|
|
998
|
+
**The problem:** You need to compute a value from multiple async states. If any source is loading, the derived value should be loading. If any errors, it should error. Writing this logic manually is verbose and error-prone.
|
|
999
|
+
|
|
1000
|
+
**With Storion:** Use `async.derive()` to create computed async state. It uses `async.wait()` internally, so it automatically handles pending/error states and re-computes when sources change.
|
|
1001
|
+
|
|
1002
|
+
```ts
|
|
1003
|
+
import { store } from "storion";
|
|
1004
|
+
import { async, type AsyncState } from "storion/async";
|
|
1005
|
+
|
|
1006
|
+
interface User {
|
|
1007
|
+
id: string;
|
|
1008
|
+
name: string;
|
|
1009
|
+
}
|
|
1010
|
+
|
|
1011
|
+
interface Post {
|
|
1012
|
+
id: string;
|
|
1013
|
+
title: string;
|
|
1014
|
+
authorId: string;
|
|
1015
|
+
}
|
|
1016
|
+
|
|
1017
|
+
export const dashboardStore = store({
|
|
1018
|
+
name: "dashboard",
|
|
1019
|
+
state: {
|
|
1020
|
+
user: async.fresh<User>(),
|
|
1021
|
+
posts: async.fresh<Post[]>(),
|
|
1022
|
+
// Derived async state - computed from user + posts
|
|
1023
|
+
summary: async.fresh<{ userName: string; postCount: number }>(),
|
|
1024
|
+
},
|
|
1025
|
+
setup({ state, focus }) {
|
|
1026
|
+
// Fetch actions
|
|
1027
|
+
const userActions = async(focus("user"), async (ctx, userId: string) => {
|
|
1028
|
+
const res = await fetch(`/api/users/${userId}`, { signal: ctx.signal });
|
|
1029
|
+
return res.json();
|
|
1030
|
+
});
|
|
1031
|
+
|
|
1032
|
+
const postsActions = async(focus("posts"), async (ctx, userId: string) => {
|
|
1033
|
+
const res = await fetch(`/api/users/${userId}/posts`, {
|
|
1034
|
+
signal: ctx.signal,
|
|
1035
|
+
});
|
|
1036
|
+
return res.json();
|
|
1037
|
+
});
|
|
1038
|
+
|
|
1039
|
+
// Derive summary from user + posts
|
|
1040
|
+
// - If user OR posts is pending → summary is pending
|
|
1041
|
+
// - If user OR posts has error → summary has error
|
|
1042
|
+
// - If both succeed → summary is success with computed value
|
|
1043
|
+
async.derive(focus("summary"), () => {
|
|
1044
|
+
const user = async.wait(state.user);
|
|
1045
|
+
const posts = async.wait(state.posts);
|
|
1046
|
+
return {
|
|
1047
|
+
userName: user.name,
|
|
1048
|
+
postCount: posts.length,
|
|
1049
|
+
};
|
|
1050
|
+
});
|
|
1051
|
+
|
|
1052
|
+
return {
|
|
1053
|
+
fetchUser: userActions.dispatch,
|
|
1054
|
+
fetchPosts: postsActions.dispatch,
|
|
1055
|
+
};
|
|
1056
|
+
},
|
|
1057
|
+
});
|
|
1058
|
+
```
|
|
1059
|
+
|
|
1060
|
+
**Conditional dependencies:**
|
|
1061
|
+
|
|
1062
|
+
```ts
|
|
1063
|
+
// Derive with conditional async sources
|
|
1064
|
+
async.derive(focus("result"), () => {
|
|
1065
|
+
const type = async.wait(state.type);
|
|
1066
|
+
|
|
1067
|
+
// Dynamically choose which async state to wait for
|
|
1068
|
+
if (type === "user") {
|
|
1069
|
+
return async.wait(state.userData);
|
|
1070
|
+
} else {
|
|
1071
|
+
return async.wait(state.guestData);
|
|
1072
|
+
}
|
|
1073
|
+
});
|
|
1074
|
+
```
|
|
1075
|
+
|
|
1076
|
+
**Parallel waiting with `async.all()`:**
|
|
1077
|
+
|
|
1078
|
+
```ts
|
|
1079
|
+
// Wait for multiple states in parallel (more efficient)
|
|
1080
|
+
async.derive(focus("combined"), () => {
|
|
1081
|
+
const [user, posts, comments] = async.all(
|
|
1082
|
+
state.user,
|
|
1083
|
+
state.posts,
|
|
1084
|
+
state.comments
|
|
1085
|
+
);
|
|
1086
|
+
return { user, posts, comments };
|
|
1087
|
+
});
|
|
1088
|
+
```
|
|
1089
|
+
|
|
1090
|
+
**Stale mode - preserve data during recomputation:**
|
|
1091
|
+
|
|
1092
|
+
```ts
|
|
1093
|
+
state: {
|
|
1094
|
+
// Stale mode: keeps previous computed value while recomputing
|
|
1095
|
+
summary: async.stale({ userName: "Loading...", postCount: 0 }),
|
|
1096
|
+
}
|
|
1097
|
+
|
|
1098
|
+
// The derive will preserve stale data during pending/error
|
|
1099
|
+
async.derive(focus("summary"), () => {
|
|
1100
|
+
const user = async.wait(state.user);
|
|
1101
|
+
const posts = async.wait(state.posts);
|
|
1102
|
+
return { userName: user.name, postCount: posts.length };
|
|
1103
|
+
});
|
|
1104
|
+
```
|
|
1105
|
+
|
|
1106
|
+
**Key behaviors:**
|
|
1107
|
+
|
|
1108
|
+
| Source State | Derived State |
|
|
1109
|
+
| ------------------ | ----------------------------------- |
|
|
1110
|
+
| Any source pending | `pending` (stale: preserves data) |
|
|
1111
|
+
| Any source error | `error` (stale: preserves data) |
|
|
1112
|
+
| All sources ready | `success` with computed value |
|
|
1113
|
+
| Sources change | Auto-recomputes via effect tracking |
|
|
1114
|
+
|
|
1115
|
+
**`async.derive()` vs manual effects:**
|
|
1116
|
+
|
|
1117
|
+
```ts
|
|
1118
|
+
// ❌ Manual - verbose, error-prone
|
|
1119
|
+
effect(() => {
|
|
1120
|
+
if (state.user.status === "pending" || state.posts.status === "pending") {
|
|
1121
|
+
state.summary = asyncState("fresh", "pending");
|
|
1122
|
+
return;
|
|
1123
|
+
}
|
|
1124
|
+
if (state.user.status === "error") {
|
|
1125
|
+
state.summary = asyncState("fresh", "error", state.user.error);
|
|
1126
|
+
return;
|
|
1127
|
+
}
|
|
1128
|
+
if (state.posts.status === "error") {
|
|
1129
|
+
state.summary = asyncState("fresh", "error", state.posts.error);
|
|
1130
|
+
return;
|
|
1131
|
+
}
|
|
1132
|
+
state.summary = asyncState("fresh", "success", {
|
|
1133
|
+
userName: state.user.data.name,
|
|
1134
|
+
postCount: state.posts.data.length,
|
|
1135
|
+
});
|
|
1136
|
+
});
|
|
1137
|
+
|
|
1138
|
+
// ✅ With async.derive - clean and automatic
|
|
1139
|
+
async.derive(focus("summary"), () => {
|
|
1140
|
+
const user = async.wait(state.user);
|
|
1141
|
+
const posts = async.wait(state.posts);
|
|
1142
|
+
return { userName: user.name, postCount: posts.length };
|
|
1143
|
+
});
|
|
1144
|
+
```
|
|
1145
|
+
|
|
947
1146
|
### Dependency Injection
|
|
948
1147
|
|
|
949
1148
|
**The problem:** Your stores need shared services (API clients, loggers, config) but importing singletons directly causes issues:
|
|
@@ -1287,6 +1486,7 @@ const result = useStore(({ get, create, mixin, once }) => {
|
|
|
1287
1486
|
| `async.all(...states)` | Wait for all states to be ready |
|
|
1288
1487
|
| `async.any(...states)` | Get first ready state |
|
|
1289
1488
|
| `async.race(states)` | Race between states |
|
|
1489
|
+
| `async.derive(focus, computeFn)` | Derive async state from other async states |
|
|
1290
1490
|
| `async.hasData(state)` | Check if state has data |
|
|
1291
1491
|
| `async.isLoading(state)` | Check if state is loading |
|
|
1292
1492
|
| `async.isError(state)` | Check if state has error |
|
package/dist/async/async.d.ts
CHANGED
|
@@ -114,6 +114,55 @@ export declare namespace async {
|
|
|
114
114
|
status: "error";
|
|
115
115
|
error: Error;
|
|
116
116
|
};
|
|
117
|
+
/**
|
|
118
|
+
* Derive an async state from other async states using a synchronous computation.
|
|
119
|
+
* The computation function uses `async.wait()` to extract data from async states,
|
|
120
|
+
* which throws promises when states are pending.
|
|
121
|
+
*
|
|
122
|
+
* Key behaviors:
|
|
123
|
+
* - If `computeFn` throws a promise (via `async.wait`), sets focus to pending and re-runs after promise settles
|
|
124
|
+
* - If `computeFn` throws an error, sets focus to error state
|
|
125
|
+
* - If `computeFn` returns a value, sets focus to success state
|
|
126
|
+
* - If `computeFn` returns a promise (not throws), throws an error - must be synchronous
|
|
127
|
+
* - Uses a single wrapper promise to avoid cascading re-renders
|
|
128
|
+
*
|
|
129
|
+
* @param focus - Focus to update with derived async state
|
|
130
|
+
* @param computeFn - Synchronous computation function that uses `async.wait()` to read async states
|
|
131
|
+
* @returns Dispose function to stop the derivation
|
|
132
|
+
*
|
|
133
|
+
* @example
|
|
134
|
+
* // Basic usage - derive from multiple async states
|
|
135
|
+
* async.derive(focus('c'), () => {
|
|
136
|
+
* const a = async.wait(state.a);
|
|
137
|
+
* const b = async.wait(state.b);
|
|
138
|
+
* return a + b;
|
|
139
|
+
* });
|
|
140
|
+
*
|
|
141
|
+
* @example
|
|
142
|
+
* // Conditional dependencies
|
|
143
|
+
* async.derive(focus('result'), () => {
|
|
144
|
+
* const type = async.wait(state.type);
|
|
145
|
+
* if (type === 'user') {
|
|
146
|
+
* return async.wait(state.userData);
|
|
147
|
+
* } else {
|
|
148
|
+
* return async.wait(state.guestData);
|
|
149
|
+
* }
|
|
150
|
+
* });
|
|
151
|
+
*
|
|
152
|
+
* @example
|
|
153
|
+
* // For parallel waiting, use async.all
|
|
154
|
+
* async.derive(focus('combined'), () => {
|
|
155
|
+
* const [a, b, c] = async.all(state.a, state.b, state.c);
|
|
156
|
+
* return { a, b, c };
|
|
157
|
+
* });
|
|
158
|
+
*
|
|
159
|
+
* @example
|
|
160
|
+
* // With stale mode - preserves data during loading/error
|
|
161
|
+
* async.derive(focus('result'), () => {
|
|
162
|
+
* return async.wait(state.userData);
|
|
163
|
+
* });
|
|
164
|
+
*/
|
|
165
|
+
function derive<T, M extends AsyncMode = "fresh">(focus: Focus<AsyncState<T, M>>, computeFn: () => T): VoidFunction;
|
|
117
166
|
}
|
|
118
167
|
export {};
|
|
119
168
|
//# sourceMappingURL=async.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"async.d.ts","sourceRoot":"","sources":["../../src/async/async.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,UAAU,CAAC;AACtC,OAAO,KAAK,EACV,UAAU,EACV,SAAS,EAET,YAAY,EACZ,YAAY,EACZ,YAAY,EAEZ,kBAAkB,EAElB,cAAc,EAEd,YAAY,EACZ,gBAAgB,EAChB,UAAU,EACV,QAAQ,EACR,cAAc,EAEf,MAAM,SAAS,CAAC;
|
|
1
|
+
{"version":3,"file":"async.d.ts","sourceRoot":"","sources":["../../src/async/async.ts"],"names":[],"mappings":"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"}
|
package/dist/async/index.js
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { e as effect } from "../effect-DPAYSuW3.js";
|
|
2
|
+
import { u as untrack } from "../emitter-BA44OHdL.js";
|
|
1
3
|
class AsyncNotReadyError extends Error {
|
|
2
4
|
constructor(message, status) {
|
|
3
5
|
super(message);
|
|
@@ -523,6 +525,54 @@ function asyncState(mode, status, dataOrError, errorOrExtra, extra) {
|
|
|
523
525
|
return state.status === "error";
|
|
524
526
|
}
|
|
525
527
|
async2.isError = isError;
|
|
528
|
+
function derive(focus, computeFn) {
|
|
529
|
+
const [getState, setState] = focus;
|
|
530
|
+
let hasSetPending = false;
|
|
531
|
+
return effect((ctx) => {
|
|
532
|
+
const currentState = untrack(getState);
|
|
533
|
+
const mode = currentState.mode;
|
|
534
|
+
const staleData = mode === "stale" ? currentState.data : currentState.status === "success" ? currentState.data : void 0;
|
|
535
|
+
try {
|
|
536
|
+
const result = computeFn();
|
|
537
|
+
if (result !== null && result !== void 0 && typeof result.then === "function") {
|
|
538
|
+
throw new Error(
|
|
539
|
+
"async.derive: computeFn must be synchronous. Use async.wait() for async values, not async/await or returning promises."
|
|
540
|
+
);
|
|
541
|
+
}
|
|
542
|
+
hasSetPending = false;
|
|
543
|
+
if (mode === "stale") {
|
|
544
|
+
setState(asyncState("stale", "success", result));
|
|
545
|
+
} else {
|
|
546
|
+
setState(asyncState("fresh", "success", result));
|
|
547
|
+
}
|
|
548
|
+
} catch (ex) {
|
|
549
|
+
if (ex !== null && ex !== void 0 && typeof ex.then === "function") {
|
|
550
|
+
if (!hasSetPending) {
|
|
551
|
+
hasSetPending = true;
|
|
552
|
+
if (mode === "stale") {
|
|
553
|
+
setState(
|
|
554
|
+
asyncState("stale", "pending", staleData)
|
|
555
|
+
);
|
|
556
|
+
} else {
|
|
557
|
+
setState(asyncState("fresh", "pending"));
|
|
558
|
+
}
|
|
559
|
+
}
|
|
560
|
+
ctx.safe(ex).then(ctx.refresh, ctx.refresh);
|
|
561
|
+
} else {
|
|
562
|
+
hasSetPending = false;
|
|
563
|
+
const error = ex instanceof Error ? ex : new Error(String(ex));
|
|
564
|
+
if (mode === "stale") {
|
|
565
|
+
setState(
|
|
566
|
+
asyncState("stale", "error", staleData, error)
|
|
567
|
+
);
|
|
568
|
+
} else {
|
|
569
|
+
setState(asyncState("fresh", "error", error));
|
|
570
|
+
}
|
|
571
|
+
}
|
|
572
|
+
}
|
|
573
|
+
});
|
|
574
|
+
}
|
|
575
|
+
async2.derive = derive;
|
|
526
576
|
})(async || (async = {}));
|
|
527
577
|
export {
|
|
528
578
|
AsyncAggregateError,
|
package/dist/core/effect.d.ts
CHANGED
|
@@ -115,6 +115,26 @@ export interface EffectContext {
|
|
|
115
115
|
* });
|
|
116
116
|
*/
|
|
117
117
|
safe<TArgs extends unknown[], TReturn>(callback: (...args: TArgs) => TReturn): (...args: TArgs) => TReturn | undefined;
|
|
118
|
+
/**
|
|
119
|
+
* Manually trigger a re-run of the effect.
|
|
120
|
+
* Useful for async.derive pattern where thrown promises should trigger re-computation.
|
|
121
|
+
*
|
|
122
|
+
* Note: If called while the effect is currently running, the refresh will be
|
|
123
|
+
* scheduled for after the current run completes.
|
|
124
|
+
*
|
|
125
|
+
* @example
|
|
126
|
+
* effect((ctx) => {
|
|
127
|
+
* try {
|
|
128
|
+
* const data = async.wait(state.asyncData); // throws if pending
|
|
129
|
+
* state.computed = transform(data);
|
|
130
|
+
* } catch (ex) {
|
|
131
|
+
* if (isPromise(ex)) {
|
|
132
|
+
* ctx.safe(ex).then(ctx.refresh, ctx.refresh);
|
|
133
|
+
* }
|
|
134
|
+
* }
|
|
135
|
+
* });
|
|
136
|
+
*/
|
|
137
|
+
refresh(): void;
|
|
118
138
|
}
|
|
119
139
|
/**
|
|
120
140
|
* Effect function type.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"effect.d.ts","sourceRoot":"","sources":["../../src/core/effect.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAgBH;;GAEG;AACH,MAAM,WAAW,iBAAiB;IAChC,uCAAuC;IACvC,UAAU,EAAE,MAAM,CAAC;IACnB,mEAAmE;IACnE,KAAK,CAAC,EAAE,MAAM,GAAG,CAAC,CAAC,OAAO,EAAE,MAAM,KAAK,MAAM,CAAC,CAAC;CAChD;AAED;;GAEG;AACH,MAAM,WAAW,kBAAkB;IACjC,gCAAgC;IAChC,KAAK,EAAE,OAAO,CAAC;IACf,2CAA2C;IAC3C,KAAK,EAAE,MAAM,IAAI,CAAC;IAClB,4DAA4D;IAC5D,UAAU,EAAE,MAAM,CAAC;CACpB;AAED;;GAEG;AACH,MAAM,MAAM,mBAAmB,GAC3B,UAAU,GACV,WAAW,GACX,iBAAiB,GACjB,CAAC,CAAC,OAAO,EAAE,kBAAkB,KAAK,IAAI,CAAC,CAAC;AAE5C;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B,8BAA8B;IAC9B,OAAO,CAAC,EAAE,mBAAmB,CAAC;CAC/B;AAED;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B,oEAAoE;IACpE,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,IAAI,CAAC;CACpC;AAMD;;;GAGG;AACH,MAAM,WAAW,aAAa;IAC5B;;;;;;;;;;;;;OAaG;IACH,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IAErB;;;;;;;;OAQG;IACH,QAAQ,CAAC,MAAM,EAAE,WAAW,CAAC;IAE7B;;;;;;;;;;;;;OAaG;IACH,SAAS,CAAC,QAAQ,EAAE,YAAY,GAAG,YAAY,CAAC;IAEhD;;;;;;;;;;;OAWG;IACH,IAAI,CAAC,CAAC,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;IAEzC;;;;;;;;;;;;;OAaG;IACH,IAAI,CAAC,KAAK,SAAS,OAAO,EAAE,EAAE,OAAO,EACnC,QAAQ,EAAE,CAAC,GAAG,IAAI,EAAE,KAAK,KAAK,OAAO,GACpC,CAAC,GAAG,IAAI,EAAE,KAAK,KAAK,OAAO,GAAG,SAAS,CAAC;
|
|
1
|
+
{"version":3,"file":"effect.d.ts","sourceRoot":"","sources":["../../src/core/effect.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAgBH;;GAEG;AACH,MAAM,WAAW,iBAAiB;IAChC,uCAAuC;IACvC,UAAU,EAAE,MAAM,CAAC;IACnB,mEAAmE;IACnE,KAAK,CAAC,EAAE,MAAM,GAAG,CAAC,CAAC,OAAO,EAAE,MAAM,KAAK,MAAM,CAAC,CAAC;CAChD;AAED;;GAEG;AACH,MAAM,WAAW,kBAAkB;IACjC,gCAAgC;IAChC,KAAK,EAAE,OAAO,CAAC;IACf,2CAA2C;IAC3C,KAAK,EAAE,MAAM,IAAI,CAAC;IAClB,4DAA4D;IAC5D,UAAU,EAAE,MAAM,CAAC;CACpB;AAED;;GAEG;AACH,MAAM,MAAM,mBAAmB,GAC3B,UAAU,GACV,WAAW,GACX,iBAAiB,GACjB,CAAC,CAAC,OAAO,EAAE,kBAAkB,KAAK,IAAI,CAAC,CAAC;AAE5C;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B,8BAA8B;IAC9B,OAAO,CAAC,EAAE,mBAAmB,CAAC;CAC/B;AAED;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B,oEAAoE;IACpE,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,IAAI,CAAC;CACpC;AAMD;;;GAGG;AACH,MAAM,WAAW,aAAa;IAC5B;;;;;;;;;;;;;OAaG;IACH,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IAErB;;;;;;;;OAQG;IACH,QAAQ,CAAC,MAAM,EAAE,WAAW,CAAC;IAE7B;;;;;;;;;;;;;OAaG;IACH,SAAS,CAAC,QAAQ,EAAE,YAAY,GAAG,YAAY,CAAC;IAEhD;;;;;;;;;;;OAWG;IACH,IAAI,CAAC,CAAC,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;IAEzC;;;;;;;;;;;;;OAaG;IACH,IAAI,CAAC,KAAK,SAAS,OAAO,EAAE,EAAE,OAAO,EACnC,QAAQ,EAAE,CAAC,GAAG,IAAI,EAAE,KAAK,KAAK,OAAO,GACpC,CAAC,GAAG,IAAI,EAAE,KAAK,KAAK,OAAO,GAAG,SAAS,CAAC;IAE3C;;;;;;;;;;;;;;;;;;OAkBG;IACH,OAAO,IAAI,IAAI,CAAC;CACjB;AAkHD;;;GAGG;AACH,MAAM,MAAM,QAAQ,GAAG,CAAC,GAAG,EAAE,aAAa,KAAK,IAAI,CAAC;AAsBpD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+CG;AACH,wBAAgB,MAAM,CAAC,EAAE,EAAE,QAAQ,EAAE,OAAO,CAAC,EAAE,aAAa,GAAG,YAAY,CAyS1E"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"storeContext.d.ts","sourceRoot":"","sources":["../../src/core/storeContext.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAEL,KAAK,SAAS,EACd,KAAK,WAAW,EAChB,KAAK,SAAS,EACd,KAAK,aAAa,EAClB,KAAK,QAAQ,EACb,KAAK,YAAY,EAGjB,KAAK,KAAK,EACV,KAAK,YAAY,EAElB,MAAM,UAAU,CAAC;AAUlB;;GAEG;AACH,MAAM,WAAW,YAAY,CAAC,MAAM,SAAS,SAAS;IACpD,wBAAwB;IACxB,QAAQ,EAAE,MAAM,MAAM,CAAC;IACvB,4CAA4C;IAC5C,MAAM,EAAE,CAAC,OAAO,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,KAAK,IAAI,CAAC;IACnD,iCAAiC;IACjC,SAAS,EAAE,CAAC,QAAQ,EAAE,MAAM,IAAI,KAAK,YAAY,CAAC;CACnD;AAED;;GAEG;AACH,MAAM,WAAW,yBAAyB,CACxC,MAAM,SAAS,SAAS,EACxB,QAAQ,SAAS,WAAW;IAE5B,8BAA8B;IAC9B,IAAI,EAAE,SAAS,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;IAClC,oCAAoC;IACpC,QAAQ,EAAE,QAAQ,CAAC;IACnB,gCAAgC;IAChC,eAAe,EAAE,MAAM,MAAM,CAAC;IAC9B,+BAA+B;IAC/B,MAAM,EAAE,CAAC,OAAO,EAAE,CAAC,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC,GAAG,OAAO,CAAC,MAAM,CAAC,KAAK,IAAI,CAAC;IACvE,iCAAiC;IACjC,SAAS,EAAE,CAAC,QAAQ,EAAE,MAAM,IAAI,KAAK,YAAY,CAAC;IAClD,iCAAiC;IACjC,KAAK,EAAE,CAAC,IAAI,CAAC,EAAE,MAAM,MAAM,KAAK,OAAO,CAAC;IACxC,6BAA6B;IAC7B,KAAK,EAAE,MAAM,IAAI,CAAC;IAClB,wDAAwD;IACxD,WAAW,EAAE,MAAM,aAAa,CAAC,MAAM,EAAE,QAAQ,CAAC,GAAG,IAAI,CAAC;IAC1D,2CAA2C;IAC3C,YAAY,CAAC,EAAE,CAAC,QAAQ,EAAE,aAAa,CAAC,GAAG,EAAE,GAAG,CAAC,KAAK,IAAI,CAAC;IAC3D,4DAA4D;IAC5D,SAAS,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,IAAI,KAAK,IAAI,CAAC;IAC3C,8BAA8B;IAC9B,YAAY,EAAE,MAAM,OAAO,CAAC;CAC7B;AAkBD;;;;;;GAMG;AACH,wBAAgB,WAAW,CAAC,MAAM,SAAS,SAAS,EAAE,MAAM,EAC1D,QAAQ,EAAE,YAAY,CAAC,MAAM,CAAC,EAC9B,IAAI,EAAE,MAAM,EACZ,OAAO,CAAC,EAAE,YAAY,CAAC,MAAM,CAAC,GAC7B,KAAK,CAAC,MAAM,CAAC,CAsHf;AA2CD;;;;;;;;;;;;GAYG;AACH,wBAAgB,kBAAkB,CAChC,MAAM,SAAS,SAAS,EACxB,QAAQ,SAAS,WAAW,EAC5B,OAAO,EAAE,yBAAyB,CAAC,MAAM,EAAE,QAAQ,CAAC,GAAG,YAAY,CAAC,MAAM,CAAC,
|
|
1
|
+
{"version":3,"file":"storeContext.d.ts","sourceRoot":"","sources":["../../src/core/storeContext.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAEL,KAAK,SAAS,EACd,KAAK,WAAW,EAChB,KAAK,SAAS,EACd,KAAK,aAAa,EAClB,KAAK,QAAQ,EACb,KAAK,YAAY,EAGjB,KAAK,KAAK,EACV,KAAK,YAAY,EAElB,MAAM,UAAU,CAAC;AAUlB;;GAEG;AACH,MAAM,WAAW,YAAY,CAAC,MAAM,SAAS,SAAS;IACpD,wBAAwB;IACxB,QAAQ,EAAE,MAAM,MAAM,CAAC;IACvB,4CAA4C;IAC5C,MAAM,EAAE,CAAC,OAAO,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,KAAK,IAAI,CAAC;IACnD,iCAAiC;IACjC,SAAS,EAAE,CAAC,QAAQ,EAAE,MAAM,IAAI,KAAK,YAAY,CAAC;CACnD;AAED;;GAEG;AACH,MAAM,WAAW,yBAAyB,CACxC,MAAM,SAAS,SAAS,EACxB,QAAQ,SAAS,WAAW;IAE5B,8BAA8B;IAC9B,IAAI,EAAE,SAAS,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;IAClC,oCAAoC;IACpC,QAAQ,EAAE,QAAQ,CAAC;IACnB,gCAAgC;IAChC,eAAe,EAAE,MAAM,MAAM,CAAC;IAC9B,+BAA+B;IAC/B,MAAM,EAAE,CAAC,OAAO,EAAE,CAAC,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC,GAAG,OAAO,CAAC,MAAM,CAAC,KAAK,IAAI,CAAC;IACvE,iCAAiC;IACjC,SAAS,EAAE,CAAC,QAAQ,EAAE,MAAM,IAAI,KAAK,YAAY,CAAC;IAClD,iCAAiC;IACjC,KAAK,EAAE,CAAC,IAAI,CAAC,EAAE,MAAM,MAAM,KAAK,OAAO,CAAC;IACxC,6BAA6B;IAC7B,KAAK,EAAE,MAAM,IAAI,CAAC;IAClB,wDAAwD;IACxD,WAAW,EAAE,MAAM,aAAa,CAAC,MAAM,EAAE,QAAQ,CAAC,GAAG,IAAI,CAAC;IAC1D,2CAA2C;IAC3C,YAAY,CAAC,EAAE,CAAC,QAAQ,EAAE,aAAa,CAAC,GAAG,EAAE,GAAG,CAAC,KAAK,IAAI,CAAC;IAC3D,4DAA4D;IAC5D,SAAS,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,IAAI,KAAK,IAAI,CAAC;IAC3C,8BAA8B;IAC9B,YAAY,EAAE,MAAM,OAAO,CAAC;CAC7B;AAkBD;;;;;;GAMG;AACH,wBAAgB,WAAW,CAAC,MAAM,SAAS,SAAS,EAAE,MAAM,EAC1D,QAAQ,EAAE,YAAY,CAAC,MAAM,CAAC,EAC9B,IAAI,EAAE,MAAM,EACZ,OAAO,CAAC,EAAE,YAAY,CAAC,MAAM,CAAC,GAC7B,KAAK,CAAC,MAAM,CAAC,CAsHf;AA2CD;;;;;;;;;;;;GAYG;AACH,wBAAgB,kBAAkB,CAChC,MAAM,SAAS,SAAS,EACxB,QAAQ,SAAS,WAAW,EAC5B,OAAO,EAAE,yBAAyB,CAAC,MAAM,EAAE,QAAQ,CAAC,GAAG,YAAY,CAAC,MAAM,CAAC,CAwK5E"}
|
package/dist/devtools/index.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { c as createStoreInstance, S as STORION_TYPE } from "../store-BroaE7p4.js";
|
|
2
|
+
import { e as emitter } from "../emitter-BA44OHdL.js";
|
|
2
3
|
let snapshotIdCounter = 0;
|
|
3
4
|
let eventIdCounter = 0;
|
|
4
5
|
const DEFAULT_MAX_EVENTS = 200;
|