bb-relay 0.0.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.
Files changed (100) hide show
  1. package/.husky/pre-commit +1 -0
  2. package/README.md +47 -0
  3. package/dist/chunk-S47CVTVK.mjs +33 -0
  4. package/dist/chunk-UJCSKKID.mjs +30 -0
  5. package/dist/dev.d.mts +11 -0
  6. package/dist/dev.d.ts +11 -0
  7. package/dist/dev.js +5028 -0
  8. package/dist/dev.mjs +4991 -0
  9. package/dist/index.d.mts +666 -0
  10. package/dist/index.d.ts +666 -0
  11. package/dist/index.js +405 -0
  12. package/dist/index.mjs +376 -0
  13. package/eslint.config.mts +19 -0
  14. package/jest.config.js +11 -0
  15. package/package.json +60 -0
  16. package/src/dev.ts +4 -0
  17. package/src/index.ts +72 -0
  18. package/src/load-virtual-editor/app/StatusState.ts +6 -0
  19. package/src/load-virtual-editor/app/css.ts +154 -0
  20. package/src/load-virtual-editor/app/store.ts +25 -0
  21. package/src/load-virtual-editor/events/handle-dir-update.ts +23 -0
  22. package/src/load-virtual-editor/events/handle-file-update.ts +23 -0
  23. package/src/load-virtual-editor/events/handle-load.ts +39 -0
  24. package/src/load-virtual-editor/events/handle-selected.ts +30 -0
  25. package/src/load-virtual-editor/index.ts +52 -0
  26. package/src/load-virtual-editor/lib/indexedStorage.ts +28 -0
  27. package/src/load-virtual-editor/mocks/generate-files.ts +25 -0
  28. package/src/load-virtual-editor/node/NodeState.ts +23 -0
  29. package/src/load-virtual-editor/node/copyDir.ts +14 -0
  30. package/src/load-virtual-editor/node/copyFile.ts +14 -0
  31. package/src/load-virtual-editor/node/createDir.ts +10 -0
  32. package/src/load-virtual-editor/node/createFile.ts +13 -0
  33. package/src/load-virtual-editor/node/deleteDir.ts +10 -0
  34. package/src/load-virtual-editor/node/deleteFile.ts +13 -0
  35. package/src/load-virtual-editor/node/formatPath.ts +13 -0
  36. package/src/load-virtual-editor/node/formatText.ts +19 -0
  37. package/src/load-virtual-editor/node/generateDirs.ts +13 -0
  38. package/src/load-virtual-editor/node/getDescendantLevel.ts +9 -0
  39. package/src/load-virtual-editor/node/getDirInfo.ts +33 -0
  40. package/src/load-virtual-editor/node/getFileInfo.ts +31 -0
  41. package/src/load-virtual-editor/node/getFiles.ts +17 -0
  42. package/src/load-virtual-editor/node/getParent.ts +11 -0
  43. package/src/load-virtual-editor/node/readDir.ts +41 -0
  44. package/src/load-virtual-editor/node/readFile.ts +46 -0
  45. package/src/load-virtual-editor/node/store.ts +206 -0
  46. package/src/load-virtual-editor/node/watch.ts +9 -0
  47. package/src/load-virtual-editor/node/writeFile.ts +21 -0
  48. package/src/load-virtual-editor/postResponse.ts +21 -0
  49. package/src/load-virtual-editor/request/requestFS.ts +199 -0
  50. package/src/load-virtual-editor/request/requestSelected.ts +45 -0
  51. package/src/load-virtual-editor/selected/SelectedState.ts +7 -0
  52. package/src/load-virtual-editor/selected/selectDir.ts +13 -0
  53. package/src/load-virtual-editor/selected/selectFile.ts +13 -0
  54. package/src/load-virtual-editor/selected/store.ts +27 -0
  55. package/src/load-virtual-editor/selected/watch.ts +9 -0
  56. package/src/locales/en-GB.ts +117 -0
  57. package/src/locales/fr-FR.ts +125 -0
  58. package/src/relay/index.ts +89 -0
  59. package/src/relay/registerEvent.ts +16 -0
  60. package/src/relay/registerRequest.ts +16 -0
  61. package/src/relay/storage-bridge.ts +71 -0
  62. package/src/types/BBEvent.ts +51 -0
  63. package/src/types/BBRequest.ts +8 -0
  64. package/src/types/Checkpoint.ts +11 -0
  65. package/src/types/CopyArg.ts +6 -0
  66. package/src/types/DirectoryContents.ts +4 -0
  67. package/src/types/DirectoryStats.ts +4 -0
  68. package/src/types/EventParam.ts +8 -0
  69. package/src/types/EventReturn.ts +9 -0
  70. package/src/types/FileContent.ts +9 -0
  71. package/src/types/GitFileStatus.ts +5 -0
  72. package/src/types/IconArg.ts +6 -0
  73. package/src/types/Language.ts +5 -0
  74. package/src/types/Locale.ts +3 -0
  75. package/src/types/MenuContent.ts +10 -0
  76. package/src/types/Nav.ts +3 -0
  77. package/src/types/PluginItem.ts +14 -0
  78. package/src/types/RenameType.ts +4 -0
  79. package/src/types/RequestParam.ts +9 -0
  80. package/src/types/RequestReturn.ts +11 -0
  81. package/src/types/Result.ts +6 -0
  82. package/src/types/Route.ts +1 -0
  83. package/src/types/Settings.ts +7 -0
  84. package/src/types/TutorialHeader.ts +10 -0
  85. package/src/types/User.ts +9 -0
  86. package/src/types/WatchFSEvent.ts +1 -0
  87. package/src/types/database.types.ts +266 -0
  88. package/src/types/dir/DirInfo.ts +10 -0
  89. package/src/types/dir/index.ts +32 -0
  90. package/src/types/files/FileInfo.ts +12 -0
  91. package/src/types/files/FileTypes.ts +13 -0
  92. package/src/types/files/ReadFile.ts +17 -0
  93. package/src/types/files/index.ts +31 -0
  94. package/src/types/project/Project.ts +35 -0
  95. package/src/types/project/index.ts +11 -0
  96. package/src/types/status/Load.ts +16 -0
  97. package/src/types/storage/index.ts +11 -0
  98. package/src/utils/inject-styles.ts +13 -0
  99. package/tsconfig.json +20 -0
  100. package/tsup.config.ts +16 -0
