@jant/core 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/jant.js +188 -0
- package/drizzle.config.ts +10 -0
- package/lingui.config.ts +16 -0
- package/package.json +116 -0
- package/src/app.tsx +377 -0
- package/src/assets/datastar.min.js +8 -0
- package/src/auth.ts +38 -0
- package/src/client.ts +6 -0
- package/src/db/index.ts +14 -0
- package/src/db/migrations/0000_solid_moon_knight.sql +118 -0
- package/src/db/migrations/0001_add_search_fts.sql +40 -0
- package/src/db/migrations/0002_collection_path.sql +2 -0
- package/src/db/migrations/0003_collection_path_nullable.sql +21 -0
- package/src/db/migrations/0004_media_uuid.sql +35 -0
- package/src/db/migrations/meta/0000_snapshot.json +784 -0
- package/src/db/migrations/meta/_journal.json +41 -0
- package/src/db/schema.ts +159 -0
- package/src/i18n/EXAMPLES.md +235 -0
- package/src/i18n/README.md +296 -0
- package/src/i18n/Trans.tsx +31 -0
- package/src/i18n/context.tsx +101 -0
- package/src/i18n/detect.ts +100 -0
- package/src/i18n/i18n.ts +62 -0
- package/src/i18n/index.ts +65 -0
- package/src/i18n/locales/en.po +875 -0
- package/src/i18n/locales/en.ts +1 -0
- package/src/i18n/locales/zh-Hans.po +875 -0
- package/src/i18n/locales/zh-Hans.ts +1 -0
- package/src/i18n/locales/zh-Hant.po +875 -0
- package/src/i18n/locales/zh-Hant.ts +1 -0
- package/src/i18n/locales.ts +14 -0
- package/src/i18n/middleware.ts +59 -0
- package/src/index.ts +42 -0
- package/src/lib/assets.ts +47 -0
- package/src/lib/constants.ts +67 -0
- package/src/lib/image.ts +107 -0
- package/src/lib/index.ts +9 -0
- package/src/lib/markdown.ts +93 -0
- package/src/lib/schemas.ts +92 -0
- package/src/lib/sqid.ts +79 -0
- package/src/lib/sse.ts +152 -0
- package/src/lib/time.ts +117 -0
- package/src/lib/url.ts +107 -0
- package/src/middleware/auth.ts +59 -0
- package/src/routes/api/posts.ts +127 -0
- package/src/routes/api/search.ts +53 -0
- package/src/routes/api/upload.ts +240 -0
- package/src/routes/dash/collections.tsx +341 -0
- package/src/routes/dash/index.tsx +89 -0
- package/src/routes/dash/media.tsx +551 -0
- package/src/routes/dash/pages.tsx +245 -0
- package/src/routes/dash/posts.tsx +202 -0
- package/src/routes/dash/redirects.tsx +155 -0
- package/src/routes/dash/settings.tsx +93 -0
- package/src/routes/feed/rss.ts +119 -0
- package/src/routes/feed/sitemap.ts +75 -0
- package/src/routes/pages/archive.tsx +223 -0
- package/src/routes/pages/collection.tsx +79 -0
- package/src/routes/pages/home.tsx +93 -0
- package/src/routes/pages/page.tsx +64 -0
- package/src/routes/pages/post.tsx +81 -0
- package/src/routes/pages/search.tsx +162 -0
- package/src/services/collection.ts +180 -0
- package/src/services/index.ts +40 -0
- package/src/services/media.ts +97 -0
- package/src/services/post.ts +279 -0
- package/src/services/redirect.ts +74 -0
- package/src/services/search.ts +117 -0
- package/src/services/settings.ts +76 -0
- package/src/theme/components/ActionButtons.tsx +98 -0
- package/src/theme/components/CrudPageHeader.tsx +48 -0
- package/src/theme/components/DangerZone.tsx +77 -0
- package/src/theme/components/EmptyState.tsx +56 -0
- package/src/theme/components/ListItemRow.tsx +24 -0
- package/src/theme/components/PageForm.tsx +114 -0
- package/src/theme/components/Pagination.tsx +196 -0
- package/src/theme/components/PostForm.tsx +122 -0
- package/src/theme/components/PostList.tsx +68 -0
- package/src/theme/components/ThreadView.tsx +118 -0
- package/src/theme/components/TypeBadge.tsx +28 -0
- package/src/theme/components/VisibilityBadge.tsx +33 -0
- package/src/theme/components/index.ts +12 -0
- package/src/theme/index.ts +24 -0
- package/src/theme/layouts/BaseLayout.tsx +49 -0
- package/src/theme/layouts/DashLayout.tsx +108 -0
- package/src/theme/layouts/index.ts +2 -0
- package/src/theme/styles/main.css +52 -0
- package/src/types.ts +222 -0
- package/static/assets/datastar.min.js +7 -0
- package/static/assets/image-processor.js +234 -0
- package/tsconfig.json +16 -0
- package/vite.config.ts +82 -0
- package/wrangler.toml +21 -0
package/src/app.tsx
ADDED
|
@@ -0,0 +1,377 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Jant App Factory
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { Hono } from "hono";
|
|
6
|
+
import type { FC } from "hono/jsx";
|
|
7
|
+
import { createDatabase } from "./db/index.js";
|
|
8
|
+
import { createServices, type Services } from "./services/index.js";
|
|
9
|
+
import { createAuth, type Auth } from "./auth.js";
|
|
10
|
+
import { i18nMiddleware, useLingui } from "./i18n/index.js";
|
|
11
|
+
import type { Bindings, JantConfig } from "./types.js";
|
|
12
|
+
|
|
13
|
+
// Routes - Pages
|
|
14
|
+
import { homeRoutes } from "./routes/pages/home.js";
|
|
15
|
+
import { postRoutes } from "./routes/pages/post.js";
|
|
16
|
+
import { pageRoutes } from "./routes/pages/page.js";
|
|
17
|
+
import { collectionRoutes } from "./routes/pages/collection.js";
|
|
18
|
+
import { archiveRoutes } from "./routes/pages/archive.js";
|
|
19
|
+
import { searchRoutes } from "./routes/pages/search.js";
|
|
20
|
+
|
|
21
|
+
// Routes - Dashboard
|
|
22
|
+
import { dashIndexRoutes } from "./routes/dash/index.js";
|
|
23
|
+
import { postsRoutes as dashPostsRoutes } from "./routes/dash/posts.js";
|
|
24
|
+
import { pagesRoutes as dashPagesRoutes } from "./routes/dash/pages.js";
|
|
25
|
+
import { mediaRoutes as dashMediaRoutes } from "./routes/dash/media.js";
|
|
26
|
+
import { settingsRoutes as dashSettingsRoutes } from "./routes/dash/settings.js";
|
|
27
|
+
import { redirectsRoutes as dashRedirectsRoutes } from "./routes/dash/redirects.js";
|
|
28
|
+
import { collectionsRoutes as dashCollectionsRoutes } from "./routes/dash/collections.js";
|
|
29
|
+
|
|
30
|
+
// Routes - API
|
|
31
|
+
import { postsApiRoutes } from "./routes/api/posts.js";
|
|
32
|
+
import { uploadApiRoutes } from "./routes/api/upload.js";
|
|
33
|
+
import { searchApiRoutes } from "./routes/api/search.js";
|
|
34
|
+
|
|
35
|
+
// Routes - Feed
|
|
36
|
+
import { rssRoutes } from "./routes/feed/rss.js";
|
|
37
|
+
import { sitemapRoutes } from "./routes/feed/sitemap.js";
|
|
38
|
+
|
|
39
|
+
// Middleware
|
|
40
|
+
import { requireAuth } from "./middleware/auth.js";
|
|
41
|
+
|
|
42
|
+
// Layouts for auth pages
|
|
43
|
+
import { BaseLayout } from "./theme/layouts/index.js";
|
|
44
|
+
|
|
45
|
+
// Extend Hono's context variables
|
|
46
|
+
export interface AppVariables {
|
|
47
|
+
services: Services;
|
|
48
|
+
auth: Auth;
|
|
49
|
+
config: JantConfig;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export type App = Hono<{ Bindings: Bindings; Variables: AppVariables }>;
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Create a Jant application
|
|
56
|
+
*
|
|
57
|
+
* @param config - Optional configuration
|
|
58
|
+
* @returns Hono app instance
|
|
59
|
+
*
|
|
60
|
+
* @example
|
|
61
|
+
* ```typescript
|
|
62
|
+
* import { createApp } from "@jant/core";
|
|
63
|
+
*
|
|
64
|
+
* export default createApp({
|
|
65
|
+
* site: { name: "My Blog" },
|
|
66
|
+
* theme: { components: { PostCard: MyPostCard } },
|
|
67
|
+
* });
|
|
68
|
+
* ```
|
|
69
|
+
*/
|
|
70
|
+
export function createApp(config: JantConfig = {}): App {
|
|
71
|
+
const app = new Hono<{ Bindings: Bindings; Variables: AppVariables }>();
|
|
72
|
+
|
|
73
|
+
// Initialize services, auth, and config middleware
|
|
74
|
+
app.use("*", async (c, next) => {
|
|
75
|
+
const db = createDatabase(c.env.DB);
|
|
76
|
+
const services = createServices(db, c.env.DB);
|
|
77
|
+
c.set("services", services);
|
|
78
|
+
c.set("config", config);
|
|
79
|
+
|
|
80
|
+
if (c.env.AUTH_SECRET) {
|
|
81
|
+
const auth = createAuth(c.env.DB, {
|
|
82
|
+
secret: c.env.AUTH_SECRET,
|
|
83
|
+
baseURL: c.env.SITE_URL,
|
|
84
|
+
});
|
|
85
|
+
c.set("auth", auth);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
await next();
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
// i18n middleware
|
|
92
|
+
app.use("*", i18nMiddleware());
|
|
93
|
+
|
|
94
|
+
// Trailing slash redirect (redirect /foo/ to /foo)
|
|
95
|
+
app.use("*", async (c, next) => {
|
|
96
|
+
const url = new URL(c.req.url);
|
|
97
|
+
if (url.pathname !== "/" && url.pathname.endsWith("/")) {
|
|
98
|
+
const newUrl = url.pathname.slice(0, -1) + url.search;
|
|
99
|
+
return c.redirect(newUrl, 301);
|
|
100
|
+
}
|
|
101
|
+
await next();
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
// Redirect middleware
|
|
105
|
+
app.use("*", async (c, next) => {
|
|
106
|
+
const path = new URL(c.req.url).pathname;
|
|
107
|
+
// Skip redirect check for API routes and static assets
|
|
108
|
+
if (path.startsWith("/api/") || path.startsWith("/assets/")) {
|
|
109
|
+
return next();
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
const redirect = await c.var.services.redirects.getByPath(path);
|
|
113
|
+
if (redirect) {
|
|
114
|
+
return c.redirect(redirect.toPath, redirect.type);
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
await next();
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
// Health check
|
|
121
|
+
app.get("/health", (c) =>
|
|
122
|
+
c.json({
|
|
123
|
+
status: "ok",
|
|
124
|
+
auth: c.env.AUTH_SECRET ? "configured" : "missing",
|
|
125
|
+
authSecretLength: c.env.AUTH_SECRET?.length ?? 0,
|
|
126
|
+
})
|
|
127
|
+
);
|
|
128
|
+
|
|
129
|
+
// better-auth handler
|
|
130
|
+
app.all("/api/auth/*", async (c) => {
|
|
131
|
+
if (!c.var.auth) {
|
|
132
|
+
return c.json({ error: "Auth not configured. Set AUTH_SECRET." }, 500);
|
|
133
|
+
}
|
|
134
|
+
return c.var.auth.handler(c.req.raw);
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
// API Routes
|
|
138
|
+
app.route("/api/posts", postsApiRoutes);
|
|
139
|
+
|
|
140
|
+
// Setup page component
|
|
141
|
+
const SetupContent: FC<{ error?: string }> = ({ error }) => {
|
|
142
|
+
const { t } = useLingui();
|
|
143
|
+
|
|
144
|
+
return (
|
|
145
|
+
<div class="min-h-screen flex items-center justify-center">
|
|
146
|
+
<div class="card max-w-md w-full">
|
|
147
|
+
<header>
|
|
148
|
+
<h2>{t({ message: "Welcome to Jant", comment: "@context: Setup page welcome heading" })}</h2>
|
|
149
|
+
<p>{t({ message: "Let's set up your site.", comment: "@context: Setup page description" })}</p>
|
|
150
|
+
</header>
|
|
151
|
+
<section>
|
|
152
|
+
{error && <p class="text-destructive text-sm mb-4">{error}</p>}
|
|
153
|
+
<form method="post" action="/setup" class="flex flex-col gap-4">
|
|
154
|
+
<div class="field">
|
|
155
|
+
<label class="label">{t({ message: "Site Name", comment: "@context: Setup form field - site name" })}</label>
|
|
156
|
+
<input type="text" name="siteName" class="input" required placeholder={t({ message: "My Blog", comment: "@context: Setup site name placeholder" })} />
|
|
157
|
+
</div>
|
|
158
|
+
<div class="field">
|
|
159
|
+
<label class="label">{t({ message: "Your Name", comment: "@context: Setup form field - user name" })}</label>
|
|
160
|
+
<input type="text" name="name" class="input" required placeholder="John Doe" />
|
|
161
|
+
</div>
|
|
162
|
+
<div class="field">
|
|
163
|
+
<label class="label">{t({ message: "Email", comment: "@context: Setup/signin form field - email" })}</label>
|
|
164
|
+
<input type="email" name="email" class="input" required placeholder="you@example.com" />
|
|
165
|
+
</div>
|
|
166
|
+
<div class="field">
|
|
167
|
+
<label class="label">{t({ message: "Password", comment: "@context: Setup/signin form field - password" })}</label>
|
|
168
|
+
<input type="password" name="password" class="input" required minLength={8} />
|
|
169
|
+
</div>
|
|
170
|
+
<button type="submit" class="btn">{t({ message: "Complete Setup", comment: "@context: Setup form submit button" })}</button>
|
|
171
|
+
</form>
|
|
172
|
+
</section>
|
|
173
|
+
</div>
|
|
174
|
+
</div>
|
|
175
|
+
);
|
|
176
|
+
};
|
|
177
|
+
|
|
178
|
+
// Setup page
|
|
179
|
+
app.get("/setup", async (c) => {
|
|
180
|
+
const isComplete = await c.var.services.settings.isOnboardingComplete();
|
|
181
|
+
if (isComplete) return c.redirect("/");
|
|
182
|
+
|
|
183
|
+
const error = c.req.query("error");
|
|
184
|
+
|
|
185
|
+
return c.html(
|
|
186
|
+
<BaseLayout title="Setup - Jant" c={c}>
|
|
187
|
+
<SetupContent error={error} />
|
|
188
|
+
</BaseLayout>
|
|
189
|
+
);
|
|
190
|
+
});
|
|
191
|
+
|
|
192
|
+
app.post("/setup", async (c) => {
|
|
193
|
+
const isComplete = await c.var.services.settings.isOnboardingComplete();
|
|
194
|
+
if (isComplete) return c.redirect("/");
|
|
195
|
+
|
|
196
|
+
const formData = await c.req.formData();
|
|
197
|
+
const siteName = formData.get("siteName") as string;
|
|
198
|
+
const name = formData.get("name") as string;
|
|
199
|
+
const email = formData.get("email") as string;
|
|
200
|
+
const password = formData.get("password") as string;
|
|
201
|
+
|
|
202
|
+
if (!siteName || !name || !email || !password) {
|
|
203
|
+
return c.redirect("/setup?error=All fields are required");
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
if (password.length < 8) {
|
|
207
|
+
return c.redirect("/setup?error=Password must be at least 8 characters");
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
if (!c.var.auth) {
|
|
211
|
+
return c.redirect("/setup?error=AUTH_SECRET not configured");
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
try {
|
|
215
|
+
const signUpResponse = await c.var.auth.api.signUpEmail({
|
|
216
|
+
body: { name, email, password },
|
|
217
|
+
});
|
|
218
|
+
|
|
219
|
+
if (!signUpResponse || "error" in signUpResponse) {
|
|
220
|
+
return c.redirect("/setup?error=Failed to create account");
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
await c.var.services.settings.setMany({
|
|
224
|
+
SITE_NAME: siteName,
|
|
225
|
+
SITE_LANGUAGE: "en",
|
|
226
|
+
});
|
|
227
|
+
await c.var.services.settings.completeOnboarding();
|
|
228
|
+
|
|
229
|
+
return c.redirect("/signin");
|
|
230
|
+
} catch (err) {
|
|
231
|
+
// eslint-disable-next-line no-console -- Error logging is intentional
|
|
232
|
+
console.error("Setup error:", err);
|
|
233
|
+
return c.redirect("/setup?error=Failed to create account");
|
|
234
|
+
}
|
|
235
|
+
});
|
|
236
|
+
|
|
237
|
+
// Signin page component
|
|
238
|
+
const SigninContent: FC<{ error?: string }> = ({ error }) => {
|
|
239
|
+
const { t } = useLingui();
|
|
240
|
+
|
|
241
|
+
return (
|
|
242
|
+
<div class="min-h-screen flex items-center justify-center">
|
|
243
|
+
<div class="card max-w-md w-full">
|
|
244
|
+
<header>
|
|
245
|
+
<h2>{t({ message: "Sign In", comment: "@context: Sign in page heading" })}</h2>
|
|
246
|
+
</header>
|
|
247
|
+
<section>
|
|
248
|
+
{error && <p class="text-destructive text-sm mb-4">{error}</p>}
|
|
249
|
+
<form method="post" action="/signin" class="flex flex-col gap-4">
|
|
250
|
+
<div class="field">
|
|
251
|
+
<label class="label">{t({ message: "Email", comment: "@context: Setup/signin form field - email" })}</label>
|
|
252
|
+
<input type="email" name="email" class="input" required />
|
|
253
|
+
</div>
|
|
254
|
+
<div class="field">
|
|
255
|
+
<label class="label">{t({ message: "Password", comment: "@context: Setup/signin form field - password" })}</label>
|
|
256
|
+
<input type="password" name="password" class="input" required />
|
|
257
|
+
</div>
|
|
258
|
+
<button type="submit" class="btn">{t({ message: "Sign In", comment: "@context: Sign in form submit button" })}</button>
|
|
259
|
+
</form>
|
|
260
|
+
</section>
|
|
261
|
+
</div>
|
|
262
|
+
</div>
|
|
263
|
+
);
|
|
264
|
+
};
|
|
265
|
+
|
|
266
|
+
// Signin page
|
|
267
|
+
app.get("/signin", async (c) => {
|
|
268
|
+
const error = c.req.query("error");
|
|
269
|
+
|
|
270
|
+
return c.html(
|
|
271
|
+
<BaseLayout title="Sign In - Jant" c={c}>
|
|
272
|
+
<SigninContent error={error} />
|
|
273
|
+
</BaseLayout>
|
|
274
|
+
);
|
|
275
|
+
});
|
|
276
|
+
|
|
277
|
+
app.post("/signin", async (c) => {
|
|
278
|
+
if (!c.var.auth) {
|
|
279
|
+
return c.redirect("/signin?error=Auth not configured");
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
const formData = await c.req.formData();
|
|
283
|
+
const email = formData.get("email") as string;
|
|
284
|
+
const password = formData.get("password") as string;
|
|
285
|
+
|
|
286
|
+
try {
|
|
287
|
+
const signInRequest = new Request(`${c.env.SITE_URL}/api/auth/sign-in/email`, {
|
|
288
|
+
method: "POST",
|
|
289
|
+
headers: { "Content-Type": "application/json" },
|
|
290
|
+
body: JSON.stringify({ email, password }),
|
|
291
|
+
});
|
|
292
|
+
|
|
293
|
+
const response = await c.var.auth.handler(signInRequest);
|
|
294
|
+
|
|
295
|
+
if (!response.ok) {
|
|
296
|
+
return c.redirect("/signin?error=Invalid email or password");
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
const headers = new Headers(response.headers);
|
|
300
|
+
headers.set("Location", "/dash");
|
|
301
|
+
|
|
302
|
+
return new Response(null, { status: 302, headers });
|
|
303
|
+
} catch (err) {
|
|
304
|
+
// eslint-disable-next-line no-console -- Error logging is intentional
|
|
305
|
+
console.error("Signin error:", err);
|
|
306
|
+
return c.redirect("/signin?error=Invalid email or password");
|
|
307
|
+
}
|
|
308
|
+
});
|
|
309
|
+
|
|
310
|
+
app.get("/signout", async (c) => {
|
|
311
|
+
if (c.var.auth) {
|
|
312
|
+
try {
|
|
313
|
+
await c.var.auth.api.signOut({ headers: c.req.raw.headers });
|
|
314
|
+
} catch {
|
|
315
|
+
// Ignore signout errors
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
return c.redirect("/");
|
|
319
|
+
});
|
|
320
|
+
|
|
321
|
+
// Dashboard routes (protected)
|
|
322
|
+
app.use("/dash/*", requireAuth());
|
|
323
|
+
app.route("/dash", dashIndexRoutes);
|
|
324
|
+
app.route("/dash/posts", dashPostsRoutes);
|
|
325
|
+
app.route("/dash/pages", dashPagesRoutes);
|
|
326
|
+
app.route("/dash/media", dashMediaRoutes);
|
|
327
|
+
app.route("/dash/settings", dashSettingsRoutes);
|
|
328
|
+
app.route("/dash/redirects", dashRedirectsRoutes);
|
|
329
|
+
app.route("/dash/collections", dashCollectionsRoutes);
|
|
330
|
+
|
|
331
|
+
// API routes
|
|
332
|
+
app.route("/api/upload", uploadApiRoutes);
|
|
333
|
+
app.route("/api/search", searchApiRoutes);
|
|
334
|
+
|
|
335
|
+
// Media files from R2 (UUIDv7-based URLs with extension)
|
|
336
|
+
app.get("/media/:idWithExt", async (c) => {
|
|
337
|
+
if (!c.env.R2) {
|
|
338
|
+
return c.notFound();
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
// Extract ID from "uuid.ext" format
|
|
342
|
+
const idWithExt = c.req.param("idWithExt");
|
|
343
|
+
const mediaId = idWithExt.replace(/\.[^.]+$/, "");
|
|
344
|
+
|
|
345
|
+
const media = await c.var.services.media.getById(mediaId);
|
|
346
|
+
if (!media) {
|
|
347
|
+
return c.notFound();
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
const object = await c.env.R2.get(media.r2Key);
|
|
351
|
+
if (!object) {
|
|
352
|
+
return c.notFound();
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
const headers = new Headers();
|
|
356
|
+
headers.set("Content-Type", object.httpMetadata?.contentType || media.mimeType);
|
|
357
|
+
headers.set("Cache-Control", "public, max-age=31536000, immutable");
|
|
358
|
+
|
|
359
|
+
return new Response(object.body, { headers });
|
|
360
|
+
});
|
|
361
|
+
|
|
362
|
+
// Feed routes
|
|
363
|
+
app.route("/feed", rssRoutes);
|
|
364
|
+
app.route("/", sitemapRoutes);
|
|
365
|
+
|
|
366
|
+
// Frontend routes
|
|
367
|
+
app.route("/search", searchRoutes);
|
|
368
|
+
app.route("/archive", archiveRoutes);
|
|
369
|
+
app.route("/c", collectionRoutes);
|
|
370
|
+
app.route("/p", postRoutes);
|
|
371
|
+
app.route("/", homeRoutes);
|
|
372
|
+
|
|
373
|
+
// Custom page catch-all (must be last)
|
|
374
|
+
app.route("/", pageRoutes);
|
|
375
|
+
|
|
376
|
+
return app;
|
|
377
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Minified by jsDelivr using Terser v5.19.2.
|
|
3
|
+
* Original file: /npm/@sudodevnull/datastar@0.19.9/dist/datastar.js
|
|
4
|
+
*
|
|
5
|
+
* Do NOT use SRI with dynamically generated files! More information: https://www.jsdelivr.com/using-sri-with-dynamic-files
|
|
6
|
+
*/
|
|
7
|
+
function ze(e){return e instanceof HTMLElement||e instanceof SVGElement?e:null}function ue(){throw new Error("Cycle detected")}function Et(){throw new Error("Computed cannot have side-effects")}const _t=Symbol.for("preact-signals"),O=1,B=2,Y=4,W=8,J=16,H=32;function fe(){G++}function de(){if(G>1)return void G--;let e,t=!1;for(;void 0!==K;){let n=K;for(K=void 0,we++;void 0!==n;){const s=n._nextBatchedEffect;if(n._nextBatchedEffect=void 0,n._flags&=~B,!(n._flags&W)&&Qe(n))try{n._callback()}catch(n){t||(e=n,t=!0)}n=s}}if(we=0,G--,t)throw e}function St(e){if(G>0)return e();fe();try{return e()}finally{de()}}let _,K,G=0,we=0,le=0;function Ze(e){if(void 0===_)return;let t=e._node;return void 0===t||t._target!==_?(t={_version:0,_source:e,_prevSource:_._sources,_nextSource:void 0,_target:_,_prevTarget:void 0,_nextTarget:void 0,_rollbackNode:t},void 0!==_._sources&&(_._sources._nextSource=t),_._sources=t,e._node=t,_._flags&H&&e._subscribe(t),t):-1===t._version?(t._version=0,void 0!==t._nextSource&&(t._nextSource._prevSource=t._prevSource,void 0!==t._prevSource&&(t._prevSource._nextSource=t._nextSource),t._prevSource=_._sources,t._nextSource=void 0,_._sources._nextSource=t,_._sources=t),t):void 0}function T(e){this._value=e,this._version=0,this._node=void 0,this._targets=void 0}function Xe(e){return new T(e)}function Qe(e){for(let t=e._sources;void 0!==t;t=t._nextSource)if(t._source._version!==t._version||!t._source._refresh()||t._source._version!==t._version)return!0;return!1}function et(e){for(let t=e._sources;void 0!==t;t=t._nextSource){const n=t._source._node;if(void 0!==n&&(t._rollbackNode=n),t._source._node=t,t._version=-1,void 0===t._nextSource){e._sources=t;break}}}function tt(e){let t,n=e._sources;for(;void 0!==n;){const e=n._prevSource;-1===n._version?(n._source._unsubscribe(n),void 0!==e&&(e._nextSource=n._nextSource),void 0!==n._nextSource&&(n._nextSource._prevSource=e)):t=n,n._source._node=n._rollbackNode,void 0!==n._rollbackNode&&(n._rollbackNode=void 0),n=e}e._sources=t}function R(e){T.call(this,void 0),this._compute=e,this._sources=void 0,this._globalVersion=le-1,this._flags=Y}function Tt(e){return new R(e)}function st(e){const t=e._cleanup;if(e._cleanup=void 0,"function"==typeof t){fe();const n=_;_=void 0;try{t()}catch(t){throw e._flags&=~O,e._flags|=W,Ne(e),t}finally{_=n,de()}}}function Ne(e){for(let t=e._sources;void 0!==t;t=t._nextSource)t._source._unsubscribe(t);e._compute=void 0,e._sources=void 0,st(e)}function At(e){if(_!==this)throw new Error("Out-of-order effect");tt(this),_=e,this._flags&=~O,this._flags&W&&Ne(this),de()}function X(e){this._compute=e,this._cleanup=void 0,this._sources=void 0,this._nextBatchedEffect=void 0,this._flags=H}function nt(e){const t=new X(e);try{t._callback()}catch(e){throw t._dispose(),e}return t._dispose.bind(t)}T.prototype.brand=_t,T.prototype._refresh=function(){return!0},T.prototype._subscribe=function(e){this._targets!==e&&void 0===e._prevTarget&&(e._nextTarget=this._targets,void 0!==this._targets&&(this._targets._prevTarget=e),this._targets=e)},T.prototype._unsubscribe=function(e){if(void 0!==this._targets){const t=e._prevTarget,n=e._nextTarget;void 0!==t&&(t._nextTarget=n,e._prevTarget=void 0),void 0!==n&&(n._prevTarget=t,e._nextTarget=void 0),e===this._targets&&(this._targets=n)}},T.prototype.subscribe=function(e){const t=this;return nt((function(){const n=t.value,s=this._flags&H;this._flags&=~H;try{e(n)}finally{this._flags|=s}}))},T.prototype.valueOf=function(){return this.value},T.prototype.toString=function(){return this.value+""},T.prototype.toJSON=function(){return this.value},T.prototype.peek=function(){return this._value},Object.defineProperty(T.prototype,"value",{get(){const e=Ze(this);return void 0!==e&&(e._version=this._version),this._value},set(e){if(_ instanceof R&&Et(),e!==this._value){we>100&&ue(),this._value=e,this._version++,le++,fe();try{for(let e=this._targets;void 0!==e;e=e._nextTarget)e._target._notify()}finally{de()}}}}),R.prototype=new T,R.prototype._refresh=function(){if(this._flags&=~B,this._flags&O)return!1;if((this._flags&(Y|H))===H||(this._flags&=~Y,this._globalVersion===le))return!0;if(this._globalVersion=le,this._flags|=O,this._version>0&&!Qe(this))return this._flags&=~O,!0;const e=_;try{et(this),_=this;const e=this._compute();(this._flags&J||this._value!==e||0===this._version)&&(this._value=e,this._flags&=~J,this._version++)}catch(e){this._value=e,this._flags|=J,this._version++}return _=e,tt(this),this._flags&=~O,!0},R.prototype._subscribe=function(e){if(void 0===this._targets){this._flags|=Y|H;for(let e=this._sources;void 0!==e;e=e._nextSource)e._source._subscribe(e)}T.prototype._subscribe.call(this,e)},R.prototype._unsubscribe=function(e){if(void 0!==this._targets&&(T.prototype._unsubscribe.call(this,e),void 0===this._targets)){this._flags&=~H;for(let e=this._sources;void 0!==e;e=e._nextSource)e._source._unsubscribe(e)}},R.prototype._notify=function(){if(!(this._flags&B)){this._flags|=Y|B;for(let e=this._targets;void 0!==e;e=e._nextTarget)e._target._notify()}},R.prototype.peek=function(){if(this._refresh()||ue(),this._flags&J)throw this._value;return this._value},Object.defineProperty(R.prototype,"value",{get(){this._flags&O&&ue();const e=Ze(this);if(this._refresh(),void 0!==e&&(e._version=this._version),this._flags&J)throw this._value;return this._value}}),X.prototype._callback=function(){const e=this._start();try{if(this._flags&W||void 0===this._compute)return;const e=this._compute();"function"==typeof e&&(this._cleanup=e)}finally{e()}},X.prototype._start=function(){this._flags&O&&ue(),this._flags|=O,this._flags&=~W,st(this),et(this),fe();const e=_;return _=this,At.bind(this,e)},X.prototype._notify=function(){this._flags&B||(this._flags|=B,this._nextBatchedEffect=K,K=this)},X.prototype._dispose=function(){this._flags|=W,this._flags&O||Ne(this)};class rt{get value(){return Ee(this)}set value(e){St((()=>Nt(this,e)))}peek(){return Ee(this,{peek:!0})}}const oe=e=>Object.assign(new rt,Object.entries(e).reduce(((e,[t,n])=>{if(["value","peek"].some((e=>e===t)))throw new Error(`${t} is a reserved property name`);return"object"!=typeof n||null===n||Array.isArray(n)?e[t]=Xe(n):e[t]=oe(n),e}),{})),Nt=(e,t)=>Object.keys(t).forEach((n=>e[n].value=t[n])),Ee=(e,{peek:t=!1}={})=>Object.entries(e).reduce(((e,[n,s])=>(s instanceof T?e[n]=t?s.peek():s.value:s instanceof rt&&(e[n]=Ee(s,{peek:t})),e)),{});function ot(e,t){if("object"!=typeof t||Array.isArray(t)||!t)return t;if("object"==typeof t&&void 0!==t.toJSON&&"function"==typeof t.toJSON)return t.toJSON();let n=e;return"object"!=typeof e&&(n={...t}),Object.keys(t).forEach((e=>{n.hasOwnProperty(e)||(n[e]=t[e]),null===t[e]?delete n[e]:n[e]=ot(n[e],t[e])})),n}const q="datastar-event",it="[a-zA-Z_$]+",Lt=it+"[0-9a-zA-Z_$.]*";function Le(e,t,n,s=!0){return new RegExp(`(?<whole>\\${e}(?<${t}>${s?Lt:it})${n})`,"g")}const kt={regexp:Le("$","signal","(?<method>\\([^\\)]*\\))?"),replacer:e=>{const{signal:t,method:n}=e,s="ctx.store()";if(!n?.length)return`${s}.${t}.value`;const o=t.split("."),r=o.pop();return`${s}.${o.join(".")}.value.${r}${n}`}},Mt={regexp:Le("$\\$","action","(?<call>\\((?<args>.*)\\))?"),replacer:({action:e,args:t})=>{const n=["ctx"];t&&n.push(...t.split(",").map((e=>e.trim())));return`ctx.actions.${e}(${n.join(",")})`}},Pt={regexp:Le("~","ref","",!1),replacer:({ref:e})=>`document.querySelector(ctx.store()._dsPlugins.refs.${e})`},$t=[Mt,kt,Pt],Ot={prefix:"store",removeNewLines:!0,preprocessors:{pre:[{regexp:/(?<whole>.+)/g,replacer:e=>{const{whole:t}=e;return`Object.assign({...ctx.store()}, ${t})`}}]},allowedModifiers:new Set(["local","session","ifmissing"]),onLoad:e=>{let t="";const n=n=>{const s=e.store(),o=JSON.stringify(s);o!==t&&(window.localStorage.setItem(U,o),t=o)},s=e.modifiers.has("local");if(s){window.addEventListener(q,n);const t=window.localStorage.getItem(U)||"{}",s=JSON.parse(t);e.mergeStore(s)}const o=e.modifiers.has("session"),r=t=>{const n=e.store(),s=JSON.stringify(n);window.sessionStorage.setItem(U,s)};if(o){window.addEventListener(q,r);const t=window.sessionStorage.getItem(U)||"{}",n=JSON.parse(t);e.mergeStore(n)}const i=e.expressionFn(e),a=lt(e.store(),i,e.modifiers.has("ifmissing"));return e.mergeStore(a),delete e.el.dataset[e.rawKey],()=>{s&&window.removeEventListener(q,n),o&&window.removeEventListener(q,r)}}},It={prefix:"computed",mustNotEmptyKey:!0,onLoad:e=>(e.store()[e.key]=e.reactivity.computed((()=>e.expressionFn(e))),()=>{delete e.store()[e.key]})},Rt={prefix:"ref",mustHaveEmptyKey:!0,mustNotEmptyExpression:!0,bypassExpressionFunctionCreation:()=>!0,onLoad:e=>{e.upsertIfMissingFromStore("_dsPlugins.refs",{});const{el:t,expression:n}=e,s={_dsPlugins:{refs:{...e.store()._dsPlugins.refs.value,[n]:at(t)}}};return e.mergeStore(s),()=>{const t=e.store(),s={...t._dsPlugins.refs.value};delete s[n],t._dsPlugins.refs=s}}},Ct=[Ot,It,Rt];function at(e){if(!e)return"null";if("string"==typeof e)return e;if(e instanceof Window)return"Window";if(e instanceof Document)return"Document";if("BODY"===e.tagName)return"BODY";const t=[];for(;e.parentElement&&"BODY"!==e.tagName;){if(e.id){t.unshift("#"+e.getAttribute("id"));break}{let n=1,s=e;for(;s.previousElementSibling;s=s.previousElementSibling,n++);t.unshift(e.tagName+":nth-child("+n+")")}e=e.parentElement}return t.join(">")}function lt(e,t,n){const s={};if(n)for(const n in t){const o=e[n]?.value;null==o&&(s[n]=t[n])}else Object.assign(s,t);return s}const U="datastar",k=`${U}-`;class Dt{constructor(e={},...t){if(this.plugins=[],this.store=oe({_dsPlugins:{}}),this.actions={},this.refs={},this.reactivity={signal:Xe,computed:Tt,effect:nt},this.parentID="",this.missingIDNext=0,this.removals=new Map,this.mergeRemovals=new Array,this.actions=Object.assign(this.actions,e),!(t=[...Ct,...t]).length)throw new Error("No plugins provided");const n=new Set;for(const e of t){if(e.requiredPluginPrefixes)for(const t of e.requiredPluginPrefixes)if(!n.has(t))throw new Error(`${e.prefix} requires ${t}`);this.plugins.push(e),n.add(e.prefix)}}run(){new MutationObserver(((e,t)=>{N("core","dom","mutation",document.body,document.body.outerHTML)})).observe(document.body,{attributes:!0,childList:!0,subtree:!0}),this.plugins.forEach((e=>{e.onGlobalInit&&(e.onGlobalInit({actions:this.actions,reactivity:this.reactivity,mergeStore:this.mergeStore.bind(this),store:this.store}),N("core","plugins","registration","BODY",`On prefix ${e.prefix}`))})),this.applyPlugins(document.body)}cleanupElementRemovals(e){const t=this.removals.get(e);if(t){for(const e of t.set)e();this.removals.delete(e)}}mergeStore(e){this.mergeRemovals.forEach((e=>e())),this.mergeRemovals=this.mergeRemovals.slice(0);const t=ot(this.store.value,e);this.store=oe(t),this.mergeRemovals.push(this.reactivity.effect((()=>{N("core","store","merged","STORE",JSON.stringify(this.store.value))})))}removeFromStore(...e){const t={...this.store.value};for(const n of e){const e=n.split(".");let s=e[0],o=t;for(let t=1;t<e.length;t++){const n=e[t];o[s]||(o[s]={}),o=o[s],s=n}delete o[s]}this.store=oe(t),this.applyPlugins(document.body)}upsertIfMissingFromStore(e,t){const n=e.split(".");let s=this.store;for(let e=0;e<n.length-1;e++){const t=n[e];s[t]||(s[t]={}),s=s[t]}const o=n[n.length-1];s[o]||(s[o]=this.reactivity.signal(t),N("core","store","upsert",e,t))}signalByName(e){return this.store[e]}applyPlugins(e){const t=new Set;this.plugins.forEach(((n,s)=>{this.walkDownDOM(e,(e=>{s||this.cleanupElementRemovals(e);for(const s in e.dataset){const o=e.dataset[s]||"";let r=o;if(!s.startsWith(n.prefix))continue;if(0===e.id.length&&(e.id=`ds-${this.parentID}-${this.missingIDNext++}`),t.clear(),n.allowedTagRegexps){const t=e.tagName.toLowerCase();if(![...n.allowedTagRegexps].some((e=>t.match(e))))throw new Error(`'${e.tagName}' not allowed for '${s}', allowed ${[[...n.allowedTagRegexps].map((e=>`'${e}'`))].join(", ")}`)}let i=s.slice(n.prefix.length),[a,...l]=i.split(".");if(n.mustHaveEmptyKey&&a.length>0)throw new Error(`'${s}' must have empty key`);if(n.mustNotEmptyKey&&0===a.length)throw new Error(`'${s}' must have non-empty key`);a.length&&(a=a[0].toLowerCase()+a.slice(1));const c=l.map((e=>{const[t,...n]=e.split("_");return{label:t,args:n}}));if(n.allowedModifiers)for(const e of c)if(!n.allowedModifiers.has(e.label))throw new Error(`'${e.label}' is not allowed`);const u=new Map;for(const e of c)u.set(e.label,e.args);if(n.mustHaveEmptyExpression&&r.length)throw new Error(`'${s}' must have empty expression`);if(n.mustNotEmptyExpression&&!r.length)throw new Error(`'${s}' must have non-empty expression`);const d=/;|\n/;n.removeNewLines&&(r=r.split("\n").map((e=>e.trim())).join(" "));const f=[...n.preprocessors?.pre||[],...$t,...n.preprocessors?.post||[]];for(const e of f){if(t.has(e))continue;t.add(e);const n=r.split(d),s=[];n.forEach((t=>{let n=t;const o=[...n.matchAll(e.regexp)];if(o.length)for(const t of o){if(!t.groups)continue;const{groups:s}=t,{whole:o}=s;n=n.replace(o,e.replacer(s))}s.push(n)})),r=s.join("; ")}const h={store:()=>this.store,mergeStore:this.mergeStore.bind(this),upsertIfMissingFromStore:this.upsertIfMissingFromStore.bind(this),removeFromStore:this.removeFromStore.bind(this),applyPlugins:this.applyPlugins.bind(this),cleanupElementRemovals:this.cleanupElementRemovals.bind(this),walkSignals:this.walkSignals.bind(this),actions:this.actions,reactivity:this.reactivity,el:e,rawKey:s,key:a,rawExpression:o,expression:r,expressionFn:()=>{throw new Error("Expression function not created")},modifiers:u,sendDatastarEvent:N};if(!n.bypassExpressionFunctionCreation?.(h)&&!n.mustHaveEmptyExpression&&r.length){const e=r.split(d).map((e=>e.trim())).filter((e=>e.length));e[e.length-1]=`return ${e[e.length-1]}`;const t=e.map((e=>` ${e}`)).join(";\n"),o=`\ntry {\n const _datastarExpression = () => {\n${t}\n }\n const _datastarReturnVal = _datastarExpression()\n ctx.sendDatastarEvent('core', 'attributes', 'expr_eval', ctx.el, '${s} equals ' + JSON.stringify(_datastarReturnVal))\n return _datastarReturnVal\n} catch (e) {\n const msg = \`\nError evaluating Datastar expression:\n${t.replaceAll("`","\\`")}\n\nError: \${e.message}\n\nCheck if the expression is valid before raising an issue.\n\`.trim()\n ctx.sendDatastarEvent('core', 'attributes', 'expr_eval_err', ctx.el, msg)\n console.error(msg)\n debugger\n}\n `;try{const e=n.argumentNames||[],t=new Function("ctx",...e,o);h.expressionFn=t}catch(e){const t=new Error(`Error creating expression function for '${o}', error: ${e}`);N("core","attributes","expr_construction_err",h.el,String(t)),console.error(t)}}const p=n.onLoad(h);p&&(this.removals.has(e)||this.removals.set(e,{id:e.id,set:new Set}),this.removals.get(e).set.add(p))}}))}))}walkSignalsStore(e,t){const n=Object.keys(e);for(let s=0;s<n.length;s++){const o=n[s],r=e[o],i=r instanceof T,a="object"==typeof r&&Object.keys(r).length>0;i?t(o,r):a&&this.walkSignalsStore(r,t)}}walkSignals(e){this.walkSignalsStore(this.store,e)}walkDownDOM(e,t,n=0){if(!e)return;const s=ze(e);if(s)for(t(s),n=0,e=e.firstElementChild;e;)this.walkDownDOM(e,t,n++),e=e.nextElementSibling}}const ct=e=>e.replace(/[A-Z]+(?![a-z])|[A-Z]/g,((e,t)=>(t?"-":"")+e.toLowerCase())),Ft={prefix:"bind",mustNotEmptyKey:!0,mustNotEmptyExpression:!0,onLoad:e=>e.reactivity.effect((async()=>{const t=ct(e.key),n=e.expressionFn(e);let s;s="string"==typeof n?n:JSON.stringify(n),s&&"false"!==s&&"null"!==s&&"undefined"!==s?e.el.setAttribute(t,s):e.el.removeAttribute(t)}))},Ht=/^data:(?<mime>[^;]+);base64,(?<contents>.*)$/,te=["change","input","keydown"],Vt={prefix:"model",mustHaveEmptyKey:!0,preprocessors:{post:[{regexp:/(?<whole>.+)/g,replacer:e=>{const{whole:t}=e;return`ctx.store().${t}`}}]},onLoad:e=>{const{el:t,expression:n}=e,s=e.expressionFn(e),o=t.tagName.toLowerCase();if(n.startsWith("ctx.store().ctx.store()"))throw new Error(`Model attribute on #${t.id} must have a signal name, you probably prefixed with $ by accident`);const r=o.includes("input"),i=t.getAttribute("type"),a=o.includes("checkbox")||r&&"checkbox"===i,l=o.includes("select"),c=o.includes("radio")||r&&"radio"===i,u=r&&"file"===i,d=n.replaceAll("ctx.store().","");c&&(t.getAttribute("name")?.length||t.setAttribute("name",d));const f=e.reactivity.effect((()=>{if(!s)throw new Error(`Signal ${d} not found`);const e="value"in t,n=s.value;if(a||c){const e=t;a?e.checked=n:c&&(e.checked=`${n}`===e.value)}else if(!u)if(l){const e=t;if(e.multiple){const t=s.value;Array.from(e.options).forEach((e=>{e?.disabled||(e.selected=t.includes(e.value))}))}else e.value=`${n}`}else e?t.value=`${n}`:t.setAttribute("value",`${n}`)})),h=async()=>{if(u){const n=[...t?.files||[]],o=[],r=[],i=[];await Promise.all(n.map((e=>new Promise((t=>{const n=new FileReader;n.onload=()=>{if("string"!=typeof n.result)throw new Error("Invalid result type: "+typeof n.result);const t=n.result.match(Ht);if(!t?.groups)throw new Error(`Invalid data URI: ${n.result}`);o.push(t.groups.contents),r.push(t.groups.mime),i.push(e.name)},n.onloadend=()=>t(void 0),n.readAsDataURL(e)}))))),s.value=o;const a=e.store(),l=`${d}Mimes`,c=`${d}Names`;return l in a&&(a[`${l}`].value=r),void(c in a&&(a[`${c}`].value=i))}const n=s.value,o=t||t;if("number"==typeof n)s.value=Number(o.value||o.getAttribute("value"));else if("string"==typeof n)s.value=o.value||o.getAttribute("value")||"";else if("boolean"==typeof n)s.value=a?o.checked||"true"===o.getAttribute("checked"):!(!o.value&&!o.getAttribute("value"));else if(!(typeof n>"u"))if("bigint"==typeof n)s.value=BigInt(o.value||o.getAttribute("value")||"0");else{if(!Array.isArray(n))throw console.log(typeof n),new Error(`Unsupported type ${typeof n} for signal ${d}`);if(l){const e=[...t.selectedOptions].map((e=>e.value));s.value=e}else s.value=JSON.parse(o.value).split(",");console.log(o.value)}},p=t.tagName.split("-");if(p.length>1){const e=p[0].toLowerCase();te.forEach((t=>{te.push(`${e}-${t}`)}))}return te.forEach((e=>t.addEventListener(e,h))),()=>{f(),te.forEach((e=>t.removeEventListener(e,h)))}}},xt={prefix:"text",mustHaveEmptyKey:!0,onLoad:e=>{const{el:t,expressionFn:n}=e;if(!(t instanceof HTMLElement))throw new Error("Element is not HTMLElement");return e.reactivity.effect((()=>{const s=n(e);t.textContent=`${s}`}))}};let $e="";const jt=new Set(["window","once","passive","capture","debounce","throttle","remote","outside"]),Ut={prefix:"on",mustNotEmptyKey:!0,mustNotEmptyExpression:!0,argumentNames:["evt"],onLoad:e=>{const{el:t,key:n,expressionFn:s}=e;let o=e.el;e.modifiers.get("window")&&(o=window);let r=t=>{N("plugin","event",n,o,"triggered"),s(e,t)};const i=e.modifiers.get("debounce");if(i){const e=_e(i),t=se(i,"leading",!1),n=se(i,"noTrail",!0);r=Jt(r,e,t,n)}const a=e.modifiers.get("throttle");if(a){const e=_e(a),t=se(a,"noLead",!0),n=se(a,"noTrail",!1);r=Kt(r,e,t,n)}const l={capture:!0,passive:!1,once:!1};e.modifiers.has("capture")||(l.capture=!1),e.modifiers.has("passive")&&(l.passive=!0),e.modifiers.has("once")&&(l.once=!0),[...e.modifiers.keys()].filter((e=>!jt.has(e))).forEach((s=>{const o=e.modifiers.get(s)||[],i=r;r=()=>{const e=event,r=e[s];let a;if("function"==typeof r)a=r(...o);else if("boolean"==typeof r)a=r;else{if("string"!=typeof r){const e=`Invalid value for ${s} modifier on ${n} on ${t}`;throw console.error(e),new Error(e)}a=r.toLowerCase().trim()===o.join("").toLowerCase().trim()}a&&i(e)}}));const c=ct(n).toLowerCase();switch(c){case"load":return r(),delete e.el.dataset.onLoad,()=>{};case"raf":let n;const s=()=>{r(),n=requestAnimationFrame(s)};return n=requestAnimationFrame(s),()=>{n&&cancelAnimationFrame(n)};case"store-change":return e.reactivity.effect((()=>{let t=e.store().value;e.modifiers.has("remote")&&(t=he(t));const n=JSON.stringify(t);$e!==n&&($e=n,r())}));default:if(e.modifiers.has("outside")){o=document;const e=r;let n=!1;r=s=>{const o=s?.target;if(!o)return;const r=t.id===o.id;r&&n&&(n=!1),!r&&!n&&(e(s),n=!0)}}return o.addEventListener(c,r,l),()=>{o.removeEventListener(c,r)}}}};function he(e){const t={};for(const[n,s]of Object.entries(e))n.startsWith("_")||("object"!=typeof s||Array.isArray(s)?t[n]=s:t[n]=he(s));return t}const Bt={prefix:"class",mustHaveEmptyKey:!0,mustNotEmptyExpression:!0,onLoad:e=>e.reactivity.effect((()=>{const t=e.expressionFn(e);for(const[n,s]of Object.entries(t))s?e.el.classList.add(n):e.el.classList.remove(n);return()=>{e.el.classList.remove(...Object.keys(t))}}))},Wt=[Ft,Vt,xt,Ut,Bt],qt={remote:async e=>he(e.store().value)};function _e(e){if(!e||0===e?.length)return 0;for(const t of e){if(t.endsWith("ms"))return Number(t.replace("ms",""));if(t.endsWith("s"))return 1e3*Number(t.replace("s",""));try{return parseFloat(t)}catch{}}return 0}function se(e,t,n=!1){return!!e&&(e.includes(t)||n)}function Jt(e,t,n=!1,s=!0){let o;const r=()=>o&&clearTimeout(o);return function(...i){r(),n&&!o&&e(...i),o=setTimeout((()=>{s&&e(...i),r()}),t)}}function Kt(e,t,n=!0,s=!1){let o=!1;return function(...r){o||(n&&e(...r),o=!0,setTimeout((()=>{o=!1,s&&e(...r)}),t))}}function Gt(e,{signal:t,headers:n,onopen:s,onmessage:o,onclose:r,onerror:i,openWhenHidden:a,...l}){return new Promise(((c,u)=>{let d=0;const f={...n};let h;function p(){h.abort(),document.hidden||y()}f.accept||(f.accept=Se),a||document.addEventListener("visibilitychange",p);let m=Oe,g=0;function v(){document.removeEventListener("visibilitychange",p),window.clearTimeout(g),h.abort()}t?.addEventListener("abort",(()=>{v(),c()}));const b=s??Zt;async function y(){h=new AbortController;try{const t=await fetch(e,{...l,headers:f,signal:h.signal});await b(t),await Xt(t.body,Qt(es((e=>{e?f[Ie]=e:delete f[Ie]}),(e=>{m=e}),o))),r?.(),v(),c()}catch(e){if(!h.signal.aborted)try{const t=i?.(e)??m;window.clearTimeout(g),g=window.setTimeout(y,t),m*=1.5,m=Math.min(m,Yt),d++,d>=zt?(v(),u(new Error("Max retries hit, check your server or network connection."))):console.error(`Error fetching event source, retrying in ${t}ms`)}catch(e){v(),u(e)}}}m=Oe,y()}))}const Se="text/event-stream",Oe=100,Yt=1e4,zt=10,Ie="last-event-id";function Zt(e){const t=e.headers.get("content-type");if(!t?.startsWith(Se))throw new Error(`Expected content-type to be ${Se}, Actual: ${t}`)}async function Xt(e,t){const n=e.getReader();for(;;){const e=await n.read();if(e.done)break;t(e.value)}}function Qt(e){let t,n,s,o=!1;return function(r){void 0===t?(t=r,n=0,s=-1):t=ts(t,r);const i=t.length;let a=0;for(;n<i;){o&&(10===t[n]&&(a=++n),o=!1);let r=-1;for(;n<i&&-1===r;++n)switch(t[n]){case 58:-1===s&&(s=n-a);break;case 13:o=!0;case 10:r=n}if(-1===r)break;e(t.subarray(a,r),s),a=n,s=-1}a===i?t=void 0:0!==a&&(t=t.subarray(a),n-=a)}}function es(e,t,n){let s=Re();const o=new TextDecoder;return function(r,i){if(0===r.length)n?.(s),s=Re();else if(i>0){const n=o.decode(r.subarray(0,i)),a=i+(32===r[i+1]?2:1),l=o.decode(r.subarray(a));switch(n){case"data":s.data=s.data?s.data+"\n"+l:l;break;case"event":s.event=l;break;case"id":e(s.id=l);break;case"retry":const n=parseInt(l,10);isNaN(n)||t(s.retry=n)}}}}function ts(e,t){const n=new Uint8Array(e.length+t.length);return n.set(e),n.set(t,e.length),n}function Re(){return{data:"",event:"",id:"",retry:void 0}}const ie=new WeakSet;function ss(e,t,n={}){let s;e instanceof Document&&(e=e.documentElement),s="string"==typeof t?as(t):t;const o=ls(s);return ut(e,o,rs(e,o,n))}function ut(e,t,n){if(n.head.block){const s=e.querySelector("head"),o=t.querySelector("head");if(s&&o){const r=dt(o,s,n);return void Promise.all(r).then((()=>{ut(e,t,Object.assign(n,{head:{block:!1,ignore:!0}}))}))}}if("innerHTML"===n.morphStyle)return ft(t,e,n),e.children;if("outerHTML"===n.morphStyle||null==n.morphStyle){const s=us(t,e,n);if(!s)throw new Error("Could not find best match");const o=s?.previousSibling,r=s?.nextSibling,i=ae(e,s,n);return s?cs(o,i,r):[]}throw"Do not understand how to morph style "+n.morphStyle}function ae(e,t,n){if(!n.ignoreActive||e!==document.activeElement){if(null==t){if(!1===n.callbacks.beforeNodeRemoved(e))return;return e.remove(),void n.callbacks.afterNodeRemoved(e)}if(ce(e,t))return!1===n.callbacks.beforeNodeMorphed(e,t)?void 0:(e instanceof HTMLHeadElement&&n.head.ignore||(t instanceof HTMLHeadElement&&e instanceof HTMLHeadElement&&"morph"!==n.head.style?dt(t,e,n):(ns(t,e),ft(t,e,n))),n.callbacks.afterNodeMorphed(e,t),e);if(!1===n.callbacks.beforeNodeRemoved(e)||!1===n.callbacks.beforeNodeAdded(t))return;if(!e.parentElement)throw new Error("oldNode has no parentElement");return e.parentElement.replaceChild(t,e),n.callbacks.afterNodeAdded(t),n.callbacks.afterNodeRemoved(e),t}}function ft(e,t,n){let s,o=e.firstChild,r=t.firstChild;for(;o;){if(s=o,o=s.nextSibling,null==r){if(!1===n.callbacks.beforeNodeAdded(s))return;t.appendChild(s),n.callbacks.afterNodeAdded(s),x(n,s);continue}if(ht(s,r,n)){ae(r,s,n),r=r.nextSibling,x(n,s);continue}let i=os(e,t,s,r,n);if(i){r=Ce(r,i,n),ae(i,s,n),x(n,s);continue}let a=is(e,s,r,n);if(a)r=Ce(r,a,n),ae(a,s,n),x(n,s);else{if(!1===n.callbacks.beforeNodeAdded(s))return;t.insertBefore(s,r),n.callbacks.afterNodeAdded(s),x(n,s)}}for(;null!==r;){let e=r;r=r.nextSibling,pt(e,n)}}function ns(e,t){let n=e.nodeType;if(1===n){for(const n of e.attributes)t.getAttribute(n.name)!==n.value&&t.setAttribute(n.name,n.value);for(const n of t.attributes)e.hasAttribute(n.name)||t.removeAttribute(n.name)}if((n===Node.COMMENT_NODE||n===Node.TEXT_NODE)&&t.nodeValue!==e.nodeValue&&(t.nodeValue=e.nodeValue),e instanceof HTMLInputElement&&t instanceof HTMLInputElement&&"file"!==e.type)t.value=e.value||"",ne(e,t,"value"),ne(e,t,"checked"),ne(e,t,"disabled");else if(e instanceof HTMLOptionElement)ne(e,t,"selected");else if(e instanceof HTMLTextAreaElement&&t instanceof HTMLTextAreaElement){const n=e.value;n!==t.value&&(t.value=n),t.firstChild&&t.firstChild.nodeValue!==n&&(t.firstChild.nodeValue=n)}}function ne(e,t,n){const s=e.getAttribute(n);s!==t.getAttribute(n)&&(s?t.setAttribute(n,s):t.removeAttribute(n))}function dt(e,t,n){const s=[],o=[],r=[],i=[],a=n.head.style,l=new Map;for(const t of e.children)l.set(t.outerHTML,t);for(const e of t.children){let t=l.has(e.outerHTML),s=n.head.shouldReAppend(e),c=n.head.shouldPreserve(e);t||c?s?o.push(e):(l.delete(e.outerHTML),r.push(e)):"append"===a?s&&(o.push(e),i.push(e)):!1!==n.head.shouldRemove(e)&&o.push(e)}i.push(...l.values());const c=[];for(const e of i){const o=document.createRange().createContextualFragment(e.outerHTML).firstChild;if(!o)throw new Error("could not create new element from: "+e.outerHTML);if(n.callbacks.beforeNodeAdded(o)){if(o.hasAttribute("href")||o.hasAttribute("src")){let e;const t=new Promise((t=>{e=t}));o.addEventListener("load",(function(){e(void 0)})),c.push(t)}t.appendChild(o),n.callbacks.afterNodeAdded(o),s.push(o)}}for(const e of o)!1!==n.callbacks.beforeNodeRemoved(e)&&(t.removeChild(e),n.callbacks.afterNodeRemoved(e));return n.head.afterHeadMorphed(t,{added:s,kept:r,removed:o}),c}function F(){}function rs(e,t,n){return{target:e,newContent:t,config:n,morphStyle:n.morphStyle,ignoreActive:n.ignoreActive,idMap:ps(e,t),deadIds:new Set,callbacks:Object.assign({beforeNodeAdded:F,afterNodeAdded:F,beforeNodeMorphed:F,afterNodeMorphed:F,beforeNodeRemoved:F,afterNodeRemoved:F},n.callbacks),head:Object.assign({style:"merge",shouldPreserve:e=>"true"===e.getAttribute("im-preserve"),shouldReAppend:e=>"true"===e.getAttribute("im-re-append"),shouldRemove:F,afterHeadMorphed:F},n.head)}}function ht(e,t,n){return!(!e||!t)&&(e.nodeType===t.nodeType&&e.tagName===t.tagName&&(!(!e?.id?.length||e.id!==t.id)||z(n,e,t)>0))}function ce(e,t){return!(!e||!t)&&(e.nodeType===t.nodeType&&e.tagName===t.tagName)}function Ce(e,t,n){for(;e!==t;){const t=e;if(e=e?.nextSibling,!t)throw new Error("tempNode is null");pt(t,n)}return x(n,t),t.nextSibling}function os(e,t,n,s,o){const r=z(o,n,t);let i=null;if(r>0){i=s;let t=0;for(;null!=i;){if(ht(n,i,o))return i;if(t+=z(o,i,e),t>r)return null;i=i.nextSibling}}return i}function is(e,t,n,s){let o=n,r=t.nextSibling,i=0;for(;o&&r;){if(z(s,o,e)>0)return null;if(ce(t,o))return o;if(ce(r,o)&&(i++,r=r.nextSibling,i>=2))return null;o=o.nextSibling}return o}const De=new DOMParser;function as(e){const t=e.replace(/<svg(\s[^>]*>|>)([\s\S]*?)<\/svg>/gim,"");if(t.match(/<\/html>/)||t.match(/<\/head>/)||t.match(/<\/body>/)){const n=De.parseFromString(e,"text/html");if(t.match(/<\/html>/))return ie.add(n),n;{let e=n.firstChild;return e?(ie.add(e),e):null}}{const t=De.parseFromString(`<body><template>${e}</template></body>`,"text/html").body.querySelector("template")?.content;if(!t)throw new Error("content is null");return ie.add(t),t}}function ls(e){if(null==e)return document.createElement("div");if(ie.has(e))return e;if(e instanceof Node){const t=document.createElement("div");return t.append(e),t}{const t=document.createElement("div");for(const n of[...e])t.append(n);return t}}function cs(e,t,n){const s=[],o=[];for(;e;)s.push(e),e=e.previousSibling;for(;s.length>0;){const e=s.pop();o.push(e),t?.parentElement?.insertBefore(e,t)}for(o.push(t);n;)s.push(n),o.push(n),n=n.nextSibling;for(;s.length;)t?.parentElement?.insertBefore(s.pop(),t.nextSibling);return o}function us(e,t,n){let s=e.firstChild,o=s,r=0;for(;s;){let e=fs(s,t,n);e>r&&(o=s,r=e),s=s.nextSibling}return o}function fs(e,t,n){return ce(e,t)?.5+z(n,e,t):0}function pt(e,t){x(t,e),!1!==t.callbacks.beforeNodeRemoved(e)&&(e.remove(),t.callbacks.afterNodeRemoved(e))}function ds(e,t){return!e.deadIds.has(t)}function hs(e,t,n){return e.idMap.get(n)?.has(t)||!1}function x(e,t){const n=e.idMap.get(t);if(n)for(const t of n)e.deadIds.add(t)}function z(e,t,n){const s=e.idMap.get(t);if(!s)return 0;let o=0;for(const t of s)ds(e,t)&&hs(e,t,n)&&++o;return o}function Fe(e,t){const n=e.parentElement,s=e.querySelectorAll("[id]");for(const e of s){let s=e;for(;s!==n&&s;){let n=t.get(s);null==n&&(n=new Set,t.set(s,n)),n.add(e.id),s=s.parentElement}}}function ps(e,t){const n=new Map;return Fe(e,n),Fe(t,n),n}const ge="display",He="none",ve="important",Ve="duration",ms="show",be=`${k}showing`,ye=`${k}hiding`,xe=`${k}show-transition-style`,gs={prefix:ms,allowedModifiers:new Set([ve,Ve]),onLoad:e=>{const{el:t,modifiers:n,expressionFn:s,reactivity:o}=e,r=n.has(ve)?ve:void 0;let i,a;const l=e.modifiers.get(Ve);if(l){let e=document.getElementById(xe);if(!e){e=document.createElement("style"),e.id=xe,document.head.appendChild(e);const t=_e(l)||"300";e.innerHTML=`\n .${be} {\n visibility: visible;\n transition: opacity ${t}ms linear;\n }\n .${ye} {\n visibility: hidden;\n transition: visibility 0s ${t}ms, opacity ${t}ms linear;\n }\n `}const n=e=>s=>{s.target===t&&(t.classList.remove(e),t.removeEventListener("transitionend",n(e)))};i=()=>{t.addEventListener("transitionend",n(be)),t.classList.add(be),requestAnimationFrame((()=>{t.style.setProperty("opacity","1",r)}))},a=()=>{t.addEventListener("transitionend",n(ye)),t.classList.add(ye),requestAnimationFrame((()=>{t.style.setProperty("opacity","0",r)}))}}else i=()=>{1===t.style.length&&t.style.display===He?t.style.removeProperty(ge):t.style.setProperty(ge,"",r)},a=()=>{t.style.setProperty(ge,He,r)};return o.effect((async()=>{await s(e)?i():a()}))}},vs="intersects",je="once",Ue="half",Be="full",bs={prefix:vs,allowedModifiers:new Set([je,Ue,Be]),mustHaveEmptyKey:!0,onLoad:e=>{const{modifiers:t}=e,n={threshold:0};t.has(Be)?n.threshold=1:t.has(Ue)&&(n.threshold=.5);const s=new IntersectionObserver((n=>{n.forEach((n=>{n.isIntersecting&&(e.expressionFn(e),t.has(je)&&(s.disconnect(),delete e.el.dataset[e.rawKey]))}))}),n);return s.observe(e.el),()=>s.disconnect()}},We="prepend",qe="append",Je=new Error("Target element must have a parent if using prepend or append"),ys={prefix:"teleport",allowedModifiers:new Set([We,qe]),allowedTagRegexps:new Set(["template"]),bypassExpressionFunctionCreation:()=>!0,onLoad:e=>{const{el:t,modifiers:n,expression:s}=e;if(!(t instanceof HTMLTemplateElement))throw new Error("el must be a template element");const o=document.querySelector(s);if(!o)throw new Error(`Target element not found: ${s}`);if(!t.content)throw new Error("Template element must have content");const r=t.content.cloneNode(!0);if(ze(r)?.firstElementChild)throw new Error("Empty template");if(n.has(We)){if(!o.parentNode)throw Je;o.parentNode.insertBefore(r,o)}else if(n.has(qe)){if(!o.parentNode)throw Je;o.parentNode.insertBefore(r,o.nextSibling)}else o.appendChild(r)}},ws={prefix:"scrollIntoView",mustHaveEmptyKey:!0,mustHaveEmptyExpression:!0,allowedModifiers:new Set(["smooth","instant","auto","hstart","hcenter","hend","hnearest","vstart","vcenter","vend","vnearest","focus"]),onLoad:({el:e,modifiers:t,rawKey:n})=>{e.tabIndex||e.setAttribute("tabindex","0");const s={behavior:"smooth",block:"center",inline:"center"};return t.has("smooth")&&(s.behavior="smooth"),t.has("instant")&&(s.behavior="instant"),t.has("auto")&&(s.behavior="auto"),t.has("hstart")&&(s.inline="start"),t.has("hcenter")&&(s.inline="center"),t.has("hend")&&(s.inline="end"),t.has("hnearest")&&(s.inline="nearest"),t.has("vstart")&&(s.block="start"),t.has("vcenter")&&(s.block="center"),t.has("vend")&&(s.block="end"),t.has("vnearest")&&(s.block="nearest"),vt(e,s,t.has("focus")),delete e.dataset[n],()=>{}}},mt=document,gt=!!mt.startViewTransition,Es={prefix:"viewTransition",onGlobalInit(){let e=!1;if(document.head.childNodes.forEach((t=>{t instanceof HTMLMetaElement&&"view-transition"===t.name&&(e=!0)})),!e){const e=document.createElement("meta");e.name="view-transition",e.content="same-origin",document.head.appendChild(e)}},onLoad:e=>{if(gt)return e.reactivity.effect((()=>{const{el:t,expressionFn:n}=e;let s=n(e);if(!s)return;t.style.viewTransitionName=s}));console.error("Browser does not support view transitions")}},_s=[gs,bs,ys,ws,Es],Ss={scroll:async(e,t,n)=>{const s=Object.assign({behavior:"smooth",vertical:"center",horizontal:"center",shouldFocus:!0},n);vt(document.querySelector(t),s)}};function vt(e,t,n=!0){if(!(e instanceof HTMLElement||e instanceof SVGElement))throw new Error("Element not found");e.tabIndex||e.setAttribute("tabindex","0"),e.scrollIntoView(t),n&&e.focus()}const Ts=500,As=!0,Ns="morph",Ls="Content-Type",ks=`${U}-request`,Ms="application/json",Ps="true",$s=`${k}fragment`,Os=`${k}signal`,Is=`${k}delete`,Rs=`${k}redirect`,Cs=`${k}console`,Z=`${k}indicator`,Te=`${Z}-loading`,Ke=`${k}settling`,re=`${k}swapping`,Ds="self",Fs="get",Hs="post",Vs="put",xs="patch",js="delete",I={MorphElement:"morph",InnerElement:"inner",OuterElement:"outer",PrependElement:"prepend",AppendElement:"append",BeforeElement:"before",AfterElement:"after",UpsertAttributes:"upsert_attributes"},Us={prefix:"fetchIndicator",mustHaveEmptyKey:!0,mustNotEmptyExpression:!0,onGlobalInit:()=>{const e=document.createElement("style");e.innerHTML=`\n.${Z}{\n opacity:0;\n transition: opacity 300ms ease-out;\n}\n.${Te} {\n opacity:1;\n transition: opacity 300ms ease-in;\n}\n`,document.head.appendChild(e)},onLoad:e=>e.reactivity.effect((()=>{e.upsertIfMissingFromStore("_dsPlugins.fetch.indicatorElements",{}),e.upsertIfMissingFromStore("_dsPlugins.fetch.indicatorsVisible",[]);const t=e.reactivity.computed((()=>`${e.expressionFn(e)}`)),n=e.store(),s=document.querySelectorAll(t.value);if(0===s.length)throw new Error("No indicator found");return s.forEach((e=>{e.classList.add(Z)})),n._dsPlugins.fetch.indicatorElements[e.el.id]=e.reactivity.signal(s),()=>{delete n._dsPlugins.fetch.indicatorElements[e.el.id]}}))},Bs={prefix:"header",mustNotEmptyKey:!0,mustNotEmptyExpression:!0,preprocessors:{post:[{regexp:/(?<whole>.+)/g,replacer:e=>{const{whole:t}=e;return`'${t}'`}}]},onLoad:e=>{e.upsertIfMissingFromStore("_dsPlugins.fetch.headers",{});const t=e.key.replace(/([a-z](?=[A-Z]))/g,"$1-").toUpperCase(),n=e.expressionFn(e);return e.store()._dsPlugins.fetch.headers[t]=n,()=>{delete e.store()._dsPlugins.fetch.headers[t]}}},Ws=[Us,Bs];async function qs(e,t,n,s=!0){const o=n.store();if(!t)throw new Error(`No signal for ${e} on ${t}`);let r={...o.value};s&&(r=he(r));const i=JSON.stringify(r),a=n.el;N("plugin","backend","fetch_start",a,JSON.stringify({method:e,urlExpression:t,onlyRemote:s,storeJSON:i}));const l=o?._dsPlugins?.fetch?.indicatorElements&&o._dsPlugins.fetch.indicatorElements[a.id]?.value||[],c=o?._dsPlugins.fetch?.indicatorsVisible;l?.forEach&&l.forEach((e=>{if(!e||!c)return;const t=c.value.findIndex((t=>!!t&&e.isSameNode(t.el)));if(t>-1){const n=c.value[t],s=[...c.value];delete s[t],c.value=[...s.filter((e=>!!e)),{el:e,count:n.count+1}]}else e.classList.remove(Z),e.classList.add(Te),c.value=[...c.value,{el:e,count:1}]}));const u=new URL(t,window.location.origin),d={method:e=e.toUpperCase(),headers:{[Ls]:Ms,[ks]:Ps},onmessage:e=>{if(e.event)switch(e.event.startsWith(k)||console.log(`Unknown event: ${e.event}`),e.event){case $s:const t=e.data.trim().split("\n"),s=["selector","merge","settle","fragment","vt"];let o="",r=Ns,i=Ts,a=As,l=!1,c="",u="";for(let e=0;e<t.length;e++){let n=t[e];if(!n?.length)continue;const d=n.split(" ",1)[0];if(s.includes(d)&&d!==u)switch(u=d,n=n.slice(d.length+1),u){case"selector":c=n;break;case"merge":if(r=n,l=Object.values(I).includes(r),!l)throw new Error(`Unknown merge option: ${r}`);break;case"settle":i=parseInt(n);break;case"fragment":break;case"vt":a="true"===n;break;default:throw new Error("Unknown data type")}"fragment"===u&&(o+=n+"\n")}o?.length||(o="<div></div>"),Js(n,c,r,o,i,a),N("plugin","backend","merge",c,JSON.stringify({fragment:o,settleTime:i,useViewTransition:a}));break;case Os:let d=!1,f="";const h=e.data.trim().split("\n");for(let e=0;e<h.length;e++){const t=h[e],[n,...s]=t.split(" "),o=s.join(" ");switch(n){case"onlyIfMissing":d="true"===o.trim();break;case"store":f+=`${o}\n`;break;default:throw new Error(`Unknown signal type: ${n}`)}}const p=` return Object.assign({...ctx.store()}, ${f})`;try{const e=new Function("ctx",p)(n),t=lt(n.store(),e,d);n.mergeStore(t),n.applyPlugins(document.body)}catch(e){console.log(p),console.error(e)}break;case Is:const[m,...g]=e.data.trim().split(" ");switch(m){case"selector":const e=g.join(" ");document.querySelectorAll(e).forEach((e=>e.remove()));break;case"paths":const t=g.join(" ").split(" ");n.removeFromStore(...t);break;default:throw new Error(`Unknown delete prefix: ${m}`)}break;case Rs:const[v,...b]=e.data.trim().split(" ");if("url"!==v)throw new Error(`Unknown redirect selector: ${v}`);const y=b.join(" ");N("plugin","backend","redirect","WINDOW",y),window.location.href=y;break;case Cs:const[w,..._]=e.data.trim().split(" "),E=_.join(" ");switch(w){case"debug":case"error":case"info":case"group":case"groupEnd":case"log":case"warn":console[w](E);break;default:throw new Error(`Unknown console mode: '${w}', message: '${E}'`)}}},onerror:e=>{console.error(e)},onclose:()=>{try{const e=n.store(),t=e?._dsPlugins?.fetch?.indicatorsVisible||[],s=e?._dsPlugins?.fetch?.indicatorElements&&e._dsPlugins.fetch.indicatorElements[a.id]?.value||[],o=[];s?.forEach&&s.forEach((e=>{if(!e||!t)return;const n=t.value,s=n.findIndex((t=>!!t&&e.isSameNode(t.el))),r=n[s];r&&(r.count<2?(o.push(new Promise((()=>setTimeout((()=>{e.classList.remove(Te),e.classList.add(Z)}),300)))),delete n[s]):s>-1&&(n[s].count=n[s].count-1),t.value=n.filter((e=>!!e)))})),Promise.all(o)}catch(e){console.error(e)}finally{N("plugin","backend","fetch_end",a,JSON.stringify({method:e,urlExpression:t}))}}};if("GET"===e){const e=new URLSearchParams(u.search);e.append("datastar",i),u.search=e.toString()}else d.body=i;const f=o?._dsPlugins?.fetch?.headers||{};if(d.headers)for(const[e,t]of Object.entries(f))e.startsWith("_")||(d.headers[e]=`${t}`);Gt(u,d)}const Ge=document.createElement("template");function Js(e,t,n,s,o,r){const{el:i}=e;Ge.innerHTML=s.trim(),[...Ge.content.children].forEach((s=>{if(!(s instanceof Element))throw new Error("No fragment found");const a=t=>{for(const r of t){r.classList.add(re);const t=r.outerHTML;let i=r;switch(n){case I.MorphElement:const t=ss(i,s,{callbacks:{beforeNodeRemoved:(t,n)=>(e.cleanupElementRemovals(t),!0)}});if(!t?.length)throw new Error("No morph result");i=t[0];break;case I.InnerElement:i.innerHTML=s.innerHTML;break;case I.OuterElement:i.replaceWith(s);break;case I.PrependElement:i.prepend(s);break;case I.AppendElement:i.append(s);break;case I.BeforeElement:i.before(s);break;case I.AfterElement:i.after(s);break;case I.UpsertAttributes:s.getAttributeNames().forEach((e=>{const t=s.getAttribute(e);i.setAttribute(e,t)}));break;default:throw new Error(`Unknown merge type: ${n}`)}e.cleanupElementRemovals(i),i.classList.add(re),e.applyPlugins(document.body),setTimeout((()=>{r.classList.remove(re),i.classList.remove(re)}),o);t!==i.outerHTML&&(i.classList.add(Ke),setTimeout((()=>{i.classList.remove(Ke)}),o))}};let l;if(t===Ds)l=[i];else{const e=t||`#${s.getAttribute("id")}`;if(l=document.querySelectorAll(e)||[],!l)throw new Error(`No targets found for ${e}`)}const c=[...l];if(!c.length)throw new Error(`No targets found for ${t}`);gt&&r?mt.startViewTransition((()=>a(c))):a(c)}))}const Ks=[Fs,Hs,Vs,xs,js].reduce(((e,t)=>(e[t]=(e,n,s)=>{const o=["true",!0,void 0].includes(s);qs(t,n,e,o)},e)),{isFetching:(e,t)=>{const n=[...document.querySelectorAll(t)],s=e.store()?._dsPlugins?.fetch.indicatorsVisible?.value||[];return!!n.length&&n.some((e=>s.filter((e=>!!e)).some((t=>t.el.isSameNode(e)&&t.count>0))))}}),Ye="0.19.9",ke=(e,t,n,s,o,r)=>(t-n)/(s-n)*(r-o)+o,Gs=(e,t,n,s,o,r)=>Math.round(ke(0,t,n,s,o,r)),bt=(e,t,n,s,o,r)=>Math.max(o,Math.min(r,ke(0,t,n,s,o,r))),Ys=(e,t,n,s,o,r)=>Math.round(bt(0,t,n,s,o,r)),zs={setAll:(e,t,n)=>{const s=new RegExp(t);e.walkSignals(((e,t)=>s.test(e)&&(t.value=n)))},toggleAll:(e,t)=>{const n=new RegExp(t);e.walkSignals(((e,t)=>n.test(e)&&(t.value=!t.value)))},clipboard:(e,t)=>{if(!navigator.clipboard)throw new Error("Clipboard API not available");navigator.clipboard.writeText(t)},fit:ke,fitInt:Gs,clampFit:bt,clampFitInt:Ys};function Zs(e={},...t){const n=new Dt(e,...t);return n.run(),n}function Xs(e={},...t){return Zs(Object.assign({},zs,qt,Ks,Ss,e),...[...Ws,..._s,...Wt,...t])}const Qs={bubbles:!0,cancelable:!0,composed:!0},Ae=window,N=(e,t,n,s,o,r=Qs)=>{Ae.dispatchEvent(new CustomEvent(q,Object.assign({detail:{time:new Date,category:e,subcategory:t,type:n,target:at(s),message:o}},r)))};Ae.ds||setTimeout((()=>{N("core","init","start",document.body,`Datastar v${Ye} loading`);const e=performance.now();Ae.ds=Xs();const t=performance.now();N("core","init","end",document.body,`Datastar v${Ye} loaded and attached to all DOM elements in ${(t-e).toFixed(2)}ms`);const n=document.createElement("style");n.innerHTML="\n.datastar-inspector-highlight {\n border: 2px solid blue;\n}\n",document.head.appendChild(n),window.addEventListener("datastar-inspector-event",(e=>{if("detail"in e&&"object"==typeof e.detail&&e.detail){const{detail:t}=e;if("script"in t&&"string"==typeof t.script)try{new Function(t.script)()}catch(e){console.error(e)}}}))}),0);export{qt as AttributeActions,Wt as AttributePlugins,Ks as BackendActions,Ws as BackendPlugins,Ft as BindAttributePlugin,Bt as ClassPlugin,Ct as CorePlugins,$t as CorePreprocessors,k as DATASTAR_CLASS_PREFIX,U as DATASTAR_STR,Dt as Datastar,Ut as EventPlugin,Us as FetchIndicatorPlugin,Bs as HeadersPlugin,bs as IntersectionPlugin,ws as ScrollIntoViewPlugin,gs as ShowPlugin,ys as TeleportPlugin,xt as TextPlugin,Vt as TwoWayBindingModelPlugin,Es as ViewTransitionPlugin,Ss as VisibilityActions,_s as VisibilityPlugins,ot as apply,se as argsHas,_e as argsToMs,q as datastarEventName,mt as docWithViewTransitionAPI,at as elemToSelector,Js as mergeHTMLFragment,he as remoteSignals,Zs as runDatastarWith,Xs as runDatastarWithAllPlugins,N as sendDatastarEvent,lt as storeFromPossibleContents,gt as supportsViewTransitions,ze as toHTMLorSVGElement};
|
|
8
|
+
//# sourceMappingURL=/sm/f6f92b3ab2fb83c5537b1f460774e082dabf5f4b2965609c51fc3065ab07633d.map
|
package/src/auth.ts
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Authentication with better-auth
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { betterAuth } from "better-auth";
|
|
6
|
+
import { drizzleAdapter } from "better-auth/adapters/drizzle";
|
|
7
|
+
import { drizzle } from "drizzle-orm/d1";
|
|
8
|
+
import * as schema from "./db/schema.js";
|
|
9
|
+
|
|
10
|
+
export function createAuth(d1: D1Database, options: { secret: string; baseURL: string }) {
|
|
11
|
+
const db = drizzle(d1, { schema });
|
|
12
|
+
|
|
13
|
+
return betterAuth({
|
|
14
|
+
database: drizzleAdapter(db, {
|
|
15
|
+
provider: "sqlite",
|
|
16
|
+
schema: {
|
|
17
|
+
user: schema.user,
|
|
18
|
+
session: schema.session,
|
|
19
|
+
account: schema.account,
|
|
20
|
+
verification: schema.verification,
|
|
21
|
+
},
|
|
22
|
+
}),
|
|
23
|
+
secret: options.secret,
|
|
24
|
+
baseURL: options.baseURL,
|
|
25
|
+
emailAndPassword: {
|
|
26
|
+
enabled: true,
|
|
27
|
+
autoSignIn: true,
|
|
28
|
+
},
|
|
29
|
+
session: {
|
|
30
|
+
cookieCache: {
|
|
31
|
+
enabled: true,
|
|
32
|
+
maxAge: 60 * 5, // 5 minutes
|
|
33
|
+
},
|
|
34
|
+
},
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export type Auth = ReturnType<typeof createAuth>;
|
package/src/client.ts
ADDED
package/src/db/index.ts
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Database utilities
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { drizzle } from "drizzle-orm/d1";
|
|
6
|
+
import * as schema from "./schema.js";
|
|
7
|
+
|
|
8
|
+
export type Database = ReturnType<typeof createDatabase>;
|
|
9
|
+
|
|
10
|
+
export function createDatabase(d1: D1Database) {
|
|
11
|
+
return drizzle(d1, { schema });
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export { schema };
|