stow-cli 1.0.3 → 2.0.2

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 (63) hide show
  1. package/dist/{app-JPUDM4LJ.js → app-2A2CFVBC.js} +1 -1
  2. package/dist/app-2H4TLSN7.js +239 -0
  3. package/dist/app-DTW2LNXW.js +249 -0
  4. package/dist/app-HYCPA7GA.js +239 -0
  5. package/dist/app-IZGSPZPX.js +239 -0
  6. package/dist/app-UGUM75MC.js +239 -0
  7. package/dist/app-XPOEAZJC.js +239 -0
  8. package/dist/app-YITP5APT.js +233 -0
  9. package/dist/{backfill-QZTVNJZM.js → backfill-G57M2BRA.js} +3 -3
  10. package/dist/{buckets-JQKZ3PH3.js → buckets-NXIVHPW5.js} +2 -2
  11. package/dist/chunk-2AORPTQB.js +23 -0
  12. package/dist/chunk-5LU25QZK.js +17 -0
  13. package/dist/chunk-FEMMZ4YZ.js +125 -0
  14. package/dist/chunk-LYCXXF2T.js +79 -0
  15. package/dist/chunk-MHRMBH4Y.js +36 -0
  16. package/dist/{chunk-WAQSCS57.js → chunk-QF7PVPWQ.js} +1 -1
  17. package/dist/chunk-R5CCBTXZ.js +79 -0
  18. package/dist/chunk-TOADDO2F.js +23 -0
  19. package/dist/chunk-YRHPOFJT.js +115 -0
  20. package/dist/chunk-ZDVARBCV.js +43 -0
  21. package/dist/cli.d.ts +1 -0
  22. package/dist/cli.js +43 -43
  23. package/dist/delete-AECEJX5W.js +18 -0
  24. package/dist/delete-GEX3O7YS.js +14 -0
  25. package/dist/delete-KYOZEODD.js +18 -0
  26. package/dist/delete-OLOAJRRO.js +18 -0
  27. package/dist/delete-V4EY4UBG.js +18 -0
  28. package/dist/{drops-QXGTYB5E.js → drops-RD55IDZ4.js} +2 -2
  29. package/dist/{files-OCYICIAM.js → files-E662TXUP.js} +3 -3
  30. package/dist/{health-YMZTZUFX.js → health-6LWM7KAT.js} +3 -3
  31. package/dist/{jobs-6JY4SVV5.js → jobs-CLXYKZ3B.js} +4 -4
  32. package/dist/{jobs-OKKGKSIH.js → jobs-K3LTNETU.js} +5 -5
  33. package/dist/list-7A3VZA2T.js +97 -0
  34. package/dist/list-DHXVIMRI.js +94 -0
  35. package/dist/list-DJEAKEZJ.js +106 -0
  36. package/dist/list-DQRU6QHO.js +106 -0
  37. package/dist/list-I5A6LTHX.js +106 -0
  38. package/dist/list-KEQPJY7I.js +109 -0
  39. package/dist/list-Z3MPT6MI.js +109 -0
  40. package/dist/{maintenance-EZUHQK5Q.js → maintenance-7LOAGG6J.js} +6 -6
  41. package/dist/open-2YNHG3MA.js +15 -0
  42. package/dist/open-F73Q2OHD.js +15 -0
  43. package/dist/{profiles-GWLBEEIT.js → profiles-C6SCFXS6.js} +2 -2
  44. package/dist/{queues-EQX7EJZF.js → queues-2GJAMMNF.js} +4 -4
  45. package/dist/{search-2PXM6XQ6.js → search-DV4VV62L.js} +2 -2
  46. package/dist/{tags-LSVEIIUF.js → tags-URHK2YH5.js} +2 -2
  47. package/dist/upload-3NS5O3UL.js +120 -0
  48. package/dist/upload-5RIDB2C5.js +92 -0
  49. package/dist/upload-B2PGW3AN.js +125 -0
  50. package/dist/{upload-ESYKBYHA.js → upload-DQDBDIDI.js} +1 -1
  51. package/dist/upload-FGNGNPC3.js +93 -0
  52. package/dist/upload-HKUPWTK2.js +173 -0
  53. package/dist/upload-JDVSJVWK.js +173 -0
  54. package/dist/upload-K4H7ZVRW.js +98 -0
  55. package/dist/upload-MI6VFGTC.js +92 -0
  56. package/dist/whoami-2SLCNVKP.js +27 -0
  57. package/dist/whoami-5IYRZKWS.js +28 -0
  58. package/dist/{whoami-4UYMSRVP.js → whoami-754O5IML.js} +1 -1
  59. package/dist/whoami-DOMX3Z5K.js +28 -0
  60. package/dist/whoami-IPMCUEUH.js +27 -0
  61. package/dist/whoami-JSQA2IDN.js +27 -0
  62. package/dist/whoami-RKH5HHPR.js +27 -0
  63. package/package.json +4 -4
