@putkoff/abstract-securefiles 0.0.48 → 0.0.50

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 (197) hide show
  1. package/dist/ConfirmButton.d.ts +5 -0
  2. package/dist/CopyButton.d.ts +4 -0
  3. package/dist/FolderSelect.d.ts +6 -0
  4. package/dist/SecureFiles.d.ts +3 -0
  5. package/dist/ServerFiles.d.ts +6 -0
  6. package/dist/ShareDialog.d.ts +6 -0
  7. package/dist/UploadPanel.d.ts +6 -0
  8. package/dist/api.d.ts +47 -0
  9. package/dist/index.cjs +529 -1004
  10. package/dist/index.cjs.map +1 -1
  11. package/dist/index.d.ts +4 -8
  12. package/dist/index.js +522 -951
  13. package/dist/index.js.map +1 -1
  14. package/dist/types.d.ts +60 -0
  15. package/package.json +15 -11
  16. package/src/ConfirmButton.tsx +35 -0
  17. package/src/CopyButton.tsx +24 -0
  18. package/src/FolderSelect.tsx +68 -0
  19. package/src/SecureFiles.tsx +346 -0
  20. package/src/ServerFiles.tsx +339 -0
  21. package/src/ShareDialog.tsx +148 -0
  22. package/src/UploadPanel.tsx +217 -0
  23. package/src/api.ts +108 -0
  24. package/src/index.ts +4 -8
  25. package/src/styles.css +442 -0
  26. package/src/types.ts +56 -0
  27. package/css.d.ts +0 -2
  28. package/dist/App/SecureFiles.d.ts +0 -4
  29. package/dist/App/index.d.ts +0 -1
  30. package/dist/FileHandlers/FileRow/imports.d.ts +0 -2
  31. package/dist/FileHandlers/FileRow/index.d.ts +0 -1
  32. package/dist/FileHandlers/FileRow/src/index.d.ts +0 -1
  33. package/dist/FileHandlers/FileRow/src/row_utils.d.ts +0 -2
  34. package/dist/FileHandlers/FileTable/imports.d.ts +0 -4
  35. package/dist/FileHandlers/FileTable/index.d.ts +0 -1
  36. package/dist/FileHandlers/FileTable/src/index.d.ts +0 -1
  37. package/dist/FileHandlers/FileTable/src/table_utils.d.ts +0 -2
  38. package/dist/FileHandlers/ShareModal/imports.d.ts +0 -2
  39. package/dist/FileHandlers/ShareModal/index.d.ts +0 -1
  40. package/dist/FileHandlers/ShareModal/src/index.d.ts +0 -1
  41. package/dist/FileHandlers/ShareModal/src/share_utils.d.ts +0 -2
  42. package/dist/FileHandlers/Upload/imports.d.ts +0 -2
  43. package/dist/FileHandlers/Upload/index.d.ts +0 -1
  44. package/dist/FileHandlers/Upload/src/index.d.ts +0 -2
  45. package/dist/FileHandlers/Upload/src/upload_utils.d.ts +0 -2
  46. package/dist/FileHandlers/imports.d.ts +0 -4
  47. package/dist/FileHandlers/index.d.ts +0 -4
  48. package/dist/UI/index.d.ts +0 -28
  49. package/dist/file_utils/imports.d.ts +0 -2
  50. package/dist/file_utils/index.d.ts +0 -1
  51. package/dist/file_utils/src/cookieFetch.d.ts +0 -33
  52. package/dist/file_utils/src/delete_utils/imports.d.ts +0 -1
  53. package/dist/file_utils/src/delete_utils/index.d.ts +0 -1
  54. package/dist/file_utils/src/delete_utils/src/delete_row.d.ts +0 -2
  55. package/dist/file_utils/src/delete_utils/src/delete_select.d.ts +0 -4
  56. package/dist/file_utils/src/delete_utils/src/delete_selected.d.ts +0 -2
  57. package/dist/file_utils/src/delete_utils/src/index.d.ts +0 -3
  58. package/dist/file_utils/src/download_utils/imports.d.ts +0 -2
  59. package/dist/file_utils/src/download_utils/index.d.ts +0 -1
  60. package/dist/file_utils/src/download_utils/src/direct_download.d.ts +0 -3
  61. package/dist/file_utils/src/download_utils/src/download_file.d.ts +0 -6
  62. package/dist/file_utils/src/download_utils/src/download_select.d.ts +0 -2
  63. package/dist/file_utils/src/download_utils/src/index.d.ts +0 -5
  64. package/dist/file_utils/src/download_utils/src/target_downloads.d.ts +0 -4
  65. package/dist/file_utils/src/download_utils/src/trigger_download.d.ts +0 -2
  66. package/dist/file_utils/src/imports.d.ts +0 -2
  67. package/dist/file_utils/src/index.d.ts +0 -6
  68. package/dist/file_utils/src/list_utils/imports.d.ts +0 -1
  69. package/dist/file_utils/src/list_utils/index.d.ts +0 -1
  70. package/dist/file_utils/src/list_utils/src/index.d.ts +0 -1
  71. package/dist/file_utils/src/list_utils/src/list_utils.d.ts +0 -2
  72. package/dist/file_utils/src/select_utils/index.d.ts +0 -1
  73. package/dist/file_utils/src/select_utils/src/index.d.ts +0 -3
  74. package/dist/file_utils/src/select_utils/src/init_select_all.d.ts +0 -2
  75. package/dist/file_utils/src/select_utils/src/sync_header_checkbox.d.ts +0 -5
  76. package/dist/file_utils/src/select_utils/src/toggle_checkboxes.d.ts +0 -2
  77. package/dist/file_utils/src/share_utils/imports.d.ts +0 -1
  78. package/dist/file_utils/src/share_utils/index.d.ts +0 -1
  79. package/dist/file_utils/src/share_utils/src/index.d.ts +0 -1
  80. package/dist/file_utils/src/share_utils/src/share_utils.d.ts +0 -7
  81. package/dist/file_utils/src/upload_utils/imports.d.ts +0 -0
  82. package/dist/file_utils/src/upload_utils/index.d.ts +0 -1
  83. package/dist/file_utils/src/upload_utils/src/index.d.ts +0 -3
  84. package/dist/file_utils/src/upload_utils/src/patch_file_settings.d.ts +0 -2
  85. package/dist/file_utils/src/upload_utils/src/upload_file.d.ts +0 -2
  86. package/dist/file_utils/src/upload_utils/src/upload_files.d.ts +0 -5
  87. package/dist/hooks/imports.d.ts +0 -3
  88. package/dist/hooks/index.d.ts +0 -1
  89. package/dist/hooks/useFiles/imports.d.ts +0 -2
  90. package/dist/hooks/useFiles/index.d.ts +0 -1
  91. package/dist/hooks/useFiles/src/deleteFile.d.ts +0 -3
  92. package/dist/hooks/useFiles/src/index.d.ts +0 -6
  93. package/dist/hooks/useFiles/src/load.d.ts +0 -3
  94. package/dist/hooks/useFiles/src/patchShareSettings.d.ts +0 -3
  95. package/dist/hooks/useFiles/src/toggleShare.d.ts +0 -3
  96. package/dist/hooks/useFiles/src/useFiles.d.ts +0 -13
  97. package/dist/hooks/useFiles/src/useSaveShareSettings.d.ts +0 -7
  98. package/dist/imports.d.ts +0 -6
  99. package/dist/index.css +0 -1
  100. package/dist/styles/index.d.ts +0 -1
  101. package/dist/types/index.d.ts +0 -1
  102. package/dist/types/src/index.d.ts +0 -1
  103. package/dist/types/src/types.d.ts +0 -75
  104. package/index.ts +0 -1
  105. package/postcss.config.cjs +0 -8
  106. package/rollup.config.js +0 -38
  107. package/rollup.config.mjs +0 -35
  108. package/src/App/SecureFiles.tsx +0 -45
  109. package/src/App/index.ts +0 -1
  110. package/src/FileHandlers/FileRow/imports.ts +0 -2
  111. package/src/FileHandlers/FileRow/index.ts +0 -1
  112. package/src/FileHandlers/FileRow/src/index.ts +0 -1
  113. package/src/FileHandlers/FileRow/src/row_utils.tsx +0 -143
  114. package/src/FileHandlers/FileTable/imports.ts +0 -15
  115. package/src/FileHandlers/FileTable/index.ts +0 -1
  116. package/src/FileHandlers/FileTable/src/index.ts +0 -1
  117. package/src/FileHandlers/FileTable/src/table_utils.tsx +0 -251
  118. package/src/FileHandlers/ShareModal/imports.ts +0 -2
  119. package/src/FileHandlers/ShareModal/index.ts +0 -1
  120. package/src/FileHandlers/ShareModal/src/index.ts +0 -1
  121. package/src/FileHandlers/ShareModal/src/share_utils.tsx +0 -155
  122. package/src/FileHandlers/Upload/imports.ts +0 -3
  123. package/src/FileHandlers/Upload/index.ts +0 -1
  124. package/src/FileHandlers/Upload/src/index.ts +0 -2
  125. package/src/FileHandlers/Upload/src/upload_utils.tsx +0 -369
  126. package/src/FileHandlers/imports.ts +0 -17
  127. package/src/FileHandlers/index.ts +0 -4
  128. package/src/UI/index.tsx +0 -122
  129. package/src/custom.d.ts +0 -7
  130. package/src/file_utils/imports.ts +0 -2
  131. package/src/file_utils/index.ts +0 -1
  132. package/src/file_utils/src/cookieFetch.ts +0 -109
  133. package/src/file_utils/src/delete_utils/imports.ts +0 -1
  134. package/src/file_utils/src/delete_utils/index.ts +0 -1
  135. package/src/file_utils/src/delete_utils/src/delete_row.ts +0 -11
  136. package/src/file_utils/src/delete_utils/src/delete_select.ts +0 -10
  137. package/src/file_utils/src/delete_utils/src/delete_selected.ts +0 -15
  138. package/src/file_utils/src/delete_utils/src/index.ts +0 -3
  139. package/src/file_utils/src/download_utils/imports.ts +0 -3
  140. package/src/file_utils/src/download_utils/index.ts +0 -1
  141. package/src/file_utils/src/download_utils/src/direct_download.ts +0 -22
  142. package/src/file_utils/src/download_utils/src/download_file.ts +0 -25
  143. package/src/file_utils/src/download_utils/src/download_select.ts +0 -25
  144. package/src/file_utils/src/download_utils/src/index.ts +0 -5
  145. package/src/file_utils/src/download_utils/src/target_downloads.ts +0 -21
  146. package/src/file_utils/src/download_utils/src/trigger_download.ts +0 -14
  147. package/src/file_utils/src/imports.ts +0 -3
  148. package/src/file_utils/src/index.ts +0 -6
  149. package/src/file_utils/src/list_utils/imports.ts +0 -2
  150. package/src/file_utils/src/list_utils/index.ts +0 -1
  151. package/src/file_utils/src/list_utils/src/index.ts +0 -1
  152. package/src/file_utils/src/list_utils/src/list_utils.ts +0 -28
  153. package/src/file_utils/src/select_utils/index.ts +0 -1
  154. package/src/file_utils/src/select_utils/src/index.ts +0 -3
  155. package/src/file_utils/src/select_utils/src/init_select_all.ts +0 -37
  156. package/src/file_utils/src/select_utils/src/sync_header_checkbox.ts +0 -18
  157. package/src/file_utils/src/select_utils/src/toggle_checkboxes.ts +0 -11
  158. package/src/file_utils/src/share_utils/imports.ts +0 -1
  159. package/src/file_utils/src/share_utils/index.ts +0 -1
  160. package/src/file_utils/src/share_utils/src/index.ts +0 -1
  161. package/src/file_utils/src/share_utils/src/share_utils.ts +0 -20
  162. package/src/file_utils/src/upload_utils/imports.ts +0 -1
  163. package/src/file_utils/src/upload_utils/index.ts +0 -1
  164. package/src/file_utils/src/upload_utils/src/index.ts +0 -3
  165. package/src/file_utils/src/upload_utils/src/patch_file_settings.ts +0 -20
  166. package/src/file_utils/src/upload_utils/src/upload_file.ts +0 -27
  167. package/src/file_utils/src/upload_utils/src/upload_files.ts +0 -19
  168. package/src/hooks/imports.ts +0 -3
  169. package/src/hooks/index.ts +0 -1
  170. package/src/hooks/useFiles/imports.ts +0 -3
  171. package/src/hooks/useFiles/index.ts +0 -1
  172. package/src/hooks/useFiles/src/deleteFile.ts +0 -23
  173. package/src/hooks/useFiles/src/index.ts +0 -6
  174. package/src/hooks/useFiles/src/load.ts +0 -39
  175. package/src/hooks/useFiles/src/logs/clipit_logs.log +0 -0
  176. package/src/hooks/useFiles/src/logs/routes_bp.log +0 -0
  177. package/src/hooks/useFiles/src/patchShareSettings.ts +0 -27
  178. package/src/hooks/useFiles/src/toggleShare.ts +0 -28
  179. package/src/hooks/useFiles/src/useFiles.ts +0 -35
  180. package/src/hooks/useFiles/src/useSaveShareSettings.ts +0 -31
  181. package/src/imports.ts +0 -18
  182. package/src/styles/SecureFiles/App.css +0 -42
  183. package/src/styles/SecureFiles/index.css +0 -10
  184. package/src/styles/SecureFiles/logs/clipit_logs.log +0 -0
  185. package/src/styles/SecureFiles/logs/routes_bp.log +0 -0
  186. package/src/styles/SecureFiles/tailwind.css +0 -3
  187. package/src/styles/SecureFiles/window-manager.css +0 -283
  188. package/src/styles/SecureFilesStyles.module.css +0 -287
  189. package/src/styles/index.ts +0 -1
  190. package/src/types/index.ts +0 -1
  191. package/src/types/src/index.ts +0 -1
  192. package/src/types/src/types.ts +0 -88
  193. package/tailwind.config.cjs +0 -7
  194. package/testit.mjs +0 -11
  195. package/testit.ts +0 -3
  196. package/tsconfig.json +0 -27
  197. /package/src/{global.d.ts → css.d.ts} +0 -0
