storion 0.5.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 CHANGED
@@ -282,9 +282,7 @@ export const settingsStore = store({
282
282
 
283
283
  return {
284
284
  // Direct value
285
- setTheme: (theme: "light" | "dark") => {
286
- setTheme(theme);
287
- },
285
+ setTheme,
288
286
 
289
287
  // Reducer - returns new value
290
288
  toggleTheme: () => {
@@ -387,6 +385,60 @@ export const syncStore = store({
387
385
  });
388
386
  ```
389
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
+
390
442
  ### Effect with Safe Async
391
443
 
392
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.
@@ -745,17 +797,14 @@ function Dashboard() {
745
797
 
746
798
  // 3c. With custom deps - refetch when deps change
747
799
  function UserById({ userId }: { userId: string }) {
748
- const { user } = useStore(
749
- ({ get, trigger }) => {
750
- const [state, actions] = get(userStore);
800
+ const { user } = useStore(({ get, trigger }) => {
801
+ const [state, actions] = get(userStore);
751
802
 
752
- // Refetch when userId prop changes
753
- trigger(() => actions.currentUser.dispatch(), [userId]);
803
+ // Refetch when userId prop changes
804
+ trigger(actions.currentUser.dispatch, [userId]);
754
805
 
755
- return { user: state.currentUser };
756
- },
757
- [userId] // selector deps for proper tracking
758
- );
806
+ return { user: state.currentUser };
807
+ });
759
808
 
760
809
  return <div>{user.data?.name}</div>;
761
810
  }
@@ -824,7 +873,7 @@ function SearchBox() {
824
873
  │ │ │
825
874
  │ ├── Once ever? ────► trigger(fn, []) │
826
875
  │ │ │
827
- │ ├── Every visit? ──► trigger(fn, [id])
876
+ │ ├── Every visit? ──► trigger(fn, [context.id])
828
877
  │ │ │
829
878
  │ └── When deps change? ► trigger(fn, [dep1, dep2]) │
830
879
  │ │
@@ -888,9 +937,9 @@ function Dashboard() {
888
937
  const [postState, postActions] = get(postStore);
889
938
  const [commentState, commentActions] = get(commentStore);
890
939
 
891
- trigger(userActions.fetch, []);
892
- trigger(postActions.fetch, []);
893
- trigger(commentActions.fetch, []);
940
+ trigger(userActions.fetch);
941
+ trigger(postActions.fetch);
942
+ trigger(commentActions.fetch);
894
943
 
895
944
  // Wait for ALL async states - suspends until all are ready
896
945
  const [user, posts, comments] = async.all(
@@ -919,10 +968,8 @@ function FastestResult() {
919
968
  const { result } = useStore(({ get, trigger }) => {
920
969
  const [state, actions] = get(searchStore);
921
970
 
922
- trigger(() => {
923
- actions.searchAPI1(query);
924
- actions.searchAPI2(query);
925
- }, [query]);
971
+ trigger(actions.searchAPI1, [], query);
972
+ trigger(actions.searchAPI2, [], query);
926
973
 
927
974
  // Returns whichever finishes first
928
975
  return {
@@ -946,6 +993,156 @@ function FastestResult() {
946
993
  | `async.isLoading(state)` | `boolean` | Loading indicator |
947
994
  | `async.isError(state)` | `boolean` | Error check |
948
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
+
949
1146
  ### Dependency Injection
950
1147
 
951
1148
  **The problem:** Your stores need shared services (API clients, loggers, config) but importing singletons directly causes issues:
@@ -1026,6 +1223,72 @@ testApp.clear(); // Clear all cached instances
1026
1223
  testApp.dispose(); // Dispose container and all instances
1027
1224
  ```
1028
1225
 
1226
+ ### Parameterized Factories with `create()`
1227
+
1228
+ **The problem:** Some services need configuration at creation time (database connections, loggers with namespaces, API clients with different endpoints). But `get()` only works with parameterless factories since it caches instances.
1229
+
1230
+ **With Storion:** Use `create()` for parameterized factories. Unlike `get()`, `create()` always returns fresh instances and supports additional arguments.
1231
+
1232
+ ```ts
1233
+ import { store, container, type Resolver } from "storion";
1234
+
1235
+ // Parameterized factory - receives resolver + custom args
1236
+ function createLogger(resolver: Resolver, namespace: string) {
1237
+ return {
1238
+ info: (msg: string) => console.log(`[${namespace}] INFO: ${msg}`),
1239
+ error: (msg: string) => console.error(`[${namespace}] ERROR: ${msg}`),
1240
+ };
1241
+ }
1242
+
1243
+ function createDatabase(
1244
+ resolver: Resolver,
1245
+ config: { host: string; port: number }
1246
+ ) {
1247
+ return {
1248
+ query: (sql: string) =>
1249
+ fetch(`http://${config.host}:${config.port}/query`, {
1250
+ method: "POST",
1251
+ body: sql,
1252
+ }),
1253
+ close: () => {
1254
+ /* cleanup */
1255
+ },
1256
+ };
1257
+ }
1258
+
1259
+ // Use in store setup
1260
+ const userStore = store({
1261
+ name: "user",
1262
+ state: { users: [] as User[] },
1263
+ setup({ create }) {
1264
+ // Each call creates a fresh instance with specific config
1265
+ const logger = create(createLogger, "user-store");
1266
+ const db = create(createDatabase, { host: "localhost", port: 5432 });
1267
+
1268
+ return {
1269
+ fetchUsers: async () => {
1270
+ logger.info("Fetching users...");
1271
+ await db.query("SELECT * FROM users");
1272
+ },
1273
+ };
1274
+ },
1275
+ });
1276
+
1277
+ // Also works with container directly
1278
+ const app = container();
1279
+ const authLogger = app.create(createLogger, "auth");
1280
+ const adminDb = app.create(createDatabase, { host: "admin.db", port: 5433 });
1281
+ ```
1282
+
1283
+ **Key differences between `get()` and `create()`:**
1284
+
1285
+ | Feature | `get()` | `create()` |
1286
+ | ---------- | --------------------------- | --------------------------------------------- |
1287
+ | Caching | Yes (singleton per factory) | No (always fresh) |
1288
+ | Arguments | None (parameterless only) | Supports additional arguments |
1289
+ | Use case | Shared services | Configured instances, child stores |
1290
+ | Middleware | Applied | Applied (without args) / Bypassed (with args) |
1291
+
1029
1292
  ### Middleware
1030
1293
 
1031
1294
  **The problem:** You need cross-cutting behavior (logging, persistence, devtools) applied to some or all stores, without modifying each store individually.
@@ -1145,8 +1408,11 @@ const myStore = store({
1145
1408
  ```ts
