@notionx/core 0.1.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 (208) hide show
  1. package/dist/admin/index.d.ts +137 -0
  2. package/dist/admin/index.js +206 -0
  3. package/dist/admin/index.js.map +1 -0
  4. package/dist/admin/pages/index.d.ts +324 -0
  5. package/dist/admin/pages/index.js +827 -0
  6. package/dist/admin/pages/index.js.map +1 -0
  7. package/dist/auth/auth-pages/forgot-password.d.ts +20 -0
  8. package/dist/auth/auth-pages/forgot-password.js +70 -0
  9. package/dist/auth/auth-pages/forgot-password.js.map +1 -0
  10. package/dist/auth/auth-pages/index.d.ts +6 -0
  11. package/dist/auth/auth-pages/index.js +342 -0
  12. package/dist/auth/auth-pages/index.js.map +1 -0
  13. package/dist/auth/auth-pages/login.d.ts +30 -0
  14. package/dist/auth/auth-pages/login.js +125 -0
  15. package/dist/auth/auth-pages/login.js.map +1 -0
  16. package/dist/auth/auth-pages/register.d.ts +17 -0
  17. package/dist/auth/auth-pages/register.js +81 -0
  18. package/dist/auth/auth-pages/register.js.map +1 -0
  19. package/dist/auth/auth-pages/reset-password.d.ts +18 -0
  20. package/dist/auth/auth-pages/reset-password.js +72 -0
  21. package/dist/auth/auth-pages/reset-password.js.map +1 -0
  22. package/dist/auth/index.d.ts +72 -0
  23. package/dist/auth/index.js +1011 -0
  24. package/dist/auth/index.js.map +1 -0
  25. package/dist/auth/passwords.d.ts +6 -0
  26. package/dist/auth/passwords.js +79 -0
  27. package/dist/auth/passwords.js.map +1 -0
  28. package/dist/auth/rate-limit.d.ts +28 -0
  29. package/dist/auth/rate-limit.js +245 -0
  30. package/dist/auth/rate-limit.js.map +1 -0
  31. package/dist/auth/routes/google-callback.d.ts +6 -0
  32. package/dist/auth/routes/google-callback.js +404 -0
  33. package/dist/auth/routes/google-callback.js.map +1 -0
  34. package/dist/auth/routes/google.d.ts +6 -0
  35. package/dist/auth/routes/google.js +250 -0
  36. package/dist/auth/routes/google.js.map +1 -0
  37. package/dist/auth/routes/index.d.ts +22 -0
  38. package/dist/auth/routes/index.js +619 -0
  39. package/dist/auth/routes/index.js.map +1 -0
  40. package/dist/auth/routes/verify-email.d.ts +6 -0
  41. package/dist/auth/routes/verify-email.js +317 -0
  42. package/dist/auth/routes/verify-email.js.map +1 -0
  43. package/dist/auth/routes/viewer.d.ts +6 -0
  44. package/dist/auth/routes/viewer.js +372 -0
  45. package/dist/auth/routes/viewer.js.map +1 -0
  46. package/dist/auth/session.d.ts +9 -0
  47. package/dist/auth/session.js +1 -0
  48. package/dist/auth/session.js.map +1 -0
  49. package/dist/auth/turnstile.d.ts +20 -0
  50. package/dist/auth/turnstile.js +301 -0
  51. package/dist/auth/turnstile.js.map +1 -0
  52. package/dist/auth/user-session.d.ts +42 -0
  53. package/dist/auth/user-session.js +419 -0
  54. package/dist/auth/user-session.js.map +1 -0
  55. package/dist/auth/users.d.ts +112 -0
  56. package/dist/auth/users.js +558 -0
  57. package/dist/auth/users.js.map +1 -0
  58. package/dist/bootstrap-CN2g76M6.d.ts +67 -0
  59. package/dist/cache/index.d.ts +6 -0
  60. package/dist/cache/index.js +47 -0
  61. package/dist/cache/index.js.map +1 -0
  62. package/dist/content/admin-summary.d.ts +24 -0
  63. package/dist/content/admin-summary.js +36 -0
  64. package/dist/content/admin-summary.js.map +1 -0
  65. package/dist/content/index.d.ts +9 -0
  66. package/dist/content/index.js +473 -0
  67. package/dist/content/index.js.map +1 -0
  68. package/dist/content/models.d.ts +69 -0
  69. package/dist/content/models.js +24 -0
  70. package/dist/content/models.js.map +1 -0
  71. package/dist/content/prewarm.d.ts +28 -0
  72. package/dist/content/prewarm.js +56 -0
  73. package/dist/content/prewarm.js.map +1 -0
  74. package/dist/content/revalidate.d.ts +37 -0
  75. package/dist/content/revalidate.js +170 -0
  76. package/dist/content/revalidate.js.map +1 -0
  77. package/dist/content/search-index.d.ts +54 -0
  78. package/dist/content/search-index.js +172 -0
  79. package/dist/content/search-index.js.map +1 -0
  80. package/dist/content/search.d.ts +8 -0
  81. package/dist/content/search.js +57 -0
  82. package/dist/content/search.js.map +1 -0
  83. package/dist/doctor/cli.d.ts +1 -0
  84. package/dist/doctor/cli.js +360 -0
  85. package/dist/doctor/cli.js.map +1 -0
  86. package/dist/doctor/index.d.ts +139 -0
  87. package/dist/doctor/index.js +289 -0
  88. package/dist/doctor/index.js.map +1 -0
  89. package/dist/email/index.d.ts +38 -0
  90. package/dist/email/index.js +126 -0
  91. package/dist/email/index.js.map +1 -0
  92. package/dist/env-C5qu-0R-.d.ts +35 -0
  93. package/dist/hooks/index.d.ts +2 -0
  94. package/dist/hooks/index.js +1 -0
  95. package/dist/hooks/index.js.map +1 -0
  96. package/dist/i18n/index.d.ts +26 -0
  97. package/dist/i18n/index.js +73 -0
  98. package/dist/i18n/index.js.map +1 -0
  99. package/dist/index.d.ts +8 -0
  100. package/dist/index.js +1281 -0
  101. package/dist/index.js.map +1 -0
  102. package/dist/internal/admin/index.d.ts +75 -0
  103. package/dist/internal/admin/index.js +365 -0
  104. package/dist/internal/admin/index.js.map +1 -0
  105. package/dist/media/index.d.ts +24 -0
  106. package/dist/media/index.js +86 -0
  107. package/dist/media/index.js.map +1 -0
  108. package/dist/media/routes/index.d.ts +1 -0
  109. package/dist/media/routes/index.js +585 -0
  110. package/dist/media/routes/index.js.map +1 -0
  111. package/dist/media/routes/notion-media.d.ts +19 -0
  112. package/dist/media/routes/notion-media.js +588 -0
  113. package/dist/media/routes/notion-media.js.map +1 -0
  114. package/dist/middleware.d.ts +95 -0
  115. package/dist/middleware.js +79 -0
  116. package/dist/middleware.js.map +1 -0
  117. package/dist/notion/block-text.d.ts +5 -0
  118. package/dist/notion/block-text.js +37 -0
  119. package/dist/notion/block-text.js.map +1 -0
  120. package/dist/notion/blocks.d.ts +24 -0
  121. package/dist/notion/blocks.js +46 -0
  122. package/dist/notion/blocks.js.map +1 -0
  123. package/dist/notion/client.d.ts +7 -0
  124. package/dist/notion/client.js +13 -0
  125. package/dist/notion/client.js.map +1 -0
  126. package/dist/notion/config.d.ts +25 -0
  127. package/dist/notion/config.js +147 -0
  128. package/dist/notion/config.js.map +1 -0
  129. package/dist/notion/content-cache.d.ts +45 -0
  130. package/dist/notion/content-cache.js +166 -0
  131. package/dist/notion/content-cache.js.map +1 -0
  132. package/dist/notion/generic-source.d.ts +61 -0
  133. package/dist/notion/generic-source.js +408 -0
  134. package/dist/notion/generic-source.js.map +1 -0
  135. package/dist/notion/index.d.ts +13 -0
  136. package/dist/notion/index.js +1278 -0
  137. package/dist/notion/index.js.map +1 -0
  138. package/dist/notion/mappers.d.ts +1 -0
  139. package/dist/notion/mappers.js +152 -0
  140. package/dist/notion/mappers.js.map +1 -0
  141. package/dist/notion/media.d.ts +22 -0
  142. package/dist/notion/media.js +209 -0
  143. package/dist/notion/media.js.map +1 -0
  144. package/dist/notion/property-mappers.d.ts +24 -0
  145. package/dist/notion/property-mappers.js +152 -0
  146. package/dist/notion/property-mappers.js.map +1 -0
  147. package/dist/notion/routes/index.d.ts +8 -0
  148. package/dist/notion/routes/index.js +428 -0
  149. package/dist/notion/routes/index.js.map +1 -0
  150. package/dist/notion/routes/webhook.d.ts +98 -0
  151. package/dist/notion/routes/webhook.js +428 -0
  152. package/dist/notion/routes/webhook.js.map +1 -0
  153. package/dist/notion/types.d.ts +152 -0
  154. package/dist/notion/types.js +1 -0
  155. package/dist/notion/types.js.map +1 -0
  156. package/dist/notion/webhook.d.ts +83 -0
  157. package/dist/notion/webhook.js +490 -0
  158. package/dist/notion/webhook.js.map +1 -0
  159. package/dist/platform/capabilities.d.ts +34 -0
  160. package/dist/platform/capabilities.js +42 -0
  161. package/dist/platform/capabilities.js.map +1 -0
  162. package/dist/platform/current.d.ts +13 -0
  163. package/dist/platform/current.js +181 -0
  164. package/dist/platform/current.js.map +1 -0
  165. package/dist/platform/index.d.ts +5 -0
  166. package/dist/platform/index.js +269 -0
  167. package/dist/platform/index.js.map +1 -0
  168. package/dist/platform/runtime.d.ts +118 -0
  169. package/dist/platform/runtime.js +160 -0
  170. package/dist/platform/runtime.js.map +1 -0
  171. package/dist/platform/selection.d.ts +10 -0
  172. package/dist/platform/selection.js +22 -0
  173. package/dist/platform/selection.js.map +1 -0
  174. package/dist/storage/index.d.ts +17 -0
  175. package/dist/storage/index.js +218 -0
  176. package/dist/storage/index.js.map +1 -0
  177. package/dist/storage/routes/cdn.d.ts +19 -0
  178. package/dist/storage/routes/cdn.js +289 -0
  179. package/dist/storage/routes/cdn.js.map +1 -0
  180. package/dist/storage/routes/files.d.ts +27 -0
  181. package/dist/storage/routes/files.js +216 -0
  182. package/dist/storage/routes/files.js.map +1 -0
  183. package/dist/storage/routes/index.d.ts +2 -0
  184. package/dist/storage/routes/index.js +352 -0
  185. package/dist/storage/routes/index.js.map +1 -0
  186. package/dist/types-BsAcZSNX.d.ts +94 -0
  187. package/dist/types.d.ts +78 -0
  188. package/dist/types.js +1 -0
  189. package/dist/types.js.map +1 -0
  190. package/dist/util/index.d.ts +18 -0
  191. package/dist/util/index.js +48 -0
  192. package/dist/util/index.js.map +1 -0
  193. package/dist/worker/index.d.ts +6 -0
  194. package/dist/worker/index.js +1026 -0
  195. package/dist/worker/index.js.map +1 -0
  196. package/dist/worker/routes/content-prewarm.d.ts +34 -0
  197. package/dist/worker/routes/content-prewarm.js +38 -0
  198. package/dist/worker/routes/content-prewarm.js.map +1 -0
  199. package/dist/worker/routes/content-revalidate.d.ts +81 -0
  200. package/dist/worker/routes/content-revalidate.js +64 -0
  201. package/dist/worker/routes/content-revalidate.js.map +1 -0
  202. package/dist/worker/routes/health.d.ts +14 -0
  203. package/dist/worker/routes/health.js +278 -0
  204. package/dist/worker/routes/health.js.map +1 -0
  205. package/dist/worker/routes/index.d.ts +6 -0
  206. package/dist/worker/routes/index.js +373 -0
  207. package/dist/worker/routes/index.js.map +1 -0
  208. package/package.json +124 -0