@@ -0,0 +1,239 @@
1
+ import {
2
+ formatBytes
3
+ } from "./chunk-ZDVARBCV.js";
4
+ import {
5
+ apiRequest
6
+ } from "./chunk-LYCXXF2T.js";
7
+ import "./chunk-OZ7QQTIZ.js";
8
+
9
+ // src/interactive/app.tsx
10
+ import { render } from "ink";
11
+ import { useEffect as useEffect3, useState as useState3 } from "react";
12
+
13
+ // src/interactive/components/bucket-list.tsx
14
+ import { Box as Box3, Text as Text3, useApp, useInput } from "ink";
15
+ import Spinner from "ink-spinner";
16
+ import { useEffect, useState } from "react";
17
+
18
+ // src/interactive/components/header.tsx
19
+ import { Box, Text } from "ink";
20
+ import { jsx, jsxs } from "react/jsx-runtime";
21
+ function Header({ path, email, size }) {
22
+ return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", children: [
23
+ /* @__PURE__ */ jsxs(Box, { justifyContent: "space-between", width: "100%", children: [
24
+ /* @__PURE__ */ jsxs(Text, { bold: true, children: [
25
+ "STOW",
26
+ path ? ` > ${path}` : ""
27
+ ] }),
28
+ /* @__PURE__ */ jsx(Text, { dimColor: true, children: size || email || "" })
29
+ ] }),
30
+ /* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u2500".repeat(50) })
31
+ ] });
32
+ }
33
+
34
+ // src/interactive/components/status-bar.tsx
35
+ import { Box as Box2, Text as Text2 } from "ink";
36
+ import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
37
+ function StatusBar({ hints }) {
38
+ return /* @__PURE__ */ jsx2(Box2, { marginTop: 1, children: hints.map((h, i) => /* @__PURE__ */ jsx2(Box2, { marginRight: 2, children: /* @__PURE__ */ jsxs2(Text2, { dimColor: true, children: [
39
+ "[",
40
+ h.key,
41
+ "]",
42
+ h.label,
43
+ i < hints.length - 1 ? "" : ""
44
+ ] }) }, h.key)) });
45
+ }
46
+
47
+ // src/interactive/components/bucket-list.tsx
48
+ import { jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
49
+ function BucketList({ onSelect, email }) {
50
+ const { exit } = useApp();
51
+ const [buckets, setBuckets] = useState([]);
52
+ const [loading, setLoading] = useState(true);
53
+ const [error, setError] = useState(null);
54
+ const [cursor, setCursor] = useState(0);
55
+ useEffect(() => {
56
+ apiRequest("/api/buckets").then((data) => {
57
+ setBuckets(data.buckets);
58
+ setLoading(false);
59
+ }).catch((err) => {
60
+ setError(err instanceof Error ? err.message : String(err));
61
+ setLoading(false);
62
+ });
63
+ }, []);
64
+ useInput((input, key) => {
65
+ if (input === "q") {
66
+ exit();
67
+ return;
68
+ }
69
+ if (key.upArrow) {
70
+ setCursor((c) => Math.max(0, c - 1));
71
+ } else if (key.downArrow) {
72
+ setCursor((c) => Math.min(buckets.length - 1, c + 1));
73
+ } else if (key.return && buckets.length > 0) {
74
+ onSelect(buckets[cursor]);
75
+ }
76
+ });
77
+ if (loading) {
78
+ return /* @__PURE__ */ jsx3(Box3, { children: /* @__PURE__ */ jsxs3(Text3, { children: [
79
+ /* @__PURE__ */ jsx3(Spinner, { type: "dots" }),
80
+ " Loading buckets..."
81
+ ] }) });
82
+ }
83
+ if (error) {
84
+ return /* @__PURE__ */ jsx3(Box3, { flexDirection: "column", children: /* @__PURE__ */ jsxs3(Text3, { color: "red", children: [
85
+ "Error: ",
86
+ error
87
+ ] }) });
88
+ }
89
+ return /* @__PURE__ */ jsxs3(Box3, { flexDirection: "column", children: [
90
+ /* @__PURE__ */ jsx3(Header, { email }),
91
+ buckets.length === 0 ? /* @__PURE__ */ jsx3(Text3, { dimColor: true, children: "No buckets yet. Press 'n' to create one." }) : buckets.map((b, i) => /* @__PURE__ */ jsx3(Box3, { children: /* @__PURE__ */ jsxs3(Text3, { color: i === cursor ? "cyan" : void 0, children: [
92
+ i === cursor ? "\u25B8 " : " ",
93
+ b.name.padEnd(20),
94
+ `${b.fileCount} files`.padEnd(14),
95
+ formatBytes(b.usageBytes)
96
+ ] }) }, b.id)),
97
+ /* @__PURE__ */ jsx3(
98
+ StatusBar,
99
+ {
100
+ hints: [
101
+ { key: "\u2191\u2193", label: "navigate" },
102
+ { key: "\u21B5", label: "open" },
103
+ { key: "q", label: "uit" }
104
+ ]
105
+ }
106
+ )
107
+ ] });
108
+ }
109
+
110
+ // src/interactive/components/file-list.tsx
111
+ import { Box as Box4, Text as Text4, useInput as useInput2 } from "ink";
112
+ import Spinner2 from "ink-spinner";
113
+ import { useEffect as useEffect2, useState as useState2 } from "react";
114
+ import { jsx as jsx4, jsxs as jsxs4 } from "react/jsx-runtime";
115
+ function FileList({ bucket, onBack }) {
116
+ const [files, setFiles] = useState2([]);
117
+ const [loading, setLoading] = useState2(true);
118
+ const [error, setError] = useState2(null);
119
+ const [cursor, setCursor] = useState2(0);
120
+ const [nextCursor, setNextCursor] = useState2(null);
121
+ const [copied, setCopied] = useState2(false);
122
+ useEffect2(() => {
123
+ loadFiles();
124
+ }, []);
125
+ function loadFiles(pageCursor) {
126
+ setLoading(true);
127
+ const params = new URLSearchParams({ bucket: bucket.name });
128
+ if (pageCursor) {
129
+ params.set("cursor", pageCursor);
130
+ }
131
+ apiRequest(
132
+ `/api/files?${params}`
133
+ ).then((data) => {
134
+ setFiles(
135
+ (prev) => pageCursor ? [...prev, ...data.files] : data.files
136
+ );
137
+ setNextCursor(data.nextCursor);
138
+ setLoading(false);
139
+ }).catch((err) => {
140
+ setError(err instanceof Error ? err.message : String(err));
141
+ setLoading(false);
142
+ });
143
+ }
144
+ useInput2((input, key) => {
145
+ if (key.escape || key.backspace || key.leftArrow && !loading) {
146
+ onBack();
147
+ return;
148
+ }
149
+ if (key.upArrow) {
150
+ setCursor((c) => Math.max(0, c - 1));
151
+ } else if (key.downArrow) {
152
+ setCursor((c) => {
153
+ const next = Math.min(files.length - 1, c + 1);
154
+ if (next >= files.length - 3 && nextCursor && !loading) {
155
+ loadFiles(nextCursor);
156
+ }
157
+ return next;
158
+ });
159
+ } else if (input === "c" && files.length > 0) {
160
+ import("clipboardy").then(({ default: clipboard }) => {
161
+ clipboard.write(files[cursor].url).then(() => {
162
+ setCopied(true);
163
+ setTimeout(() => setCopied(false), 2e3);
164
+ });
165
+ });
166
+ }
167
+ });
168
+ if (error) {
169
+ return /* @__PURE__ */ jsxs4(Box4, { flexDirection: "column", children: [
170
+ /* @__PURE__ */ jsxs4(Text4, { color: "red", children: [
171
+ "Error: ",
172
+ error
173
+ ] }),
174
+ /* @__PURE__ */ jsx4(Text4, { dimColor: true, children: "Press Esc to go back." })
175
+ ] });
176
+ }
177
+ return /* @__PURE__ */ jsxs4(Box4, { flexDirection: "column", children: [
178
+ /* @__PURE__ */ jsx4(Header, { path: bucket.name, size: formatBytes(bucket.usageBytes) }),
179
+ loading && files.length === 0 && /* @__PURE__ */ jsxs4(Text4, { children: [
180
+ /* @__PURE__ */ jsx4(Spinner2, { type: "dots" }),
181
+ " Loading files..."
182
+ ] }),
183
+ !loading && files.length === 0 && /* @__PURE__ */ jsx4(Text4, { dimColor: true, children: "No files in this bucket." }),
184
+ files.length > 0 && files.map((f, i) => /* @__PURE__ */ jsx4(Box4, { children: /* @__PURE__ */ jsxs4(Text4, { color: i === cursor ? "cyan" : void 0, children: [
185
+ i === cursor ? "\u25B8 " : " ",
186
+ f.key.padEnd(28),
187
+ formatBytes(f.size).padEnd(10),
188
+ f.lastModified.split("T")[0]
189
+ ] }) }, f.key)),
190
+ loading && files.length > 0 && /* @__PURE__ */ jsxs4(Text4, { dimColor: true, children: [
191
+ /* @__PURE__ */ jsx4(Spinner2, { type: "dots" }),
192
+ " Loading more..."
193
+ ] }),
194
+ copied && /* @__PURE__ */ jsx4(Text4, { color: "green", children: "Copied URL to clipboard!" }),
195
+ /* @__PURE__ */ jsx4(
196
+ StatusBar,
197
+ {
198
+ hints: [
199
+ { key: "\u2191\u2193", label: "navigate" },
200
+ { key: "c", label: "opy url" },
201
+ { key: "\u2190", label: "back" }
202
+ ]
203
+ }
204
+ )
205
+ ] });
206
+ }
207
+
208
+ // src/interactive/app.tsx
209
+ import { jsx as jsx5 } from "react/jsx-runtime";
210
+ function App() {
211
+ const [screen, setScreen] = useState3({ type: "buckets" });
212
+ const [email, setEmail] = useState3();
213
+ useEffect3(() => {
214
+ apiRequest("/api/whoami").then((data) => setEmail(data.user.email)).catch(() => {
215
+ });
216
+ }, []);
217
+ if (screen.type === "files") {
218
+ return /* @__PURE__ */ jsx5(
219
+ FileList,
220
+ {
221
+ bucket: screen.bucket,
222
+ onBack: () => setScreen({ type: "buckets" })
223
+ }
224
+ );
225
+ }
226
+ return /* @__PURE__ */ jsx5(
227
+ BucketList,
228
+ {
229
+ email,
230
+ onSelect: (bucket) => setScreen({ type: "files", bucket })
231
+ }
232
+ );
233
+ }
234
+ function startInteractive() {
235
+ render(/* @__PURE__ */ jsx5(App, {}));
236
+ }
237
+ export {
238
+ startInteractive
239
+ };
@@ -0,0 +1,239 @@
1
+ import {
2
+ apiRequest
3
+ } from "./chunk-LYCXXF2T.js";
4
+ import {
5
+ formatBytes
6
+ } from "./chunk-ZDVARBCV.js";
7
+ import "./chunk-OZ7QQTIZ.js";
8
+
9
+ // src/interactive/app.tsx
10
+ import { render } from "ink";
11
+ import { useEffect as useEffect3, useState as useState3 } from "react";
12
+
13
+ // src/interactive/components/bucket-list.tsx
14
+ import { Box as Box3, Text as Text3, useApp, useInput } from "ink";
15
+ import Spinner from "ink-spinner";
16
+ import { useEffect, useState } from "react";
17
+
18
+ // src/interactive/components/header.tsx
19
+ import { Box, Text } from "ink";
20
+ import { jsx, jsxs } from "react/jsx-runtime";
21
+ function Header({ path, email, size }) {
22
+ return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", children: [
23
+ /* @__PURE__ */ jsxs(Box, { justifyContent: "space-between", width: "100%", children: [
24
+ /* @__PURE__ */ jsxs(Text, { bold: true, children: [
25
+ "STOW",
26
+ path ? ` > ${path}` : ""
27
+ ] }),
28
+ /* @__PURE__ */ jsx(Text, { dimColor: true, children: size || email || "" })
29
+ ] }),
30
+ /* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u2500".repeat(50) })
31
+ ] });
32
+ }
33
+
34
+ // src/interactive/components/status-bar.tsx
35
+ import { Box as Box2, Text as Text2 } from "ink";
36
+ import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
37
+ function StatusBar({ hints }) {
38
+ return /* @__PURE__ */ jsx2(Box2, { marginTop: 1, children: hints.map((h, i) => /* @__PURE__ */ jsx2(Box2, { marginRight: 2, children: /* @__PURE__ */ jsxs2(Text2, { dimColor: true, children: [
39
+ "[",
40
+ h.key,
41
+ "]",
42
+ h.label,
43
+ i < hints.length - 1 ? "" : ""
44
+ ] }) }, h.key)) });
45
+ }
46
+
47
+ // src/interactive/components/bucket-list.tsx
48
+ import { jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
49
+ function BucketList({ onSelect, email }) {
50
+ const { exit } = useApp();
51
+ const [buckets, setBuckets] = useState([]);
52
+ const [loading, setLoading] = useState(true);
53
+ const [error, setError] = useState(null);
54
+ const [cursor, setCursor] = useState(0);
55
+ useEffect(() => {
56
+ apiRequest("/api/buckets").then((data) => {
57
+ setBuckets(data.buckets);
58
+ setLoading(false);
59
+ }).catch((err) => {
60
+ setError(err instanceof Error ? err.message : String(err));
61
+ setLoading(false);
62
+ });
63
+ }, []);
64
+ useInput((input, key) => {
65
+ if (input === "q") {
66
+ exit();
67
+ return;
68
+ }
69
+ if (key.upArrow) {
70
+ setCursor((c) => Math.max(0, c - 1));
71
+ } else if (key.downArrow) {
72
+ setCursor((c) => Math.min(buckets.length - 1, c + 1));
73
+ } else if (key.return && buckets.length > 0) {
74
+ onSelect(buckets[cursor]);
75
+ }
76
+ });
77
+ if (loading) {
78
+ return /* @__PURE__ */ jsx3(Box3, { children: /* @__PURE__ */ jsxs3(Text3, { children: [
79
+ /* @__PURE__ */ jsx3(Spinner, { type: "dots" }),
80
+ " Loading buckets..."
81
+ ] }) });
82
+ }
83
+ if (error) {
84
+ return /* @__PURE__ */ jsx3(Box3, { flexDirection: "column", children: /* @__PURE__ */ jsxs3(Text3, { color: "red", children: [
85
+ "Error: ",
86
+ error
87
+ ] }) });
88
+ }
89
+ return /* @__PURE__ */ jsxs3(Box3, { flexDirection: "column", children: [
90
+ /* @__PURE__ */ jsx3(Header, { email }),
91
+ buckets.length === 0 ? /* @__PURE__ */ jsx3(Text3, { dimColor: true, children: "No buckets yet. Press 'n' to create one." }) : buckets.map((b, i) => /* @__PURE__ */ jsx3(Box3, { children: /* @__PURE__ */ jsxs3(Text3, { color: i === cursor ? "cyan" : void 0, children: [
92
+ i === cursor ? "\u25B8 " : " ",
93
+ b.name.padEnd(20),
94
+ `${b.fileCount} files`.padEnd(14),
95
+ formatBytes(b.usageBytes)
96
+ ] }) }, b.id)),
97
+ /* @__PURE__ */ jsx3(
98
+ StatusBar,
99
+ {
100
+ hints: [
101
+ { key: "\u2191\u2193", label: "navigate" },
102
+ { key: "\u21B5", label: "open" },
103
+ { key: "q", label: "uit" }
104
+ ]
105
+ }
106
+ )
107
+ ] });
108
+ }
109
+
110
+ // src/interactive/components/file-list.tsx
111
+ import { Box as Box4, Text as Text4, useInput as useInput2 } from "ink";
112
+ import Spinner2 from "ink-spinner";
113
+ import { useEffect as useEffect2, useState as useState2 } from "react";
114
+ import { jsx as jsx4, jsxs as jsxs4 } from "react/jsx-runtime";
115
+ function FileList({ bucket, onBack }) {
116
+ const [files, setFiles] = useState2([]);
117
+ const [loading, setLoading] = useState2(true);
118
+ const [error, setError] = useState2(null);
119
+ const [cursor, setCursor] = useState2(0);
120
+ const [nextCursor, setNextCursor] = useState2(null);
121
+ const [copied, setCopied] = useState2(false);
122
+ useEffect2(() => {
123
+ loadFiles();
124
+ }, []);
125
+ function loadFiles(pageCursor) {
126
+ setLoading(true);
127
+ const params = new URLSearchParams({ bucket: bucket.name });
128
+ if (pageCursor) {
129
+ params.set("cursor", pageCursor);
130
+ }
131
+ apiRequest(
132
+ `/api/files?${params}`
133
+ ).then((data) => {
134
+ setFiles(
135
+ (prev) => pageCursor ? [...prev, ...data.files] : data.files
136
+ );
137
+ setNextCursor(data.nextCursor);
138
+ setLoading(false);
139
+ }).catch((err) => {
140
+ setError(err instanceof Error ? err.message : String(err));
141
+ setLoading(false);
142
+ });
143
+ }
144
+ useInput2((input, key) => {
145
+ if (key.escape || key.backspace || key.leftArrow && !loading) {
146
+ onBack();
147
+ return;
148
+ }
149
+ if (key.upArrow) {
150
+ setCursor((c) => Math.max(0, c - 1));
151
+ } else if (key.downArrow) {
152
+ setCursor((c) => {
153
+ const next = Math.min(files.length - 1, c + 1);
154
+ if (next >= files.length - 3 && nextCursor && !loading) {
155
+ loadFiles(nextCursor);
156
+ }
157
+ return next;
158
+ });
159
+ } else if (input === "c" && files.length > 0) {
160
+ import("clipboardy").then(({ default: clipboard }) => {
161
+ clipboard.write(files[cursor].url).then(() => {
162
+ setCopied(true);
163
+ setTimeout(() => setCopied(false), 2e3);
164
+ });
165
+ });
166
+ }
167
+ });
168
+ if (error) {
169
+ return /* @__PURE__ */ jsxs4(Box4, { flexDirection: "column", children: [
170
+ /* @__PURE__ */ jsxs4(Text4, { color: "red", children: [
171
+ "Error: ",
172
+ error
173
+ ] }),
174
+ /* @__PURE__ */ jsx4(Text4, { dimColor: true, children: "Press Esc to go back." })
175
+ ] });
176
+ }
177
+ return /* @__PURE__ */ jsxs4(Box4, { flexDirection: "column", children: [
178
+ /* @__PURE__ */ jsx4(Header, { path: bucket.name, size: formatBytes(bucket.usageBytes) }),
179
+ loading && files.length === 0 && /* @__PURE__ */ jsxs4(Text4, { children: [
180
+ /* @__PURE__ */ jsx4(Spinner2, { type: "dots" }),
181
+ " Loading files..."
182
+ ] }),
183
+ !loading && files.length === 0 && /* @__PURE__ */ jsx4(Text4, { dimColor: true, children: "No files in this bucket." }),
184
+ files.length > 0 && files.map((f, i) => /* @__PURE__ */ jsx4(Box4, { children: /* @__PURE__ */ jsxs4(Text4, { color: i === cursor ? "cyan" : void 0, children: [
185
+ i === cursor ? "\u25B8 " : " ",
186
+ f.key.padEnd(28),
187
+ formatBytes(f.size).padEnd(10),
188
+ f.lastModified.split("T")[0]
189
+ ] }) }, f.key)),
190
+ loading && files.length > 0 && /* @__PURE__ */ jsxs4(Text4, { dimColor: true, children: [
191
+ /* @__PURE__ */ jsx4(Spinner2, { type: "dots" }),
192
+ " Loading more..."
193
+ ] }),
194
+ copied && /* @__PURE__ */ jsx4(Text4, { color: "green", children: "Copied URL to clipboard!" }),
195
+ /* @__PURE__ */ jsx4(
196
+ StatusBar,
197
+ {
198
+ hints: [
199
+ { key: "\u2191\u2193", label: "navigate" },
200
+ { key: "c", label: "opy url" },
201
+ { key: "\u2190", label: "back" }
202
+ ]
203
+ }
204
+ )
205
+ ] });
206
+ }
207
+
208
+ // src/interactive/app.tsx
209
+ import { jsx as jsx5 } from "react/jsx-runtime";
210
+ function App() {
211
+ const [screen, setScreen] = useState3({ type: "buckets" });
212
+ const [email, setEmail] = useState3();
213
+ useEffect3(() => {
214
+ apiRequest("/api/whoami").then((data) => setEmail(data.user.email)).catch(() => {
215
+ });
216
+ }, []);
217
+ if (screen.type === "files") {
218
+ return /* @__PURE__ */ jsx5(
219
+ FileList,
220
+ {
221
+ bucket: screen.bucket,
222
+ onBack: () => setScreen({ type: "buckets" })
223
+ }
224
+ );
225
+ }
226
+ return /* @__PURE__ */ jsx5(
227
+ BucketList,
228
+ {
229
+ email,
230
+ onSelect: (bucket) => setScreen({ type: "files", bucket })
231
+ }
232
+ );
233
+ }
234
+ function startInteractive() {
235
+ render(/* @__PURE__ */ jsx5(App, {}));
236
+ }
237
+ export {
238
+ startInteractive
239
+ };