- commit
- 380ad6c
- parent
- bfbb83c
- author
- Eric Bower
- date
- 2024-03-04 19:46:44 +0000 UTC
refactor: merge `starfx/store` into `starfx` (#43) I'm looking for ways to simplify the API in order to make this lib more ergonomic. DEPRECATED: `configureStore` is now `createStore` BREAKING CHANGE: removed `starfx/store`
M
deps.ts
+1,
-0
1@@ -34,6 +34,7 @@ export {
2 spawn,
3 suspend,
4 useAbortSignal,
5+ useScope,
6 } from "https://deno.land/x/effection@3.0.0-beta.3/mod.ts";
7
8 import React from "https://esm.sh/react@18.2.0?pin=v122";
+0,
-23
1@@ -4,26 +4,3 @@ description: Our API for public consumption
2 ---
3
4 WIP
5-
6-# query
7-
8-# fx
9-
10-## `parallel`
11-
12-This is `Promise.all` on steroids and doesn't cancel all other tasks when one
13-fails.
14-
15-It can wait for all tasks to complete, receive them in the order in which they
16-were created, or receive them in the order in which they were completed. They
17-are safe, meaning one task won't crash another one -- or the parent task.
18-
19-## `race`
20-
21-## `safe`
22-
23-# store
24-
25-# schema
26-
27-# react
+7,
-4
1@@ -8,11 +8,12 @@ a supervisor, it has a middleware stack, and it hijacks the unique id for our
2 thunks and turns it into a router.
3
4 ```ts
5-import { createApi, mdw } from "starfx";
6+import { createApi, createStore, mdw } from "starfx";
7+import { initialState, schema } from "./schema";
8
9 const api = createApi();
10 // composition of handy middleware for createApi to function
11-api.use(mdw.api());
12+api.use(mdw.api({ schema }));
13 api.use(api.routes());
14 // calls `window.fetch` with `ctx.request` and sets to `ctx.response`
15 api.use(mdw.fetch({ baseUrl: "https://jsonplaceholder.typicode.com" }));
16@@ -31,6 +32,9 @@ export const updateUser = api.post<{ id: string; name: string }>(
17 },
18 );
19
20+const store = createStore(initialState);
21+store.run(api.bootup);
22+
23 store.dispatch(fetchUsers());
24 // now accessible with useCache(fetchUsers)
25
26@@ -338,8 +342,7 @@ const [schema, initialState] = createSchema({
27 type WebState = typeof initialState;
28
29 const api = createApi();
30-api.use(mdw.api());
31-api.use(storeMdw.store(schema));
32+api.use(mdw.api({ schema }));
33 api.use(api.routes());
34
35 // do some request setup before making fetch call
+50,
-54
1@@ -5,29 +5,29 @@ description: Use starfx with deno, node, or the browser
2
3 # motivation
4
5-We've been sold a lie. You think you need a react framework or server-side
6-rendering because that's where money is being made. If you are building a
7-highly dynamic and interactive web application then you probably don't need
8-SSR. These frameworks sell you that they are an easier way to build web apps,
9-but that's not true. Just think of it this way: if you can build your web
10-app using only static assets, isn't that simpler than having static assets and a
11-react framework server?
12+We've been sold a lie. You think you need a react framework or server-side
13+rendering because that's where money is being made. If you are building a highly
14+dynamic and interactive web application then you probably don't need SSR. These
15+frameworks sell you that they are an easier way to build web apps, but that's
16+not true. Just think of it this way: if you can build your web app using only
17+static assets, isn't that simpler than having static assets and a react
18+framework server?
19
20 React hook-based fetching and caching libraries dramatically simplify data
21-synchronization but are so tightly coupled to a component's life cycle that
22-it creates waterfall fetches and loading spinners everywhere. You also have
23-the downside of not being able to normalize your cache which means you have to
24-spend time thinking about how and when to invalidate your various caches that
25-hold the same API entities.
26-
27-Further, all of these data caching libraries have sold you another lie. In
28-every library you are going to see a line similar to this: "Data normalization
29-is hard and it isn't worth it." Wrong. Their libraries are not built with
30-data normalization in mind so they claim it's an anti-feature. Why do we want
31-to normalize data in the backend but not the frontend? Data normalization is
32+synchronization but are so tightly coupled to a component's life cycle that it
33+creates waterfall fetches and loading spinners everywhere. You also have the
34+downside of not being able to normalize your cache which means you have to spend
35+time thinking about how and when to invalidate your various caches that hold the
36+identical API entities.
37+
38+Further, all of these data caching libraries have sold you another lie. In every
39+library you are going to see a line similar to this: "Data normalization is hard
40+and it isn't worth it." Wrong. Their libraries are not built with data
41+normalization in mind so they claim it's an anti-feature. Why do we want to
42+normalize data in the backend but not the frontend? Data normalization is
43 critically important because it makes CRUD operations automatically update your
44-web app without having to invalidate your cache so the app will refetch the
45-data you already have.
46+web app without having to invalidate your cache so the app will refetch the data
47+you already have.
48
49 So what if you are building a highly interactive web app that doesn't need SEO
50 and you also need more control over data synchronization and caching?
51@@ -42,12 +42,12 @@ Are you frustrated by the following issues in your react app?
52 - State management boilerplate
53 - Lack of async flow control tooling
54
55-We built `starfx` because we looked at the web app landscape and felt like
56-there was something missing.
57+We built `starfx` because we looked at the web app landscape and felt like there
58+was something missing.
59
60 Do you want a library that:
61
62-- Makes SPAs its only use case
63+- Design for single-page applications (SPAs)
64 - Has a powerful middleware system similar to express to handle requests and
65 responses
66 - Makes data normalization easy and straightforward
67@@ -57,8 +57,8 @@ Do you want a library that:
68
69 # when to use this library?
70
71-The primary target for this library are single-page apps (SPAs). This is for an
72-app that might be hosted inside an object store (like s3) or with a simple web
73+The primary target for this library are single-page apps. This is for an app
74+that might be hosted inside an object store (like s3) or with a simple web
75 server that serves files and that's it.
76
77 Is your app highly interactive, requiring it to persist data across pages? This
78@@ -74,55 +74,51 @@ minutes**, mimicking the basic features of `react-query`.
79 [Codesanbox](https://codesandbox.io/p/sandbox/starfx-simplest-dgqc9v?file=%2Fsrc%2Findex.tsx)
80
81 ```tsx
82-import ReactDOM from "react-dom/client";
83-import { createApi, mdw, timer } from "starfx";
84-import { configureStore, createSchema, slice, storeMdw } from "starfx/store";
85+import { createApi, createSchema, createStore, mdw, timer } from "starfx";
86 import { Provider, useCache } from "starfx/react";
87
88-const [schema, initialState] = createSchema({
89- loaders: slice.loaders(),
90- cache: slice.table(),
91-});
92+const [schema, initialState] = createSchema();
93+const store = createStore(initialState);
94
95 const api = createApi();
96-api.use(mdw.api());
97-api.use(storeMdw.store(schema));
98+// mdw = middleware
99+api.use(mdw.api({ schema }));
100 api.use(api.routes());
101-api.use(mdw.fetch({ baseUrl: "https://jsonplaceholder.typicode.com" }));
102+api.use(mdw.fetch({ baseUrl: "https://api.github.com" }));
103
104-const fetchUsers = api.get(
105- "/users",
106+const fetchRepo = api.get(
107+ "/repos/neurosnap/starfx",
108 { supervisor: timer() },
109 api.cache(),
110 );
111
112-const store = configureStore(initialState);
113-type WebState = typeof initialState;
114-
115 store.run(api.bootup);
116
117 function App() {
118- const { isLoading, data: users } = useCache(fetchUsers());
119+ return (
120+ <Provider schema={schema} store={store}>
121+ <App />
122+ </Provider>
123+ );
124+}
125
126- if (isLoading) {
127- return <div>Loading ...</div>;
128- }
129+function Example() {
130+ const { isLoading, isError, message, data = [] } = useCache(fetchRepo());
131+
132+ if (isLoading) return "Loading ...";
133+
134+ if (isError) return `An error has occurred: ${message}`;
135
136 return (
137 <div>
138- {users?.map(
139- (user) => <div key={user.id}>{user.name}</div>,
140- )}
141+ <h1>{data.name}</h1>
142+ <p>{data.description}</p>
143+ <strong>👀 {data.subscribers_count}</strong>{" "}
144+ <strong>✨ {data.stargazers_count}</strong>{" "}
145+ <strong>🍴 {data.forks_count}</strong>
146 </div>
147 );
148 }
149-
150-const root = document.getElementById("root") as HTMLElement;
151-ReactDOM.createRoot(root).render(
152- <Provider schema={schema} store={store}>
153- <App />
154- </Provider>,
155-);
156 ```
157
158 # install
+5,
-6
1@@ -18,12 +18,11 @@ For example, the recommended mdw stack for `createApi()` looks like this:
2
3 ```ts
4 import { createApi, mdw } from "starfx";
5-import { storeMdw } from "starfx/store";
6+import { schema } from "./schema";
7
8 // this api:
9 const api = createApi();
10-api.use(mdw.api());
11-api.use(storeMdw.store());
12+api.use(mdw.api({ schema }));
13 api.use(api.routes());
14 api.use(mdw.fetch({ baseUrl: "https://api.com" }));
15
16@@ -33,9 +32,9 @@ api.use(mdw.fetch({ baseUrl: "https://api.com" }));
17 mdw.queryCtx,
18 mdw.customKey,
19 mdw.nameParser,
20- storeMdw.actions,
21- storeMdw.loaderApi(),
22- storeMdw.cache(props.cache),
23+ mdw.actions,
24+ mdw.loaderApi({ schema }),
25+ mdw.cache({ schema }),
26 api.routes(),
27 mdw.composeUrl("https://api.com"),
28 mdw.payload,
+3,
-3
1@@ -39,7 +39,7 @@ This gets us closer to treating our store like a traditional database while
2 still being flexible for our needs on the FE.
3
4 ```ts
5-import { configureStore, createSchema, select, slice } from "starfx/store";
6+import { createSchema, createStore, select, slice } from "starfx";
7
8 interface User {
9 id: string;
10@@ -96,7 +96,7 @@ There are **three** ways to update state, each with varying degrees of type
11 safety:
12
13 ```ts
14-import { updateStore } from "starfx/store";
15+import { updateStore } from "starfx";
16
17 function*() {
18 // good types
19@@ -127,7 +127,7 @@ However, it is very easy to create a controller to do simple tasks like updating
20 state:
21
22 ```ts
23-import type { StoreUpdater } from "starfx/store";
24+import type { StoreUpdater } from "starfx";
25
26 const updater = thunks.create<StoreUpdater[]>("update", function* (ctx, next) {
27 yield* updateStore(ctx.payload);
R query/fetch.ts =>
mdw/fetch.ts
+2,
-2
1@@ -1,7 +1,7 @@
2 import { sleep } from "../deps.ts";
3 import { safe } from "../fx/mod.ts";
4-import type { FetchCtx, FetchJsonCtx } from "./types.ts";
5-import { isObject, noop } from "./util.ts";
6+import type { FetchCtx, FetchJsonCtx } from "../query/mod.ts";
7+import { isObject, noop } from "../query/util.ts";
8 import type { Next } from "../types.ts";
9
10 /**
+4,
-0
1@@ -0,0 +1,4 @@
2+import * as queryMdw from "./query.ts";
3+import * as storeMdw from "./store.ts";
4+
5+export const mdw = { ...queryMdw, ...storeMdw };
R query/mdw.ts =>
mdw/query.ts
+6,
-20
1@@ -8,9 +8,9 @@ import type {
2 PerfCtx,
3 RequiredApiRequest,
4 ThunkCtx,
5-} from "./types.ts";
6+} from "../query/types.ts";
7 import type { AnyAction, Next } from "../types.ts";
8-import { mergeRequest } from "./util.ts";
9+import { mergeRequest } from "../query/util.ts";
10 import * as fetchMdw from "./fetch.ts";
11 import { call, Callable } from "../deps.ts";
12 import { put } from "../action.ts";
13@@ -33,11 +33,13 @@ export function* err<Ctx extends ThunkCtx = ThunkCtx>(
14 ) {
15 ctx.result = yield* safe(next);
16 if (!ctx.result.ok) {
17+ const message =
18+ `Error: ${ctx.result.error.message}. Check the endpoint [${ctx.name}]`;
19+ console.error(message, ctx);
20 yield* put({
21 type: "error:query",
22 payload: {
23- message:
24- `Error: ${ctx.result.error.message}. Check the endpoint [${ctx.name}]`,
25+ message,
26 ctx,
27 },
28 });
29@@ -108,22 +110,6 @@ export function* actions(ctx: { actions: AnyAction[] }, next: Next) {
30 yield* put(ctx.actions);
31 }
32
33-/**
34- * This middleware is a composition of many middleware used to faciliate
35- * the {@link createApi}.
36- *
37- * It is not required, however, it is battle-tested and highly recommended.
38- */
39-export function api<Ctx extends ApiCtx = ApiCtx>() {
40- return compose<Ctx>([
41- err,
42- actions,
43- queryCtx,
44- customKey,
45- fetchMdw.nameParser,
46- ]);
47-}
48-
49 /**
50 * This middleware will add `performance.now()` before and after your
51 * middleware pipeline.
R store/mdw.ts =>
mdw/store.ts
+71,
-47
1@@ -1,21 +1,43 @@
2 import type { ApiCtx, ThunkCtx } from "../query/mod.ts";
3 import { compose } from "../compose.ts";
4 import type { AnyState, Next } from "../types.ts";
5-import { select, updateStore } from "./fx.ts";
6-import { LoaderOutput } from "./slice/loaders.ts";
7-import { TableOutput } from "./slice/table.ts";
8+import {
9+ LoaderOutput,
10+ select,
11+ TableOutput,
12+ updateStore,
13+} from "../store/mod.ts";
14+import { actions, customKey, err, queryCtx } from "./query.ts";
15+import { nameParser } from "./fetch.ts";
16
17-export function store<
18+interface ApiMdwProps<
19 Ctx extends ApiCtx = ApiCtx,
20 M extends AnyState = AnyState,
21->(props: {
22- loaders: LoaderOutput<M, AnyState>;
23- cache: TableOutput<any, AnyState>;
24+> {
25+ schema: {
26+ loaders: LoaderOutput<M, AnyState>;
27+ cache: TableOutput<any, AnyState>;
28+ };
29 errorFn?: (ctx: Ctx) => string;
30-}) {
31+}
32+
33+/**
34+ * This middleware is a composition of many middleware used to faciliate
35+ * the {@link createApi}.
36+ *
37+ * It is not required, however, it is battle-tested and highly recommended.
38+ */
39+export function api<Ctx extends ApiCtx = ApiCtx, S extends AnyState = AnyState>(
40+ props: ApiMdwProps<Ctx, S>,
41+) {
42 return compose<Ctx>([
43- loaderApi(props.loaders, props.errorFn),
44- cache(props.cache),
45+ err,
46+ actions,
47+ queryCtx,
48+ customKey,
49+ nameParser,
50+ loaderApi(props),
51+ cache(props.schema),
52 ]);
53 }
54
55@@ -23,14 +45,16 @@ export function store<
56 * This middleware will automatically cache any data found inside `ctx.json`
57 * which is where we store JSON data from the {@link mdw.fetch} middleware.
58 */
59-export function cache<Ctx extends ApiCtx = ApiCtx>(
60- dataSchema: TableOutput<any, AnyState>,
61-) {
62- return function* (
63+export function cache<
64+ Ctx extends ApiCtx = ApiCtx,
65+>(schema: {
66+ cache: TableOutput<any, AnyState>;
67+}) {
68+ return function* cache(
69 ctx: Ctx,
70 next: Next,
71 ) {
72- ctx.cacheData = yield* select(dataSchema.selectById, { id: ctx.key });
73+ ctx.cacheData = yield* select(schema.cache.selectById, { id: ctx.key });
74 yield* next();
75 if (!ctx.cache) return;
76 let data;
77@@ -39,7 +63,7 @@ export function cache<Ctx extends ApiCtx = ApiCtx>(
78 } else {
79 data = ctx.json.error;
80 }
81- yield* updateStore(dataSchema.add({ [ctx.key]: data }));
82+ yield* updateStore(schema.cache.add({ [ctx.key]: data }));
83 ctx.cacheData = data;
84 };
85 }
86@@ -47,66 +71,66 @@ export function cache<Ctx extends ApiCtx = ApiCtx>(
87 /**
88 * This middleware will track the status of a middleware fn
89 */
90-export function loader<
91- Ctx extends ThunkCtx = ThunkCtx,
92- M extends AnyState = AnyState,
93->(
94- loaderSchema: LoaderOutput<M, AnyState>,
95-) {
96- return function* (ctx: Ctx, next: Next) {
97+export function loader<M extends AnyState = AnyState>(schema: {
98+ loaders: LoaderOutput<M, AnyState>;
99+}) {
100+ return function* <
101+ Ctx extends ThunkCtx = ThunkCtx,
102+ >(ctx: Ctx, next: Next) {
103 yield* updateStore([
104- loaderSchema.start({ id: ctx.name }),
105- loaderSchema.start({ id: ctx.key }),
106+ schema.loaders.start({ id: ctx.name }),
107+ schema.loaders.start({ id: ctx.key }),
108 ]);
109
110 try {
111 yield* next();
112 yield* updateStore([
113- loaderSchema.success({ id: ctx.name }),
114- loaderSchema.success({ id: ctx.key }),
115+ schema.loaders.success({ id: ctx.name }),
116+ schema.loaders.success({ id: ctx.key }),
117 ]);
118 } catch (err) {
119 yield* updateStore([
120- loaderSchema.error({
121+ schema.loaders.error({
122 id: ctx.name,
123 message: err.message,
124 }),
125- loaderSchema.error({
126+ schema.loaders.error({
127 id: ctx.key,
128 message: err.message,
129 }),
130 ]);
131 } finally {
132 const loaders = yield* select((s: any) =>
133- loaderSchema.selectByIds(s, { ids: [ctx.name, ctx.key] })
134+ schema.loaders.selectByIds(s, { ids: [ctx.name, ctx.key] })
135 );
136 const ids = loaders
137 .filter((loader) => loader.status === "loading")
138 .map((loader) => loader.id);
139- yield* updateStore(loaderSchema.resetByIds(ids));
140+ yield* updateStore(schema.loaders.resetByIds(ids));
141 }
142 };
143 }
144
145+function defaultErrorFn<Ctx extends ApiCtx = ApiCtx>(ctx: Ctx) {
146+ const jso = ctx.json;
147+ if (jso.ok) return "";
148+ return jso.error?.message || "";
149+}
150+
151 /**
152 * This middleware will track the status of a fetch request.
153 */
154 export function loaderApi<
155 Ctx extends ApiCtx = ApiCtx,
156- M extends AnyState = AnyState,
157+ S extends AnyState = AnyState,
158 >(
159- loaderSchema: LoaderOutput<M, AnyState>,
160- errorFn: (ctx: Ctx) => string = (ctx) => {
161- const jso = ctx.json;
162- if (jso.ok) return "";
163- return jso.error?.message || "";
164- },
165+ { schema, errorFn = defaultErrorFn }: ApiMdwProps<Ctx, S>,
166 ) {
167 return function* trackLoading(ctx: Ctx, next: Next) {
168 try {
169 yield* updateStore([
170- loaderSchema.start({ id: ctx.name }),
171- loaderSchema.start({ id: ctx.key }),
172+ schema.loaders.start({ id: ctx.name }),
173+ schema.loaders.start({ id: ctx.key }),
174 ]);
175 if (!ctx.loader) ctx.loader = {} as any;
176
177@@ -114,7 +138,7 @@ export function loaderApi<
178
179 if (!ctx.response) {
180 yield* updateStore(
181- loaderSchema.resetByIds([ctx.name, ctx.key]),
182+ schema.loaders.resetByIds([ctx.name, ctx.key]),
183 );
184 return;
185 }
186@@ -125,12 +149,12 @@ export function loaderApi<
187
188 if (!ctx.response.ok) {
189 yield* updateStore([
190- loaderSchema.error({
191+ schema.loaders.error({
192 id: ctx.name,
193 message: errorFn(ctx),
194 ...ctx.loader,
195 }),
196- loaderSchema.error({
197+ schema.loaders.error({
198 id: ctx.key,
199 message: errorFn(ctx),
200 ...ctx.loader,
201@@ -140,17 +164,17 @@ export function loaderApi<
202 }
203
204 yield* updateStore([
205- loaderSchema.success({ id: ctx.name, ...ctx.loader }),
206- loaderSchema.success({ id: ctx.key, ...ctx.loader }),
207+ schema.loaders.success({ id: ctx.name, ...ctx.loader }),
208+ schema.loaders.success({ id: ctx.key, ...ctx.loader }),
209 ]);
210 } finally {
211 const loaders = yield* select((s: any) =>
212- loaderSchema.selectByIds(s, { ids: [ctx.name, ctx.key] })
213+ schema.loaders.selectByIds(s, { ids: [ctx.name, ctx.key] })
214 );
215 const ids = loaders
216 .filter((loader) => loader.status === "loading")
217 .map((loader) => loader.id);
218- yield* updateStore(loaderSchema.resetByIds(ids));
219+ yield* updateStore(schema.loaders.resetByIds(ids));
220 }
221 };
222 }
M
mod.ts
+3,
-0
1@@ -1,5 +1,8 @@
2 export * from "./fx/mod.ts";
3 export * from "./query/mod.ts";
4+export * from "./store/mod.ts";
5+export * from "./mdw/mod.ts";
6+
7 export * from "./types.ts";
8 export * from "./compose.ts";
9 export * from "./action.ts";
M
npm.ts
+0,
-4
1@@ -21,10 +21,6 @@ async function init() {
2 name: "./react",
3 path: "react.ts",
4 },
5- {
6- name: "./store",
7- path: "./store/mod.ts",
8- },
9 ],
10 mappings: {
11 "https://deno.land/x/effection@3.0.0-beta.3/mod.ts": {
+1,
-26
1@@ -1,37 +1,12 @@
2 import { createThunks, type ThunksApi } from "./thunk.ts";
3-import * as mdw from "./mdw.ts";
4
5 export * from "./api.ts";
6 export * from "./types.ts";
7 export * from "./create-key.ts";
8
9-export { createThunks, mdw, ThunksApi };
10+export { createThunks, ThunksApi };
11
12 /**
13 * @deprecated Use {@link createThunks} instead;
14 */
15 export const createPipe = createThunks;
16-/**
17- * @deprecated Use {@link mdw.err} instead;
18- */
19-export const errorHandler = mdw.err;
20-/**
21- * @deprecated Use {@link mdw.query} instead;
22- */
23-export const queryCtx = mdw.queryCtx;
24-/**
25- * @deprecated Use {@link fetchMdw.composeUrl} instead;
26- */
27-export const urlParser = mdw.composeUrl;
28-/**
29- * @deprecated Use {@link mdw.customKey} instead;
30- */
31-export const customKey = mdw.customKey;
32-/**
33- * @deprecated Use {@link mdw.api} instead;
34- */
35-export const requestMonitor = mdw.api;
36-/**
37- * @deprecated Use {@link mdw.fetch} instead;
38- */
39-export const fetcher = mdw.fetch;
+0,
-1
1@@ -6,5 +6,4 @@ export const StoreUpdateContext = createContext<Channel<void, void>>(
2 "starfx:store:update",
3 createChannel<void, void>(),
4 );
5-
6 export const StoreContext = createContext<FxStore<AnyState>>("starfx:store");
+0,
-2
1@@ -7,5 +7,3 @@ export * from "./slice/mod.ts";
2 export * from "./schema.ts";
3 export * from "./batch.ts";
4 export * from "./persist.ts";
5-import * as storeMdw from "./mdw.ts";
6-export { storeMdw };
+21,
-0
1@@ -0,0 +1,21 @@
2+import { Callable, Operation, Result, Scope, Task } from "../deps.ts";
3+import { parallel, safe } from "../fx/mod.ts";
4+
5+export function createRun(scope: Scope) {
6+ function run<T>(op: Callable<T>[]): Task<Result<T>[]>;
7+ function run<T>(op: Callable<T>): Task<Result<T>>;
8+ function run<T>(
9+ op: Callable<T> | Callable<T>[],
10+ ): Task<Result<T> | Result<T>[]> {
11+ if (Array.isArray(op)) {
12+ return scope.run(function* (): Operation<Result<T>[]> {
13+ const group = yield* parallel(op);
14+ const result = yield* group;
15+ return result;
16+ });
17+ }
18+ return scope.run(() => safe(op));
19+ }
20+
21+ return run;
22+}
+6,
-1
1@@ -1,11 +1,16 @@
2 import { updateStore } from "./fx.ts";
3+import { slice } from "./slice/mod.ts";
4 import { FxMap, FxSchema, StoreUpdater } from "./types.ts";
5
6+const defaultSchema = function <O>(): O {
7+ return { cache: slice.table(), loaders: slice.loaders() } as O;
8+};
9+
10 export function createSchema<
11 O extends FxMap,
12 S extends { [key in keyof O]: ReturnType<O[key]>["initialState"] },
13 >(
14- slices: O,
15+ slices: O = defaultSchema<O>(),
16 ): [FxSchema<S, O>, S] {
17 const db = Object.keys(slices).reduce<FxSchema<S, O>>((acc, key) => {
18 // deno-lint-ignore no-explicit-any
+8,
-15
1@@ -1,21 +1,18 @@
2 import {
3- Callable,
4 createScope,
5 createSignal,
6 enablePatches,
7 Ok,
8 produceWithPatches,
9- Result,
10 Scope,
11- Task,
12 } from "../deps.ts";
13 import { BaseMiddleware, compose } from "../compose.ts";
14 import type { AnyAction, AnyState, Next } from "../types.ts";
15-import { safe } from "../fx/mod.ts";
16 import type { FxStore, Listener, StoreUpdater, UpdaterCtx } from "./types.ts";
17 import { StoreContext, StoreUpdateContext } from "./context.ts";
18 import { ActionContext, emit } from "../action.ts";
19 import { API_ACTION_PREFIX } from "../action.ts";
20+import { createRun } from "./run.ts";
21
22 const stubMsg = "This is merely a stub, not implemented";
23
24@@ -147,10 +144,6 @@ export function createStore<S extends AnyState>({
25 emit({ signal, action });
26 }
27
28- function run<T>(op: Callable<T>): Task<Result<T>> {
29- return scope.run(() => safe(op));
30- }
31-
32 function getInitialState() {
33 return initialState;
34 }
35@@ -168,13 +161,13 @@ export function createStore<S extends AnyState>({
36 });
37 }
38
39- return {
40+ const store = {
41 getScope,
42 getState,
43 subscribe,
44 update,
45 reset,
46- run,
47+ run: createRun(scope),
48 // instead of actions relating to store mutation, they
49 // refer to pieces of business logic -- that can also mutate state
50 dispatch,
51@@ -188,13 +181,13 @@ export function createStore<S extends AnyState>({
52 getInitialState,
53 [Symbol.observable]: observable,
54 };
55-}
56
57-export function configureStore<S extends AnyState>(
58- props: CreateStore<S>,
59-): FxStore<S> {
60- const store = createStore<S>(props);
61 // deno-lint-ignore no-explicit-any
62 store.getScope().set(StoreContext, store as any);
63 return store;
64 }
65+
66+/**
67+ * @deprecated use {@link createStore}
68+ */
69+export const configureStore = createStore;
+3,
-9
1@@ -1,15 +1,9 @@
2 import type { LoaderOutput } from "./slice/loaders.ts";
3 import type { TableOutput } from "./slice/table.ts";
4-import type {
5- Callable,
6- Operation,
7- Patch,
8- Result,
9- Scope,
10- Task,
11-} from "../deps.ts";
12+import type { Operation, Patch, Scope } from "../deps.ts";
13 import { BaseCtx } from "../mod.ts";
14 import type { AnyAction, AnyState } from "../types.ts";
15+import { createRun } from "./run.ts";
16
17 export type StoreUpdater<S extends AnyState> = (s: S) => S | void;
18
19@@ -54,7 +48,7 @@ export interface FxStore<S extends AnyState> {
20 subscribe: (fn: Listener) => () => void;
21 update: (u: StoreUpdater<S> | StoreUpdater<S>[]) => Operation<UpdaterCtx<S>>;
22 reset: (ignoreList?: (keyof S)[]) => Operation<UpdaterCtx<S>>;
23- run: <T>(op: Callable<T>) => Task<Result<T>>;
24+ run: ReturnType<typeof createRun>;
25 // deno-lint-ignore no-explicit-any
26 dispatch: (a: AnyAction) => any;
27 replaceReducer: (r: (s: S, a: AnyAction) => S) => void;
+14,
-18
1@@ -1,10 +1,9 @@
2 import { describe, expect, it } from "../test.ts";
3 import {
4- configureStore,
5 createSchema,
6+ createStore,
7 select,
8 slice,
9- storeMdw,
10 updateStore,
11 waitForLoader,
12 } from "../store/mod.ts";
13@@ -38,7 +37,7 @@ const testStore = () => {
14 loaders: slice.loaders(),
15 cache: slice.table({ empty: {} }),
16 });
17- const store = configureStore({ initialState });
18+ const store = createStore({ initialState });
19 return { schema, store };
20 };
21
22@@ -101,7 +100,7 @@ it(tests, "POST", async () => {
23 },
24 );
25
26- const store = configureStore({ initialState: { users: {} } });
27+ const store = createStore({ initialState: { users: {} } });
28 store.run(query.bootup);
29
30 store.dispatch(createUser({ email: mockUser.email }));
31@@ -158,7 +157,7 @@ it(tests, "POST with uri", () => {
32 },
33 );
34
35- const store = configureStore({ initialState: { users: {} } });
36+ const store = createStore({ initialState: { users: {} } });
37 store.run(query.bootup);
38 store.dispatch(createUser({ email: mockUser.email }));
39 });
40@@ -178,7 +177,7 @@ it(tests, "middleware - with request fn", () => {
41 { supervisor: takeEvery },
42 query.request({ method: "POST" }),
43 );
44- const store = configureStore({ initialState: { users: {} } });
45+ const store = createStore({ initialState: { users: {} } });
46 store.run(query.bootup);
47 store.dispatch(createUser());
48 });
49@@ -206,7 +205,7 @@ it(tests, "run() on endpoint action - should run the effect", () => {
50 },
51 );
52
53- const store = configureStore({ initialState: { users: {} } });
54+ const store = createStore({ initialState: { users: {} } });
55 store.run(api.bootup);
56 store.dispatch(action2());
57 });
58@@ -240,7 +239,7 @@ it(tests, "run() from a normal saga", () => {
59 yield* takeEvery(`${action2}`, onAction);
60 }
61
62- const store = configureStore({ initialState: { users: {} } });
63+ const store = createStore({ initialState: { users: {} } });
64 store.run(() => keepAlive([api.bootup, watchAction]));
65 store.dispatch(action2());
66 });
67@@ -248,8 +247,7 @@ it(tests, "run() from a normal saga", () => {
68 it(tests, "with hash key on a large post", async () => {
69 const { store, schema } = testStore();
70 const query = createApi();
71- query.use(mdw.api());
72- query.use(storeMdw.store(schema));
73+ query.use(mdw.api({ schema }));
74 query.use(query.routes());
75 query.use(function* fetchApi(ctx, next) {
76 const data = {
77@@ -318,8 +316,7 @@ it(tests, "two identical endpoints", () => {
78 const actual: string[] = [];
79 const { store, schema } = testStore();
80 const api = createApi();
81- api.use(mdw.api());
82- api.use(storeMdw.store(schema));
83+ api.use(mdw.api({ schema }));
84 api.use(api.routes());
85
86 const first = api.get(
87@@ -375,7 +372,7 @@ it(tests, "ensure types for get() endpoint", () => {
88 },
89 );
90
91- const store = configureStore({ initialState: { users: {} } });
92+ const store = createStore({ initialState: { users: {} } });
93 store.run(api.bootup);
94
95 store.dispatch(action1({ id: "1" }));
96@@ -413,7 +410,7 @@ it(tests, "ensure ability to cast `ctx` in function definition", () => {
97 },
98 );
99
100- const store = configureStore({ initialState: { users: {} } });
101+ const store = createStore({ initialState: { users: {} } });
102 store.run(api.bootup);
103 store.dispatch(action1({ id: "1" }));
104 expect(acc).toEqual(["1", "wow"]);
105@@ -449,7 +446,7 @@ it(
106 },
107 );
108
109- const store = configureStore({ initialState: { users: {} } });
110+ const store = createStore({ initialState: { users: {} } });
111 store.run(api.bootup);
112 store.dispatch(action1());
113 expect(acc).toEqual(["wow"]);
114@@ -458,7 +455,7 @@ it(
115
116 it(tests, "should bubble up error", () => {
117 let error: any = null;
118- const { store, schema } = testStore();
119+ const { store } = testStore();
120 const api = createApi();
121 api.use(function* (_, next) {
122 try {
123@@ -468,7 +465,6 @@ it(tests, "should bubble up error", () => {
124 }
125 });
126 api.use(mdw.queryCtx);
127- api.use(storeMdw.store(schema));
128 api.use(api.routes());
129
130 const fetchUser = api.get(
131@@ -518,7 +514,7 @@ it(
132 },
133 );
134
135- const store = configureStore({ initialState: { users: {} } });
136+ const store = createStore({ initialState: { users: {} } });
137 store.run(api.bootup);
138
139 function _App() {
+2,
-2
1@@ -1,8 +1,8 @@
2 import { describe, expect, it } from "../test.ts";
3 import {
4- configureStore,
5 createBatchMdw,
6 createSchema,
7+ createStore,
8 slice,
9 } from "../store/mod.ts";
10 import { parallel } from "../mod.ts";
11@@ -14,7 +14,7 @@ it(batch, "should batch notify subscribers based on mdw", async () => {
12 cache: slice.table({ empty: {} }),
13 loaders: slice.loaders(),
14 });
15- const store = configureStore({
16+ const store = createStore({
17 initialState,
18 middleware: [createBatchMdw(queueMicrotask)],
19 });
R test/configureStore.test.ts =>
test/create-store.test.ts
+4,
-4
1@@ -1,8 +1,8 @@
2 import { describe, expect, it } from "../test.ts";
3-import { configureStore, select } from "../store/mod.ts";
4+import { createStore, select } from "../store/mod.ts";
5 import { call } from "../mod.ts";
6
7-const tests = describe("configureStore()");
8+const tests = describe("createStore()");
9
10 interface TestState {
11 user: { id: string };
12@@ -10,7 +10,7 @@ interface TestState {
13
14 it(tests, "should be able to grab values from store", async () => {
15 let actual;
16- const store = configureStore({ initialState: { user: { id: "1" } } });
17+ const store = createStore({ initialState: { user: { id: "1" } } });
18 await store.run(function* () {
19 actual = yield* select((s: TestState) => s.user);
20 });
21@@ -19,7 +19,7 @@ it(tests, "should be able to grab values from store", async () => {
22
23 it(tests, "should be able to grab store from a nested call", async () => {
24 let actual;
25- const store = configureStore({ initialState: { user: { id: "2" } } });
26+ const store = createStore({ initialState: { user: { id: "2" } } });
27 await store.run(function* () {
28 actual = yield* call(function* () {
29 return yield* select((s: TestState) => s.user);
+14,
-27
1@@ -1,9 +1,8 @@
2 import { describe, expect, install, it, mock } from "../test.ts";
3 import {
4- configureStore,
5 createSchema,
6+ createStore,
7 slice,
8- storeMdw,
9 waitForLoader,
10 waitForLoaders,
11 } from "../store/mod.ts";
12@@ -19,7 +18,7 @@ const testStore = () => {
13 loaders: slice.loaders(),
14 cache: slice.table({ empty: {} }),
15 });
16- const store = configureStore({ initialState });
17+ const store = createStore({ initialState });
18 return { schema, store };
19 };
20
21@@ -39,8 +38,7 @@ it(
22
23 const { store, schema } = testStore();
24 const api = createApi();
25- api.use(mdw.api());
26- api.use(storeMdw.store(schema));
27+ api.use(mdw.api({ schema }));
28 api.use(api.routes());
29 api.use(mdw.headers);
30 api.use(mdw.fetch({ baseUrl }));
31@@ -87,8 +85,7 @@ it(
32
33 const { store, schema } = testStore();
34 const api = createApi();
35- api.use(mdw.api());
36- api.use(storeMdw.store(schema));
37+ api.use(mdw.api({ schema }));
38 api.use(api.routes());
39 api.use(mdw.fetch({ baseUrl }));
40
41@@ -124,8 +121,7 @@ it(tests, "error handling", async () => {
42
43 const { schema, store } = testStore();
44 const api = createApi();
45- api.use(mdw.api());
46- api.use(storeMdw.store(schema));
47+ api.use(mdw.api({ schema }));
48 api.use(api.routes());
49 api.use(mdw.fetch({ baseUrl }));
50
51@@ -160,8 +156,7 @@ it(tests, "status 204", async () => {
52
53 const { schema, store } = testStore();
54 const api = createApi();
55- api.use(mdw.api());
56- api.use(storeMdw.store(schema));
57+ api.use(mdw.api({ schema }));
58 api.use(api.routes());
59 api.use(function* (ctx, next) {
60 const url = ctx.req().url;
61@@ -200,8 +195,7 @@ it(tests, "malformed json", async () => {
62
63 const { schema, store } = testStore();
64 const api = createApi();
65- api.use(mdw.api());
66- api.use(storeMdw.store(schema));
67+ api.use(mdw.api({ schema }));
68 api.use(api.routes());
69 api.use(function* (ctx, next) {
70 const url = ctx.req().url;
71@@ -245,8 +239,7 @@ it(tests, "POST", async () => {
72
73 const { schema, store } = testStore();
74 const api = createApi();
75- api.use(mdw.api());
76- api.use(storeMdw.store(schema));
77+ api.use(mdw.api({ schema }));
78 api.use(api.routes());
79 api.use(mdw.headers);
80 api.use(mdw.fetch({ baseUrl }));
81@@ -297,8 +290,7 @@ it(tests, "POST multiple endpoints with same uri", async () => {
82
83 const { store, schema } = testStore();
84 const api = createApi();
85- api.use(mdw.api());
86- api.use(storeMdw.store(schema));
87+ api.use(mdw.api({ schema }));
88 api.use(api.routes());
89 api.use(mdw.headers);
90 api.use(mdw.fetch({ baseUrl }));
91@@ -385,8 +377,7 @@ it(
92 () => {
93 const { store, schema } = testStore();
94 const api = createApi();
95- api.use(mdw.api());
96- api.use(storeMdw.store(schema));
97+ api.use(mdw.api({ schema }));
98 api.use(api.routes());
99 api.use(mdw.fetch({ baseUrl }));
100 let actual = "";
101@@ -432,8 +423,7 @@ it(
102
103 const { schema, store } = testStore();
104 const api = createApi();
105- api.use(mdw.api());
106- api.use(storeMdw.store(schema));
107+ api.use(mdw.api({ schema }));
108 api.use(api.routes());
109 api.use(mdw.fetch({ baseUrl }));
110
111@@ -481,8 +471,7 @@ it(
112 const { schema, store } = testStore();
113 let actual = null;
114 const api = createApi();
115- api.use(mdw.api());
116- api.use(storeMdw.store(schema));
117+ api.use(mdw.api({ schema }));
118 api.use(api.routes());
119 api.use(mdw.fetch({ baseUrl }));
120
121@@ -515,8 +504,7 @@ it(
122 const { schema, store } = testStore();
123 let actual = null;
124 const api = createApi();
125- api.use(mdw.api());
126- api.use(storeMdw.store(schema));
127+ api.use(mdw.api({ schema }));
128 api.use(api.routes());
129 api.use(mdw.fetch({ baseUrl }));
130
131@@ -543,8 +531,7 @@ it(tests, "should use dynamic mdw to mock response", async () => {
132 const { schema, store } = testStore();
133 let actual = null;
134 const api = createApi();
135- api.use(mdw.api());
136- api.use(storeMdw.store(schema));
137+ api.use(mdw.api({ schema }));
138 api.use(api.routes());
139 api.use(mdw.fetch({ baseUrl }));
140
+17,
-27
1@@ -1,9 +1,8 @@
2 import { assertLike, asserts, describe, expect, it } from "../test.ts";
3 import {
4- configureStore,
5 createSchema,
6+ createStore,
7 slice,
8- storeMdw,
9 updateStore,
10 waitForLoader,
11 } from "../store/mod.ts";
12@@ -40,17 +39,16 @@ const testStore = () => {
13 loaders: slice.loaders(),
14 cache: slice.table({ empty: {} }),
15 });
16- const store = configureStore({ initialState });
17+ const store = createStore({ initialState });
18 return { schema, store };
19 };
20
21 const tests = describe("middleware");
22
23 it(tests, "basic", () => {
24- const { store } = testStore();
25+ const { store, schema } = testStore();
26 const query = createApi<ApiCtx>();
27- query.use(mdw.queryCtx);
28- query.use(mdw.api());
29+ query.use(mdw.api({ schema }));
30 query.use(query.routes());
31 query.use(function* fetchApi(ctx, next) {
32 if (`${ctx.req().url}`.startsWith("/users/")) {
33@@ -113,8 +111,7 @@ it(tests, "basic", () => {
34 it(tests, "with loader", () => {
35 const { schema, store } = testStore();
36 const api = createApi<ApiCtx>();
37- api.use(mdw.api());
38- api.use(storeMdw.store(schema));
39+ api.use(mdw.api({ schema }));
40 api.use(api.routes());
41 api.use(function* fetchApi(ctx, next) {
42 ctx.response = new Response(jsonBlob(mockUser), { status: 200 });
43@@ -156,8 +153,7 @@ it(tests, "with loader", () => {
44 it(tests, "with item loader", () => {
45 const { store, schema } = testStore();
46 const api = createApi<ApiCtx>();
47- api.use(mdw.api());
48- api.use(storeMdw.store(schema));
49+ api.use(mdw.api({ schema }));
50 api.use(api.routes());
51 api.use(function* fetchApi(ctx, next) {
52 ctx.response = new Response(jsonBlob(mockUser), { status: 200 });
53@@ -200,9 +196,10 @@ it(tests, "with item loader", () => {
54 });
55
56 it(tests, "with POST", () => {
57+ const { store, schema } = testStore();
58 const query = createApi();
59 query.use(mdw.queryCtx);
60- query.use(mdw.api());
61+ query.use(mdw.api({ schema }));
62 query.use(query.routes());
63 query.use(function* fetchApi(ctx, next) {
64 const request = ctx.req();
65@@ -245,7 +242,6 @@ it(tests, "with POST", () => {
66 },
67 );
68
69- const { store } = testStore();
70 store.run(query.bootup);
71 store.dispatch(createUser({ email: mockUser.email }));
72 });
73@@ -253,8 +249,7 @@ it(tests, "with POST", () => {
74 it(tests, "simpleCache", () => {
75 const { store, schema } = testStore();
76 const api = createApi<ApiCtx>();
77- api.use(mdw.api());
78- api.use(storeMdw.store(schema));
79+ api.use(mdw.api({ schema }));
80 api.use(api.routes());
81 api.use(function* fetchApi(ctx, next) {
82 const data = { users: [mockUser] };
83@@ -283,8 +278,7 @@ it(tests, "simpleCache", () => {
84 it(tests, "overriding default loader behavior", () => {
85 const { store, schema } = testStore();
86 const api = createApi<ApiCtx>();
87- api.use(mdw.api());
88- api.use(storeMdw.store(schema));
89+ api.use(mdw.api({ schema }));
90 api.use(api.routes());
91 api.use(function* fetchApi(ctx, next) {
92 const data = { users: [mockUser] };
93@@ -340,8 +334,7 @@ it(tests, "mdw.api() - error handler", () => {
94
95 const { schema, store } = testStore();
96 const query = createApi<ApiCtx>();
97- query.use(mdw.api());
98- query.use(storeMdw.store(schema));
99+ query.use(mdw.api({ schema }));
100 query.use(query.routes());
101 query.use(function* () {
102 throw new Error("something happened");
103@@ -356,8 +349,7 @@ it(tests, "mdw.api() - error handler", () => {
104 it(tests, "createApi with own key", async () => {
105 const { schema, store } = testStore();
106 const query = createApi();
107- query.use(mdw.api());
108- query.use(storeMdw.store(schema));
109+ query.use(mdw.api({ schema }));
110 query.use(query.routes());
111 query.use(mdw.customKey);
112 query.use(function* fetchApi(ctx, next) {
113@@ -429,8 +421,7 @@ it(tests, "createApi with own key", async () => {
114 it(tests, "createApi with custom key but no payload", async () => {
115 const { store, schema } = testStore();
116 const query = createApi();
117- query.use(mdw.api());
118- query.use(storeMdw.store(schema));
119+ query.use(mdw.api({ schema }));
120 query.use(query.routes());
121 query.use(mdw.customKey);
122 query.use(function* fetchApi(ctx, next) {
123@@ -539,7 +530,7 @@ it(tests, "errorHandler", () => {
124 },
125 );
126
127- const store = configureStore({
128+ const store = createStore({
129 initialState: {
130 users: {},
131 },
132@@ -554,12 +545,14 @@ it(tests, "errorHandler", () => {
133
134 it(tests, "stub predicate", async () => {
135 let actual: { ok: boolean } = { ok: false };
136+ const { store, schema } = testStore();
137 const api = createApi();
138 api.use(function* (ctx, next) {
139 ctx.stub = true;
140 yield* next();
141 });
142- api.use(mdw.api());
143+
144+ api.use(mdw.api({ schema }));
145 api.use(api.routes());
146 api.use(mdw.fetch({ baseUrl: "http://nowhere.com" }));
147
148@@ -577,9 +570,6 @@ it(tests, "stub predicate", async () => {
149 }),
150 ]);
151
152- const store = configureStore({
153- initialState: {},
154- });
155 store.run(api.bootup);
156 store.dispatch(fetchUsers());
157
+3,
-3
1@@ -1,8 +1,8 @@
2 import { asserts, describe, it } from "../test.ts";
3 import {
4- configureStore,
5 createPersistor,
6 createSchema,
7+ createStore,
8 PERSIST_LOADER_ID,
9 PersistAdapter,
10 persistStoreMdw,
11@@ -34,7 +34,7 @@ it(tests, "can persist to storage adapters", async () => {
12 };
13 const persistor = createPersistor<State>({ adapter, allowlist: ["token"] });
14 const mdw = persistStoreMdw(persistor);
15- const store = configureStore({
16+ const store = createStore({
17 initialState,
18 middleware: [mdw],
19 });
20@@ -82,7 +82,7 @@ it(tests, "rehydrates state", async () => {
21 };
22 const persistor = createPersistor<State>({ adapter, allowlist: ["token"] });
23 const mdw = persistStoreMdw(persistor);
24- const store = configureStore({
25+ const store = createStore({
26 initialState,
27 middleware: [mdw],
28 });
+5,
-5
1@@ -1,6 +1,6 @@
2 import { describe, expect, it } from "../test.ts";
3 import { ActionContext, each, put, sleep, spawn, take } from "../mod.ts";
4-import { configureStore } from "../store/mod.ts";
5+import { createStore } from "../store/mod.ts";
6
7 const putTests = describe("put()");
8
9@@ -26,7 +26,7 @@ it(putTests, "should send actions through channel", async () => {
10 yield* task;
11 }
12
13- const store = configureStore({ initialState: {} });
14+ const store = createStore({ initialState: {} });
15 await store.run(() => genFn("arg"));
16
17 const expected = ["arg", "2"];
18@@ -56,7 +56,7 @@ it(putTests, "should handle nested puts", async () => {
19 yield* spawn(genA);
20 }
21
22- const store = configureStore({ initialState: {} });
23+ const store = createStore({ initialState: {} });
24 await store.run(() => root());
25
26 const expected = ["put b", "put a"];
27@@ -74,7 +74,7 @@ it(
28 yield* sleep(0);
29 }
30
31- const store = configureStore({ initialState: {} });
32+ const store = createStore({ initialState: {} });
33 await store.run(() => root());
34 expect(true).toBe(true);
35 },
36@@ -102,7 +102,7 @@ it(
37 yield* tsk;
38 }
39
40- const store = configureStore({ initialState: {} });
41+ const store = createStore({ initialState: {} });
42 await store.run(root);
43 const expected = ["didn't get missed"];
44 expect(actual).toEqual(expected);
+26,
-3
1@@ -1,5 +1,5 @@
2 import { asserts, describe, it } from "../test.ts";
3-import { configureStore, createSchema, select, slice } from "../store/mod.ts";
4+import { createSchema, createStore, select, slice } from "../store/mod.ts";
5
6 const tests = describe("createSchema()");
7
8@@ -12,6 +12,29 @@ interface UserWithRoles extends User {
9 }
10
11 const emptyUser = { id: "", name: "" };
12+
13+it(tests, "default schema", async () => {
14+ const [schema, initialState] = createSchema();
15+ const store = createStore({ initialState });
16+ asserts.assertEquals(store.getState(), {
17+ cache: {},
18+ loaders: {},
19+ });
20+
21+ await store.run(function* () {
22+ yield* schema.update(schema.loaders.start({ id: "1" }));
23+ yield* schema.update(schema.cache.add({ "1": true }));
24+ });
25+
26+ asserts.assertEquals(schema.cache.selectTable(store.getState()), {
27+ "1": true,
28+ });
29+ asserts.assertEquals(
30+ schema.loaders.selectById(store.getState(), { id: "1" }).status,
31+ "loading",
32+ );
33+});
34+
35 it(tests, "general types and functionality", async () => {
36 const [db, initialState] = createSchema({
37 users: slice.table<User>({
38@@ -25,7 +48,7 @@ it(tests, "general types and functionality", async () => {
39 cache: slice.table({ empty: {} }),
40 loaders: slice.loaders(),
41 });
42- const store = configureStore({ initialState });
43+ const store = createStore({ initialState });
44
45 asserts.assertEquals(store.getState(), {
46 users: { "1": { id: "1", name: "wow" } },
47@@ -75,7 +98,7 @@ it(tests, "can work with a nested object", async () => {
48 cache: slice.table({ empty: {} }),
49 loaders: slice.loaders(),
50 });
51- const store = configureStore({ initialState });
52+ const store = createStore({ initialState });
53 await store.run(function* () {
54 yield* db.update(db.currentUser.update({ key: "name", value: "vvv" }));
55 const curUser = yield* select(db.currentUser.select);
+3,
-4
1@@ -1,6 +1,5 @@
2 import { asserts, describe, it } from "../test.ts";
3 import {
4- configureStore,
5 createStore,
6 StoreContext,
7 StoreUpdateContext,
8@@ -94,7 +93,7 @@ it(tests, "update store and receives update from `subscribe()`", async () => {
9 theme: "",
10 token: "",
11 };
12- const store = configureStore({ initialState });
13+ const store = createStore({ initialState });
14
15 store.subscribe(() => {
16 asserts.assertEquals(store.getState(), {
17@@ -117,7 +116,7 @@ it(tests, "emit Action and update store", async () => {
18 theme: "",
19 token: "",
20 };
21- const store = configureStore({ initialState });
22+ const store = createStore({ initialState });
23
24 await store.run(function* (): Operation<void> {
25 const result = yield* parallel([
26@@ -147,7 +146,7 @@ it(tests, "resets store", async () => {
27 theme: "",
28 token: "",
29 };
30- const store = configureStore({ initialState });
31+ const store = createStore({ initialState });
32
33 await store.run(function* () {
34 yield* store.update((s) => {
+4,
-4
1@@ -1,5 +1,5 @@
2 import { describe, expect, it } from "../test.ts";
3-import { configureStore } from "../store/mod.ts";
4+import { createStore } from "../store/mod.ts";
5 import type { AnyAction } from "../mod.ts";
6 import { sleep, take, takeEvery, takeLatest, takeLeading } from "../mod.ts";
7 import { spawn } from "../deps.ts";
8@@ -22,7 +22,7 @@ it(testLatest, "should cancel previous tasks and only use latest", async () => {
9 yield* take("CANCEL_WATCHER");
10 yield* task.halt();
11 }
12- const store = configureStore({ initialState: {} });
13+ const store = createStore({ initialState: {} });
14 const task = store.run(root);
15
16 store.dispatch({ type: "ACTION", payload: "1" });
17@@ -49,7 +49,7 @@ it(testLeading, "should keep first action and discard the rest", async () => {
18 yield* sleep(150);
19 yield* task.halt();
20 }
21- const store = configureStore({ initialState: {} });
22+ const store = createStore({ initialState: {} });
23 const task = store.run(root);
24
25 store.dispatch({ type: "ACTION", payload: "1" });
26@@ -82,7 +82,7 @@ it(testEvery, "should receive all actions", async () => {
27 actual.push([arg1, arg2, action.payload]);
28 }
29
30- const store = configureStore({ initialState: {} });
31+ const store = createStore({ initialState: {} });
32 const task = store.run(root);
33
34 for (let i = 1; i <= loop / 2; i += 1) {
+3,
-3
1@@ -1,7 +1,7 @@
2 import { describe, expect, it } from "../test.ts";
3 import type { AnyAction } from "../mod.ts";
4 import { put, sleep, spawn, take } from "../mod.ts";
5-import { configureStore } from "../store/mod.ts";
6+import { createStore } from "../store/mod.ts";
7
8 const takeTests = describe("take()");
9
10@@ -24,7 +24,7 @@ it(
11 actual.push(yield* take("action-1"));
12 }
13
14- const store = configureStore({ initialState: {} });
15+ const store = createStore({ initialState: {} });
16 await store.run(root);
17
18 expect(actual).toEqual([
19@@ -84,7 +84,7 @@ it(takeTests, "take from default channel", async () => {
20 }
21 }
22
23- const store = configureStore({ initialState: {} });
24+ const store = createStore({ initialState: {} });
25 await store.run(genFn);
26
27 const expected = [
+13,
-13
1@@ -1,5 +1,5 @@
2 import { assertLike, asserts, describe, it } from "../test.ts";
3-import { configureStore, updateStore } from "../store/mod.ts";
4+import { createStore, updateStore } from "../store/mod.ts";
5 import {
6 call,
7 createThunks,
8@@ -135,7 +135,7 @@ it(
9 api.use(processTickets);
10 const fetchUsers = api.create(`/users`, { supervisor: takeEvery });
11
12- const store = configureStore<TestState>({
13+ const store = createStore<TestState>({
14 initialState: { users: {}, tickets: {} },
15 });
16 store.run(api.bootup);
17@@ -172,7 +172,7 @@ it(
18 yield* put(fetchUsers());
19 });
20
21- const store = configureStore<TestState>({
22+ const store = createStore<TestState>({
23 initialState: { users: {}, tickets: {} },
24 });
25 store.run(api.bootup);
26@@ -202,7 +202,7 @@ it(tests, "error handling", () => {
27
28 const action = api.create(`/error`, { supervisor: takeEvery });
29
30- const store = configureStore({ initialState: {} });
31+ const store = createStore({ initialState: {} });
32 store.run(api.bootup);
33 store.dispatch(action());
34 asserts.assertStrictEquals(called, true);
35@@ -227,7 +227,7 @@ it(tests, "error handling inside create", () => {
36 }
37 },
38 );
39- const store = configureStore({ initialState: {} });
40+ const store = createStore({ initialState: {} });
41 store.run(api.bootup);
42 store.dispatch(action());
43 asserts.assertStrictEquals(called, true);
44@@ -254,7 +254,7 @@ it(tests, "error inside endpoint mdw", () => {
45 },
46 );
47
48- const store = configureStore({
49+ const store = createStore({
50 initialState: {
51 users: {},
52 },
53@@ -289,7 +289,7 @@ it(tests, "create fn is an array", () => {
54 },
55 ]);
56
57- const store = configureStore({ initialState: {} });
58+ const store = createStore({ initialState: {} });
59 store.run(api.bootup);
60 store.dispatch(action());
61 });
62@@ -328,7 +328,7 @@ it(tests, "run() on endpoint action - should run the effect", () => {
63 },
64 );
65
66- const store = configureStore({ initialState: {} });
67+ const store = createStore({ initialState: {} });
68 store.run(api.bootup);
69 store.dispatch(action2());
70 });
71@@ -370,7 +370,7 @@ it(
72 },
73 );
74
75- const store = configureStore({ initialState: {} });
76+ const store = createStore({ initialState: {} });
77 store.run(api.bootup);
78 store.dispatch(action2());
79 },
80@@ -408,7 +408,7 @@ it(tests, "middleware order of execution", async () => {
81 },
82 );
83
84- const store = configureStore({ initialState: {} });
85+ const store = createStore({ initialState: {} });
86 store.run(api.bootup);
87 store.dispatch(action());
88
89@@ -440,7 +440,7 @@ it(tests, "retry with actionFn", async () => {
90 },
91 );
92
93- const store = configureStore({ initialState: {} });
94+ const store = createStore({ initialState: {} });
95 store.run(api.bootup);
96 store.dispatch(action());
97
98@@ -470,7 +470,7 @@ it(tests, "retry with actionFn with payload", async () => {
99 },
100 );
101
102- const store = configureStore({ initialState: {} });
103+ const store = createStore({ initialState: {} });
104 store.run(api.bootup);
105 store.dispatch(action({ page: 1 }));
106
107@@ -500,7 +500,7 @@ it(tests, "should only call thunk once", () => {
108 },
109 );
110
111- const store = configureStore({ initialState: {} });
112+ const store = createStore({ initialState: {} });
113 store.run(api.bootup);
114 store.dispatch(action2());
115 asserts.assertEquals(acc, "a");