1146
1409
  interface StoreContext<TState, TActions> {
1147
1410
  state: TState; // First-level props only (state.x = y)
1148
- get<T>(spec: StoreSpec<T>): StoreTuple; // Get dependency store
1149
- get<T>(factory: Factory<T>): T; // Get DI service
1411
+ get<T>(spec: StoreSpec<T>): StoreTuple; // Get dependency store (cached)
1412
+ get<T>(factory: Factory<T>): T; // Get DI service (cached)
1413
+ create<T>(spec: StoreSpec<T>): StoreInstance<T>; // Create child store (fresh)
1414
+ create<T>(factory: Factory<T>): T; // Create service (fresh)
1415
+ create<R, A>(factory: (r, ...a: A) => R, ...a: A): R; // Parameterized factory
1150
1416
  focus<P extends Path>(path: P): Focus; // Lens-like accessor
1151
1417
  update(fn: (draft: TState) => void): void; // For nested/array mutations
1152
1418
  dirty(prop?: keyof TState): boolean; // Check if state changed
@@ -1157,6 +1423,29 @@ interface StoreContext<TState, TActions> {
1157
1423
 
1158
1424
  > **Note:** `state` allows direct assignment only for first-level properties. Use `update()` for nested objects, arrays, or batch updates.
1159
1425
 
1426
+ **`get()` vs `create()` — When to use each:**
1427
+
1428
+ | Method | Caching | Use case |
1429
+ | ---------- | -------- | ------------------------------------------------------ |
1430
+ | `get()` | Cached | Shared dependencies, singleton services |
1431
+ | `create()` | No cache | Child stores, parameterized factories, fresh instances |
1432
+
1433
+ ```ts
1434
+ setup({ get, create }) {
1435
+ // get() - cached, same instance every time
1436
+ const api = get(apiService); // Singleton
1437
+
1438
+ // create() - fresh instance each call
1439
+ const childStore = create(childSpec); // New store instance
1440
+
1441
+ // create() with arguments - parameterized factory
1442
+ const db = create(createDatabase, { host: 'localhost', port: 5432 });
1443
+ const logger = create(createLogger, 'auth-store');
1444
+
1445
+ return { /* ... */ };
1446
+ }
1447
+ ```
1448
+
1160
1449
  ### React (`storion/react`)
1161
1450
 
1162
1451
  | Export | Description |
@@ -1171,10 +1460,13 @@ interface StoreContext<TState, TActions> {
1171
1460
  #### useStore Selector
1172
1461
 
1173
1462
  ```ts
1174
- // Selector receives context with get() for accessing stores
1175
- const result = useStore(({ get, mixin, once }) => {
1463
+ // Selector receives context with get(), create(), mixin(), once()
1464
+ const result = useStore(({ get, create, mixin, once }) => {
1176
1465
  const [state, actions] = get(myStore);
1177
- const service = get(myFactory);
1466
+ const service = get(myFactory); // Cached
1467
+
1468
+ // create() for parameterized factories (fresh instance each render)
1469
+ const logger = create(createLogger, "my-component");
1178
1470
 
1179
1471
  // Run once on mount
1180
1472
  once(() => actions.init());
@@ -1194,6 +1486,7 @@ const result = useStore(({ get, mixin, once }) => {
1194
1486
  | `async.all(...states)` | Wait for all states to be ready |
1195
1487
  | `async.any(...states)` | Get first ready state |
1196
1488
  | `async.race(states)` | Race between states |
1489
+ | `async.derive(focus, computeFn)` | Derive async state from other async states |
1197
1490
  | `async.hasData(state)` | Check if state has data |
1198
1491
  | `async.isLoading(state)` | Check if state is loading |
1199
1492
  | `async.isError(state)` | Check if state has error |
@@ -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":"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"}
1
+ {"version":3,"file":"async.d.ts","sourceRoot":"","sources":["../../src/async/async.ts"],"names":[],"mappings":"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"}
@@ -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,
@@ -1,3 +1,15 @@
1
+ export interface Collection<TKey, TValue> {
2
+ with(key: TKey, callback: (item: TValue) => void): this;
3
+ has(key: TKey): boolean;
4
+ get(key: TKey): TValue;
5
+ set(key: TKey, value: TValue): this;
6
+ size: number;
7
+ clear(): this;
8
+ delete(key: TKey): this;
9
+ keys(): IterableIterator<TKey>;
10
+ values(): IterableIterator<TValue>;
11
+ entries(): IterableIterator<[TKey, TValue]>;
12
+ }
1
13
  /**
2
14
  * Lazy-instantiation Map wrapper.
3
15
  *
@@ -18,25 +30,5 @@
18
30
  * @param initialItems - Optional initial entries
19
31
  * @returns A Map-like object with lazy instantiation on `get()`
20
32
  */
21
- export declare function collection<TKey, TValue>(createItem: (key: TKey) => TValue, initialItems?: readonly [TKey, TValue][]): {
22
- with(key: TKey, callback: (item: TValue) => void): /*elided*/ any;
23
- /** Check if key exists (does NOT create item) */
24
- has(key: TKey): boolean;
25
- /** Get item by key, creating it if it doesn't exist */
26
- get(key: TKey): NonNullable<TValue>;
27
- /** Explicitly set an item */
28
- set(key: TKey, value: TValue): /*elided*/ any;
29
- /** Number of items in the collection */
30
- readonly size: number;
31
- /** Remove all items */
32
- clear(): /*elided*/ any;
33
- /** Remove a specific item */
34
- delete(key: TKey): /*elided*/ any;
35
- /** Iterate over keys */
36
- keys(): MapIterator<TKey>;
37
- /** Iterate over values */
38
- values(): MapIterator<TValue>;
39
- /** Iterate over [key, value] pairs */
40
- entries(): MapIterator<[TKey, TValue]>;
41
- };
33
+ export declare function collection<TKey, TValue>(createItem: (key: TKey) => TValue, initialItems?: readonly [TKey, TValue][]): Collection<TKey, TValue>;
42
34
  //# sourceMappingURL=collection.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"collection.d.ts","sourceRoot":"","sources":["../src/collection.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,EACrC,UAAU,EAAE,CAAC,GAAG,EAAE,IAAI,KAAK,MAAM,EACjC,YAAY,CAAC,EAAE,SAAS,CAAC,IAAI,EAAE,MAAM,CAAC,EAAE;cAK5B,IAAI,YAAY,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI;IAOhD,iDAAiD;aACxC,IAAI;IAIb,uDAAuD;aAC9C,IAAI;IAOb,6BAA6B;aACpB,IAAI,SAAS,MAAM;IAK5B,wCAAwC;;IAKxC,uBAAuB;;IAMvB,6BAA6B;gBACjB,IAAI;IAKhB,wBAAwB;;IAKxB,0BAA0B;;IAK1B,sCAAsC;;EAKzC"}
1
+ {"version":3,"file":"collection.d.ts","sourceRoot":"","sources":["../src/collection.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,UAAU,CAAC,IAAI,EAAE,MAAM;IACtC,IAAI,CAAC,GAAG,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,GAAG,IAAI,CAAC;IACxD,GAAG,CAAC,GAAG,EAAE,IAAI,GAAG,OAAO,CAAC;IACxB,GAAG,CAAC,GAAG,EAAE,IAAI,GAAG,MAAM,CAAC;IACvB,GAAG,CAAC,GAAG,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACpC,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,IAAI,IAAI,CAAC;IACd,MAAM,CAAC,GAAG,EAAE,IAAI,GAAG,IAAI,CAAC;IACxB,IAAI,IAAI,gBAAgB,CAAC,IAAI,CAAC,CAAC;IAC/B,MAAM,IAAI,gBAAgB,CAAC,MAAM,CAAC,CAAC;IACnC,OAAO,IAAI,gBAAgB,CAAC,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC,CAAC;CAC7C;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,EACrC,UAAU,EAAE,CAAC,GAAG,EAAE,IAAI,KAAK,MAAM,EACjC,YAAY,CAAC,EAAE,SAAS,CAAC,IAAI,EAAE,MAAM,CAAC,EAAE,GACvC,UAAU,CAAC,IAAI,EAAE,MAAM,CAAC,CA8D1B"}
@@ -1 +1 @@
1
- {"version":3,"file":"container.d.ts","sourceRoot":"","sources":["../../src/core/container.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,EAML,KAAK,cAAc,EACnB,KAAK,gBAAgB,EACrB,KAAK,UAAU,EAEhB,MAAM,UAAU,CAAC;AAWlB,UAAU,uBAAuB;IAC/B,sDAAsD;IACtD,GAAG,CAAC,EAAE,UAAU,EAAE,CAAC;IACnB,qDAAqD;IACrD,IAAI,CAAC,EAAE,UAAU,EAAE,CAAC;CACrB;AAYD;;GAEG;AACH,UAAU,WAAW;IACnB,CAAC,OAAO,CAAC,EAAE,gBAAgB,GAAG,cAAc,CAAC;IAC7C;;OAEG;IACH,QAAQ,EAAE;QACR,CAAC,MAAM,CAAC,EAAE,uBAAuB,GAAG,IAAI,CAAC;QACzC,KAAK,IAAI,IAAI,CAAC;KACf,CAAC;CACH;AAED;;;;;;;GAOG;AACH,eAAO,MAAM,SAAS,EAAE,WAoLvB,CAAC"}
1
+ {"version":3,"file":"container.d.ts","sourceRoot":"","sources":["../../src/core/container.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,EAML,KAAK,cAAc,EACnB,KAAK,gBAAgB,EACrB,KAAK,UAAU,EAEhB,MAAM,UAAU,CAAC;AAYlB,UAAU,uBAAuB;IAC/B,sDAAsD;IACtD,GAAG,CAAC,EAAE,UAAU,EAAE,CAAC;IACnB,qDAAqD;IACrD,IAAI,CAAC,EAAE,UAAU,EAAE,CAAC;CACrB;AAYD;;GAEG;AACH,UAAU,WAAW;IACnB,CAAC,OAAO,CAAC,EAAE,gBAAgB,GAAG,cAAc,CAAC;IAC7C;;OAEG;IACH,QAAQ,EAAE;QACR,CAAC,MAAM,CAAC,EAAE,uBAAuB,GAAG,IAAI,CAAC;QACzC,KAAK,IAAI,IAAI,CAAC;KACf,CAAC;CACH;AAED;;;;;;;GAOG;AACH,eAAO,MAAM,SAAS,EAAE,WAkLvB,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"createResolver.d.ts","sourceRoot":"","sources":["../../src/core/createResolver.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AAEH,OAAO,KAAK,EACV,OAAO,EAEP,UAAU,EACV,QAAQ,EACR,eAAe,EAIhB,MAAM,UAAU,CAAC;AAIlB,YAAY,EACV,OAAO,EACP,UAAU,EACV,iBAAiB,EACjB,QAAQ,EACR,eAAe,GAChB,MAAM,UAAU,CAAC;AAmClB;;GAEG;AACH,wBAAgB,cAAc,CAAC,OAAO,GAAE,eAAoB,GAAG,QAAQ,CAkKtE;AAMD;;;;;;;;;;;;;GAaG;AACH,wBAAgB,IAAI,CAClB,SAAS,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,OAAO,EACxC,UAAU,EAAE,UAAU,GACrB,UAAU,CAOZ;AAED;;;;;;;;;GASG;AACH,wBAAgB,uBAAuB,CAAC,MAAM,SAAa,GAAG,UAAU,CAUvE;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,0BAA0B,CACxC,QAAQ,EAAE,CAAC,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,KAAK,IAAI,GACpD,UAAU,CAMZ"}
1
+ {"version":3,"file":"createResolver.d.ts","sourceRoot":"","sources":["../../src/core/createResolver.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AAEH,OAAO,KAAK,EACV,OAAO,EAEP,UAAU,EACV,QAAQ,EACR,eAAe,EAIhB,MAAM,UAAU,CAAC;AAKlB,YAAY,EACV,OAAO,EACP,UAAU,EACV,iBAAiB,EACjB,QAAQ,EACR,eAAe,GAChB,MAAM,UAAU,CAAC;AAmClB;;GAEG;AACH,wBAAgB,cAAc,CAAC,OAAO,GAAE,eAAoB,GAAG,QAAQ,CA6JtE;AAMD;;;;;;;;;;;;;GAaG;AACH,wBAAgB,IAAI,CAClB,SAAS,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,OAAO,EACxC,UAAU,EAAE,UAAU,GACrB,UAAU,CAOZ;AAED;;;;;;;;;GASG;AACH,wBAAgB,uBAAuB,CAAC,MAAM,SAAa,GAAG,UAAU,CAUvE;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,0BAA0B,CACxC,QAAQ,EAAE,CAAC,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,KAAK,IAAI,GACpD,UAAU,CAMZ"}
@@ -0,0 +1,18 @@
1
+ import { Disposable } from '../types';
2
+
3
+ /**
4
+ * Attempts to dispose a value if it has a `dispose` property.
5
+ *
6
+ * Supports multiple disposal patterns:
7
+ * - If `dispose` is a function, it will be called directly
8
+ * - If `dispose` is an array, each item will be processed:
9
+ * - Functions are called directly
10
+ * - Objects are recursively disposed via `tryDispose`
11
+ *
12
+ * @param value - The value to attempt disposal on. Can be any type;
13
+ * non-disposable values are safely ignored.
14
+ */
15
+ export declare function tryDispose(value: unknown): void;
16
+ export declare function isDisposable(value: unknown): value is Disposable;
17
+ export declare function willDispose(value: unknown): VoidFunction;
18
+ //# sourceMappingURL=disposable.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"disposable.d.ts","sourceRoot":"","sources":["../../src/core/disposable.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AAE3C;;;;;;;;;;;GAWG;AACH,wBAAgB,UAAU,CAAC,KAAK,EAAE,OAAO,QAoBxC;AAED,wBAAgB,YAAY,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,UAAU,CAMhE;AAED,wBAAgB,WAAW,CAAC,KAAK,EAAE,OAAO,GAAG,YAAY,CAExD"}
@@ -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.