@jant/core 0.1.2 → 0.2.0

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 (288) hide show
  1. package/dist/app.d.ts +34 -0
  2. package/dist/app.d.ts.map +1 -0
  3. package/dist/app.js +474 -0
  4. package/dist/assets/datastar.min.js +1775 -0
  5. package/dist/auth.d.ts +23 -0
  6. package/dist/auth.d.ts.map +1 -0
  7. package/dist/auth.js +34 -0
  8. package/{src/client.ts → dist/client.d.ts} +1 -1
  9. package/dist/client.d.ts.map +1 -0
  10. package/dist/client.js +4 -0
  11. package/dist/db/index.d.ts +10 -0
  12. package/dist/db/index.d.ts.map +1 -0
  13. package/dist/db/index.js +10 -0
  14. package/dist/db/schema.d.ts +1507 -0
  15. package/dist/db/schema.d.ts.map +1 -0
  16. package/dist/db/schema.js +183 -0
  17. package/{src/i18n/Trans.tsx → dist/i18n/Trans.d.ts} +4 -10
  18. package/dist/i18n/Trans.d.ts.map +1 -0
  19. package/dist/i18n/Trans.js +24 -0
  20. package/dist/i18n/context.d.ts +69 -0
  21. package/dist/i18n/context.d.ts.map +1 -0
  22. package/dist/i18n/context.js +61 -0
  23. package/dist/i18n/detect.d.ts +31 -0
  24. package/dist/i18n/detect.d.ts.map +1 -0
  25. package/dist/i18n/detect.js +77 -0
  26. package/{src/i18n/i18n.ts → dist/i18n/i18n.d.ts} +5 -25
  27. package/dist/i18n/i18n.d.ts.map +1 -0
  28. package/dist/i18n/i18n.js +55 -0
  29. package/dist/i18n/index.d.ts +41 -0
  30. package/dist/i18n/index.d.ts.map +1 -0
  31. package/{src/i18n/index.ts → dist/i18n/index.js} +3 -24
  32. package/dist/i18n/locales/en.d.ts +3 -0
  33. package/dist/i18n/locales/en.d.ts.map +1 -0
  34. package/dist/i18n/locales/en.js +1 -0
  35. package/dist/i18n/locales/zh-Hans.d.ts +3 -0
  36. package/dist/i18n/locales/zh-Hans.d.ts.map +1 -0
  37. package/dist/i18n/locales/zh-Hans.js +1 -0
  38. package/dist/i18n/locales/zh-Hant.d.ts +3 -0
  39. package/dist/i18n/locales/zh-Hant.d.ts.map +1 -0
  40. package/dist/i18n/locales/zh-Hant.js +1 -0
  41. package/dist/i18n/locales.d.ts +11 -0
  42. package/dist/i18n/locales.d.ts.map +1 -0
  43. package/dist/i18n/locales.js +13 -0
  44. package/dist/i18n/middleware.d.ts +24 -0
  45. package/dist/i18n/middleware.d.ts.map +1 -0
  46. package/dist/i18n/middleware.js +41 -0
  47. package/dist/index.d.ts +16 -0
  48. package/dist/index.d.ts.map +1 -0
  49. package/{src/index.ts → dist/index.js} +1 -28
  50. package/dist/lib/assets.d.ts +19 -0
  51. package/dist/lib/assets.d.ts.map +1 -0
  52. package/dist/lib/assets.js +33 -0
  53. package/dist/lib/constants.d.ts +36 -0
  54. package/dist/lib/constants.d.ts.map +1 -0
  55. package/dist/lib/constants.js +50 -0
  56. package/{src/lib/image.ts → dist/lib/image.d.ts} +13 -47
  57. package/dist/lib/image.d.ts.map +1 -0
  58. package/dist/lib/image.js +77 -0
  59. package/{src/lib/index.ts → dist/lib/index.d.ts} +1 -1
  60. package/dist/lib/index.d.ts.map +1 -0
  61. package/dist/lib/index.js +7 -0
  62. package/dist/lib/markdown.d.ts +60 -0
  63. package/dist/lib/markdown.d.ts.map +1 -0
  64. package/{src/lib/markdown.ts → dist/lib/markdown.js} +16 -26
  65. package/dist/lib/schemas.d.ts +113 -0
  66. package/dist/lib/schemas.d.ts.map +1 -0
  67. package/dist/lib/schemas.js +71 -0
  68. package/dist/lib/sqid.d.ts +60 -0
  69. package/dist/lib/sqid.d.ts.map +1 -0
  70. package/{src/lib/sqid.ts → dist/lib/sqid.js} +15 -22
  71. package/dist/lib/sse.d.ts +95 -0
  72. package/dist/lib/sse.d.ts.map +1 -0
  73. package/dist/lib/sse.js +81 -0
  74. package/dist/lib/time.d.ts +90 -0
  75. package/dist/lib/time.d.ts.map +1 -0
  76. package/{src/lib/time.ts → dist/lib/time.js} +20 -33
  77. package/{src/lib/url.ts → dist/lib/url.d.ts} +5 -30
  78. package/dist/lib/url.d.ts.map +1 -0
  79. package/dist/lib/url.js +89 -0
  80. package/dist/middleware/auth.d.ts +24 -0
  81. package/dist/middleware/auth.d.ts.map +1 -0
  82. package/dist/middleware/auth.js +52 -0
  83. package/dist/routes/api/posts.d.ts +13 -0
  84. package/dist/routes/api/posts.d.ts.map +1 -0
  85. package/dist/routes/api/posts.js +124 -0
  86. package/dist/routes/api/search.d.ts +13 -0
  87. package/dist/routes/api/search.d.ts.map +1 -0
  88. package/dist/routes/api/search.js +49 -0
  89. package/dist/routes/api/upload.d.ts +16 -0
  90. package/dist/routes/api/upload.d.ts.map +1 -0
  91. package/dist/routes/api/upload.js +227 -0
  92. package/dist/routes/dash/collections.d.ts +13 -0
  93. package/dist/routes/dash/collections.d.ts.map +1 -0
  94. package/dist/routes/dash/collections.js +512 -0
  95. package/dist/routes/dash/index.d.ts +15 -0
  96. package/dist/routes/dash/index.d.ts.map +1 -0
  97. package/dist/routes/dash/index.js +117 -0
  98. package/dist/routes/dash/media.d.ts +16 -0
  99. package/dist/routes/dash/media.d.ts.map +1 -0
  100. package/dist/routes/dash/media.js +589 -0
  101. package/dist/routes/dash/pages.d.ts +15 -0
  102. package/dist/routes/dash/pages.d.ts.map +1 -0
  103. package/dist/routes/dash/pages.js +290 -0
  104. package/dist/routes/dash/posts.d.ts +13 -0
  105. package/dist/routes/dash/posts.d.ts.map +1 -0
  106. package/dist/routes/dash/posts.js +226 -0
  107. package/dist/routes/dash/redirects.d.ts +13 -0
  108. package/dist/routes/dash/redirects.d.ts.map +1 -0
  109. package/dist/routes/dash/redirects.js +237 -0
  110. package/dist/routes/dash/settings.d.ts +13 -0
  111. package/dist/routes/dash/settings.d.ts.map +1 -0
  112. package/dist/routes/dash/settings.js +154 -0
  113. package/dist/routes/feed/rss.d.ts +13 -0
  114. package/dist/routes/feed/rss.d.ts.map +1 -0
  115. package/dist/routes/feed/rss.js +95 -0
  116. package/dist/routes/feed/sitemap.d.ts +13 -0
  117. package/dist/routes/feed/sitemap.d.ts.map +1 -0
  118. package/dist/routes/feed/sitemap.js +59 -0
  119. package/dist/routes/pages/archive.d.ts +15 -0
  120. package/dist/routes/pages/archive.d.ts.map +1 -0
  121. package/dist/routes/pages/archive.js +255 -0
  122. package/dist/routes/pages/collection.d.ts +13 -0
  123. package/dist/routes/pages/collection.d.ts.map +1 -0
  124. package/dist/routes/pages/collection.js +93 -0
  125. package/dist/routes/pages/home.d.ts +13 -0
  126. package/dist/routes/pages/home.d.ts.map +1 -0
  127. package/dist/routes/pages/home.js +122 -0
  128. package/dist/routes/pages/page.d.ts +15 -0
  129. package/dist/routes/pages/page.d.ts.map +1 -0
  130. package/dist/routes/pages/page.js +69 -0
  131. package/dist/routes/pages/post.d.ts +13 -0
  132. package/dist/routes/pages/post.d.ts.map +1 -0
  133. package/dist/routes/pages/post.js +90 -0
  134. package/dist/routes/pages/search.d.ts +13 -0
  135. package/dist/routes/pages/search.d.ts.map +1 -0
  136. package/dist/routes/pages/search.js +180 -0
  137. package/dist/services/collection.d.ts +31 -0
  138. package/dist/services/collection.d.ts.map +1 -0
  139. package/dist/services/collection.js +108 -0
  140. package/dist/services/index.d.ts +28 -0
  141. package/dist/services/index.d.ts.map +1 -0
  142. package/dist/services/index.js +20 -0
  143. package/dist/services/media.d.ts +27 -0
  144. package/dist/services/media.d.ts.map +1 -0
  145. package/dist/services/media.js +62 -0
  146. package/dist/services/post.d.ts +31 -0
  147. package/dist/services/post.d.ts.map +1 -0
  148. package/dist/services/post.js +191 -0
  149. package/dist/services/redirect.d.ts +15 -0
  150. package/dist/services/redirect.d.ts.map +1 -0
  151. package/dist/services/redirect.js +48 -0
  152. package/dist/services/search.d.ts +26 -0
  153. package/dist/services/search.d.ts.map +1 -0
  154. package/dist/services/search.js +61 -0
  155. package/dist/services/settings.d.ts +17 -0
  156. package/dist/services/settings.d.ts.map +1 -0
  157. package/dist/services/settings.js +65 -0
  158. package/dist/theme/components/ActionButtons.d.ts +43 -0
  159. package/dist/theme/components/ActionButtons.d.ts.map +1 -0
  160. package/dist/theme/components/ActionButtons.js +50 -0
  161. package/dist/theme/components/CrudPageHeader.d.ts +23 -0
  162. package/dist/theme/components/CrudPageHeader.d.ts.map +1 -0
  163. package/dist/theme/components/CrudPageHeader.js +22 -0
  164. package/dist/theme/components/DangerZone.d.ts +36 -0
  165. package/dist/theme/components/DangerZone.d.ts.map +1 -0
  166. package/dist/theme/components/DangerZone.js +39 -0
  167. package/dist/theme/components/EmptyState.d.ts +27 -0
  168. package/dist/theme/components/EmptyState.d.ts.map +1 -0
  169. package/dist/theme/components/EmptyState.js +27 -0
  170. package/dist/theme/components/ListItemRow.d.ts +15 -0
  171. package/dist/theme/components/ListItemRow.d.ts.map +1 -0
  172. package/dist/theme/components/ListItemRow.js +21 -0
  173. package/dist/theme/components/PageForm.d.ts +14 -0
  174. package/dist/theme/components/PageForm.d.ts.map +1 -0
  175. package/dist/theme/components/PageForm.js +173 -0
  176. package/dist/theme/components/Pagination.d.ts +46 -0
  177. package/dist/theme/components/Pagination.d.ts.map +1 -0
  178. package/dist/theme/components/Pagination.js +159 -0
  179. package/dist/theme/components/PostForm.d.ts +12 -0
  180. package/dist/theme/components/PostForm.d.ts.map +1 -0
  181. package/dist/theme/components/PostForm.js +230 -0
  182. package/dist/theme/components/PostList.d.ts +10 -0
  183. package/dist/theme/components/PostList.d.ts.map +1 -0
  184. package/dist/theme/components/PostList.js +73 -0
  185. package/dist/theme/components/ThreadView.d.ts +15 -0
  186. package/dist/theme/components/ThreadView.d.ts.map +1 -0
  187. package/dist/theme/components/ThreadView.js +111 -0
  188. package/dist/theme/components/TypeBadge.d.ts +12 -0
  189. package/dist/theme/components/TypeBadge.d.ts.map +1 -0
  190. package/dist/theme/components/TypeBadge.js +39 -0
  191. package/dist/theme/components/VisibilityBadge.d.ts +12 -0
  192. package/dist/theme/components/VisibilityBadge.d.ts.map +1 -0
  193. package/dist/theme/components/VisibilityBadge.js +37 -0
  194. package/{src/theme/components/index.ts → dist/theme/components/index.d.ts} +1 -0
  195. package/dist/theme/components/index.d.ts.map +1 -0
  196. package/dist/theme/components/index.js +12 -0
  197. package/dist/theme/index.d.ts +21 -0
  198. package/dist/theme/index.d.ts.map +1 -0
  199. package/{src/theme/index.ts → dist/theme/index.js} +1 -4
  200. package/dist/theme/layouts/BaseLayout.d.ts +16 -0
  201. package/dist/theme/layouts/BaseLayout.d.ts.map +1 -0
  202. package/dist/theme/layouts/BaseLayout.js +58 -0
  203. package/dist/theme/layouts/DashLayout.d.ts +15 -0
  204. package/dist/theme/layouts/DashLayout.d.ts.map +1 -0
  205. package/dist/theme/layouts/DashLayout.js +139 -0
  206. package/{src/theme/layouts/index.ts → dist/theme/layouts/index.d.ts} +1 -0
  207. package/dist/theme/layouts/index.d.ts.map +1 -0
  208. package/dist/theme/layouts/index.js +2 -0
  209. package/dist/theme/styles/main.css +2 -0
  210. package/dist/types.d.ts +179 -0
  211. package/dist/types.d.ts.map +1 -0
  212. package/dist/types.js +19 -0
  213. package/package.json +26 -26
  214. package/drizzle.config.ts +0 -10
  215. package/lingui.config.ts +0 -16
  216. package/src/app.tsx +0 -377
  217. package/src/assets/datastar.min.js +0 -8
  218. package/src/auth.ts +0 -38
  219. package/src/db/index.ts +0 -14
  220. package/src/db/migrations/0000_solid_moon_knight.sql +0 -118
  221. package/src/db/migrations/0001_add_search_fts.sql +0 -40
  222. package/src/db/migrations/0002_collection_path.sql +0 -2
  223. package/src/db/migrations/0003_collection_path_nullable.sql +0 -21
  224. package/src/db/migrations/0004_media_uuid.sql +0 -35
  225. package/src/db/migrations/meta/0000_snapshot.json +0 -784
  226. package/src/db/migrations/meta/_journal.json +0 -41
  227. package/src/db/schema.ts +0 -159
  228. package/src/i18n/EXAMPLES.md +0 -235
  229. package/src/i18n/README.md +0 -296
  230. package/src/i18n/context.tsx +0 -101
  231. package/src/i18n/detect.ts +0 -100
  232. package/src/i18n/locales/en.po +0 -875
  233. package/src/i18n/locales/en.ts +0 -1
  234. package/src/i18n/locales/zh-Hans.po +0 -875
  235. package/src/i18n/locales/zh-Hans.ts +0 -1
  236. package/src/i18n/locales/zh-Hant.po +0 -875
  237. package/src/i18n/locales/zh-Hant.ts +0 -1
  238. package/src/i18n/locales.ts +0 -14
  239. package/src/i18n/middleware.ts +0 -59
  240. package/src/lib/assets.ts +0 -47
  241. package/src/lib/constants.ts +0 -67
  242. package/src/lib/schemas.ts +0 -92
  243. package/src/lib/sse.ts +0 -152
  244. package/src/middleware/auth.ts +0 -59
  245. package/src/routes/api/posts.ts +0 -127
  246. package/src/routes/api/search.ts +0 -53
  247. package/src/routes/api/upload.ts +0 -240
  248. package/src/routes/dash/collections.tsx +0 -341
  249. package/src/routes/dash/index.tsx +0 -89
  250. package/src/routes/dash/media.tsx +0 -551
  251. package/src/routes/dash/pages.tsx +0 -245
  252. package/src/routes/dash/posts.tsx +0 -202
  253. package/src/routes/dash/redirects.tsx +0 -155
  254. package/src/routes/dash/settings.tsx +0 -93
  255. package/src/routes/feed/rss.ts +0 -119
  256. package/src/routes/feed/sitemap.ts +0 -75
  257. package/src/routes/pages/archive.tsx +0 -223
  258. package/src/routes/pages/collection.tsx +0 -79
  259. package/src/routes/pages/home.tsx +0 -93
  260. package/src/routes/pages/page.tsx +0 -64
  261. package/src/routes/pages/post.tsx +0 -81
  262. package/src/routes/pages/search.tsx +0 -162
  263. package/src/services/collection.ts +0 -180
  264. package/src/services/index.ts +0 -40
  265. package/src/services/media.ts +0 -97
  266. package/src/services/post.ts +0 -279
  267. package/src/services/redirect.ts +0 -74
  268. package/src/services/search.ts +0 -117
  269. package/src/services/settings.ts +0 -76
  270. package/src/theme/components/ActionButtons.tsx +0 -98
  271. package/src/theme/components/CrudPageHeader.tsx +0 -48
  272. package/src/theme/components/DangerZone.tsx +0 -77
  273. package/src/theme/components/EmptyState.tsx +0 -56
  274. package/src/theme/components/ListItemRow.tsx +0 -24
  275. package/src/theme/components/PageForm.tsx +0 -114
  276. package/src/theme/components/Pagination.tsx +0 -196
  277. package/src/theme/components/PostForm.tsx +0 -122
  278. package/src/theme/components/PostList.tsx +0 -68
  279. package/src/theme/components/ThreadView.tsx +0 -118
  280. package/src/theme/components/TypeBadge.tsx +0 -28
  281. package/src/theme/components/VisibilityBadge.tsx +0 -33
  282. package/src/theme/layouts/BaseLayout.tsx +0 -49
  283. package/src/theme/layouts/DashLayout.tsx +0 -108
  284. package/src/theme/styles/main.css +0 -52
  285. package/src/types.ts +0 -222
  286. package/tsconfig.json +0 -16
  287. package/vite.config.ts +0 -82
  288. package/wrangler.toml +0 -21
