@bbki.ng/site 1.1.28 → 1.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,9 @@
1
1
  # @bbki.ng/site
2
2
 
3
+ ## 1.2.1
4
+
5
+ ## 1.2.0
6
+
3
7
  ## 1.1.28
4
8
 
5
9
  ## 1.1.27
@@ -832,7 +832,7 @@ define(["exports"], function (exports) {
832
832
  }
833
833
  /**
834
834
  * @return {Map<string, Array<workbox-routing.Route>>} routes A `Map` of HTTP
835
- * method name ('GET', etc.) to an array of all the corresponding `Route`
835
+ * method title ('GET', etc.) to an array of all the corresponding `Route`
836
836
  * instances that are registered.
837
837
  */
838
838
 
@@ -1958,7 +1958,7 @@ define(["exports"], function (exports) {
1958
1958
  url,
1959
1959
  timestamp,
1960
1960
  cacheName: this._cacheName,
1961
- // Creating an ID from the URL and cache name won't be necessary once
1961
+ // Creating an ID from the URL and cache title won't be necessary once
1962
1962
  // Edge switches to Chromium and all browsers we support work with
1963
1963
  // array keyPaths.
1964
1964
  id: this._getId(url),
@@ -2055,7 +2055,7 @@ define(["exports"], function (exports) {
2055
2055
  */
2056
2056
 
2057
2057
  _getId(url) {
2058
- // Creating an ID from the URL and cache name won't be necessary once
2058
+ // Creating an ID from the URL and cache title won't be necessary once
2059
2059
  // Edge switches to Chromium and all browsers we support work with
2060
2060
  // array keyPaths.
2061
2061
  return this._cacheName + "|" + normalizeURL(url);
@@ -2276,7 +2276,7 @@ define(["exports"], function (exports) {
2276
2276
  * It can only be used with `workbox-strategy` instances that have a
2277
2277
  * [custom `cacheName` property set](/web/tools/workbox/guides/configure-workbox#custom_cache_names_in_strategies).
2278
2278
  * In other words, it can't be used to expire entries in strategy that uses the
2279
- * default runtime cache name.
2279
+ * default runtime cache title.
2280
2280
  *
2281
2281
  * Whenever a cached response is used or updated, this plugin will look
2282
2282
  * at the associated cache and remove any old or extra responses.
@@ -2435,7 +2435,7 @@ define(["exports"], function (exports) {
2435
2435
  }
2436
2436
  /**
2437
2437
  * A simple helper method to return a CacheExpiration instance for a given
2438
- * cache name.
2438
+ * cache title.
2439
2439
  *
2440
2440
  * @param {string} cacheName
2441
2441
  * @return {CacheExpiration}
@@ -2523,7 +2523,7 @@ define(["exports"], function (exports) {
2523
2523
  * metadata is also cleanly removed and open IndexedDB instances are deleted.
2524
2524
  *
2525
2525
  * Note that if you're *not* using cache expiration for a given cache, calling
2526
- * `caches.delete()` and passing in the cache's name should be sufficient.
2526
+ * `caches.delete()` and passing in the cache's title should be sufficient.
2527
2527
  * There is no Workbox-specific method needed for cleanup in that case.
2528
2528
  */
2529
2529
 
@@ -2911,7 +2911,7 @@ define(["exports"], function (exports) {
2911
2911
  /**
2912
2912
  * The request the strategy is performing (passed to the strategy's
2913
2913
  * `handle()` or `handleAll()` method).
2914
- * @name request
2914
+ * @title request
2915
2915
  * @instance
2916
2916
  * @type {Request}
2917
2917
  * @memberof workbox-strategies.StrategyHandler
@@ -2919,7 +2919,7 @@ define(["exports"], function (exports) {
2919
2919
 
2920
2920
  /**
2921
2921
  * The event associated with this request.
2922
- * @name event
2922
+ * @title event
2923
2923
  * @instance
2924
2924
  * @type {ExtendableEvent}
2925
2925
  * @memberof workbox-strategies.StrategyHandler
@@ -2930,7 +2930,7 @@ define(["exports"], function (exports) {
2930
2930
  * `handle()` or `handleAll()` method).
2931
2931
  * Note: the `url` param will be present if the strategy was invoked
2932
2932
  * from a workbox `Route` object.
2933
- * @name url
2933
+ * @title url
2934
2934
  * @instance
2935
2935
  * @type {URL|undefined}
2936
2936
  * @memberof workbox-strategies.StrategyHandler
@@ -2943,7 +2943,7 @@ define(["exports"], function (exports) {
2943
2943
  * from a workbox `Route` object and the
2944
2944
  * {@link workbox-routing~matchCallback} returned
2945
2945
  * a truthy value (it will be that value).
2946
- * @name params
2946
+ * @title params
2947
2947
  * @instance
2948
2948
  * @type {*|undefined}
2949
2949
  * @memberof workbox-strategies.StrategyHandler
@@ -3305,7 +3305,7 @@ define(["exports"], function (exports) {
3305
3305
  * Returns true if the strategy has at least one plugin with the given
3306
3306
  * callback.
3307
3307
  *
3308
- * @param {string} name The name of the callback to check for.
3308
+ * @param {string} name The title of the callback to check for.
3309
3309
  * @return {boolean}
3310
3310
  */
3311
3311
 
@@ -3319,7 +3319,7 @@ define(["exports"], function (exports) {
3319
3319
  return false;
3320
3320
  }
3321
3321
  /**
3322
- * Runs all plugin callbacks matching the given name, in order, passing the
3322
+ * Runs all plugin callbacks matching the given title, in order, passing the
3323
3323
  * given param object (merged ith the current plugin state) as the only
3324
3324
  * argument.
3325
3325
  *
@@ -3329,7 +3329,7 @@ define(["exports"], function (exports) {
3329
3329
  * {@link workbox-strategies.StrategyHandler#iterateCallbacks}
3330
3330
  * below for how to handle that case.
3331
3331
  *
3332
- * @param {string} name The name of the callback to run within each plugin.
3332
+ * @param {string} name The title of the callback to run within each plugin.
3333
3333
  * @param {Object} param The object to pass as the first (and only) param
3334
3334
  * when executing each callback. This object will be merged with the
3335
3335
  * current plugin state prior to callback execution.
@@ -3348,7 +3348,7 @@ define(["exports"], function (exports) {
3348
3348
  * you call each callback, whatever object parameter you pass it will
3349
3349
  * be merged with the plugin's current state).
3350
3350
  *
3351
- * @param {string} name The name fo the callback to run
3351
+ * @param {string} name The title fo the callback to run
3352
3352
  * @return {Array<Function>}
3353
3353
  */
3354
3354
 
@@ -3497,7 +3497,7 @@ define(["exports"], function (exports) {
3497
3497
  * constructor.
3498
3498
  *
3499
3499
  * @param {Object} [options]
3500
- * @param {string} [options.cacheName] Cache name to store and retrieve
3500
+ * @param {string} [options.cacheName] Cache title to store and retrieve
3501
3501
  * requests. Defaults to the cache names provided by
3502
3502
  * {@link workbox-core.cacheNames}.
3503
3503
  * @param {Array<Object>} [options.plugins] [Plugins]{@link https://developers.google.com/web/tools/workbox/guides/using-plugins}
@@ -3512,7 +3512,7 @@ define(["exports"], function (exports) {
3512
3512
  */
3513
3513
  constructor(options = {}) {
3514
3514
  /**
3515
- * Cache name to store and retrieve
3515
+ * Cache title to store and retrieve
3516
3516
  * requests. Defaults to the cache names provided by
3517
3517
  * {@link workbox-core.cacheNames}.
3518
3518
  *
@@ -3728,7 +3728,7 @@ define(["exports"], function (exports) {
3728
3728
  * cache, cache options, fetch options and plugins are used (per the current
3729
3729
  * strategy instance).
3730
3730
  *
3731
- * @name _handle
3731
+ * @title _handle
3732
3732
  * @instance
3733
3733
  * @abstract
3734
3734
  * @function
@@ -4263,7 +4263,7 @@ define(["exports"], function (exports) {
4263
4263
  /**
4264
4264
  *
4265
4265
  * @param {Object} [options]
4266
- * @param {string} [options.cacheName] Cache name to store and retrieve
4266
+ * @param {string} [options.cacheName] Cache title to store and retrieve
4267
4267
  * requests. Defaults to the cache names provided by
4268
4268
  * {@link workbox-core.cacheNames}.
4269
4269
  * @param {Array<Object>} [options.plugins] {@link https://developers.google.com/web/tools/workbox/guides/using-plugins|Plugins}
@@ -4777,7 +4777,7 @@ define(["exports"], function (exports) {
4777
4777
  * [`cache.match()`](https://developer.mozilla.org/en-US/docs/Web/API/Cache/match)
4778
4778
  * with the following differences:
4779
4779
  *
4780
- * - It knows what the name of the precache is, and only checks in that cache.
4780
+ * - It knows what the title of the precache is, and only checks in that cache.
4781
4781
  * - It allows you to pass in an "original" URL without versioning parameters,
4782
4782
  * and it will automatically look up the correct cache key for the currently
4783
4783
  * active revision of that URL.
@@ -4866,7 +4866,7 @@ define(["exports"], function (exports) {
4866
4866
  *
4867
4867
  * @param {URL} urlObject The original URL.
4868
4868
  * @param {Array<RegExp>} ignoreURLParametersMatching RegExps to test against
4869
- * each search parameter name. Matches mean that the search parameter should be
4869
+ * each search parameter title. Matches mean that the search parameter should be
4870
4870
  * ignored.
4871
4871
  * @return {URL} The URL with any ignored search parameters removed.
4872
4872
  *
@@ -5118,7 +5118,7 @@ define(["exports"], function (exports) {
5118
5118
  * This should be safe to use as long as you don't include `substringToFind`
5119
5119
  * (defaulting to `-precache-`) in your non-precache cache names.
5120
5120
  *
5121
- * @param {string} currentPrecacheName The cache name currently in use for
5121
+ * @param {string} currentPrecacheName The cache title currently in use for
5122
5122
  * precaching. This cache won't be deleted.
5123
5123
  * @param {string} [substringToFind='-precache-'] Cache names which include this
5124
5124
  * substring will be deleted (excluding `currentPrecacheName`).
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bbki.ng/site",
3
- "version": "1.1.28",
3
+ "version": "1.2.1",
4
4
  "description": "code behind bbki.ng",
5
5
  "main": "index.js",
6
6
  "scripts": {
@@ -16,7 +16,7 @@
16
16
  "url": "git+https://github.com/bbbottle/bbki.ng.git"
17
17
  },
18
18
  "dependencies": {
19
- "@bbki.ng/components": "workspace:2.1.43",
19
+ "@bbki.ng/components": "workspace:2.2.0",
20
20
  "@supabase/supabase-js": "^1.30.6",
21
21
  "classnames": "2.3.1",
22
22
  "react": "^18.0.0",
@@ -25,10 +25,10 @@
25
25
  "react-hotkeys-hook": "^3.4.3",
26
26
  "react-router-dom": "6",
27
27
  "sonner": "1.4.0",
28
- "swr": "^1.2.1"
28
+ "swr": "^2.2.5"
29
29
  },
30
30
  "devDependencies": {
31
- "@bbki.ng/stylebase": "workspace:0.0.22",
31
+ "@bbki.ng/stylebase": "workspace:0.1.0",
32
32
  "@mdx-js/mdx": "2.0.0-next.9",
33
33
  "@mdx-js/react": "^1.6.22",
34
34
  "@mdx-js/rollup": "3.0.0",
@@ -10,15 +10,18 @@ import { SpinnerDemo } from "@/demo/SpinnerDemo";
10
10
  import { DemoBox } from "@/demo/DemoBox";
11
11
 
12
12
  <SpinnerDemo />
13
- ## 前言
14
- >《她》是讲述在不远的未来人与人工智能相爱的科幻爱情电影。主人公西奥多(杰昆·菲尼克斯 Joaquin Phoenix 饰)是一位信件撰写人,心思细腻而深邃,能写出最感人肺腑的信件。他刚结束与妻子凯瑟琳(鲁妮·玛拉 Rooney Mara 饰)的婚姻,还没走出心碎的阴影。一次偶然机会让他接触到最新的人工智能系统 OS1 ……
13
+ ## 前言 >《她》是讲述在不远的未来人与人工智能相爱的科幻爱情电影。主人公西奥多(杰昆·菲尼克斯
14
+ Joaquin Phoenix 饰)是一位信件撰写人,心思细腻而深邃,能写出最感人肺腑的信件。他刚结束与妻子凯瑟琳(鲁妮·玛拉
15
+ Rooney Mara 饰)的婚姻,还没走出心碎的阴影。一次偶然机会让他接触到最新的人工智能系统
16
+ OS1 ……
15
17
 
16
18
  相信大多数人,在看这部电影的时候,不仅仅会被剧情打动,也会被电影的镜头美学吸引。《她》呈现出一个没有被冷酷金属主导的科幻世界,那里光线柔和,色调温暖。人们的着装跟我们并没有太大区别,但是人工智能操作系统能完成的事情以及普及程度,现在看来很难想象。有意思的是,技术的发展并没有消灭「加载时间」,OS1 在安装的时候,西奥多依然需要等待。屏幕上精美的加载动画给我留下深刻的印象,从那时候起,就希望动画能出现在我的网站上。
17
19
 
18
20
  ## 灵感
21
+
19
22
  根据 Atwood's Law
20
23
 
21
- > Any application that _can_ be written in JavaScript, _will_ eventually be written in JavaScript.
24
+ > Any application that *can* be written in JavaScript, *will* eventually be written in JavaScript.
22
25
 
23
26
  肯定有人已经用 JS 实现 OS1 系统的加载动画。没错,这个人是 [@psyonline](https://codepen.io/psyonline),他的[在线示例](https://codepen.io/psyonline/pen/yayYWg)也非常惊艳。
24
27
  那么,直接复制粘贴过来可以吗?该示例使用 Three.js 实现,写这篇文章的时候,根据 [bundlephobia](https://bundlephobia.com/package/three@0.142.0) 显示,`three@142.0` 压缩后仍然有 `596.9kB`。对于个人网站,仅仅用来实现一个加载动画,无疑很不划算。
@@ -29,16 +32,21 @@ import { DemoBox } from "@/demo/DemoBox";
29
32
  - [W](https://xem.github.io/W/)
30
33
 
31
34
  前者压缩后,只有 `5.4KB`。正是我想找的工具。接下来,只需要 3 步就能实现文首的动画:
35
+
32
36
  1. 熟悉 phenomenon 的 API
33
37
  2. 用 phenomenon 绘制曲线
34
38
  3. 让曲线动起来
35
39
 
36
40
  ## 行动
41
+
37
42
  ### WebGL
43
+
38
44
  进行第一步时,发现自己还完全不了解 WebGL。看完 [The Book of Shaders](https://thebookofshaders.com/) 后,能基本理解 phenomenon 的[示例](https://codepen.io/collection/AOpMrm/)。至此,已经可以复制粘贴示例并修修改改,验证书中的概念和自己的理解。直到手痒痒想绘制自己想要的曲线,就进行到下一步。
39
45
 
40
46
  ### Curve
47
+
41
48
  @psyonline [示例](https://codepen.io/psyonline/pen/yayYWg)中不难找到绘制曲线的代码:
49
+
42
50
  ```
43
51
  function(percent) {
44
52
  var x = length*Math.sin(pi2*percent)
@@ -61,6 +69,7 @@ function(percent) {
61
69
  ```
62
70
 
63
71
  我的主要目标变成移植这段代码,其中 `pi2`, `length` 和 `radius` 均为常量,原文取值:
72
+
64
73
  ```
65
74
  const length = 30;
66
75
  const radius = 5.6;
@@ -68,10 +77,11 @@ const pi2 = Math.PI * 2;
68
77
  ```
69
78
 
70
79
  还有一个比较重要的参数 `percent`,打印发现取值范围为 0 到 1。有了这些,我愉快的写好 phenomenon 的 attributes:
80
+
71
81
  ```
72
82
  const attributes = [
73
83
  {
74
- name: 'pos',
84
+ title: 'pos',
75
85
  data: (index: number, total: number) => {
76
86
  const percent = index / total;
77
87
  // ...
@@ -84,13 +94,17 @@ const attributes = [
84
94
  },
85
95
  ]
86
96
  ```
97
+
87
98
  然后得到一个空白的画布
99
+
88
100
  <DemoBox />
89
101
 
90
102
  因为对 WebGL 的了解依然接近于 0 在胡乱猜测并修改一通后,画布依然一片空白,于是沮丧放弃。直到晚上,突然想着将半径和长度都降低两个数量级,画布中终于出现一个扭曲的麻花。上次这么开心还是上一次。
91
103
 
92
104
  ### Matrix
105
+
93
106
  现在可以回想一下大学课堂线性代数中矩阵运算的知识。回想不起来也没关系,如果有一个正在念大学的弟弟的话,他会帮助写出 `rotate` 方法。
107
+
94
108
  ```
95
109
  export const VERTEX_SHADER = `
96
110
  attribute vec3 pos;
@@ -121,6 +135,7 @@ export const VERTEX_SHADER = `
121
135
  这些碎片代码,和碎片想法,最终组装出心心念念的动画。
122
136
 
123
137
  ## 参考链接
138
+
124
139
  1. https://codepen.io/psyonline/pen/yayYWg
125
140
  2. https://twitter.com/shuding_/status/1475916082875666441
126
141
  3. https://thebookofshaders.com/
@@ -42,12 +42,12 @@ export const PHOTO_PROJECTS: PhotoProject[] = [
42
42
  ],
43
43
  },
44
44
  // {
45
- // name: "光前",
45
+ // title: "光前",
46
46
  // description: "城中村,个人深圳经历出入口。",
47
47
  // images: [OSS_PHOTOS.oldMan, OSS_PHOTOS.oldWomen, OSS_PHOTOS.littleChild],
48
48
  // },
49
49
  // {
50
- // name: "三百零一",
50
+ // title: "三百零一",
51
51
  // description: "陋室光影",
52
52
  // images: [OSS_PHOTOS.phone, OSS_PHOTOS.chair],
53
53
  // },
@@ -20,6 +20,7 @@ export const API_ENDPOINT = "https://api.bbki.ng";
20
20
  export const API = {
21
21
  PROJECTS: "projects",
22
22
  UPLOAD_IMG: "upload",
23
+ POST: "post",
23
24
  MOVIES: "movies",
24
25
  IMAGES: "images",
25
26
  BOOKS: "books",
@@ -0,0 +1,7 @@
1
+ import { useSupabaseSession } from "@/hooks/use_supa_session";
2
+
3
+ export const useAuthed = (): boolean => {
4
+ const { access_token: token, isKing } = useSupabaseSession() || {};
5
+
6
+ return !(!token || !isKing);
7
+ };
@@ -0,0 +1,8 @@
1
+ import { useSupabaseSession } from "@/hooks/use_supa_session";
2
+ import { apiFetcher, withToken } from "@/utils";
3
+ import { useCallback } from "react";
4
+
5
+ export const useAuthedFetcher = () => {
6
+ const { access_token: token } = useSupabaseSession() || {};
7
+ return useCallback(withToken(apiFetcher)(token), [token]);
8
+ };
@@ -0,0 +1,33 @@
1
+ import { useTextPlainFile } from "@/hooks/use_text_plain_file";
2
+ import { useContext, useEffect } from "react";
3
+ import { usePost } from "@/hooks/use_post";
4
+ import { GlobalLoadingContext } from "@/global_loading_state_provider";
5
+
6
+ export type fileReader = (f: File) => void;
7
+ export const useFile2Post = (): fileReader => {
8
+ const { content, title, reader } = useTextPlainFile();
9
+
10
+ const { setIsLoading } = useContext(GlobalLoadingContext);
11
+
12
+ const post = usePost();
13
+
14
+ useEffect(() => {
15
+ if (!content || !title) {
16
+ return;
17
+ }
18
+
19
+ setIsLoading(true);
20
+
21
+ post(title, content)
22
+ .then((r) => {
23
+ console.log(r);
24
+ })
25
+ .finally(() => {
26
+ setIsLoading(false);
27
+ });
28
+ }, [title, content]);
29
+
30
+ return (f: File) => {
31
+ reader(f);
32
+ };
33
+ };
@@ -0,0 +1,26 @@
1
+ import { useCallback } from "react";
2
+ import { API } from "@/constants/routes";
3
+ import { useAuthedFetcher } from "@/hooks/use_authed_fetcher";
4
+
5
+ export const usePost = () => {
6
+ const authedFetcher = useAuthedFetcher();
7
+
8
+ const req = useCallback(
9
+ async (
10
+ url: string,
11
+ { arg }: { arg: { title: string; content: string } }
12
+ ) => {
13
+ return authedFetcher(url, {
14
+ method: "POST",
15
+ body: JSON.stringify(arg),
16
+ });
17
+ },
18
+ [authedFetcher]
19
+ );
20
+
21
+ return useCallback(
22
+ (title: string, content: string) =>
23
+ req(API.POSTS, { arg: { title, content } }),
24
+ [req]
25
+ );
26
+ };
@@ -26,7 +26,9 @@ export const useProjects = (name: string = "", suspense?: boolean) => {
26
26
  if (!n) {
27
27
  return;
28
28
  }
29
- return cache.get("projects")?.find((p: { name: string }) => p.name === n);
29
+ return cache
30
+ .get("projects")
31
+ ?.data.find((p: { name: string }) => p.name === n);
30
32
  };
31
33
 
32
34
  const refresh = useCallback(() => {
@@ -0,0 +1,36 @@
1
+ import { useEffect, useState } from "react";
2
+
3
+ export type Result = {
4
+ content: string;
5
+ title: string;
6
+ reader: (f: File) => void;
7
+ };
8
+
9
+ export const useTextPlainFile = (): Result => {
10
+ const [content, setContent] = useState("");
11
+ const [file, setFile] = useState<File | null>(null);
12
+
13
+ const reader = new FileReader();
14
+
15
+ useEffect(() => {
16
+ if (file != null) {
17
+ reader.readAsText(file, "utf-8");
18
+ }
19
+
20
+ reader.onload = function () {
21
+ setContent(reader.result as string);
22
+ };
23
+
24
+ return () => {
25
+ reader.onload = null;
26
+ };
27
+ }, [file]);
28
+
29
+ return {
30
+ content,
31
+ title: file?.name ?? "",
32
+ reader: (f: File) => {
33
+ setFile(f);
34
+ },
35
+ };
36
+ };
@@ -1,9 +1,11 @@
1
1
  import React from "react";
2
2
  import { ArticleList } from "./consts";
3
- import { LinkList, LinkProps } from "@bbki.ng/components";
3
+ import { LinkProps, DropZone } from "@bbki.ng/components";
4
4
  import { useRouteName } from "@/hooks";
5
5
  import { usePosts } from "@/hooks/use_posts";
6
- import { CenterLinkList, MySuspense } from "@/components";
6
+ import { CenterLinkList } from "@/components";
7
+ import { useAuthed } from "@/hooks/use_authed";
8
+ import { useFile2Post } from "@/hooks/use_file_to_post";
7
9
 
8
10
  type TxtProps = {
9
11
  title?: string;
@@ -30,9 +32,12 @@ const Posts = (props: TxtProps) => {
30
32
  };
31
33
 
32
34
  export default (props: TxtProps) => {
35
+ const reader = useFile2Post();
36
+ const isKing = useAuthed();
37
+
33
38
  return (
34
- // <MySuspense>
35
- <Posts {...props} />
36
- // </MySuspense>
39
+ <DropZone onDrop={reader} disabled={!isKing}>
40
+ <Posts {...props} />
41
+ </DropZone>
37
42
  );
38
43
  };
@@ -2,7 +2,9 @@ import { Photo } from "@/types/photo";
2
2
  import { ossProcessType } from "@/types/oss";
3
3
  import { API_ENDPOINT, OSS_ADDRESS } from "@/constants/routes";
4
4
  import { DEFAULT_DELAY } from "@/constants";
5
- import useSWR, { Fetcher } from "swr";
5
+ import useSWR from "swr";
6
+
7
+ type Fetcher = (resource: string, init?: any) => Promise<any>;
6
8
 
7
9
  export const floatNumberToPercentageString = (num: number): string => {
8
10
  return `${num * 100}%`;
@@ -96,7 +98,7 @@ export const withToken =
96
98
  };
97
99
 
98
100
  export const withBBApi =
99
- (fetcher: Fetcher<Promise<void>>) =>
101
+ (fetcher: Fetcher) =>
100
102
  (apiEndPoint = API_ENDPOINT): Fetcher =>
101
103
  async (resource: string, init: RequestInit = {}) =>
102
104
  fetcher(`${apiEndPoint}/${resource}`, { ...init, mode: "cors" });