repos / starfx

supercharged async flow control library.
git clone https://github.com/neurosnap/starfx.git

commit
a57267b
parent
442f5d7
author
Eric Bower
date
2023-07-14 15:28:27 +0000 UTC
refactor: switch default createPipe() supervisor to redux
7 files changed,  +241, -150
M query/api.test.ts
+41, -21
  1@@ -53,6 +53,7 @@ it(tests, "createApi - POST", async () => {
  2 
  3   const createUser = query.post<{ email: string }, { users: User[] }>(
  4     `/users`,
  5+    { supervisor: takeEvery },
  6     function* processUsers(ctx, next) {
  7       ctx.request = ctx.req({
  8         method: "POST",
  9@@ -113,23 +114,26 @@ it(tests, "POST with uri", async () => {
 10   });
 11 
 12   const userApi = query.uri("/users");
 13-  const createUser = userApi.post<{ email: string }>(function* processUsers(
 14-    ctx: ApiCtx<{ email: string }, { users: User[] }>,
 15-    next,
 16-  ) {
 17-    ctx.request = ctx.req({
 18-      body: JSON.stringify({ email: ctx.payload.email }),
 19-    });
 20+  const createUser = userApi.post<{ email: string }>(
 21+    { supervisor: takeEvery },
 22+    function* processUsers(
 23+      ctx: ApiCtx<{ email: string }, { users: User[] }>,
 24+      next,
 25+    ) {
 26+      ctx.request = ctx.req({
 27+        body: JSON.stringify({ email: ctx.payload.email }),
 28+      });
 29 
 30-    yield* next();
 31-    if (!ctx.json.ok) return;
 32-    const { users } = ctx.json.data;
 33-    yield* updateStore<{ users: { [key: string]: User } }>((state) => {
 34-      users.forEach((u) => {
 35-        state.users[u.id] = u;
 36+      yield* next();
 37+      if (!ctx.json.ok) return;
 38+      const { users } = ctx.json.data;
 39+      yield* updateStore<{ users: { [key: string]: User } }>((state) => {
 40+        users.forEach((u) => {
 41+          state.users[u.id] = u;
 42+        });
 43       });
 44-    });
 45-  });
 46+    },
 47+  );
 48 
 49   const store = await configureStore({ initialState: { users: {} } });
 50   store.run(query.bootup);
 51@@ -146,7 +150,11 @@ it(tests, "middleware - with request fn", async () => {
 52     expect(ctx.req().url).toEqual("/users");
 53     yield* next();
 54   });
 55-  const createUser = query.create("/users", query.request({ method: "POST" }));
 56+  const createUser = query.create(
 57+    "/users",
 58+    { supervisor: takeEvery },
 59+    query.request({ method: "POST" }),
 60+  );
 61   const store = await configureStore({ initialState: { users: {} } });
 62   store.run(query.bootup);
 63   store.dispatch(createUser());
 64@@ -158,6 +166,7 @@ it(tests, "run() on endpoint action - should run the effect", async () => {
 65   let acc = "";
 66   const action1 = api.get<{ id: string }, { result: boolean }>(
 67     "/users/:id",
 68+    { supervisor: takeEvery },
 69     function* (_, next) {
 70       yield* next();
 71       acc += "a";
 72@@ -179,7 +188,9 @@ it(tests, "run() from a normal saga", async () => {
 73   const api = createApi();
 74   api.use(api.routes());
 75   let acc = "";
 76-  const action1 = api.get<{ id: string }>("/users/:id", function* (_, next) {
 77+  const action1 = api.get<{ id: string }>("/users/:id", {
 78+    supervisor: takeEvery,
 79+  }, function* (_, next) {
 80     yield* next();
 81     acc += "a";
 82   });
 83@@ -222,6 +233,7 @@ it(tests, "createApi with hash key on a large post", async () => {
 84   });
 85   const createUserDefaultKey = query.post<{ email: string; largetext: string }>(
 86     `/users`,
 87+    { supervisor: takeEvery },
 88     function* processUsers(ctx, next) {
 89       ctx.cache = true;
 90       yield* next();
 91@@ -283,13 +295,18 @@ it(tests, "createApi - two identical endpoints", async () => {
 92   api.use(storeMdw());
 93   api.use(api.routes());
 94 
 95-  const first = api.get("/health", function* (ctx, next) {
 96-    actual.push(ctx.req().url);
 97-    yield* next();
 98-  });
 99+  const first = api.get(
100+    "/health",
101+    { supervisor: takeEvery },
102+    function* (ctx, next) {
103+      actual.push(ctx.req().url);
104+      yield* next();
105+    },
106+  );
107 
108   const second = api.get(
109     ["/health", "poll"],
110+    { supervisor: takeEvery },
111     function* (ctx, next) {
112       actual.push(ctx.req().url);
113       yield* next();
114@@ -322,6 +339,7 @@ it(tests, "ensure types for get() endpoint", async () => {
115   const acc: string[] = [];
116   const action1 = api.get<{ id: string }, { result: string }>(
117     "/users/:id",
118+    { supervisor: takeEvery },
119     function* (ctx, next) {
120       ctx.something = false;
121       acc.push(ctx.payload.id);
122@@ -358,6 +376,7 @@ it(tests, "ensure ability to cast `ctx` in function definition", async () => {
123   const acc: string[] = [];
124   const action1 = api.get<FetchUserProps>(
125     "/users/:id",
126+    { supervisor: takeEvery },
127     function* (ctx: FetchUserCtx, next) {
128       ctx.something = false;
129       acc.push(ctx.payload.id);
130@@ -393,6 +412,7 @@ it(
131     const acc: string[] = [];
132     const action1 = api.get<never, { result: string }>(
133       "/users",
134+      { supervisor: takeEvery },
135       function* (ctx: FetchUserSecondCtx, next) {
136         ctx.something = false;
137 
M query/fetch.test.ts
+82, -56
  1@@ -1,5 +1,5 @@
  2 import { describe, expect, install, it, mock } from "../test.ts";
  3-import { configureStore, storeMdw } from "../store/mod.ts";
  4+import { configureStore, storeMdw, takeEvery } from "../store/mod.ts";
  5 import { createQueryState } from "../action.ts";
  6 import type { QueryState } from "../types.ts";
  7 
  8@@ -33,20 +33,24 @@ it(
  9     api.use(api.routes());
 10     api.use(fetcher({ baseUrl }));
 11 
 12-    const fetchUsers = api.get("/users", function* (ctx, next) {
 13-      ctx.cache = true;
 14-      yield* next();
 15+    const fetchUsers = api.get(
 16+      "/users",
 17+      { supervisor: takeEvery },
 18+      function* (ctx, next) {
 19+        ctx.cache = true;
 20+        yield* next();
 21 
 22-      expect(ctx.request).toEqual({
 23-        url: `${baseUrl}/users`,
 24-        method: "GET",
 25-        headers: {
 26-          "Content-Type": "application/json",
 27-        },
 28-      });
 29+        expect(ctx.request).toEqual({
 30+          url: `${baseUrl}/users`,
 31+          method: "GET",
 32+          headers: {
 33+            "Content-Type": "application/json",
 34+          },
 35+        });
 36 
 37-      expect(ctx.json).toEqual({ ok: true, data: mockUser });
 38-    });
 39+        expect(ctx.json).toEqual({ ok: true, data: mockUser });
 40+      },
 41+    );
 42 
 43     const store = await configureStore<QueryState>({
 44       initialState: createQueryState(),
 45@@ -77,12 +81,16 @@ it(
 46     api.use(api.routes());
 47     api.use(fetcher({ baseUrl }));
 48 
 49-    const fetchUsers = api.get("/users", function* (ctx, next) {
 50-      ctx.cache = true;
 51-      ctx.bodyType = "text";
 52-      yield next();
 53-      expect(ctx.json).toEqual({ ok: true, data: "this is some text" });
 54-    });
 55+    const fetchUsers = api.get(
 56+      "/users",
 57+      { supervisor: takeEvery },
 58+      function* (ctx, next) {
 59+        ctx.cache = true;
 60+        ctx.bodyType = "text";
 61+        yield next();
 62+        expect(ctx.json).toEqual({ ok: true, data: "this is some text" });
 63+      },
 64+    );
 65 
 66     const store = await configureStore<QueryState>({
 67       initialState: createQueryState(),
 68@@ -113,12 +121,16 @@ it(tests, "fetch - error handling", async () => {
 69   });
 70   api.use(fetcher());
 71 
 72-  const fetchUsers = api.get("/users", function* (ctx, next) {
 73-    ctx.cache = true;
 74-    yield* next();
 75+  const fetchUsers = api.get(
 76+    "/users",
 77+    { supervisor: takeEvery },
 78+    function* (ctx, next) {
 79+      ctx.cache = true;
 80+      yield* next();
 81 
 82-    expect(ctx.json).toEqual({ ok: false, data: errMsg });
 83-  });
 84+      expect(ctx.json).toEqual({ ok: false, data: errMsg });
 85+    },
 86+  );
 87 
 88   const store = await configureStore<QueryState>({
 89     initialState: createQueryState(),
 90@@ -150,12 +162,16 @@ it(tests, "fetch - status 204", async () => {
 91   });
 92   api.use(fetcher());
 93 
 94-  const fetchUsers = api.get("/users", function* (ctx, next) {
 95-    ctx.cache = true;
 96-    yield* next();
 97+  const fetchUsers = api.get(
 98+    "/users",
 99+    { supervisor: takeEvery },
100+    function* (ctx, next) {
101+      ctx.cache = true;
102+      yield* next();
103 
104-    expect(ctx.json).toEqual({ ok: true, data: {} });
105-  });
106+      expect(ctx.json).toEqual({ ok: true, data: {} });
107+    },
108+  );
109 
110   const store = await configureStore<QueryState>({
111     initialState: createQueryState(),
112@@ -187,18 +203,22 @@ it(tests, "fetch - malformed json", async () => {
113   });
114   api.use(fetcher());
115 
116-  const fetchUsers = api.get("/users", function* (ctx, next) {
117-    ctx.cache = true;
118-    yield* next();
119+  const fetchUsers = api.get(
120+    "/users",
121+    { supervisor: takeEvery },
122+    function* (ctx, next) {
123+      ctx.cache = true;
124+      yield* next();
125 
126-    expect(ctx.json).toEqual({
127-      ok: false,
128-      data: {
129-        message:
130-          "invalid json response body at https://saga-query.com/users reason: Unexpected token o in JSON at position 1",
131-      },
132-    });
133-  });
134+      expect(ctx.json).toEqual({
135+        ok: false,
136+        data: {
137+          message:
138+            "invalid json response body at https://saga-query.com/users reason: Unexpected token o in JSON at position 1",
139+        },
140+      });
141+    },
142+  );
143 
144   const store = await configureStore<QueryState>({
145     initialState: createQueryState(),
146@@ -221,22 +241,26 @@ it(tests, "fetch - POST", async () => {
147   api.use(api.routes());
148   api.use(fetcher({ baseUrl }));
149 
150-  const fetchUsers = api.post("/users", function* (ctx, next) {
151-    ctx.cache = true;
152-    ctx.request = ctx.req({ body: JSON.stringify(mockUser) });
153-    yield* next();
154+  const fetchUsers = api.post(
155+    "/users",
156+    { supervisor: takeEvery },
157+    function* (ctx, next) {
158+      ctx.cache = true;
159+      ctx.request = ctx.req({ body: JSON.stringify(mockUser) });
160+      yield* next();
161 
162-    expect(ctx.req()).toEqual({
163-      url: `${baseUrl}/users`,
164-      headers: {
165-        "Content-Type": "application/json",
166-      },
167-      method: "POST",
168-      body: JSON.stringify(mockUser),
169-    });
170+      expect(ctx.req()).toEqual({
171+        url: `${baseUrl}/users`,
172+        headers: {
173+          "Content-Type": "application/json",
174+        },
175+        method: "POST",
176+        body: JSON.stringify(mockUser),
177+      });
178 
179-    expect(ctx.json).toEqual({ ok: true, data: mockUser });
180-  });
181+      expect(ctx.json).toEqual({ ok: true, data: mockUser });
182+    },
183+  );
184 
185   const store = await configureStore<QueryState>({
186     initialState: createQueryState(),
187@@ -261,6 +285,7 @@ it(tests, "fetch - POST multiple endpoints with same uri", async () => {
188 
189   const fetchUsers = api.post<{ id: string }>(
190     "/users/:id/something",
191+    { supervisor: takeEvery },
192     function* (ctx, next) {
193       ctx.cache = true;
194       ctx.request = ctx.req({ body: JSON.stringify(mockUser) });
195@@ -322,6 +347,7 @@ it(
196 
197     const fetchUsers = api.post<{ id: string }>(
198       "/users/:id",
199+      { supervisor: takeEvery },
200       function* (ctx, next) {
201         ctx.cache = true;
202         ctx.request = ctx.req({ body: JSON.stringify(mockUser) });
203@@ -368,7 +394,7 @@ it(
204     api.use(api.routes());
205     api.use(fetcher({ baseUrl }));
206 
207-    const fetchUsers = api.get("/users", [
208+    const fetchUsers = api.get("/users", { supervisor: takeEvery }, [
209       function* (ctx, next) {
210         ctx.cache = true;
211         yield* next();
212@@ -413,7 +439,7 @@ it.ignore(
213     api.use(api.routes());
214     api.use(fetcher({ baseUrl }));
215 
216-    const fetchUsers = api.get("/users", [
217+    const fetchUsers = api.get("/users", { supervisor: takeEvery }, [
218       function* (ctx, next) {
219         ctx.cache = true;
220         yield* next();
M query/middleware.test.ts
+18, -6
  1@@ -20,6 +20,7 @@ import {
  2   defaultLoader,
  3   selectDataById,
  4   storeMdw,
  5+  takeEvery,
  6   takeLatest,
  7   undo,
  8   undoer,
  9@@ -66,6 +67,7 @@ it(tests, "basic", async () => {
 10 
 11   const fetchUsers = query.create(
 12     `/users`,
 13+    { supervisor: takeEvery },
 14     function* processUsers(ctx: ApiCtx<unknown, { users: User[] }>, next) {
 15       yield* next();
 16       if (!ctx.json.ok) return;
 17@@ -128,6 +130,7 @@ it(tests, "with loader", async () => {
 18 
 19   const fetchUsers = api.create(
 20     `/users`,
 21+    { supervisor: takeEvery },
 22     function* processUsers(ctx: ApiCtx<unknown, { users: User[] }>, next) {
 23       yield* next();
 24       if (!ctx.json.ok) return;
 25@@ -171,6 +174,7 @@ it(tests, "with item loader", async () => {
 26 
 27   const fetchUser = api.create<{ id: string }>(
 28     `/users/:id`,
 29+    { supervisor: takeEvery },
 30     function* processUsers(ctx: ApiCtx<unknown, { users: User[] }>, next) {
 31       yield* next();
 32       if (!ctx.json.ok) return;
 33@@ -227,6 +231,7 @@ it(tests, "with POST", async () => {
 34 
 35   const createUser = query.create<{ email: string }>(
 36     `/users [POST]`,
 37+    { supervisor: takeEvery },
 38     function* processUsers(
 39       ctx: ApiCtx<{ email: string }, { users: User[] }>,
 40       next,
 41@@ -269,7 +274,7 @@ it(tests, "simpleCache", async () => {
 42     yield* next();
 43   });
 44 
 45-  const fetchUsers = api.get("/users", api.cache());
 46+  const fetchUsers = api.get("/users", { supervisor: takeEvery }, api.cache());
 47   const store = await configureStore<UserState>({
 48     initialState: { ...createQueryState(), users: {} },
 49   });
 50@@ -303,6 +308,7 @@ it(tests, "overriding default loader behavior", async () => {
 51 
 52   const fetchUsers = api.create(
 53     `/users`,
 54+    { supervisor: takeEvery },
 55     function* (ctx: ApiCtx<unknown, { users: User[] }>, next) {
 56       const id = ctx.name;
 57       yield* next();
 58@@ -353,10 +359,14 @@ it(tests, "undo", async () => {
 59     yield* next();
 60   });
 61 
 62-  const createUser = api.post("/users", function* (ctx, next) {
 63-    ctx.undoable = true;
 64-    yield* next();
 65-  });
 66+  const createUser = api.post(
 67+    "/users",
 68+    { supervisor: takeEvery },
 69+    function* (ctx, next) {
 70+      ctx.undoable = true;
 71+      yield* next();
 72+    },
 73+  );
 74 
 75   const store = await configureStore<UserState>({
 76     initialState: { ...createQueryState(), users: {} },
 77@@ -395,7 +405,7 @@ it(tests, "requestMonitor - error handler", async () => {
 78     throw new Error("something happened");
 79   });
 80 
 81-  const fetchUsers = query.create(`/users`);
 82+  const fetchUsers = query.create(`/users`, { supervisor: takeEvery });
 83 
 84   const store = await configureStore<UserState>({
 85     initialState: { ...createQueryState(), users: {} },
 86@@ -423,6 +433,7 @@ it(tests, "createApi with own key", async () => {
 87 
 88   const createUserCustomKey = query.post<{ email: string }>(
 89     `/users`,
 90+    { supervisor: takeEvery },
 91     function* processUsers(ctx: ApiCtx, next) {
 92       ctx.cache = true;
 93       ctx.key = theTestKey; // or some calculated key //
 94@@ -493,6 +504,7 @@ it(tests, "createApi with custom key but no payload", async () => {
 95 
 96   const getUsers = query.get(
 97     `/users`,
 98+    { supervisor: takeEvery },
 99     function* processUsers(ctx: ApiCtx, next) {
100       ctx.cache = true;
101       ctx.key = theTestKey; // or some calculated key //
M query/pipe.test.ts
+96, -62
  1@@ -1,6 +1,6 @@
  2 import { assertLike, asserts, describe, it } from "../test.ts";
  3 import { call } from "../fx/mod.ts";
  4-import { configureStore, put } from "../store/mod.ts";
  5+import { configureStore, put, takeEvery } from "../store/mod.ts";
  6 import { sleep as delay } from "../deps.ts";
  7 import type { QueryState } from "../types.ts";
  8 import { createQueryState } from "../action.ts";
  9@@ -133,7 +133,7 @@ it(
 10     api.use(onFetchApi);
 11     api.use(processUsers);
 12     api.use(processTickets);
 13-    const fetchUsers = api.create(`/users`);
 14+    const fetchUsers = api.create(`/users`, { supervisor: takeEvery });
 15 
 16     const store = await configureStore<TestState>({
 17       initialState: { ...createQueryState(), users: {}, tickets: {} },
 18@@ -150,7 +150,7 @@ it(
 19   },
 20 );
 21 
 22-it.only(
 23+it(
 24   tests,
 25   "when providing a generator the to api.create function - should call that generator before all other middleware",
 26   async () => {
 27@@ -160,8 +160,10 @@ it.only(
 28     api.use(onFetchApi);
 29     api.use(processUsers);
 30     api.use(processTickets);
 31-    const fetchUsers = api.create(`/users`);
 32-    const fetchTickets = api.create(`/ticket-wrong-url`, function* (ctx, next) {
 33+    const fetchUsers = api.create(`/users`, { supervisor: takeEvery });
 34+    const fetchTickets = api.create(`/ticket-wrong-url`, {
 35+      supervisor: takeEvery,
 36+    }, function* (ctx, next) {
 37       // before middleware has been triggered
 38       ctx.url = "/tickets";
 39 
 40@@ -199,7 +201,7 @@ it(tests, "error handling", async () => {
 41     throw new Error("some error");
 42   });
 43 
 44-  const action = api.create(`/error`);
 45+  const action = api.create(`/error`, { supervisor: takeEvery });
 46 
 47   const store = await configureStore({ initialState: {} });
 48   store.run(api.bootup);
 49@@ -213,13 +215,17 @@ it(tests, "error handling inside create", async () => {
 50     throw new Error("some error");
 51   });
 52 
 53-  const action = api.create(`/error`, function* (_, next) {
 54-    try {
 55-      yield* next();
 56-    } catch (_) {
 57-      asserts.assert(true);
 58-    }
 59-  });
 60+  const action = api.create(
 61+    `/error`,
 62+    { supervisor: takeEvery },
 63+    function* (_, next) {
 64+      try {
 65+        yield* next();
 66+      } catch (_) {
 67+        asserts.assert(true);
 68+      }
 69+    },
 70+  );
 71   const store = await configureStore({ initialState: {} });
 72   store.run(api.bootup);
 73   store.dispatch(action());
 74@@ -232,7 +238,7 @@ it(tests, "error handling - error handler", async () => {
 75     throw new Error("failure");
 76   });
 77 
 78-  const action = api.create(`/error`);
 79+  const action = api.create(`/error`, { supervisor: takeEvery });
 80   const store = await configureStore({ initialState: {} });
 81   store.run(api.bootup);
 82 
 83@@ -251,7 +257,7 @@ it(tests, "create fn is an array", async () => {
 84     });
 85     yield* next();
 86   });
 87-  const action = api.create("/users", [
 88+  const action = api.create("/users", { supervisor: takeEvery }, [
 89     function* (ctx, next) {
 90       ctx.request = {
 91         method: "POST",
 92@@ -273,27 +279,35 @@ it(tests, "run() on endpoint action - should run the effect", async () => {
 93   const api = createPipe<RoboCtx>();
 94   api.use(api.routes());
 95   let acc = "";
 96-  const action1 = api.create("/users", function* (ctx, next) {
 97-    yield* next();
 98-    ctx.request = { method: "expect this" };
 99-    acc += "a";
100-  });
101-  const action2 = api.create("/users2", function* (_, next) {
102-    yield* next();
103-    const curCtx = yield* call(() => action1.run(action1()));
104-    acc += "b";
105-    asserts.assert(acc === "ab");
106-    assertLike(curCtx, {
107-      action: {
108-        type: `@@saga-query${action1}`,
109-        payload: {
110-          name: "/users",
111+  const action1 = api.create(
112+    "/users",
113+    { supervisor: takeEvery },
114+    function* (ctx, next) {
115+      yield* next();
116+      ctx.request = { method: "expect this" };
117+      acc += "a";
118+    },
119+  );
120+  const action2 = api.create(
121+    "/users2",
122+    { supervisor: takeEvery },
123+    function* (_, next) {
124+      yield* next();
125+      const curCtx = yield* call(() => action1.run(action1()));
126+      acc += "b";
127+      asserts.assert(acc === "ab");
128+      assertLike(curCtx, {
129+        action: {
130+          type: `@@saga-query${action1}`,
131+          payload: {
132+            name: "/users",
133+          },
134         },
135-      },
136-      name: "/users",
137-      request: { method: "expect this" },
138-    });
139-  });
140+        name: "/users",
141+        request: { method: "expect this" },
142+      });
143+    },
144+  );
145 
146   const store = await configureStore({ initialState: {} });
147   store.run(api.bootup);
148@@ -321,11 +335,15 @@ it(tests, "middleware order of execution", async () => {
149     acc += "e";
150   });
151 
152-  const action = api.create("/api", function* (_, next) {
153-    acc += "a";
154-    yield* next();
155-    acc += "g";
156-  });
157+  const action = api.create(
158+    "/api",
159+    { supervisor: takeEvery },
160+    function* (_, next) {
161+      acc += "a";
162+      yield* next();
163+      acc += "g";
164+    },
165+  );
166 
167   const store = await configureStore({ initialState: {} });
168   store.run(api.bootup);
169@@ -342,16 +360,20 @@ it.ignore(tests, "retry with actionFn", async () => {
170   const api = createPipe();
171   api.use(api.routes());
172 
173-  const action = api.create("/api", function* (ctx, next) {
174-    acc += "a";
175-    yield* next();
176-    acc += "g";
177+  const action = api.create(
178+    "/api",
179+    { supervisor: takeEvery },
180+    function* (ctx, next) {
181+      acc += "a";
182+      yield* next();
183+      acc += "g";
184 
185-    if (!called) {
186-      called = true;
187-      yield* put(ctx.actionFn());
188-    }
189-  });
190+      if (!called) {
191+        called = true;
192+        yield* put(ctx.actionFn());
193+      }
194+    },
195+  );
196 
197   const store = await configureStore({ initialState: {} });
198   store.run(api.bootup);
199@@ -373,11 +395,15 @@ it.ignore(tests, "retry with actionFn with payload", async () => {
200     }
201   });
202 
203-  const action = api.create<{ page: number }>("/api", function* (_, next) {
204-    acc += "a";
205-    yield* next();
206-    acc += "g";
207-  });
208+  const action = api.create<{ page: number }>(
209+    "/api",
210+    { supervisor: takeEvery },
211+    function* (_, next) {
212+      acc += "a";
213+      yield* next();
214+      acc += "g";
215+    },
216+  );
217 
218   const store = await configureStore({ initialState: {} });
219   const task = store.run(api.bootup);
220@@ -393,14 +419,22 @@ it(tests, "should only call thunk once", async () => {
221   api.use(api.routes());
222   let acc = "";
223 
224-  const action1 = api.create<number>("/users", function* (_, next) {
225-    yield* next();
226-    acc += "a";
227-  });
228-  const action2 = api.create("/users2", function* (_, next) {
229-    yield* next();
230-    yield* put(action1(1));
231-  });
232+  const action1 = api.create<number>(
233+    "/users",
234+    { supervisor: takeEvery },
235+    function* (_, next) {
236+      yield* next();
237+      acc += "a";
238+    },
239+  );
240+  const action2 = api.create(
241+    "/users2",
242+    { supervisor: takeEvery },
243+    function* (_, next) {
244+      yield* next();
245+      yield* put(action1(1));
246+    },
247+  );
248 
249   const store = await configureStore({ initialState: {} });
250   store.run(api.bootup);
M query/pipe.ts
+1, -1
1@@ -4,7 +4,7 @@ import type { OpFn, Payload } from "../types.ts";
2 import { parallel } from "../mod.ts";
3 
4 // TODO: remove store deps
5-import { takeEvery } from "../store/mod.ts";
6+import { takeEvery } from "../redux/mod.ts";
7 
8 import { isFn, isObject } from "./util.ts";
9 import { createKey } from "./create-key.ts";
M query/react.ts
+1, -1
1@@ -3,7 +3,7 @@ import { React, useDispatch, useSelector } from "../deps.ts";
2 const { useState, useEffect } = React;
3 
4 // TODO: remove store deps
5-import { selectDataById, selectLoaderById } from "../store/mod.ts";
6+import { selectDataById, selectLoaderById } from "../redux/mod.ts";
7 
8 type ActionFn<P = any> = (p: P) => { toString: () => string };
9 type ActionFnSimple = () => { toString: () => string };
M store/store.ts
+2, -3
 1@@ -116,7 +116,7 @@ export function createStore<S extends AnyState>({
 2     const result = yield* mdw(ctx);
 3     // TODO: dev mode only?
 4     if (!result.ok) {
 5-      console.error(result.error);
 6+      console.error(result);
 7     }
 8     return result;
 9   }
10@@ -160,9 +160,8 @@ export function register<S extends AnyState>(store: FxStore<S>) {
11   });
12 }
13 
14-const defaultScope = createScope();
15 export async function configureStore<S extends AnyState>({
16-  scope = defaultScope,
17+  scope = createScope(),
18   ...props
19 }: CreateStore<S>): Promise<FxStore<S>> {
20   const store = createStore<S>({ scope, ...props });