@@ -0,0 +1,227 @@
1
+ /**
2
+ * Upload API Routes
3
+ *
4
+ * Handles file uploads to R2 storage.
5
+ * Supports both JSON and SSE (Datastar) responses.
6
+ */ import { Hono } from "hono";
7
+ import { html } from "hono/html";
8
+ import { requireAuthApi } from "../../middleware/auth.js";
9
+ import { getMediaUrl, getImageUrl } from "../../lib/image.js";
10
+ import { sse } from "../../lib/sse.js";
11
+ export const uploadApiRoutes = new Hono();
12
+ // Require auth for all upload routes
13
+ uploadApiRoutes.use("*", requireAuthApi());
14
+ /**
15
+ * Render a media card HTML string for SSE response
16
+ */ function renderMediaCard(media, r2PublicUrl, imageTransformUrl) {
17
+ const fullUrl = getMediaUrl(media.id, media.r2Key, r2PublicUrl);
18
+ const thumbnailUrl = getImageUrl(fullUrl, imageTransformUrl, {
19
+ width: 300,
20
+ quality: 80,
21
+ format: "auto",
22
+ fit: "cover"
23
+ });
24
+ const isImage = media.mimeType.startsWith("image/");
25
+ const displayName = media.alt || media.originalName;
26
+ const sizeStr = formatSize(media.size);
27
+ if (isImage) {
28
+ return html`
29
+ <div class="group relative" data-media-id="${media.id}">
30
+ <button
31
+ type="button"
32
+ class="block w-full aspect-square bg-muted rounded-lg overflow-hidden border hover:border-primary cursor-pointer"
33
+ onclick="document.getElementById('lightbox-img').src = '${fullUrl}'; document.getElementById('lightbox').showModal()"
34
+ >
35
+ <img
36
+ src="${thumbnailUrl}"
37
+ alt="${displayName}"
38
+ class="w-full h-full object-cover"
39
+ loading="lazy"
40
+ />
41
+ </button>
42
+ <a href="/dash/media/${media.id}" class="block mt-2 text-xs truncate hover:underline" title="${media.originalName}">
43
+ ${media.originalName}
44
+ </a>
45
+ <div class="text-xs text-muted-foreground">${sizeStr}</div>
46
+ </div>
47
+ `.toString();
48
+ }
49
+ return html`
50
+ <div class="group relative" data-media-id="${media.id}">
51
+ <a
52
+ href="/dash/media/${media.id}"
53
+ class="block aspect-square bg-muted rounded-lg overflow-hidden border hover:border-primary"
54
+ >
55
+ <div class="w-full h-full flex items-center justify-center text-muted-foreground">
56
+ <span class="text-xs">${media.mimeType}</span>
57
+ </div>
58
+ </a>
59
+ <a href="/dash/media/${media.id}" class="block mt-2 text-xs truncate hover:underline" title="${media.originalName}">
60
+ ${media.originalName}
61
+ </a>
62
+ <div class="text-xs text-muted-foreground">${sizeStr}</div>
63
+ </div>
64
+ `.toString();
65
+ }
66
+ function formatSize(bytes) {
67
+ if (bytes < 1024) return `${bytes} B`;
68
+ if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;
69
+ return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
70
+ }
71
+ /**
72
+ * Check if request wants SSE response (from Datastar)
73
+ */ function wantsSSE(c) {
74
+ const accept = c.req.header("accept") || "";
75
+ return accept.includes("text/event-stream");
76
+ }
77
+ // Upload a file
78
+ uploadApiRoutes.post("/", async (c)=>{
79
+ if (!c.env.R2) {
80
+ if (wantsSSE(c)) {
81
+ return sse(c, async (stream)=>{
82
+ await stream.patchSignals({
83
+ _uploadError: "R2 storage not configured"
84
+ });
85
+ });
86
+ }
87
+ return c.json({
88
+ error: "R2 storage not configured"
89
+ }, 500);
90
+ }
91
+ const formData = await c.req.formData();
92
+ const file = formData.get("file");
93
+ if (!file) {
94
+ if (wantsSSE(c)) {
95
+ return sse(c, async (stream)=>{
96
+ await stream.patchSignals({
97
+ _uploadError: "No file provided"
98
+ });
99
+ });
100
+ }
101
+ return c.json({
102
+ error: "No file provided"
103
+ }, 400);
104
+ }
105
+ // Validate file type
106
+ const allowedTypes = [
107
+ "image/jpeg",
108
+ "image/png",
109
+ "image/gif",
110
+ "image/webp",
111
+ "image/svg+xml"
112
+ ];
113
+ if (!allowedTypes.includes(file.type)) {
114
+ if (wantsSSE(c)) {
115
+ return sse(c, async (stream)=>{
116
+ await stream.patchSignals({
117
+ _uploadError: "File type not allowed"
118
+ });
119
+ });
120
+ }
121
+ return c.json({
122
+ error: "File type not allowed"
123
+ }, 400);
124
+ }
125
+ // Validate file size (max 10MB)
126
+ const maxSize = 10 * 1024 * 1024;
127
+ if (file.size > maxSize) {
128
+ if (wantsSSE(c)) {
129
+ return sse(c, async (stream)=>{
130
+ await stream.patchSignals({
131
+ _uploadError: "File too large (max 10MB)"
132
+ });
133
+ });
134
+ }
135
+ return c.json({
136
+ error: "File too large (max 10MB)"
137
+ }, 400);
138
+ }
139
+ // Generate unique filename
140
+ const ext = file.name.split(".").pop() || "bin";
141
+ const timestamp = Date.now();
142
+ const random = Math.random().toString(36).substring(2, 8);
143
+ const filename = `${timestamp}-${random}.${ext}`;
144
+ const r2Key = `uploads/${filename}`;
145
+ try {
146
+ // Upload to R2
147
+ await c.env.R2.put(r2Key, file.stream(), {
148
+ httpMetadata: {
149
+ contentType: file.type
150
+ }
151
+ });
152
+ // Save to database
153
+ const media = await c.var.services.media.create({
154
+ filename,
155
+ originalName: file.name,
156
+ mimeType: file.type,
157
+ size: file.size,
158
+ r2Key
159
+ });
160
+ // SSE response for Datastar
161
+ if (wantsSSE(c)) {
162
+ const cardHtml = renderMediaCard(media, c.env.R2_PUBLIC_URL, c.env.IMAGE_TRANSFORM_URL);
163
+ return sse(c, async (stream)=>{
164
+ // Replace placeholder with real media card
165
+ await stream.patchElements(cardHtml, {
166
+ mode: "outer",
167
+ selector: "#upload-placeholder"
168
+ });
169
+ });
170
+ }
171
+ // JSON response for API clients
172
+ const publicUrl = getMediaUrl(media.id, r2Key, c.env.R2_PUBLIC_URL);
173
+ return c.json({
174
+ id: media.id,
175
+ filename: media.filename,
176
+ url: publicUrl,
177
+ mimeType: media.mimeType,
178
+ size: media.size
179
+ });
180
+ } catch (err) {
181
+ // eslint-disable-next-line no-console -- Error logging is intentional
182
+ console.error("Upload error:", err);
183
+ // Return error - client will handle updating the placeholder
184
+ return c.json({
185
+ error: "Upload failed"
186
+ }, 500);
187
+ }
188
+ });
189
+ // List uploaded files (JSON only)
190
+ uploadApiRoutes.get("/", async (c)=>{
191
+ const limit = parseInt(c.req.query("limit") ?? "50", 10);
192
+ const mediaList = await c.var.services.media.list(limit);
193
+ return c.json({
194
+ media: mediaList.map((m)=>({
195
+ id: m.id,
196
+ filename: m.filename,
197
+ url: getMediaUrl(m.id, m.r2Key, c.env.R2_PUBLIC_URL),
198
+ mimeType: m.mimeType,
199
+ size: m.size,
200
+ createdAt: m.createdAt
201
+ }))
202
+ });
203
+ });
204
+ // Delete a file
205
+ uploadApiRoutes.delete("/:id", async (c)=>{
206
+ const id = c.req.param("id");
207
+ const media = await c.var.services.media.getById(id);
208
+ if (!media) {
209
+ return c.json({
210
+ error: "Not found"
211
+ }, 404);
212
+ }
213
+ // Delete from R2
214
+ if (c.env.R2) {
215
+ try {
216
+ await c.env.R2.delete(media.r2Key);
217
+ } catch (err) {
218
+ // eslint-disable-next-line no-console -- Error logging is intentional
219
+ console.error("R2 delete error:", err);
220
+ }
221
+ }
222
+ // Delete from database
223
+ await c.var.services.media.delete(id);
224
+ return c.json({
225
+ success: true
226
+ });
227
+ });
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Dashboard Collections Routes
3
+ */
4
+ import { Hono } from "hono";
5
+ import type { Bindings } from "../../types.js";
6
+ import type { AppVariables } from "../../app.js";
7
+ type Env = {
8
+ Bindings: Bindings;
9
+ Variables: AppVariables;
10
+ };
11
+ export declare const collectionsRoutes: Hono<Env, import("hono/types").BlankSchema, "/">;
12
+ export {};
13
+ //# sourceMappingURL=collections.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"collections.d.ts","sourceRoot":"","sources":["../../../src/routes/dash/collections.tsx"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAE5B,OAAO,KAAK,EAAE,QAAQ,EAAoB,MAAM,gBAAgB,CAAC;AACjE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAKjD,KAAK,GAAG,GAAG;IAAE,QAAQ,EAAE,QAAQ,CAAC;IAAC,SAAS,EAAE,YAAY,CAAA;CAAE,CAAC;AAE3D,eAAO,MAAM,iBAAiB,kDAAkB,CAAC"}