@@ -0,0 +1,41 @@
1
+ import formatPath from "./formatPath";
2
+ import { getDescendantLevel } from "./getDescendantLevel";
3
+ import { nodeStore } from "./store";
4
+
5
+ export function readDir(
6
+ path: string,
7
+ callback: (
8
+ err: Error | null,
9
+ data: { path: string; type: "file" | "dir" }[]
10
+ ) => void
11
+ ) {
12
+ try {
13
+ const dirList = nodeStore
14
+ .getState()
15
+ .directories.filter(
16
+ (dir) =>
17
+ dir.startsWith(path) &&
18
+ formatPath(dir) !== formatPath(path) &&
19
+ getDescendantLevel(dir, path) === 1
20
+ );
21
+ const fileList = nodeStore
22
+ .getState()
23
+ .files.filter((file) => formatPath(file.directory) === formatPath(path));
24
+ const dir: { path: string; type: "file" | "dir" }[] = dirList.map(
25
+ (dir) => ({
26
+ path: dir,
27
+ type: "dir",
28
+ })
29
+ );
30
+ const files: { path: string; type: "file" | "dir" }[] = fileList.map(
31
+ (file) => ({
32
+ path: formatPath(`${file.directory}/${file.name}`),
33
+ type: "file",
34
+ })
35
+ );
36
+ const data: { path: string; type: "file" | "dir" }[] = [...dir, ...files];
37
+ callback(null, data);
38
+ } catch (err) {
39
+ callback(err as Error, []);
40
+ }
41
+ }
@@ -0,0 +1,46 @@
1
+ import { stringToBinary } from "./formatText";
2
+ import { nodeStore } from "./store";
3
+
4
+ export default function readFile(
5
+ arg: { path: string; type: "text" | "binary" },
6
+ callback: (
7
+ err: Error | null,
8
+ data:
9
+ | {
10
+ type: "text";
11
+ data: string | null;
12
+ }
13
+ | {
14
+ type: "binary";
15
+ data: Uint8Array | null;
16
+ }
17
+ ) => void
18
+ ) {
19
+ try {
20
+ const fullPath = arg.path.split("/");
21
+ const dir = fullPath.slice(0, -1);
22
+ const name = fullPath.slice(-1)[0];
23
+ const parentPath = dir.join("/");
24
+ const file = nodeStore
25
+ .getState()
26
+ .files.find(
27
+ (item) => item.directory === parentPath && item.name === name
28
+ );
29
+ if (!file) throw new Error(`File not found: ${arg.path}`);
30
+ if (arg.type === "text")
31
+ callback(null, {
32
+ type: "text",
33
+ data: file.content,
34
+ });
35
+ else
36
+ callback(null, {
37
+ type: "binary",
38
+ data: stringToBinary(file.content),
39
+ });
40
+ } catch (err) {
41
+ callback(err as Error, {
42
+ type: arg.type,
43
+ data: null,
44
+ });
45
+ }
46
+ }
@@ -0,0 +1,206 @@
1
+ import { create } from "zustand";
2
+ import { createJSONStorage, persist } from "zustand/middleware";
3
+ import formatPath from "./formatPath";
4
+ import { getParent } from "./getParent";
5
+ import { NodeState } from "./NodeState";
6
+ import { generateDirs } from "./generateDirs";
7
+ import { indexedStorage } from "@/load-virtual-editor/lib/indexedStorage";
8
+
9
+ export const nodeStore = create<NodeState>()(
10
+ persist(
11
+ (set) => ({
12
+ directories: [],
13
+ files: [],
14
+ addDir: (path: string) => {
15
+ const allDirs = generateDirs(path, nodeStore.getState().directories);
16
+ set({
17
+ directories: allDirs,
18
+ record: {
19
+ file: null,
20
+ dir: getParent(path),
21
+ },
22
+ });
23
+ },
24
+ addFile: (arg: { path: string; content?: string }) => {
25
+ const allFiles = nodeStore.getState().files;
26
+
27
+ const file = allFiles.find(
28
+ (item) =>
29
+ formatPath(`${item.directory}/${item.name}`) ===
30
+ formatPath(arg.path)
31
+ );
32
+ if (file) throw new Error(`File already exist: ${arg.path}`);
33
+ const fullPath = arg.path.split("/").filter((item) => item);
34
+ const dir = fullPath.slice(0, -1);
35
+ const name = formatPath(fullPath.slice(-1)[0]);
36
+ const parentPath = formatPath(dir.join("/"));
37
+
38
+ const dirs = generateDirs(
39
+ parentPath || "",
40
+ nodeStore.getState().directories
41
+ );
42
+ set({
43
+ files: [
44
+ ...allFiles,
45
+ {
46
+ directory: parentPath,
47
+ name,
48
+ content: arg.content ?? "",
49
+ createdAt: new Date().toISOString(),
50
+ modifiedAt: new Date().toISOString(),
51
+ },
52
+ ],
53
+ directories: dirs,
54
+ record: {
55
+ file: formatPath(arg.path),
56
+ dir: getParent(arg.path),
57
+ },
58
+ });
59
+ },
60
+ removeDir: (path: string) => {
61
+ const dirs = nodeStore.getState().directories;
62
+ const newDirs = dirs.filter((dir) => !dir.startsWith(path));
63
+ if (newDirs.length === dirs.length)
64
+ throw new Error(`Path not found: ${path}`);
65
+ const files = nodeStore.getState().files;
66
+ set({
67
+ directories: newDirs,
68
+ files: files.filter((file) => !file.directory.startsWith(path)),
69
+ record: {
70
+ file: null,
71
+ dir: getParent(path),
72
+ },
73
+ });
74
+ },
75
+ removeFile: (path) => {
76
+ const files = nodeStore.getState().files;
77
+ const file = files.find(
78
+ (item) =>
79
+ formatPath(`${item.directory}/${item.name}`) === formatPath(path)
80
+ );
81
+ if (!file) throw new Error(`File not found: ${path}`);
82
+ set({
83
+ files: files.filter(
84
+ (file) =>
85
+ formatPath(`${file.directory}/${file.name}`) !== formatPath(path)
86
+ ),
87
+ record: {
88
+ file: null,
89
+ dir: getParent(path),
90
+ },
91
+ });
92
+ },
93
+ copyDir: (source: string, destination: string) => {
94
+ const files = nodeStore.getState().files;
95
+ const directories = nodeStore.getState().directories;
96
+ const matchingSource = directories.find((path) => path === source);
97
+ if (!matchingSource) throw new Error(`Dir does not exist: ${source}`);
98
+ const matchingDestination = directories.find(
99
+ (path) => path === destination
100
+ );
101
+ if (matchingDestination)
102
+ throw new Error(`Destination already exist: ${destination}`);
103
+ const nestedFiles = files.filter((item) =>
104
+ nestedDirectories.includes(item.directory)
105
+ );
106
+ const nestedDirectories = directories.filter((dir) =>
107
+ dir.startsWith(source)
108
+ );
109
+ const newContent = nestedFiles.map((item) => ({
110
+ ...item,
111
+ directory: item.directory.replace(source, destination),
112
+ }));
113
+ const newDirectories = nestedDirectories.map((item) =>
114
+ item.replace(source, destination)
115
+ );
116
+ set({
117
+ files: [...files, ...newContent],
118
+ directories: [...directories, ...newDirectories],
119
+ record: {
120
+ file: null,
121
+ dir: getParent(destination),
122
+ },
123
+ });
124
+ },
125
+ copyFile: (source: string, destination: string) => {
126
+ const files = nodeStore.getState().files;
127
+ const matchingFile = files.find(
128
+ (item) =>
129
+ formatPath(`${item.directory}/${item.name}`) === formatPath(source)
130
+ );
131
+ if (!matchingFile) throw new Error(`Source not found: ${source}`);
132
+ const matchingDestination = files.find(
133
+ (item) =>
134
+ formatPath(`${item.directory}/${item.name}`) ===
135
+ formatPath(destination)
136
+ );
137
+ if (matchingDestination)
138
+ throw new Error(`Destination already exist: ${destination}`);
139
+ const addFile = nodeStore.getState().addFile;
140
+ addFile({
141
+ path: destination,
142
+ content: matchingFile.content,
143
+ });
144
+ },
145
+ writeFile: (arg: { path: string; content: string }) => {
146
+ const allFiles = nodeStore.getState().files;
147
+
148
+ const file = allFiles.find(
149
+ (item) =>
150
+ formatPath(`${item.directory}/${item.name}`) ===
151
+ formatPath(arg.path)
152
+ );
153
+ if (!file) throw new Error(`File does not exist: ${arg.path}`);
154
+ const fullPath = arg.path.split("/");
155
+ const dir = fullPath.slice(0, -1);
156
+ const name = fullPath.slice(-1)[0];
157
+ const parentPath = dir.join("/");
158
+
159
+ set({
160
+ files: [
161
+ ...allFiles.filter(
162
+ (item) => item.directory !== parentPath || item.name !== name
163
+ ),
164
+ {
165
+ directory: parentPath,
166
+ name,
167
+ content: arg.content,
168
+ modifiedAt: new Date().toISOString(),
169
+ createdAt: file.createdAt,
170
+ },
171
+ ],
172
+ record: {
173
+ file: arg.path,
174
+ dir: null,
175
+ },
176
+ });
177
+ },
178
+ record: {
179
+ file: null,
180
+ dir: null,
181
+ },
182
+ addFiles: (files: { path: string; content?: string }[]) => {
183
+ files.forEach(({ path, content }) => {
184
+ const allFiles = nodeStore.getState().files;
185
+ const existingFile = allFiles.find(
186
+ (item) =>
187
+ formatPath(`${item.directory}/${item.name}`) === formatPath(path)
188
+ );
189
+
190
+ if (!existingFile) {
191
+ const addFile = nodeStore.getState().addFile;
192
+ addFile({ path, content });
193
+ }
194
+ });
195
+ },
196
+ reset: () =>
197
+ set({ files: [], directories: [], record: { file: null, dir: null } }),
198
+ }),
199
+ {
200
+ name: "node-storage",
201
+ storage: createJSONStorage(() => indexedStorage),
202
+ }
203
+ )
204
+ );
205
+
206
+ export default nodeStore;
@@ -0,0 +1,9 @@
1
+ import { nodeStore } from "./store";
2
+
3
+ export function watch(
4
+ callback: (data: { file: string | null; dir: string | null }) => void
5
+ ) {
6
+ nodeStore.subscribe((curr) => {
7
+ callback(curr.record);
8
+ });
9
+ }
@@ -0,0 +1,21 @@
1
+ import { TextFile, BinaryFile } from "@/types/BBRequest";
2
+ import { nodeStore } from "./store";
3
+
4
+ export function writeFile(
5
+ arg: TextFile | BinaryFile,
6
+ callback: (err: Error | null) => void
7
+ ) {
8
+ try {
9
+ if (arg.type === "text") nodeStore.getState().writeFile(arg);
10
+ else {
11
+ const text = new TextDecoder().decode(arg.content);
12
+ nodeStore.getState().writeFile({
13
+ path: arg.path,
14
+ content: text,
15
+ });
16
+ }
17
+ callback(null);
18
+ } catch (err) {
19
+ callback(err as Error);
20
+ }
21
+ }
@@ -0,0 +1,21 @@
1
+ import BBEvent from "@/types/BBEvent";
2
+ import EventReturn from "@/types/EventReturn";
3
+ import BBRequest from "@/types/BBRequest";
4
+ import RequestReturn from "@/types/RequestReturn";
5
+
6
+ function postResponse<K extends keyof BBRequest>(
7
+ iframe: HTMLIFrameElement | null,
8
+ response: RequestReturn<K>
9
+ ): void;
10
+ function postResponse<K extends keyof BBEvent>(
11
+ iframe: HTMLIFrameElement | null,
12
+ response: EventReturn<K>
13
+ ): void;
14
+ function postResponse<K extends keyof (BBRequest | BBEvent)>(
15
+ iframe: HTMLIFrameElement | null,
16
+ response: RequestReturn<K> | EventReturn<K>
17
+ ) {
18
+ iframe?.contentWindow?.postMessage(response, "*");
19
+ }
20
+
21
+ export default postResponse;
@@ -0,0 +1,199 @@
1
+ import BBRequest from "@/types/BBRequest";
2
+ import { getFiles } from "../node/getFiles";
3
+ import { writeFile } from "../node/writeFile";
4
+ import { copyFile } from "../node/copyFile";
5
+ import { copyDir } from "../node/copyDir";
6
+ import { deleteFile } from "../node/deleteFile";
7
+ import { deleteDir } from "../node/deleteDir";
8
+ import { createFile } from "../node/createFile";
9
+ import { createDir } from "../node/createDir";
10
+ import { readDir } from "../node/readDir";
11
+ import readFile from "../node/readFile";
12
+ import RequestParam from "@/types/RequestParam";
13
+ import postResponse from "../postResponse";
14
+ import RequestReturn from "@/types/RequestReturn";
15
+ import { getDirInfo } from "../node/getDirInfo";
16
+ import { getFileInfo } from "../node/getFileInfo";
17
+
18
+ export default function requestFS<K extends keyof BBRequest>({
19
+ sidebar,
20
+ main,
21
+ request,
22
+ }: {
23
+ sidebar: HTMLIFrameElement | null;
24
+ main: HTMLIFrameElement | null;
25
+ request: RequestParam<K>;
26
+ }) {
27
+ if (request.type === "create-dir") {
28
+ const req = request as RequestParam<"create-dir">;
29
+ createDir(req.arg.path, (err) => {
30
+ const res: RequestReturn<"create-dir"> = {
31
+ id: req.id,
32
+ type: "create-dir",
33
+ response: null,
34
+ error: err?.message || null,
35
+ responseId: crypto.randomUUID(),
36
+ };
37
+ postResponse(sidebar, res);
38
+ postResponse(main, res);
39
+ });
40
+ }
41
+ if (request.type === "delete-dir") {
42
+ const req = request as RequestParam<"delete-dir">;
43
+ deleteDir(req.arg.path, (err) => {
44
+ const res: RequestReturn<"delete-dir"> = {
45
+ id: req.id,
46
+ type: "delete-dir",
47
+ response: null,
48
+ error: err?.message || null,
49
+ responseId: crypto.randomUUID(),
50
+ };
51
+ postResponse(sidebar, res);
52
+ postResponse(main, res);
53
+ });
54
+ }
55
+ if (request.type === "delete-file") {
56
+ const req = request as RequestParam<"delete-file">;
57
+ deleteFile(req.arg.path, (err) => {
58
+ const res: RequestReturn<"delete-file"> = {
59
+ id: req.id,
60
+ type: "delete-file",
61
+ response: null,
62
+ error: err?.message || null,
63
+ responseId: crypto.randomUUID(),
64
+ };
65
+ postResponse(sidebar, res);
66
+ postResponse(main, res);
67
+ });
68
+ }
69
+ if (request.type === "copy-dir") {
70
+ const req = request as RequestParam<"copy-dir">;
71
+ copyDir(req.arg.source, req.arg.destination, (err) => {
72
+ const res: RequestReturn<"copy-dir"> = {
73
+ id: req.id,
74
+ type: "copy-dir",
75
+ response: null,
76
+ error: err?.message || null,
77
+ responseId: crypto.randomUUID(),
78
+ };
79
+ postResponse(sidebar, res);
80
+ postResponse(main, res);
81
+ });
82
+ }
83
+ if (request.type === "copy-file") {
84
+ const req = request as RequestParam<"copy-file">;
85
+ copyFile(req.arg.source, req.arg.destination, (err) => {
86
+ const res: RequestReturn<"copy-file"> = {
87
+ id: req.id,
88
+ type: "copy-file",
89
+ response: null,
90
+ error: err?.message || null,
91
+ responseId: crypto.randomUUID(),
92
+ };
93
+ postResponse(sidebar, res);
94
+ postResponse(main, res);
95
+ });
96
+ }
97
+ if (request.type === "read-dir") {
98
+ const req = request as RequestParam<"read-dir">;
99
+ readDir(req.arg.path, (err, data) => {
100
+ const res: RequestReturn<"read-dir"> = {
101
+ id: req.id,
102
+ type: "read-dir",
103
+ response: data,
104
+ error: err?.message || null,
105
+ responseId: crypto.randomUUID(),
106
+ };
107
+ postResponse(sidebar, res);
108
+ postResponse(main, res);
109
+ });
110
+ }
111
+ if (request.type === "create-file") {
112
+ const req = request as RequestParam<"create-file">;
113
+ createFile(req.arg, (err) => {
114
+ const res: RequestReturn<"create-file"> = {
115
+ id: req.id,
116
+ type: "create-file",
117
+ response: null,
118
+ error: err?.message || null,
119
+ responseId: crypto.randomUUID(),
120
+ };
121
+ postResponse(sidebar, res);
122
+ postResponse(main, res);
123
+ });
124
+ }
125
+ if (request.type === "read-file") {
126
+ const req = request as RequestParam<"read-file">;
127
+ readFile(req.arg, (err, data) => {
128
+ const res: RequestReturn<"read-file"> = {
129
+ id: req.id,
130
+ type: "read-file",
131
+ response: {
132
+ path: req.arg.path,
133
+ type: data.type as "text",
134
+ content: data.data as string,
135
+ },
136
+ error: err?.message || null,
137
+ responseId: crypto.randomUUID(),
138
+ };
139
+ postResponse(sidebar, res);
140
+ postResponse(main, res);
141
+ });
142
+ }
143
+ if (request.type === "get-dir-info") {
144
+ const req = request as RequestParam<"get-dir-info">;
145
+ getDirInfo(req.arg.path, (err, data) => {
146
+ const res: RequestReturn<"get-dir-info"> = {
147
+ id: req.id,
148
+ type: "get-dir-info",
149
+ response: data,
150
+ error: err?.message || null,
151
+ responseId: crypto.randomUUID(),
152
+ };
153
+ postResponse(sidebar, res);
154
+ postResponse(main, res);
155
+ });
156
+ }
157
+ if (request.type === "write-file") {
158
+ const req = request as RequestParam<"write-file">;
159
+ writeFile(req.arg, (err) => {
160
+ const res: RequestReturn<"write-file"> = {
161
+ id: req.id,
162
+ type: "write-file",
163
+ response: null,
164
+ error: err?.message || null,
165
+ responseId: crypto.randomUUID(),
166
+ };
167
+ postResponse(sidebar, res);
168
+ postResponse(main, res);
169
+ });
170
+ }
171
+ if (request.type === "get-files") {
172
+ const req = request as RequestParam<"get-files">;
173
+ getFiles(req.arg.path, (err, data) => {
174
+ const res: RequestReturn<"get-files"> = {
175
+ id: req.id,
176
+ type: "get-files",
177
+ response: data,
178
+ error: err?.message || null,
179
+ responseId: crypto.randomUUID(),
180
+ };
181
+ postResponse(sidebar, res);
182
+ postResponse(main, res);
183
+ });
184
+ }
185
+ if (request.type === "get-file-info") {
186
+ const req = request as RequestParam<"get-file-info">;
187
+ getFileInfo(req.arg.path, (err, data) => {
188
+ const res: RequestReturn<"get-file-info"> = {
189
+ id: req.id,
190
+ type: "get-file-info",
191
+ response: data,
192
+ error: err?.message || null,
193
+ responseId: crypto.randomUUID(),
194
+ };
195
+ postResponse(sidebar, res);
196
+ postResponse(main, res);
197
+ });
198
+ }
199
+ }
@@ -0,0 +1,45 @@
1
+ import BBRequest from "@/types/BBRequest";
2
+ import RequestParam from "@/types/RequestParam";
3
+ import postResponse from "../postResponse";
4
+ import RequestReturn from "@/types/RequestReturn";
5
+ import selectFile from "../selected/selectFile";
6
+ import selectDir from "../selected/selectDir";
7
+
8
+ export default function requestSelected<K extends keyof BBRequest>({
9
+ sidebar,
10
+ main,
11
+ request,
12
+ }: {
13
+ sidebar: HTMLIFrameElement | null;
14
+ main: HTMLIFrameElement | null;
15
+ request: RequestParam<K>;
16
+ }) {
17
+ if (request.type === "select-file") {
18
+ const req = request as RequestParam<"select-file">;
19
+ selectFile(req.arg.path, (err) => {
20
+ const res: RequestReturn<"select-file"> = {
21
+ id: req.id,
22
+ type: "select-file",
23
+ response: null,
24
+ error: err?.message || null,
25
+ responseId: crypto.randomUUID(),
26
+ };
27
+ postResponse(sidebar, res);
28
+ postResponse(main, res);
29
+ });
30
+ }
31
+ if (request.type === "select-dir") {
32
+ const req = request as RequestParam<"select-dir">;
33
+ selectDir(req.arg.path, (err) => {
34
+ const res: RequestReturn<"select-dir"> = {
35
+ id: req.id,
36
+ type: "select-dir",
37
+ response: null,
38
+ error: err?.message || null,
39
+ responseId: crypto.randomUUID(),
40
+ };
41
+ postResponse(sidebar, res);
42
+ postResponse(main, res);
43
+ });
44
+ }
45
+ }
@@ -0,0 +1,7 @@
1
+ export type SelectedState = {
2
+ selectedPath: {
3
+ path: string;
4
+ type: "file" | "dir";
5
+ };
6
+ selectPath: (path: string, type: "file" | "dir") => void;
7
+ };
@@ -0,0 +1,13 @@
1
+ import { selectedStore } from "./store";
2
+
3
+ export default function selectDir(
4
+ path: string,
5
+ callback: (err: Error | null) => void
6
+ ) {
7
+ try {
8
+ selectedStore.getState().selectPath(path, "dir");
9
+ callback(null);
10
+ } catch (err) {
11
+ callback(err as Error);
12
+ }
13
+ }
@@ -0,0 +1,13 @@
1
+ import { selectedStore } from "./store";
2
+
3
+ export default function selectFile(
4
+ path: string,
5
+ callback: (err: Error | null) => void
6
+ ) {
7
+ try {
8
+ selectedStore.getState().selectPath(path, "file");
9
+ callback(null);
10
+ } catch (err) {
11
+ callback(err as Error);
12
+ }
13
+ }
@@ -0,0 +1,27 @@
1
+ import { create } from "zustand";
2
+ import { persist } from "zustand/middleware";
3
+ import { SelectedState } from "./SelectedState";
4
+
5
+ export const selectedStore = create<SelectedState>()(
6
+ persist(
7
+ (set) => ({
8
+ selectedPath: {
9
+ path: "",
10
+ type: "file",
11
+ },
12
+ selectPath: (path: string, type: "file" | "dir") => {
13
+ set({
14
+ selectedPath: {
15
+ path,
16
+ type,
17
+ },
18
+ });
19
+ },
20
+ }),
21
+ {
22
+ name: "selected-storage",
23
+ }
24
+ )
25
+ );
26
+
27
+ export default selectedStore;
@@ -0,0 +1,9 @@
1
+ import { selectedStore } from "./store";
2
+
3
+ export default function watch(
4
+ callback: (data: { path: string; type: "file" | "dir" }) => void
5
+ ) {
6
+ selectedStore.subscribe((curr) => {
7
+ callback(curr.selectedPath);
8
+ });
9
+ }