@@ -0,0 +1,217 @@
1
+ import React, { useRef, useState } from "react";
2
+ import type { SecureFilesApi } from "./api";
3
+ import { FolderSelect } from "./FolderSelect";
4
+
5
+ interface Queued {
6
+ file: File;
7
+ relPath: string;
8
+ progress: number;
9
+ error?: string;
10
+ done?: boolean;
11
+ }
12
+
13
+ function readEntries(reader: any): Promise<any[]> {
14
+ return new Promise((resolve, reject) => reader.readEntries(resolve, reject));
15
+ }
16
+
17
+ async function walkEntry(entry: any, prefix: string, out: { file: File; relPath: string }[]) {
18
+ if (entry.isFile) {
19
+ const file: File = await new Promise((resolve, reject) => entry.file(resolve, reject));
20
+ out.push({ file, relPath: prefix + file.name });
21
+ } else if (entry.isDirectory) {
22
+ const reader = entry.createReader();
23
+ let batch: any[];
24
+ do {
25
+ batch = await readEntries(reader);
26
+ for (const child of batch) await walkEntry(child, `${prefix}${entry.name}/`, out);
27
+ } while (batch.length > 0);
28
+ }
29
+ }
30
+
31
+ async function filesFromDrop(dt: DataTransfer) {
32
+ const out: { file: File; relPath: string }[] = [];
33
+ const entries = Array.from(dt.items || [])
34
+ .map((item) => (item as any).webkitGetAsEntry?.())
35
+ .filter(Boolean);
36
+ if (entries.length) {
37
+ for (const entry of entries) await walkEntry(entry, "", out);
38
+ } else {
39
+ for (const file of Array.from(dt.files)) out.push({ file, relPath: file.name });
40
+ }
41
+ return out;
42
+ }
43
+
44
+ function joinTarget(target: string, relPath: string) {
45
+ const clean = target.trim().replace(/^\/+|\/+$/g, "");
46
+ return clean ? `${clean}/${relPath}` : relPath;
47
+ }
48
+
49
+ function CloudIcon() {
50
+ return (
51
+ <svg className="sf-drop__icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth={1.5} aria-hidden="true">
52
+ <path
53
+ strokeLinecap="round"
54
+ strokeLinejoin="round"
55
+ d="M12 16.5V9.75m0 0 3 3m-3-3-3 3M6.75 19.5a4.5 4.5 0 0 1-1.41-8.775 5.25 5.25 0 0 1 10.233-2.33 3 3 0 0 1 3.758 3.848A3.752 3.752 0 0 1 18 19.5H6.75Z"
56
+ />
57
+ </svg>
58
+ );
59
+ }
60
+
61
+ export function UploadPanel({
62
+ api,
63
+ folders,
64
+ onUploaded,
65
+ }: {
66
+ api: SecureFilesApi;
67
+ folders: string[];
68
+ onUploaded: () => void;
69
+ }) {
70
+ const [queue, setQueue] = useState<Queued[]>([]);
71
+ const [mode, setMode] = useState<"files" | "folder">("files");
72
+ const [target, setTarget] = useState("");
73
+ const [dragging, setDragging] = useState(false);
74
+ const [busy, setBusy] = useState(false);
75
+ const [message, setMessage] = useState<string | null>(null);
76
+ const fileInput = useRef<HTMLInputElement>(null);
77
+ const folderInput = useRef<HTMLInputElement>(null);
78
+
79
+ const enqueue = (items: { file: File; relPath: string }[]) => {
80
+ setMessage(null);
81
+ setQueue((q) => {
82
+ const kept = q.filter((x) => !x.done);
83
+ const seen = new Set(kept.map((x) => x.relPath));
84
+ return [...kept, ...items.filter((i) => !seen.has(i.relPath)).map((i) => ({ ...i, progress: 0 }))];
85
+ });
86
+ };
87
+
88
+ const openPicker = () => (mode === "folder" ? folderInput : fileInput).current?.click();
89
+
90
+ const fromInput = (e: React.ChangeEvent<HTMLInputElement>) => {
91
+ const files = Array.from(e.target.files || []);
92
+ enqueue(files.map((file) => ({ file, relPath: (file as any).webkitRelativePath || file.name })));
93
+ e.target.value = "";
94
+ };
95
+
96
+ const uploadAll = async () => {
97
+ setBusy(true);
98
+ setMessage(null);
99
+ let failed = 0;
100
+ for (let i = 0; i < queue.length; i++) {
101
+ const item = queue[i];
102
+ if (item.done) continue;
103
+ const set = (patch: Partial<Queued>) =>
104
+ setQueue((q) => q.map((x, idx) => (idx === i ? { ...x, ...patch } : x)));
105
+ try {
106
+ await api.upload(item.file, joinTarget(target, item.relPath), (p) => set({ progress: p }));
107
+ set({ progress: 1, done: true, error: undefined });
108
+ } catch (err) {
109
+ failed++;
110
+ set({ error: err instanceof Error ? err.message : String(err) });
111
+ }
112
+ }
113
+ setBusy(false);
114
+ setMessage(failed ? `${failed} upload(s) failed` : "Upload complete");
115
+ if (!failed) setQueue([]);
116
+ onUploaded();
117
+ };
118
+
119
+ const pending = queue.filter((q) => !q.done);
120
+
121
+ return (
122
+ <section className="sf-upload">
123
+ <div className="sf-row sf-mode" role="radiogroup" aria-label="Choose what clicking the upload area picks">
124
+ <label className="sf-check sf-check--inline">
125
+ <input type="radio" checked={mode === "files"} onChange={() => setMode("files")} /> Files
126
+ </label>
127
+ <label className="sf-check sf-check--inline">
128
+ <input type="radio" checked={mode === "folder"} onChange={() => setMode("folder")} /> Folder
129
+ </label>
130
+ <span className="sf-muted">(drag-and-drop accepts either)</span>
131
+ </div>
132
+
133
+ <div
134
+ className={`sf-drop${dragging ? " sf-drop--active" : ""}`}
135
+ role="button"
136
+ tabIndex={0}
137
+ aria-label={`Upload area: click to choose ${mode === "folder" ? "a folder" : "files"}, or drop files or folders`}
138
+ onClick={openPicker}
139
+ onKeyDown={(e) => {
140
+ if (e.key === "Enter" || e.key === " ") {
141
+ e.preventDefault();
142
+ openPicker();
143
+ }
144
+ }}
145
+ onDragEnter={(e) => {
146
+ e.preventDefault();
147
+ setDragging(true);
148
+ }}
149
+ onDragOver={(e) => e.preventDefault()}
150
+ onDragLeave={(e) => {
151
+ if (!e.currentTarget.contains(e.relatedTarget as Node)) setDragging(false);
152
+ }}
153
+ onDrop={async (e) => {
154
+ e.preventDefault();
155
+ setDragging(false);
156
+ enqueue(await filesFromDrop(e.dataTransfer));
157
+ }}
158
+ >
159
+ <CloudIcon />
160
+ <div>
161
+ <p className="sf-drop__title">Drag &amp; drop files or folders here</p>
162
+ <p className="sf-muted">Click anywhere to choose {mode === "folder" ? "a folder" : "files"}</p>
163
+ {pending.length > 0 && (
164
+ <p className="sf-drop__count">
165
+ {pending.length} item{pending.length === 1 ? "" : "s"} queued
166
+ </p>
167
+ )}
168
+ </div>
169
+ </div>
170
+ <input ref={fileInput} type="file" multiple hidden onChange={fromInput} />
171
+ <input
172
+ ref={folderInput}
173
+ type="file"
174
+ multiple
175
+ hidden
176
+ onChange={fromInput}
177
+ {...({ webkitdirectory: "", directory: "" } as any)}
178
+ />
179
+
180
+ <div className="sf-row">
181
+ <FolderSelect label="Upload into" folders={folders} value={target} onChange={setTarget} />
182
+ <button type="button" className="sf-btn sf-btn--primary" disabled={busy || !pending.length} onClick={uploadAll}>
183
+ {busy ? "Uploading…" : `Upload ${pending.length}`}
184
+ </button>
185
+ {queue.length > 0 && !busy && (
186
+ <button type="button" className="sf-btn" onClick={() => setQueue([])}>
187
+ Clear
188
+ </button>
189
+ )}
190
+ </div>
191
+
192
+ {message && (
193
+ <p className={message.includes("failed") ? "sf-error" : "sf-muted"} role="status">
194
+ {message}
195
+ </p>
196
+ )}
197
+
198
+ {queue.length > 0 && (
199
+ <ul className="sf-queue">
200
+ {queue.map((q, i) => (
201
+ <li key={`${q.relPath}-${i}`}>
202
+ <span className="sf-queue__name">{joinTarget(target, q.relPath)}</span>
203
+ {q.error ? (
204
+ <span className="sf-error">{q.error}</span>
205
+ ) : (
206
+ <span className="sf-row">
207
+ <progress max={1} value={q.progress} />
208
+ <span className="sf-muted">{Math.round(q.progress * 100)}%</span>
209
+ </span>
210
+ )}
211
+ </li>
212
+ ))}
213
+ </ul>
214
+ )}
215
+ </section>
216
+ );
217
+ }
package/src/api.ts ADDED
@@ -0,0 +1,108 @@
1
+ import type { BrowseResult, LinkRoot, RootChallenge, SecureFile, ShareUpdate } from "./types";
2
+
3
+ export const DEFAULT_API_BASE = "https://api.abstractendeavors.com";
4
+
5
+ export class ApiError extends Error {
6
+ constructor(message: string, public status: number) {
7
+ super(message);
8
+ }
9
+ }
10
+
11
+ async function errorFrom(res: Response): Promise<ApiError> {
12
+ let message = `${res.status} ${res.statusText}`;
13
+ try {
14
+ const body = await res.json();
15
+ message = body?.message || body?.error || message;
16
+ } catch {
17
+ /* non-JSON error body */
18
+ }
19
+ if (res.status === 401) message = "Please log in to use Secure Files.";
20
+ return new ApiError(message, res.status);
21
+ }
22
+
23
+ export function createApi(apiBase: string = DEFAULT_API_BASE) {
24
+ const root = `${apiBase.replace(/\/+$/, "")}/secure-files`;
25
+
26
+ async function json<T>(path: string, init: RequestInit = {}): Promise<T> {
27
+ const res = await fetch(`${root}${path}`, {
28
+ credentials: "include",
29
+ ...init,
30
+ headers: { Accept: "application/json", ...(init.body ? { "Content-Type": "application/json" } : {}) },
31
+ });
32
+ if (!res.ok) throw await errorFrom(res);
33
+ return res.json();
34
+ }
35
+
36
+ return {
37
+ list: () => json<{ user_name: string; is_admin: boolean; files: SecureFile[] }>("/userInfo"),
38
+
39
+ roots: () => json<{ roots: LinkRoot[] }>("/admin/roots"),
40
+
41
+ requestRoot: (path: string) =>
42
+ json<{ challenge: RootChallenge }>("/admin/roots", { method: "POST", body: JSON.stringify({ path }) }),
43
+
44
+ confirmRoot: (nonce: string, signature: string, label?: string) =>
45
+ json<{ roots: LinkRoot[] }>("/admin/roots/confirm", {
46
+ method: "POST",
47
+ body: JSON.stringify({ nonce, signature, label }),
48
+ }),
49
+
50
+ removeRoot: (id: number) => json<{ roots: LinkRoot[] }>(`/admin/roots/${id}`, { method: "DELETE" }),
51
+
52
+ browse: (path: string) => json<BrowseResult>(`/admin/browse?path=${encodeURIComponent(path)}`),
53
+
54
+ link: (paths: string[], folder: string) =>
55
+ json<{ linked: string[]; errors: { path: string; error: string }[] }>("/admin/link", {
56
+ method: "POST",
57
+ body: JSON.stringify({ paths, folder }),
58
+ }),
59
+
60
+ updateShare: (update: ShareUpdate) =>
61
+ json<{ file: SecureFile }>("/files/share", { method: "PATCH", body: JSON.stringify(update) }),
62
+
63
+ remove: (ids: number[]) =>
64
+ json<{ removed: number[]; errors: { id: number; error: string }[] }>("/remove", {
65
+ method: "POST",
66
+ body: JSON.stringify({ ids }),
67
+ }),
68
+
69
+ /** Hand the download to the browser so it streams to disk (native progress + resume, no memory limit). */
70
+ download(ids: number[]): void {
71
+ const a = document.createElement("a");
72
+ a.href = `${root}/download?ids=${ids.join(",")}`;
73
+ a.rel = "noopener";
74
+ document.body.appendChild(a);
75
+ a.click();
76
+ a.remove();
77
+ },
78
+
79
+ upload(file: File, relPath: string, onProgress?: (fraction: number) => void): Promise<void> {
80
+ return new Promise((resolve, reject) => {
81
+ const form = new FormData();
82
+ form.append("file", file);
83
+ form.append("rel_path", relPath);
84
+ const xhr = new XMLHttpRequest();
85
+ xhr.open("POST", `${root}/upload`);
86
+ xhr.withCredentials = true;
87
+ xhr.upload.onprogress = (e) => {
88
+ if (e.lengthComputable) onProgress?.(e.loaded / e.total);
89
+ };
90
+ xhr.onload = () => {
91
+ if (xhr.status >= 200 && xhr.status < 300) return resolve();
92
+ let message = `Upload failed (${xhr.status})`;
93
+ try {
94
+ message = JSON.parse(xhr.responseText)?.message || message;
95
+ } catch {
96
+ /* non-JSON */
97
+ }
98
+ if (xhr.status === 401) message = "Please log in to use Secure Files.";
99
+ reject(new ApiError(message, xhr.status));
100
+ };
101
+ xhr.onerror = () => reject(new ApiError("Network error during upload", 0));
102
+ xhr.send(form);
103
+ });
104
+ },
105
+ };
106
+ }
107
+
108
+ export type SecureFilesApi = ReturnType<typeof createApi>;
package/src/index.ts CHANGED
@@ -1,8 +1,4 @@
1
- export { FileRow, ShareModal, FileTable, Upload } from './FileHandlers';
2
- export { useFiles } from './hooks';
3
- export * from './file_utils';
4
- export * from './hooks';
5
- export * from './UI';
6
- export * from './types';
7
- export * from './styles';
8
- export { SecureFiles } from './App'
1
+ export { default as SecureFiles } from "./SecureFiles";
2
+ export { createApi, DEFAULT_API_BASE, ApiError } from "./api";
3
+ export type { SecureFilesApi } from "./api";
4
+ export type { SecureFile, ShareUpdate, SecureFilesProps, LinkRoot, RootChallenge, BrowseResult } from "./types";