@@ -0,0 +1,827 @@
1
+ var __defProp = Object.defineProperty;
2
+ var __getOwnPropNames = Object.getOwnPropertyNames;
3
+ var __esm = (fn, res) => function __init() {
4
+ return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
5
+ };
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+
11
+ // src/admin/pages/delete-button.tsx
12
+ var delete_button_exports = {};
13
+ __export(delete_button_exports, {
14
+ default: () => AdminDeleteButton
15
+ });
16
+ import { useRef, useState } from "react";
17
+ import { Trash2 as Trash23 } from "lucide-react";
18
+ import { jsx as jsx6, jsxs as jsxs6 } from "react/jsx-runtime";
19
+ function AdminDeleteButton({
20
+ context,
21
+ slug,
22
+ title
23
+ }) {
24
+ const { ui, actions } = context;
25
+ const { Button, AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogTitle, AlertDialogTrigger } = ui;
26
+ const formRef = useRef(null);
27
+ const [open, setOpen] = useState(false);
28
+ const deleteAction = actions?.deletePost;
29
+ if (!deleteAction) return null;
30
+ return /* @__PURE__ */ jsxs6(AlertDialog, { open, onOpenChange: setOpen, children: [
31
+ /* @__PURE__ */ jsx6(AlertDialogTrigger, { asChild: true, children: /* @__PURE__ */ jsxs6(
32
+ Button,
33
+ {
34
+ variant: "ghost",
35
+ size: "sm",
36
+ className: "text-destructive hover:text-destructive",
37
+ children: [
38
+ /* @__PURE__ */ jsx6(Trash23, { className: "mr-1 h-3 w-3" }),
39
+ "\u5220\u9664"
40
+ ]
41
+ }
42
+ ) }),
43
+ /* @__PURE__ */ jsxs6(AlertDialogContent, { children: [
44
+ /* @__PURE__ */ jsxs6(AlertDialogHeader, { children: [
45
+ /* @__PURE__ */ jsx6(AlertDialogTitle, { children: "\u786E\u5B9A\u8981\u5220\u9664\u8FD9\u7BC7\u6587\u7AE0\u5417\uFF1F" }),
46
+ /* @__PURE__ */ jsxs6(AlertDialogDescription, { children: [
47
+ /* @__PURE__ */ jsx6("span", { className: "font-medium text-foreground", children: title }),
48
+ /* @__PURE__ */ jsx6("br", {}),
49
+ /* @__PURE__ */ jsx6("code", { className: "rounded bg-muted px-1.5 py-0.5 text-xs", children: slug }),
50
+ /* @__PURE__ */ jsx6("br", {}),
51
+ /* @__PURE__ */ jsx6("br", {}),
52
+ "\u6B64\u64CD\u4F5C\u4E0D\u53EF\u64A4\u9500\u3002\u6587\u7AE0\u5C06\u4ECE D1 \u6570\u636E\u5E93\u548C\u535A\u5BA2\u5217\u8868\u4E2D\u6C38\u4E45\u79FB\u9664\u3002"
53
+ ] })
54
+ ] }),
55
+ /* @__PURE__ */ jsxs6(AlertDialogFooter, { children: [
56
+ /* @__PURE__ */ jsx6(AlertDialogCancel, { children: "\u53D6\u6D88" }),
57
+ /* @__PURE__ */ jsx6(
58
+ AlertDialogAction,
59
+ {
60
+ onClick: () => formRef.current?.requestSubmit(),
61
+ className: "bg-destructive text-destructive-foreground hover:bg-destructive/90",
62
+ children: "\u786E\u8BA4\u5220\u9664"
63
+ }
64
+ )
65
+ ] })
66
+ ] }),
67
+ /* @__PURE__ */ jsx6("form", { ref: formRef, action: deleteAction, style: { display: "none" }, children: /* @__PURE__ */ jsx6("input", { type: "hidden", name: "slug", value: slug }) })
68
+ ] });
69
+ }
70
+ var init_delete_button = __esm({
71
+ "src/admin/pages/delete-button.tsx"() {
72
+ "use strict";
73
+ "use client";
74
+ }
75
+ });
76
+
77
+ // src/admin/pages/dashboard.tsx
78
+ import Link from "next/link";
79
+ import { ExternalLink, Plus } from "lucide-react";
80
+ import { jsx, jsxs } from "react/jsx-runtime";
81
+ async function AdminDashboardPage({
82
+ context,
83
+ searchParams
84
+ }) {
85
+ const { ui, data } = context;
86
+ const { Button, Badge, Table, TableHeader, TableBody, TableRow, TableHead, TableCell, Alert, AlertTitle, AlertDescription } = ui;
87
+ const { error } = searchParams;
88
+ const posts = await data?.getNotionPostsMeta?.() ?? [];
89
+ const notionHref = data?.getNotionEditBaseUrl?.() ?? "#";
90
+ return /* @__PURE__ */ jsxs("div", { className: "space-y-6", children: [
91
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between", children: [
92
+ /* @__PURE__ */ jsxs("div", { children: [
93
+ /* @__PURE__ */ jsx("h1", { className: "text-3xl font-bold tracking-tight", children: "\u6587\u7AE0\u7BA1\u7406" }),
94
+ /* @__PURE__ */ jsx("p", { className: "text-sm text-muted-foreground", children: "\u5185\u5BB9\u73B0\u7531 Notion \u7BA1\u7406\uFF0C\u8FD9\u91CC\u5C55\u793A\u516C\u5F00\u7D22\u5F15\u3002" })
95
+ ] }),
96
+ /* @__PURE__ */ jsx(Button, { asChild: true, children: /* @__PURE__ */ jsxs("a", { href: notionHref, target: "_blank", rel: "noreferrer", children: [
97
+ /* @__PURE__ */ jsx(Plus, { className: "mr-1 h-4 w-4" }),
98
+ "\u5728 Notion \u4E2D\u65B0\u5EFA"
99
+ ] }) })
100
+ ] }),
101
+ error && /* @__PURE__ */ jsxs(Alert, { variant: "destructive", children: [
102
+ /* @__PURE__ */ jsx(AlertTitle, { children: "\u65E0\u6CD5\u8BBF\u95EE" }),
103
+ /* @__PURE__ */ jsx(AlertDescription, { children: error })
104
+ ] }),
105
+ posts.length === 0 ? /* @__PURE__ */ jsx("div", { className: "rounded-lg border border-dashed py-16 text-center text-sm text-muted-foreground", children: "\u8FD8\u6CA1\u6709\u53EF\u663E\u793A\u7684 Notion \u6587\u7AE0\u3002" }) : /* @__PURE__ */ jsx("div", { className: "rounded-md border", children: /* @__PURE__ */ jsxs(Table, { children: [
106
+ /* @__PURE__ */ jsx(TableHeader, { children: /* @__PURE__ */ jsxs(TableRow, { children: [
107
+ /* @__PURE__ */ jsx(TableHead, { className: "w-[40%]", children: "\u6807\u9898" }),
108
+ /* @__PURE__ */ jsx(TableHead, { children: "\u4F5C\u8005" }),
109
+ /* @__PURE__ */ jsx(TableHead, { children: "\u65E5\u671F" }),
110
+ /* @__PURE__ */ jsx(TableHead, { children: "\u6807\u7B7E" }),
111
+ /* @__PURE__ */ jsx(TableHead, { className: "text-right", children: "\u64CD\u4F5C" })
112
+ ] }) }),
113
+ /* @__PURE__ */ jsx(TableBody, { children: posts.map((post) => /* @__PURE__ */ jsxs(TableRow, { children: [
114
+ /* @__PURE__ */ jsx(TableCell, { className: "font-medium", children: post.title }),
115
+ /* @__PURE__ */ jsx(TableCell, { children: /* @__PURE__ */ jsx("span", { className: "text-xs text-muted-foreground", children: post.author }) }),
116
+ /* @__PURE__ */ jsx(TableCell, { children: /* @__PURE__ */ jsx("time", { dateTime: post.date, children: post.date }) }),
117
+ /* @__PURE__ */ jsx(TableCell, { children: /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap gap-1", children: [
118
+ post.tags.slice(0, 2).map((tag) => /* @__PURE__ */ jsx(Badge, { variant: "secondary", className: "text-xs", children: tag }, tag)),
119
+ post.tags.length > 2 && /* @__PURE__ */ jsxs("span", { className: "text-xs text-muted-foreground", children: [
120
+ "+",
121
+ post.tags.length - 2
122
+ ] })
123
+ ] }) }),
124
+ /* @__PURE__ */ jsx(TableCell, { className: "text-right", children: /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-end gap-2", children: [
125
+ /* @__PURE__ */ jsx(Button, { asChild: true, variant: "ghost", size: "sm", children: /* @__PURE__ */ jsx(Link, { href: `/blog/${post.slug}`, prefetch: true, children: "\u67E5\u770B" }) }),
126
+ /* @__PURE__ */ jsx(Button, { asChild: true, variant: "ghost", size: "sm", children: /* @__PURE__ */ jsx(Link, { href: `/admin/${post.slug}/edit`, prefetch: true, children: "\u7F16\u8F91" }) }),
127
+ post.editUrl && /* @__PURE__ */ jsx(Button, { asChild: true, variant: "ghost", size: "sm", children: /* @__PURE__ */ jsxs(
128
+ "a",
129
+ {
130
+ href: post.editUrl,
131
+ target: "_blank",
132
+ rel: "noreferrer",
133
+ children: [
134
+ /* @__PURE__ */ jsx(ExternalLink, { className: "mr-1 h-3 w-3" }),
135
+ "Notion"
136
+ ]
137
+ }
138
+ ) })
139
+ ] }) })
140
+ ] }, post.slug)) })
141
+ ] }) })
142
+ ] });
143
+ }
144
+
145
+ // src/admin/pages/users.tsx
146
+ import { redirect } from "next/navigation";
147
+ import { Crown, LogOut, Trash2, UserCheck, Users } from "lucide-react";
148
+ import { Fragment, jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
149
+ async function AdminUsersPage({
150
+ context,
151
+ searchParams
152
+ }) {
153
+ const { ui, data, actions } = context;
154
+ const { Badge, Button, Card, CardHeader, CardTitle, CardDescription, CardContent, Alert, AlertTitle, AlertDescription, Table, TableHeader, TableBody, TableRow, TableHead, TableCell } = ui;
155
+ const viewer = await data?.getAdminViewer?.() ?? null;
156
+ if (!viewer?.viewer) redirect("/login");
157
+ if (!viewer.admin) {
158
+ redirect("/admin?error=\u9700\u8981\u7BA1\u7406\u5458\u6743\u9650");
159
+ }
160
+ const { revoked, deleted, roleUpdated, error } = searchParams;
161
+ const users = await data?.listUsersWithPostCounts?.() ?? [];
162
+ return /* @__PURE__ */ jsxs2("div", { className: "space-y-6", children: [
163
+ /* @__PURE__ */ jsxs2("div", { children: [
164
+ /* @__PURE__ */ jsxs2("h1", { className: "flex items-center gap-2 text-3xl font-bold tracking-tight", children: [
165
+ /* @__PURE__ */ jsx2(Users, { className: "h-7 w-7" }),
166
+ "\u7528\u6237\u7BA1\u7406"
167
+ ] }),
168
+ /* @__PURE__ */ jsx2("p", { className: "text-sm text-muted-foreground", children: "\u5F3A\u5236\u4E0B\u7EBF\u4F1A\u4F7F\u8BE5\u7528\u6237\u6240\u6709\u8BBE\u5907\u4E0A\u7684\u4F1A\u8BDD\u7ACB\u5373\u5931\u6548\uFF1B\u5220\u9664\u7528\u6237\u4F1A\u5C06\u5176\u6587\u7AE0\u5F52\u5C5E\u8F6C\u79FB\u7ED9\u7BA1\u7406\u5458\u3002" })
169
+ ] }),
170
+ revoked && /* @__PURE__ */ jsxs2(Alert, { children: [
171
+ /* @__PURE__ */ jsx2(AlertTitle, { children: "\u5DF2\u5F3A\u5236\u4E0B\u7EBF" }),
172
+ /* @__PURE__ */ jsxs2(AlertDescription, { children: [
173
+ revoked,
174
+ " \u7684\u6240\u6709\u4F1A\u8BDD\u5DF2\u5931\u6548\u3002"
175
+ ] })
176
+ ] }),
177
+ deleted && /* @__PURE__ */ jsxs2(Alert, { children: [
178
+ /* @__PURE__ */ jsx2(AlertTitle, { children: "\u7528\u6237\u5DF2\u5220\u9664" }),
179
+ /* @__PURE__ */ jsxs2(AlertDescription, { children: [
180
+ "\u5DF2\u5220\u9664 ",
181
+ deleted,
182
+ "\uFF0C\u5176\u6587\u7AE0\u5DF2\u5F52\u5C5E\u7BA1\u7406\u5458\u3002"
183
+ ] })
184
+ ] }),
185
+ roleUpdated && /* @__PURE__ */ jsxs2(Alert, { children: [
186
+ /* @__PURE__ */ jsx2(AlertTitle, { children: "\u89D2\u8272\u5DF2\u66F4\u65B0" }),
187
+ /* @__PURE__ */ jsxs2(AlertDescription, { children: [
188
+ roleUpdated,
189
+ " \u7684\u6743\u9650\u5DF2\u66F4\u65B0\u3002"
190
+ ] })
191
+ ] }),
192
+ error && /* @__PURE__ */ jsxs2(Alert, { variant: "destructive", children: [
193
+ /* @__PURE__ */ jsx2(AlertTitle, { children: "\u64CD\u4F5C\u5931\u8D25" }),
194
+ /* @__PURE__ */ jsx2(AlertDescription, { children: error })
195
+ ] }),
196
+ /* @__PURE__ */ jsxs2(Card, { children: [
197
+ /* @__PURE__ */ jsxs2(CardHeader, { children: [
198
+ /* @__PURE__ */ jsx2(CardTitle, { children: "\u6CE8\u518C\u7528\u6237" }),
199
+ /* @__PURE__ */ jsxs2(CardDescription, { children: [
200
+ "\u5171 ",
201
+ users.length,
202
+ " \u4E2A\u8D26\u6237"
203
+ ] })
204
+ ] }),
205
+ /* @__PURE__ */ jsx2(CardContent, { children: /* @__PURE__ */ jsxs2(Table, { children: [
206
+ /* @__PURE__ */ jsx2(TableHeader, { children: /* @__PURE__ */ jsxs2(TableRow, { children: [
207
+ /* @__PURE__ */ jsx2(TableHead, { children: "\u90AE\u7BB1" }),
208
+ /* @__PURE__ */ jsx2(TableHead, { children: "\u89D2\u8272" }),
209
+ /* @__PURE__ */ jsx2(TableHead, { children: "\u767B\u5F55\u65B9\u5F0F" }),
210
+ /* @__PURE__ */ jsx2(TableHead, { children: "\u6587\u7AE0\u6570" }),
211
+ /* @__PURE__ */ jsx2(TableHead, { children: "\u6700\u8FD1\u6D3B\u8DC3" }),
212
+ /* @__PURE__ */ jsx2(TableHead, { className: "text-right", children: "\u64CD\u4F5C" })
213
+ ] }) }),
214
+ /* @__PURE__ */ jsx2(TableBody, { children: users.map((u) => {
215
+ const isSelf = u.email === viewer.viewerEmail;
216
+ const loginMethod = u.google_sub && u.password_hash ? "Google + \u5BC6\u7801" : u.google_sub ? "Google" : "\u90AE\u7BB1\u5BC6\u7801";
217
+ const role = u.role === "admin" || u.role === "vip" ? u.role : "user";
218
+ return /* @__PURE__ */ jsxs2(TableRow, { children: [
219
+ /* @__PURE__ */ jsxs2(TableCell, { className: "font-medium", children: [
220
+ u.email,
221
+ isSelf && /* @__PURE__ */ jsx2(Badge, { variant: "secondary", className: "ml-2", children: "\u5F53\u524D" })
222
+ ] }),
223
+ /* @__PURE__ */ jsx2(TableCell, { children: role === "admin" ? /* @__PURE__ */ jsx2(Badge, { children: "\u7BA1\u7406\u5458" }) : role === "vip" ? /* @__PURE__ */ jsxs2(Badge, { variant: "secondary", className: "gap-1", children: [
224
+ /* @__PURE__ */ jsx2(Crown, { className: "h-3 w-3" }),
225
+ "VIP"
226
+ ] }) : /* @__PURE__ */ jsx2(Badge, { variant: "outline", children: "\u7528\u6237" }) }),
227
+ /* @__PURE__ */ jsx2(TableCell, { className: "text-muted-foreground", children: loginMethod }),
228
+ /* @__PURE__ */ jsx2(TableCell, { children: u.post_count }),
229
+ /* @__PURE__ */ jsx2(TableCell, { className: "text-muted-foreground text-xs", children: u.last_seen_at }),
230
+ /* @__PURE__ */ jsx2(TableCell, { className: "text-right", children: /* @__PURE__ */ jsxs2("div", { className: "flex justify-end gap-2", children: [
231
+ !isSelf && role !== "admin" && actions?.adminSetUserRole && /* @__PURE__ */ jsxs2("form", { action: actions.adminSetUserRole, children: [
232
+ /* @__PURE__ */ jsx2("input", { type: "hidden", name: "userId", value: u.id }),
233
+ /* @__PURE__ */ jsx2(
234
+ "input",
235
+ {
236
+ type: "hidden",
237
+ name: "role",
238
+ value: role === "vip" ? "user" : "vip"
239
+ }
240
+ ),
241
+ /* @__PURE__ */ jsx2(Button, { type: "submit", variant: "outline", size: "sm", children: role === "vip" ? /* @__PURE__ */ jsxs2(Fragment, { children: [
242
+ /* @__PURE__ */ jsx2(UserCheck, { className: "mr-1 h-3 w-3" }),
243
+ "\u8BBE\u4E3A\u7528\u6237"
244
+ ] }) : /* @__PURE__ */ jsxs2(Fragment, { children: [
245
+ /* @__PURE__ */ jsx2(Crown, { className: "mr-1 h-3 w-3" }),
246
+ "\u8BBE\u4E3A VIP"
247
+ ] }) })
248
+ ] }),
249
+ actions?.adminRevokeSessions && /* @__PURE__ */ jsxs2("form", { action: actions.adminRevokeSessions, children: [
250
+ /* @__PURE__ */ jsx2("input", { type: "hidden", name: "userId", value: u.id }),
251
+ /* @__PURE__ */ jsxs2(Button, { type: "submit", variant: "outline", size: "sm", children: [
252
+ /* @__PURE__ */ jsx2(LogOut, { className: "mr-1 h-3 w-3" }),
253
+ "\u5F3A\u5236\u4E0B\u7EBF"
254
+ ] })
255
+ ] }),
256
+ !isSelf && role !== "admin" && actions?.adminDeleteUser && /* @__PURE__ */ jsxs2("form", { action: actions.adminDeleteUser, children: [
257
+ /* @__PURE__ */ jsx2("input", { type: "hidden", name: "userId", value: u.id }),
258
+ /* @__PURE__ */ jsxs2(
259
+ Button,
260
+ {
261
+ type: "submit",
262
+ variant: "destructive",
263
+ size: "sm",
264
+ children: [
265
+ /* @__PURE__ */ jsx2(Trash2, { className: "mr-1 h-3 w-3" }),
266
+ "\u5220\u9664"
267
+ ]
268
+ }
269
+ )
270
+ ] })
271
+ ] }) })
272
+ ] }, u.id);
273
+ }) })
274
+ ] }) })
275
+ ] })
276
+ ] });
277
+ }
278
+
279
+ // src/admin/pages/settings.tsx
280
+ import { redirect as redirect2 } from "next/navigation";
281
+ import { Bot, Save, Power, Settings2, ShieldCheck, Webhook } from "lucide-react";
282
+ import { jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
283
+ async function AdminSettingsPage({
284
+ context,
285
+ searchParams
286
+ }) {
287
+ const { ui, data, actions } = context;
288
+ const { Card, CardHeader, CardTitle, CardDescription, CardContent, Button, Input, Label, Alert, AlertTitle, AlertDescription, Separator, Badge } = ui;
289
+ const user = await data?.getCurrentUser?.() ?? null;
290
+ if (!user) redirect2("/login");
291
+ await data?.ensureAdminBootstrap?.();
292
+ if (!await data?.isAdminEmail?.(user.email)) {
293
+ redirect2("/admin?error=\u9700\u8981\u7BA1\u7406\u5458\u6743\u9650");
294
+ }
295
+ const { saved, error } = searchParams;
296
+ const s = await data?.getAppSettings?.() ?? {
297
+ admin_email: user.email,
298
+ site_title: "",
299
+ google_enabled: 0,
300
+ google_client_id: null,
301
+ google_client_secret: null,
302
+ turnstile_enabled: 0,
303
+ turnstile_site_key: null
304
+ };
305
+ const turnstile = await data?.getTurnstilePublicConfig?.() ?? {
306
+ enabled: false,
307
+ secretConfigured: false
308
+ };
309
+ const siteHost = (() => {
310
+ try {
311
+ return new URL(data?.getSiteUrl?.() ?? "").hostname;
312
+ } catch {
313
+ return "your-domain.com";
314
+ }
315
+ })();
316
+ const callbackUrl = `<your-domain>/api/auth/google/callback`;
317
+ return /* @__PURE__ */ jsxs3("div", { className: "space-y-6", children: [
318
+ /* @__PURE__ */ jsxs3("div", { className: "flex items-center justify-between", children: [
319
+ /* @__PURE__ */ jsxs3("div", { children: [
320
+ /* @__PURE__ */ jsxs3("h1", { className: "flex items-center gap-2 text-3xl font-bold tracking-tight", children: [
321
+ /* @__PURE__ */ jsx3(Settings2, { className: "h-7 w-7" }),
322
+ "\u7CFB\u7EDF\u8BBE\u7F6E"
323
+ ] }),
324
+ /* @__PURE__ */ jsxs3("p", { className: "text-sm text-muted-foreground", children: [
325
+ "\u53EA\u6709\u7BA1\u7406\u5458 ",
326
+ /* @__PURE__ */ jsx3("code", { className: "rounded bg-muted px-1.5 py-0.5 text-xs", children: s.admin_email }),
327
+ " \u53EF\u4EE5\u8BBF\u95EE"
328
+ ] })
329
+ ] }),
330
+ /* @__PURE__ */ jsxs3(Badge, { variant: "secondary", className: "gap-1", children: [
331
+ /* @__PURE__ */ jsx3(ShieldCheck, { className: "h-3.5 w-3.5" }),
332
+ "\u7BA1\u7406\u5458"
333
+ ] })
334
+ ] }),
335
+ error && /* @__PURE__ */ jsxs3(Alert, { variant: "destructive", children: [
336
+ /* @__PURE__ */ jsx3(AlertTitle, { children: "\u4FDD\u5B58\u5931\u8D25" }),
337
+ /* @__PURE__ */ jsx3(AlertDescription, { children: error })
338
+ ] }),
339
+ saved === "google" && /* @__PURE__ */ jsxs3(Alert, { children: [
340
+ /* @__PURE__ */ jsx3(AlertTitle, { children: "\u5DF2\u4FDD\u5B58" }),
341
+ /* @__PURE__ */ jsx3(AlertDescription, { children: "Google \u767B\u5F55\u914D\u7F6E\u5DF2\u66F4\u65B0\u3002" })
342
+ ] }),
343
+ saved === "disabled" && /* @__PURE__ */ jsxs3(Alert, { children: [
344
+ /* @__PURE__ */ jsx3(AlertTitle, { children: "\u5DF2\u5173\u95ED" }),
345
+ /* @__PURE__ */ jsx3(AlertDescription, { children: "Google \u767B\u5F55\u5DF2\u505C\u7528\u3002" })
346
+ ] }),
347
+ saved === "title" && /* @__PURE__ */ jsxs3(Alert, { children: [
348
+ /* @__PURE__ */ jsx3(AlertTitle, { children: "\u5DF2\u4FDD\u5B58" }),
349
+ /* @__PURE__ */ jsx3(AlertDescription, { children: "\u7AD9\u70B9\u540D\u79F0\u5DF2\u66F4\u65B0\u3002" })
350
+ ] }),
351
+ saved === "turnstile" && /* @__PURE__ */ jsxs3(Alert, { children: [
352
+ /* @__PURE__ */ jsx3(AlertTitle, { children: "\u5DF2\u4FDD\u5B58" }),
353
+ /* @__PURE__ */ jsx3(AlertDescription, { children: "Turnstile \u4EBA\u673A\u9A8C\u8BC1\u5DF2\u66F4\u65B0\u3002" })
354
+ ] }),
355
+ saved === "turnstile_disabled" && /* @__PURE__ */ jsxs3(Alert, { children: [
356
+ /* @__PURE__ */ jsx3(AlertTitle, { children: "\u5DF2\u5173\u95ED" }),
357
+ /* @__PURE__ */ jsx3(AlertDescription, { children: "Turnstile \u4EBA\u673A\u9A8C\u8BC1\u5DF2\u505C\u7528\u3002" })
358
+ ] }),
359
+ /* @__PURE__ */ jsxs3(Card, { children: [
360
+ /* @__PURE__ */ jsxs3(CardHeader, { children: [
361
+ /* @__PURE__ */ jsx3(CardTitle, { children: "\u7AD9\u70B9\u4FE1\u606F" }),
362
+ /* @__PURE__ */ jsx3(CardDescription, { children: "\u5BF9\u6240\u6709\u7528\u6237\u53EF\u89C1\u7684\u57FA\u7840\u4FE1\u606F" })
363
+ ] }),
364
+ /* @__PURE__ */ jsx3(CardContent, { children: /* @__PURE__ */ jsxs3("form", { action: actions?.saveSiteTitle, className: "flex items-end gap-3", children: [
365
+ /* @__PURE__ */ jsxs3("div", { className: "flex-1 space-y-2", children: [
366
+ /* @__PURE__ */ jsx3(Label, { htmlFor: "site_title", children: "\u7AD9\u70B9\u540D\u79F0" }),
367
+ /* @__PURE__ */ jsx3(
368
+ Input,
369
+ {
370
+ id: "site_title",
371
+ name: "site_title",
372
+ defaultValue: s.site_title,
373
+ maxLength: 80,
374
+ required: true
375
+ }
376
+ )
377
+ ] }),
378
+ /* @__PURE__ */ jsxs3(Button, { type: "submit", children: [
379
+ /* @__PURE__ */ jsx3(Save, { className: "mr-1 h-4 w-4" }),
380
+ "\u4FDD\u5B58"
381
+ ] })
382
+ ] }) })
383
+ ] }),
384
+ /* @__PURE__ */ jsxs3(Card, { children: [
385
+ /* @__PURE__ */ jsxs3(CardHeader, { children: [
386
+ /* @__PURE__ */ jsxs3(CardTitle, { className: "flex items-center justify-between", children: [
387
+ /* @__PURE__ */ jsx3("span", { children: "Google \u767B\u5F55" }),
388
+ s.google_enabled === 1 ? /* @__PURE__ */ jsx3(Badge, { children: "\u5DF2\u542F\u7528" }) : /* @__PURE__ */ jsx3(Badge, { variant: "secondary", children: "\u672A\u542F\u7528" })
389
+ ] }),
390
+ /* @__PURE__ */ jsxs3(CardDescription, { children: [
391
+ "\u5728 Google Cloud Console \u521B\u5EFA OAuth Web \u5E94\u7528\uFF0C\u5C06\u56DE\u8C03\u5730\u5740\u586B\u4E3A",
392
+ /* @__PURE__ */ jsx3("code", { className: "mx-1 rounded bg-muted px-1.5 py-0.5 text-xs", children: callbackUrl }),
393
+ "\u7136\u540E\u628A Client ID / Secret \u586B\u5230\u4E0B\u9762\u3002"
394
+ ] })
395
+ ] }),
396
+ /* @__PURE__ */ jsxs3(CardContent, { className: "space-y-4", children: [
397
+ /* @__PURE__ */ jsxs3("form", { action: actions?.saveGoogleSettings, className: "space-y-4", children: [
398
+ /* @__PURE__ */ jsxs3("div", { className: "space-y-2", children: [
399
+ /* @__PURE__ */ jsx3(Label, { htmlFor: "google_client_id", children: "Client ID" }),
400
+ /* @__PURE__ */ jsx3(
401
+ Input,
402
+ {
403
+ id: "google_client_id",
404
+ name: "google_client_id",
405
+ defaultValue: s.google_client_id ?? "",
406
+ placeholder: "xxxxx.apps.googleusercontent.com",
407
+ autoComplete: "off"
408
+ }
409
+ )
410
+ ] }),
411
+ /* @__PURE__ */ jsxs3("div", { className: "space-y-2", children: [
412
+ /* @__PURE__ */ jsx3(Label, { htmlFor: "google_client_secret", children: "Client Secret" }),
413
+ /* @__PURE__ */ jsx3(
414
+ Input,
415
+ {
416
+ id: "google_client_secret",
417
+ name: "google_client_secret",
418
+ type: "password",
419
+ placeholder: s.google_client_secret ? "\u5DF2\u914D\u7F6E\uFF0C\u7559\u7A7A\u8868\u793A\u4E0D\u4FEE\u6539" : "GOCSPX-...",
420
+ autoComplete: "new-password"
421
+ }
422
+ ),
423
+ s.google_client_secret && /* @__PURE__ */ jsx3("p", { className: "text-xs text-muted-foreground", children: "\u5F53\u524D\u5DF2\u4FDD\u5B58\u4E00\u6761 Secret\uFF1B\u4E3A\u5B89\u5168\u8D77\u89C1\uFF0C\u8F93\u5165\u6846\u4E0D\u56DE\u663E\u660E\u6587\uFF0C\u7559\u7A7A\u4E0D\u4F1A\u6539\u52A8\u3002" })
424
+ ] }),
425
+ /* @__PURE__ */ jsx3(Separator, {}),
426
+ /* @__PURE__ */ jsxs3("label", { className: "flex cursor-pointer items-center gap-2 text-sm", children: [
427
+ /* @__PURE__ */ jsx3(
428
+ "input",
429
+ {
430
+ type: "checkbox",
431
+ name: "google_enabled",
432
+ value: "1",
433
+ defaultChecked: s.google_enabled === 1,
434
+ className: "h-4 w-4 rounded border-input"
435
+ }
436
+ ),
437
+ /* @__PURE__ */ jsx3("span", { children: "\u542F\u7528 Google \u767B\u5F55\uFF08\u767B\u5F55\u9875\u4F1A\u663E\u793A\u201C\u4F7F\u7528 Google \u767B\u5F55\u201D\u6309\u94AE\uFF09" })
438
+ ] }),
439
+ /* @__PURE__ */ jsx3("div", { className: "flex items-center gap-2", children: /* @__PURE__ */ jsxs3(Button, { type: "submit", children: [
440
+ /* @__PURE__ */ jsx3(Save, { className: "mr-1 h-4 w-4" }),
441
+ "\u4FDD\u5B58 Google \u914D\u7F6E"
442
+ ] }) })
443
+ ] }),
444
+ s.google_enabled === 1 && actions?.disableGoogleSettings && /* @__PURE__ */ jsx3("form", { action: actions.disableGoogleSettings, children: /* @__PURE__ */ jsxs3(Button, { type: "submit", variant: "outline", children: [
445
+ /* @__PURE__ */ jsx3(Power, { className: "mr-1 h-4 w-4" }),
446
+ "\u5173\u95ED Google \u767B\u5F55"
447
+ ] }) })
448
+ ] })
449
+ ] }),
450
+ /* @__PURE__ */ jsxs3(Card, { children: [
451
+ /* @__PURE__ */ jsxs3(CardHeader, { children: [
452
+ /* @__PURE__ */ jsxs3(CardTitle, { className: "flex items-center justify-between", children: [
453
+ /* @__PURE__ */ jsxs3("span", { className: "flex items-center gap-2", children: [
454
+ /* @__PURE__ */ jsx3(Bot, { className: "h-4 w-4" }),
455
+ "Turnstile \u4EBA\u673A\u9A8C\u8BC1"
456
+ ] }),
457
+ turnstile.enabled ? /* @__PURE__ */ jsx3(Badge, { children: "\u5DF2\u542F\u7528" }) : /* @__PURE__ */ jsx3(Badge, { variant: "secondary", children: "\u672A\u542F\u7528" })
458
+ ] }),
459
+ /* @__PURE__ */ jsxs3(CardDescription, { children: [
460
+ "\u4E0E Workers \u540C\u5C5E Cloudflare \u8D26\u6237\uFF0C\u4F46\u9700\u5728",
461
+ " ",
462
+ /* @__PURE__ */ jsx3(
463
+ "a",
464
+ {
465
+ href: "https://dash.cloudflare.com/?to=/:account/turnstile",
466
+ className: "underline",
467
+ target: "_blank",
468
+ rel: "noreferrer",
469
+ children: "Turnstile \u63A7\u5236\u53F0"
470
+ }
471
+ ),
472
+ " ",
473
+ "\u5355\u72EC\u521B\u5EFA Widget\u3002\u57DF\u540D\u8BF7\u5305\u542B ",
474
+ /* @__PURE__ */ jsx3("code", { className: "rounded bg-muted px-1 text-xs", children: "localhost" }),
475
+ "\u3001",
476
+ /* @__PURE__ */ jsx3("code", { className: "rounded bg-muted px-1 text-xs", children: "127.0.0.1" }),
477
+ " \u4E0E",
478
+ " ",
479
+ /* @__PURE__ */ jsx3("code", { className: "rounded bg-muted px-1 text-xs", children: siteHost }),
480
+ "\u3002"
481
+ ] })
482
+ ] }),
483
+ /* @__PURE__ */ jsxs3(CardContent, { className: "space-y-4", children: [
484
+ /* @__PURE__ */ jsxs3("form", { action: actions?.saveTurnstileSettings, className: "space-y-4", children: [
485
+ /* @__PURE__ */ jsxs3("div", { className: "space-y-2", children: [
486
+ /* @__PURE__ */ jsx3(Label, { htmlFor: "turnstile_site_key", children: "Site Key\uFF08\u516C\u5F00\uFF09" }),
487
+ /* @__PURE__ */ jsx3(
488
+ Input,
489
+ {
490
+ id: "turnstile_site_key",
491
+ name: "turnstile_site_key",
492
+ defaultValue: s.turnstile_site_key ?? "",
493
+ placeholder: "0x4AAAAAAA...",
494
+ autoComplete: "off"
495
+ }
496
+ )
497
+ ] }),
498
+ /* @__PURE__ */ jsxs3("p", { className: "text-xs text-muted-foreground", children: [
499
+ "Secret Key \u4E0D\u8981\u5199\u5165\u6570\u636E\u5E93\u3002\u751F\u4EA7\u73AF\u5883\u6267\u884C\uFF1A",
500
+ /* @__PURE__ */ jsx3("code", { className: "mx-1 rounded bg-muted px-1.5 py-0.5", children: "wrangler secret put TURNSTILE_SECRET_KEY" }),
501
+ "\uFF1B\u672C\u5730\u5728 ",
502
+ /* @__PURE__ */ jsx3("code", { className: "rounded bg-muted px-1", children: ".dev.vars" }),
503
+ " \u6DFB\u52A0\u540C\u540D\u53D8\u91CF\u3002",
504
+ turnstile.secretConfigured ? /* @__PURE__ */ jsx3("span", { className: "ml-1 text-emerald-600 dark:text-emerald-400", children: "\uFF08\u5F53\u524D\u5DF2\u68C0\u6D4B\u5230 Secret\uFF09" }) : /* @__PURE__ */ jsx3("span", { className: "ml-1 text-amber-600 dark:text-amber-400", children: "\uFF08\u5F53\u524D\u672A\u68C0\u6D4B\u5230 Secret\uFF0C\u542F\u7528\u524D\u9700\u914D\u7F6E\uFF09" })
505
+ ] }),
506
+ /* @__PURE__ */ jsxs3("label", { className: "flex cursor-pointer items-center gap-2 text-sm", children: [
507
+ /* @__PURE__ */ jsx3(
508
+ "input",
509
+ {
510
+ type: "checkbox",
511
+ name: "turnstile_enabled",
512
+ value: "1",
513
+ defaultChecked: s.turnstile_enabled === 1,
514
+ className: "h-4 w-4 rounded border-input"
515
+ }
516
+ ),
517
+ /* @__PURE__ */ jsx3("span", { children: "\u542F\u7528 Turnstile\uFF08\u767B\u5F55 / \u6CE8\u518C / \u5FD8\u8BB0\u5BC6\u7801 / \u91CD\u53D1\u9A8C\u8BC1\uFF09" })
518
+ ] }),
519
+ /* @__PURE__ */ jsxs3(Button, { type: "submit", children: [
520
+ /* @__PURE__ */ jsx3(Save, { className: "mr-1 h-4 w-4" }),
521
+ "\u4FDD\u5B58 Turnstile \u914D\u7F6E"
522
+ ] })
523
+ ] }),
524
+ s.turnstile_enabled === 1 && actions?.disableTurnstileSettings && /* @__PURE__ */ jsx3("form", { action: actions.disableTurnstileSettings, children: /* @__PURE__ */ jsxs3(Button, { type: "submit", variant: "outline", children: [
525
+ /* @__PURE__ */ jsx3(Power, { className: "mr-1 h-4 w-4" }),
526
+ "\u5173\u95ED Turnstile"
527
+ ] }) })
528
+ ] })
529
+ ] }),
530
+ /* @__PURE__ */ jsxs3(Card, { children: [
531
+ /* @__PURE__ */ jsxs3(CardHeader, { children: [
532
+ /* @__PURE__ */ jsxs3(CardTitle, { className: "flex items-center gap-2", children: [
533
+ /* @__PURE__ */ jsx3(Webhook, { className: "h-4 w-4" }),
534
+ "Google OAuth \u56DE\u8C03\u5730\u5740"
535
+ ] }),
536
+ /* @__PURE__ */ jsx3(CardDescription, { children: "\u8BF7\u5728 Google Cloud Console \u628A\u4E0B\u65B9\u5730\u5740\u4F5C\u4E3A \u201CAuthorized redirect URI\u201D" })
537
+ ] }),
538
+ /* @__PURE__ */ jsx3(CardContent, { children: /* @__PURE__ */ jsx3("code", { className: "block break-all rounded bg-muted px-3 py-2 text-xs", children: callbackUrl }) })
539
+ ] })
540
+ ] });
541
+ }
542
+
543
+ // src/admin/pages/account.tsx
544
+ import { redirect as redirect3 } from "next/navigation";
545
+ import { KeyRound, Trash2 as Trash22, UserCircle } from "lucide-react";
546
+ import { jsx as jsx4, jsxs as jsxs4 } from "react/jsx-runtime";
547
+ async function AdminAccountPage({
548
+ context,
549
+ searchParams
550
+ }) {
551
+ const { ui, data, actions } = context;
552
+ const { Button, Input, Label, Card, CardHeader, CardTitle, CardContent, CardDescription, Alert, AlertTitle, AlertDescription, Separator } = ui;
553
+ const session = await data?.getCurrentUser?.() ?? null;
554
+ if (!session) redirect3("/login");
555
+ const user = await data?.getUserById?.(session.uid) ?? null;
556
+ if (!user) redirect3("/login");
557
+ const { saved, error } = searchParams;
558
+ const hasPassword = Boolean(user.password_hash);
559
+ const isAdmin = await data?.isAdminEmail?.(user.email) ?? false;
560
+ return /* @__PURE__ */ jsxs4("div", { className: "mx-auto max-w-lg space-y-6", children: [
561
+ /* @__PURE__ */ jsxs4("div", { children: [
562
+ /* @__PURE__ */ jsxs4("h1", { className: "flex items-center gap-2 text-3xl font-bold tracking-tight", children: [
563
+ /* @__PURE__ */ jsx4(UserCircle, { className: "h-7 w-7" }),
564
+ "\u8D26\u6237\u8BBE\u7F6E"
565
+ ] }),
566
+ /* @__PURE__ */ jsx4("p", { className: "text-sm text-muted-foreground", children: "\u7BA1\u7406\u767B\u5F55\u90AE\u7BB1\u4E0E\u5BC6\u7801" })
567
+ ] }),
568
+ saved && /* @__PURE__ */ jsxs4(Alert, { children: [
569
+ /* @__PURE__ */ jsx4(AlertTitle, { children: "\u5BC6\u7801\u5DF2\u66F4\u65B0" }),
570
+ /* @__PURE__ */ jsx4(AlertDescription, { children: "\u65B0\u5BC6\u7801\u5DF2\u751F\u6548\uFF0C\u5176\u4ED6\u8BBE\u5907\u4E0A\u7684\u65E7\u4F1A\u8BDD\u5DF2\u5931\u6548\u3002" })
571
+ ] }),
572
+ error && /* @__PURE__ */ jsxs4(Alert, { variant: "destructive", children: [
573
+ /* @__PURE__ */ jsx4(AlertTitle, { children: "\u64CD\u4F5C\u5931\u8D25" }),
574
+ /* @__PURE__ */ jsx4(AlertDescription, { children: error })
575
+ ] }),
576
+ /* @__PURE__ */ jsxs4(Card, { children: [
577
+ /* @__PURE__ */ jsx4(CardHeader, { children: /* @__PURE__ */ jsx4(CardTitle, { children: "\u57FA\u672C\u4FE1\u606F" }) }),
578
+ /* @__PURE__ */ jsxs4(CardContent, { className: "space-y-2 text-sm", children: [
579
+ /* @__PURE__ */ jsxs4("div", { className: "flex justify-between gap-4", children: [
580
+ /* @__PURE__ */ jsx4("span", { className: "text-muted-foreground", children: "\u90AE\u7BB1" }),
581
+ /* @__PURE__ */ jsx4("span", { className: "font-medium", children: user.email })
582
+ ] }),
583
+ /* @__PURE__ */ jsxs4("div", { className: "flex justify-between gap-4", children: [
584
+ /* @__PURE__ */ jsx4("span", { className: "text-muted-foreground", children: "\u767B\u5F55\u65B9\u5F0F" }),
585
+ /* @__PURE__ */ jsx4("span", { className: "font-medium", children: user.google_sub && user.password_hash ? "Google + \u90AE\u7BB1\u5BC6\u7801" : user.google_sub ? "Google" : "\u90AE\u7BB1\u5BC6\u7801" })
586
+ ] })
587
+ ] })
588
+ ] }),
589
+ hasPassword ? /* @__PURE__ */ jsxs4(Card, { children: [
590
+ /* @__PURE__ */ jsxs4(CardHeader, { children: [
591
+ /* @__PURE__ */ jsxs4(CardTitle, { className: "flex items-center gap-2", children: [
592
+ /* @__PURE__ */ jsx4(KeyRound, { className: "h-4 w-4" }),
593
+ "\u4FEE\u6539\u5BC6\u7801"
594
+ ] }),
595
+ /* @__PURE__ */ jsx4(CardDescription, { children: "\u4FEE\u6539\u540E\u5F53\u524D\u53CA\u5176\u4ED6\u8BBE\u5907\u7684\u767B\u5F55\u4F1A\u8BDD\u5C06\u7ACB\u5373\u5931\u6548\u3002" })
596
+ ] }),
597
+ /* @__PURE__ */ jsx4(CardContent, { children: /* @__PURE__ */ jsxs4("form", { action: actions?.changePassword, className: "space-y-3", children: [
598
+ /* @__PURE__ */ jsxs4("div", { className: "space-y-2", children: [
599
+ /* @__PURE__ */ jsx4(Label, { htmlFor: "currentPassword", children: "\u5F53\u524D\u5BC6\u7801" }),
600
+ /* @__PURE__ */ jsx4(
601
+ Input,
602
+ {
603
+ id: "currentPassword",
604
+ name: "currentPassword",
605
+ type: "password",
606
+ required: true
607
+ }
608
+ )
609
+ ] }),
610
+ /* @__PURE__ */ jsxs4("div", { className: "space-y-2", children: [
611
+ /* @__PURE__ */ jsx4(Label, { htmlFor: "newPassword", children: "\u65B0\u5BC6\u7801" }),
612
+ /* @__PURE__ */ jsx4(
613
+ Input,
614
+ {
615
+ id: "newPassword",
616
+ name: "newPassword",
617
+ type: "password",
618
+ placeholder: "\u81F3\u5C11 8 \u4F4D\uFF0C\u5305\u542B\u5B57\u6BCD\u548C\u6570\u5B57",
619
+ required: true
620
+ }
621
+ )
622
+ ] }),
623
+ /* @__PURE__ */ jsxs4("div", { className: "space-y-2", children: [
624
+ /* @__PURE__ */ jsx4(Label, { htmlFor: "confirmPassword", children: "\u786E\u8BA4\u65B0\u5BC6\u7801" }),
625
+ /* @__PURE__ */ jsx4(
626
+ Input,
627
+ {
628
+ id: "confirmPassword",
629
+ name: "confirmPassword",
630
+ type: "password",
631
+ required: true
632
+ }
633
+ )
634
+ ] }),
635
+ /* @__PURE__ */ jsx4(Button, { type: "submit", children: "\u4FDD\u5B58\u65B0\u5BC6\u7801" })
636
+ ] }) })
637
+ ] }) : /* @__PURE__ */ jsx4(Card, { children: /* @__PURE__ */ jsxs4(CardHeader, { children: [
638
+ /* @__PURE__ */ jsx4(CardTitle, { children: "\u5BC6\u7801" }),
639
+ /* @__PURE__ */ jsx4(CardDescription, { children: "\u4F60\u4F7F\u7528 Google \u767B\u5F55\uFF0C\u8D26\u6237\u672A\u8BBE\u7F6E\u5BC6\u7801\u3002\u5982\u9700\u5BC6\u7801\u767B\u5F55\uFF0C\u8BF7\u8054\u7CFB\u7BA1\u7406\u5458\u6216\u4F7F\u7528\u90AE\u7BB1\u6CE8\u518C\u6D41\u7A0B\u3002" })
640
+ ] }) }),
641
+ !isAdmin && /* @__PURE__ */ jsxs4(Card, { className: "border-destructive/40", children: [
642
+ /* @__PURE__ */ jsxs4(CardHeader, { children: [
643
+ /* @__PURE__ */ jsxs4(CardTitle, { className: "flex items-center gap-2 text-destructive", children: [
644
+ /* @__PURE__ */ jsx4(Trash22, { className: "h-4 w-4" }),
645
+ "\u6CE8\u9500\u8D26\u6237"
646
+ ] }),
647
+ /* @__PURE__ */ jsx4(CardDescription, { children: "\u6B64\u64CD\u4F5C\u4E0D\u53EF\u6062\u590D\u3002\u4F60\u7684\u6587\u7AE0\u5C06\u8F6C\u79FB\u7ED9\u7BA1\u7406\u5458\uFF0C\u8D26\u6237\u6570\u636E\u5C06\u88AB\u6C38\u4E45\u5220\u9664\u3002" })
648
+ ] }),
649
+ /* @__PURE__ */ jsx4(CardContent, { children: /* @__PURE__ */ jsxs4("form", { action: actions?.deleteAccount, className: "space-y-3", children: [
650
+ /* @__PURE__ */ jsxs4("div", { className: "space-y-2", children: [
651
+ /* @__PURE__ */ jsxs4(Label, { htmlFor: "confirmEmail", children: [
652
+ "\u8F93\u5165\u90AE\u7BB1 ",
653
+ /* @__PURE__ */ jsx4("span", { className: "font-medium", children: user.email }),
654
+ " \u4EE5\u786E\u8BA4"
655
+ ] }),
656
+ /* @__PURE__ */ jsx4(
657
+ Input,
658
+ {
659
+ id: "confirmEmail",
660
+ name: "confirmEmail",
661
+ type: "email",
662
+ placeholder: user.email,
663
+ required: true
664
+ }
665
+ )
666
+ ] }),
667
+ hasPassword && /* @__PURE__ */ jsxs4("div", { className: "space-y-2", children: [
668
+ /* @__PURE__ */ jsx4(Label, { htmlFor: "deletePassword", children: "\u5F53\u524D\u5BC6\u7801" }),
669
+ /* @__PURE__ */ jsx4(
670
+ Input,
671
+ {
672
+ id: "deletePassword",
673
+ name: "currentPassword",
674
+ type: "password",
675
+ required: true
676
+ }
677
+ )
678
+ ] }),
679
+ /* @__PURE__ */ jsx4(Separator, {}),
680
+ /* @__PURE__ */ jsx4(Button, { type: "submit", variant: "destructive", children: "\u6C38\u4E45\u6CE8\u9500\u8D26\u6237" })
681
+ ] }) })
682
+ ] })
683
+ ] });
684
+ }
685
+
686
+ // src/admin/pages/content-models.tsx
687
+ import { Database, Route } from "lucide-react";
688
+ import { jsx as jsx5, jsxs as jsxs5 } from "react/jsx-runtime";
689
+ function statusVariant(value) {
690
+ if (value === "public+admin" || value === "public") return "default";
691
+ if (value === "admin") return "secondary";
692
+ return "outline";
693
+ }
694
+ function capabilityBadges(model) {
695
+ return [
696
+ model.capabilities.richBlocks ? "rich blocks" : "",
697
+ model.capabilities.coverImages ? "cover images" : "",
698
+ model.capabilities.gatedAssets ? "gated assets" : ""
699
+ ].filter(Boolean);
700
+ }
701
+ function AdminContentModelsPage({
702
+ context
703
+ }) {
704
+ const { ui, data } = context;
705
+ const { Badge, Card, CardHeader, CardTitle, CardDescription, CardContent, Table, TableHeader, TableBody, TableRow, TableHead, TableCell } = ui;
706
+ const models = data?.getContentModelAdminSummaries?.() ?? [];
707
+ return /* @__PURE__ */ jsxs5("div", { className: "space-y-6", children: [
708
+ /* @__PURE__ */ jsxs5("div", { children: [
709
+ /* @__PURE__ */ jsxs5("h1", { className: "flex items-center gap-2 text-3xl font-bold tracking-tight", children: [
710
+ /* @__PURE__ */ jsx5(Database, { className: "h-7 w-7" }),
711
+ "\u5185\u5BB9\u6765\u6E90"
712
+ ] }),
713
+ /* @__PURE__ */ jsx5("p", { className: "text-sm text-muted-foreground", children: "\u67E5\u770B\u5F53\u524D\u9879\u76EE\u76F4\u63A5\u5B9E\u73B0\u7684 Notion \u6570\u636E\u6E90\u3001\u516C\u5F00\u8DEF\u7531\u548C\u57FA\u7840\u80FD\u529B\u3002" })
714
+ ] }),
715
+ /* @__PURE__ */ jsxs5(Card, { children: [
716
+ /* @__PURE__ */ jsxs5(CardHeader, { children: [
717
+ /* @__PURE__ */ jsx5(CardTitle, { children: "\u6A21\u578B\u6CE8\u518C\u8868" }),
718
+ /* @__PURE__ */ jsxs5(CardDescription, { children: [
719
+ "\u8FD9\u4E9B\u6A21\u578B\u6765\u81EA ",
720
+ /* @__PURE__ */ jsx5("code", { className: "rounded bg-muted px-1.5 py-0.5 text-xs", children: "lib/content/models.ts" }),
721
+ "\u3002 \u65B0\u9886\u57DF\u7531 AI \u76F4\u63A5\u65B0\u589E\u6A21\u578B\u3001\u8DEF\u7531\u548C UI \u4EE3\u7801\u3002"
722
+ ] })
723
+ ] }),
724
+ /* @__PURE__ */ jsx5(CardContent, { children: /* @__PURE__ */ jsx5("div", { className: "rounded-md border", children: /* @__PURE__ */ jsxs5(Table, { children: [
725
+ /* @__PURE__ */ jsx5(TableHeader, { children: /* @__PURE__ */ jsxs5(TableRow, { children: [
726
+ /* @__PURE__ */ jsx5(TableHead, { children: "\u6A21\u578B" }),
727
+ /* @__PURE__ */ jsx5(TableHead, { children: "\u7C7B\u578B" }),
728
+ /* @__PURE__ */ jsx5(TableHead, { children: "\u53EF\u89C1\u6027" }),
729
+ /* @__PURE__ */ jsx5(TableHead, { children: "Notion" }),
730
+ /* @__PURE__ */ jsx5(TableHead, { children: "\u8DEF\u7531" }),
731
+ /* @__PURE__ */ jsx5(TableHead, { children: "\u80FD\u529B" }),
732
+ /* @__PURE__ */ jsx5(TableHead, { className: "text-right", children: "\u5B57\u6BB5" })
733
+ ] }) }),
734
+ /* @__PURE__ */ jsx5(TableBody, { children: models.map((model) => /* @__PURE__ */ jsxs5(TableRow, { children: [
735
+ /* @__PURE__ */ jsxs5(TableCell, { children: [
736
+ /* @__PURE__ */ jsx5("div", { className: "font-medium", children: model.name }),
737
+ /* @__PURE__ */ jsx5("div", { className: "text-xs text-muted-foreground", children: model.id })
738
+ ] }),
739
+ /* @__PURE__ */ jsx5(TableCell, { children: model.kind }),
740
+ /* @__PURE__ */ jsx5(TableCell, { children: /* @__PURE__ */ jsx5(Badge, { variant: statusVariant(model.visibility), children: model.visibility }) }),
741
+ /* @__PURE__ */ jsxs5(TableCell, { children: [
742
+ /* @__PURE__ */ jsx5("div", { className: "font-mono text-xs", children: model.dataSourceEnv }),
743
+ model.hasDefaultDataSource && /* @__PURE__ */ jsx5(Badge, { variant: "secondary", className: "mt-1", children: "default id" })
744
+ ] }),
745
+ /* @__PURE__ */ jsxs5(TableCell, { children: [
746
+ /* @__PURE__ */ jsx5("div", { className: "text-xs", children: model.listPath }),
747
+ /* @__PURE__ */ jsx5("div", { className: "text-xs text-muted-foreground", children: model.detailPath }),
748
+ model.publicApiPath && /* @__PURE__ */ jsx5("div", { className: "text-xs text-muted-foreground", children: model.publicApiPath })
749
+ ] }),
750
+ /* @__PURE__ */ jsx5(TableCell, { children: /* @__PURE__ */ jsx5("div", { className: "flex flex-wrap gap-1.5", children: capabilityBadges(model).map((capability) => /* @__PURE__ */ jsx5(Badge, { variant: "secondary", children: capability }, capability)) }) }),
751
+ /* @__PURE__ */ jsx5(TableCell, { className: "text-right", children: model.fieldCount })
752
+ ] }, model.id)) })
753
+ ] }) }) })
754
+ ] }),
755
+ /* @__PURE__ */ jsx5("div", { className: "grid gap-4 lg:grid-cols-2", children: models.map((model) => /* @__PURE__ */ jsxs5(Card, { children: [
756
+ /* @__PURE__ */ jsxs5(CardHeader, { children: [
757
+ /* @__PURE__ */ jsxs5(CardTitle, { className: "flex items-center justify-between gap-3", children: [
758
+ /* @__PURE__ */ jsx5("span", { children: model.name }),
759
+ /* @__PURE__ */ jsx5(Badge, { variant: statusVariant(model.visibility), children: model.visibility })
760
+ ] }),
761
+ /* @__PURE__ */ jsxs5(CardDescription, { className: "flex flex-wrap items-center gap-3", children: [
762
+ /* @__PURE__ */ jsxs5("span", { className: "inline-flex items-center gap-1", children: [
763
+ /* @__PURE__ */ jsx5(Route, { className: "h-3.5 w-3.5" }),
764
+ model.listPath
765
+ ] }),
766
+ /* @__PURE__ */ jsx5("span", { children: model.detailPath }),
767
+ model.publicApiPath && /* @__PURE__ */ jsx5("span", { children: model.publicApiPath })
768
+ ] })
769
+ ] }),
770
+ /* @__PURE__ */ jsx5(CardContent, { children: /* @__PURE__ */ jsxs5("div", { className: "grid gap-3 text-sm", children: [
771
+ /* @__PURE__ */ jsxs5("div", { children: [
772
+ /* @__PURE__ */ jsx5("div", { className: "text-xs font-medium text-muted-foreground", children: "Notion data source env" }),
773
+ /* @__PURE__ */ jsx5("code", { className: "mt-1 block rounded-md bg-muted px-2 py-1.5 text-xs", children: model.dataSourceEnv })
774
+ ] }),
775
+ /* @__PURE__ */ jsxs5("div", { children: [
776
+ /* @__PURE__ */ jsx5("div", { className: "text-xs font-medium text-muted-foreground", children: "Public API" }),
777
+ /* @__PURE__ */ jsx5("div", { children: model.publicApiPath ?? "None" })
778
+ ] }),
779
+ /* @__PURE__ */ jsxs5("div", { children: [
780
+ /* @__PURE__ */ jsx5("div", { className: "text-xs font-medium text-muted-foreground", children: "Capabilities" }),
781
+ /* @__PURE__ */ jsx5("div", { className: "mt-1 flex flex-wrap gap-1.5", children: capabilityBadges(model).map((capability) => /* @__PURE__ */ jsx5(Badge, { variant: "secondary", children: capability }, capability)) })
782
+ ] })
783
+ ] }) })
784
+ ] }, model.id)) })
785
+ ] });
786
+ }
787
+
788
+ // src/admin/pages/index.ts
789
+ init_delete_button();
790
+
791
+ // src/admin/pages/delete-button-lazy.tsx
792
+ import dynamic from "next/dynamic";
793
+ import { jsx as jsx7 } from "react/jsx-runtime";
794
+ var AdminDeleteButton2 = dynamic(() => Promise.resolve().then(() => (init_delete_button(), delete_button_exports)));
795
+ function AdminDeleteButtonLazy(props) {
796
+ return /* @__PURE__ */ jsx7(AdminDeleteButton2, { ...props });
797
+ }
798
+
799
+ // src/admin/pages/loading.tsx
800
+ import { jsx as jsx8, jsxs as jsxs7 } from "react/jsx-runtime";
801
+ function AdminLoadingPage({ context }) {
802
+ const { ui } = context;
803
+ const { Skeleton } = ui;
804
+ return /* @__PURE__ */ jsxs7("div", { className: "space-y-6", children: [
805
+ /* @__PURE__ */ jsxs7("div", { className: "space-y-2", children: [
806
+ /* @__PURE__ */ jsx8(Skeleton, { className: "h-9 w-40" }),
807
+ /* @__PURE__ */ jsx8(Skeleton, { className: "h-4 w-28" })
808
+ ] }),
809
+ /* @__PURE__ */ jsx8("div", { className: "rounded-md border p-4", children: /* @__PURE__ */ jsxs7("div", { className: "space-y-3", children: [
810
+ /* @__PURE__ */ jsx8(Skeleton, { className: "h-10 w-full" }),
811
+ /* @__PURE__ */ jsx8(Skeleton, { className: "h-10 w-full" }),
812
+ /* @__PURE__ */ jsx8(Skeleton, { className: "h-10 w-full" }),
813
+ /* @__PURE__ */ jsx8(Skeleton, { className: "h-10 w-11/12" })
814
+ ] }) })
815
+ ] });
816
+ }
817
+ export {
818
+ AdminAccountPage as AccountPage,
819
+ AdminContentModelsPage as ContentModelsPage,
820
+ AdminDashboardPage as DashboardPage,
821
+ AdminDeleteButton as DeleteButton,
822
+ AdminDeleteButtonLazy as DeleteButtonLazy,
823
+ AdminLoadingPage as LoadingPage,
824
+ AdminSettingsPage as SettingsPage,
825
+ AdminUsersPage as UsersPage
826
+ };
827
+ //# sourceMappingURL=index.js.map