@jant/core 0.2.15 → 0.2.17

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 (54) hide show
  1. package/dist/app.d.ts +4 -1
  2. package/dist/app.d.ts.map +1 -1
  3. package/dist/app.js +13 -4
  4. package/dist/index.d.ts +1 -1
  5. package/dist/index.d.ts.map +1 -1
  6. package/dist/lib/config.d.ts +49 -0
  7. package/dist/lib/config.d.ts.map +1 -0
  8. package/dist/lib/config.js +79 -0
  9. package/dist/routes/dash/collections.d.ts.map +1 -1
  10. package/dist/routes/dash/collections.js +5 -4
  11. package/dist/routes/dash/index.d.ts.map +1 -1
  12. package/dist/routes/dash/index.js +2 -1
  13. package/dist/routes/dash/media.d.ts.map +1 -1
  14. package/dist/routes/dash/media.js +3 -2
  15. package/dist/routes/dash/pages.d.ts.map +1 -1
  16. package/dist/routes/dash/pages.js +5 -4
  17. package/dist/routes/dash/posts.d.ts.map +1 -1
  18. package/dist/routes/dash/posts.js +5 -4
  19. package/dist/routes/dash/redirects.d.ts.map +1 -1
  20. package/dist/routes/dash/redirects.js +3 -2
  21. package/dist/routes/dash/settings.d.ts.map +1 -1
  22. package/dist/routes/dash/settings.js +4 -4
  23. package/dist/routes/pages/archive.d.ts.map +1 -1
  24. package/dist/routes/pages/archive.js +2 -1
  25. package/dist/routes/pages/collection.d.ts.map +1 -1
  26. package/dist/routes/pages/collection.js +2 -1
  27. package/dist/routes/pages/home.d.ts.map +1 -1
  28. package/dist/routes/pages/home.js +2 -1
  29. package/dist/routes/pages/page.d.ts.map +1 -1
  30. package/dist/routes/pages/page.js +2 -1
  31. package/dist/routes/pages/post.d.ts.map +1 -1
  32. package/dist/routes/pages/post.js +2 -1
  33. package/dist/routes/pages/search.d.ts.map +1 -1
  34. package/dist/routes/pages/search.js +2 -1
  35. package/dist/types.d.ts +11 -31
  36. package/dist/types.d.ts.map +1 -1
  37. package/package.json +1 -1
  38. package/src/app.tsx +14 -4
  39. package/src/index.ts +0 -2
  40. package/src/lib/config.ts +94 -0
  41. package/src/routes/dash/collections.tsx +5 -4
  42. package/src/routes/dash/index.tsx +2 -1
  43. package/src/routes/dash/media.tsx +3 -2
  44. package/src/routes/dash/pages.tsx +5 -4
  45. package/src/routes/dash/posts.tsx +5 -4
  46. package/src/routes/dash/redirects.tsx +3 -2
  47. package/src/routes/dash/settings.tsx +8 -4
  48. package/src/routes/pages/archive.tsx +2 -1
  49. package/src/routes/pages/collection.tsx +2 -1
  50. package/src/routes/pages/home.tsx +2 -1
  51. package/src/routes/pages/page.tsx +2 -1
  52. package/src/routes/pages/post.tsx +2 -1
  53. package/src/routes/pages/search.tsx +2 -1
  54. package/src/types.ts +12 -33
package/dist/app.d.ts CHANGED
@@ -20,12 +20,15 @@ export type App = Hono<{
20
20
  * @param config - Optional configuration
21
21
  * @returns Hono app instance
22
22
  *
23
+ * Site settings (name, description, language) should be configured via
24
+ * environment variables (SITE_NAME, SITE_DESCRIPTION, SITE_LANGUAGE).
25
+ * They can also be set in the dashboard, which stores them in the database.
26
+ *
23
27
  * @example
24
28
  * ```typescript
25
29
  * import { createApp } from "@jant/core";
26
30
  *
27
31
  * export default createApp({
28
- * site: { name: "My Blog" },
29
32
  * theme: { components: { PostCard: MyPostCard } },
30
33
  * });
31
34
  * ```
package/dist/app.d.ts.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"app.d.ts","sourceRoot":"","sources":["../src/app.tsx"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAG5B,OAAO,EAAkB,KAAK,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AACpE,OAAO,EAAc,KAAK,IAAI,EAAE,MAAM,WAAW,CAAC;AAGlD,OAAO,KAAK,EAAE,QAAQ,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAoCvD,MAAM,WAAW,YAAY;IAC3B,QAAQ,EAAE,QAAQ,CAAC;IACnB,IAAI,EAAE,IAAI,CAAC;IACX,MAAM,EAAE,UAAU,CAAC;CACpB;AAED,MAAM,MAAM,GAAG,GAAG,IAAI,CAAC;IAAE,QAAQ,EAAE,QAAQ,CAAC;IAAC,SAAS,EAAE,YAAY,CAAA;CAAE,CAAC,CAAC;AAExE;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,SAAS,CAAC,MAAM,GAAE,UAAe,GAAG,GAAG,CAodtD"}
1
+ {"version":3,"file":"app.d.ts","sourceRoot":"","sources":["../src/app.tsx"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAG5B,OAAO,EAAkB,KAAK,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AACpE,OAAO,EAAc,KAAK,IAAI,EAAE,MAAM,WAAW,CAAC;AAGlD,OAAO,KAAK,EAAE,QAAQ,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAoCvD,MAAM,WAAW,YAAY;IAC3B,QAAQ,EAAE,QAAQ,CAAC;IACnB,IAAI,EAAE,IAAI,CAAC;IACX,MAAM,EAAE,UAAU,CAAC;CACpB;AAED,MAAM,MAAM,GAAG,GAAG,IAAI,CAAC;IAAE,QAAQ,EAAE,QAAQ,CAAC;IAAC,SAAS,EAAE,YAAY,CAAA;CAAE,CAAC,CAAC;AAExE;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,SAAS,CAAC,MAAM,GAAE,UAAe,GAAG,GAAG,CA2dtD"}
package/dist/app.js CHANGED
@@ -40,12 +40,15 @@ import { sse } from "./lib/sse.js";
40
40
  * @param config - Optional configuration
41
41
  * @returns Hono app instance
42
42
  *
43
+ * Site settings (name, description, language) should be configured via
44
+ * environment variables (SITE_NAME, SITE_DESCRIPTION, SITE_LANGUAGE).
45
+ * They can also be set in the dashboard, which stores them in the database.
46
+ *
43
47
  * @example
44
48
  * ```typescript
45
49
  * import { createApp } from "@jant/core";
46
50
  *
47
51
  * export default createApp({
48
- * site: { name: "My Blog" },
49
52
  * theme: { components: { PostCard: MyPostCard } },
50
53
  * });
51
54
  * ```
@@ -53,12 +56,18 @@ import { sse } from "./lib/sse.js";
53
56
  const app = new Hono();
54
57
  // Initialize services, auth, and config middleware
55
58
  app.use("*", async (c, next)=>{
56
- const db = createDatabase(c.env.DB);
57
- const services = createServices(db, c.env.DB);
59
+ // Use withSession() to enable D1 Read Replication
60
+ // Automatically routes read queries to the nearest replica for lower latency
61
+ // See: https://developers.cloudflare.com/d1/best-practices/read-replication/
62
+ const session = c.env.DB.withSession();
63
+ // Note: Drizzle ORM doesn't officially support D1DatabaseSession yet (issue #2226)
64
+ // but it works at runtime. We use type assertion as a temporary workaround.
65
+ const db = createDatabase(session);
66
+ const services = createServices(db, session);
58
67
  c.set("services", services);
59
68
  c.set("config", config);
60
69
  if (c.env.AUTH_SECRET) {
61
- const auth = createAuth(c.env.DB, {
70
+ const auth = createAuth(session, {
62
71
  secret: c.env.AUTH_SECRET,
63
72
  baseURL: c.env.SITE_URL
64
73
  });
package/dist/index.d.ts CHANGED
@@ -5,7 +5,7 @@
5
5
  */
6
6
  export { createApp } from "./app.js";
7
7
  export type { App, AppVariables } from "./app.js";
8
- export type { PostType, Visibility, Bindings, Post, Media, Collection, PostCollection, Redirect, Setting, CreatePost, UpdatePost, JantConfig, JantTheme, SiteConfig, FeatureConfig, ThemeComponents, } from "./types.js";
8
+ export type { PostType, Visibility, Bindings, Post, Media, Collection, PostCollection, Redirect, Setting, CreatePost, UpdatePost, JantConfig, JantTheme, ThemeComponents, } from "./types.js";
9
9
  export { POST_TYPES, VISIBILITY_LEVELS } from "./types.js";
10
10
  export * as time from "./lib/time.js";
11
11
  export * as sqid from "./lib/sqid.js";
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAKH,OAAO,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AACrC,YAAY,EAAE,GAAG,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AAGlD,YAAY,EACV,QAAQ,EACR,UAAU,EACV,QAAQ,EACR,IAAI,EACJ,KAAK,EACL,UAAU,EACV,cAAc,EACd,QAAQ,EACR,OAAO,EACP,UAAU,EACV,UAAU,EACV,UAAU,EACV,SAAS,EACT,UAAU,EACV,aAAa,EACb,eAAe,GAChB,MAAM,YAAY,CAAC;AAEpB,OAAO,EAAE,UAAU,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAG3D,OAAO,KAAK,IAAI,MAAM,eAAe,CAAC;AACtC,OAAO,KAAK,IAAI,MAAM,eAAe,CAAC;AACtC,OAAO,KAAK,GAAG,MAAM,cAAc,CAAC;AACpC,OAAO,KAAK,QAAQ,MAAM,mBAAmB,CAAC;;AAG9C,wBAA4B"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAKH,OAAO,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AACrC,YAAY,EAAE,GAAG,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AAGlD,YAAY,EACV,QAAQ,EACR,UAAU,EACV,QAAQ,EACR,IAAI,EACJ,KAAK,EACL,UAAU,EACV,cAAc,EACd,QAAQ,EACR,OAAO,EACP,UAAU,EACV,UAAU,EACV,UAAU,EACV,SAAS,EACT,eAAe,GAChB,MAAM,YAAY,CAAC;AAEpB,OAAO,EAAE,UAAU,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAG3D,OAAO,KAAK,IAAI,MAAM,eAAe,CAAC;AACtC,OAAO,KAAK,IAAI,MAAM,eAAe,CAAC;AACtC,OAAO,KAAK,GAAG,MAAM,cAAc,CAAC;AACpC,OAAO,KAAK,QAAQ,MAAM,mBAAmB,CAAC;;AAG9C,wBAA4B"}
@@ -0,0 +1,49 @@
1
+ /**
2
+ * Unified Configuration Helpers
3
+ *
4
+ * Configuration priority: Environment Variables > Database > Default Values
5
+ *
6
+ * This follows the 12-factor app methodology where configuration is stored
7
+ * in environment variables, while allowing runtime overrides via database.
8
+ */
9
+ import type { Context } from "hono";
10
+ /**
11
+ * Get site name with fallback chain: ENV > DB > Default
12
+ *
13
+ * @param c - Hono context
14
+ * @returns Site name
15
+ *
16
+ * @example
17
+ * ```typescript
18
+ * const siteName = await getSiteName(c);
19
+ * // Returns: c.env.SITE_NAME ?? (DB: SITE_NAME) ?? "Jant"
20
+ * ```
21
+ */
22
+ export declare function getSiteName(c: Context): Promise<string>;
23
+ /**
24
+ * Get site description with fallback chain: ENV > DB > Default
25
+ *
26
+ * @param c - Hono context
27
+ * @returns Site description
28
+ *
29
+ * @example
30
+ * ```typescript
31
+ * const description = await getSiteDescription(c);
32
+ * // Returns: c.env.SITE_DESCRIPTION ?? (DB: SITE_DESCRIPTION) ?? "A microblog powered by Jant"
33
+ * ```
34
+ */
35
+ export declare function getSiteDescription(c: Context): Promise<string>;
36
+ /**
37
+ * Get site language with fallback chain: ENV > DB > Default
38
+ *
39
+ * @param c - Hono context
40
+ * @returns Site language code
41
+ *
42
+ * @example
43
+ * ```typescript
44
+ * const lang = await getSiteLanguage(c);
45
+ * // Returns: c.env.SITE_LANGUAGE ?? (DB: SITE_LANGUAGE) ?? "en"
46
+ * ```
47
+ */
48
+ export declare function getSiteLanguage(c: Context): Promise<string>;
49
+ //# sourceMappingURL=config.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/lib/config.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,MAAM,CAAC;AAEpC;;;;;;;;;;;GAWG;AACH,wBAAsB,WAAW,CAAC,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC,MAAM,CAAC,CAc7D;AAED;;;;;;;;;;;GAWG;AACH,wBAAsB,kBAAkB,CAAC,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC,MAAM,CAAC,CAcpE;AAED;;;;;;;;;;;GAWG;AACH,wBAAsB,eAAe,CAAC,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC,MAAM,CAAC,CAcjE"}
@@ -0,0 +1,79 @@
1
+ /**
2
+ * Unified Configuration Helpers
3
+ *
4
+ * Configuration priority: Environment Variables > Database > Default Values
5
+ *
6
+ * This follows the 12-factor app methodology where configuration is stored
7
+ * in environment variables, while allowing runtime overrides via database.
8
+ */ /**
9
+ * Get site name with fallback chain: ENV > DB > Default
10
+ *
11
+ * @param c - Hono context
12
+ * @returns Site name
13
+ *
14
+ * @example
15
+ * ```typescript
16
+ * const siteName = await getSiteName(c);
17
+ * // Returns: c.env.SITE_NAME ?? (DB: SITE_NAME) ?? "Jant"
18
+ * ```
19
+ */ export async function getSiteName(c) {
20
+ // 1. Check environment variable
21
+ if (c.env.SITE_NAME) {
22
+ return c.env.SITE_NAME;
23
+ }
24
+ // 2. Check database setting
25
+ const dbValue = await c.var.services.settings.get("SITE_NAME");
26
+ if (dbValue) {
27
+ return dbValue;
28
+ }
29
+ // 3. Default value
30
+ return "Jant";
31
+ }
32
+ /**
33
+ * Get site description with fallback chain: ENV > DB > Default
34
+ *
35
+ * @param c - Hono context
36
+ * @returns Site description
37
+ *
38
+ * @example
39
+ * ```typescript
40
+ * const description = await getSiteDescription(c);
41
+ * // Returns: c.env.SITE_DESCRIPTION ?? (DB: SITE_DESCRIPTION) ?? "A microblog powered by Jant"
42
+ * ```
43
+ */ export async function getSiteDescription(c) {
44
+ // 1. Check environment variable
45
+ if (c.env.SITE_DESCRIPTION) {
46
+ return c.env.SITE_DESCRIPTION;
47
+ }
48
+ // 2. Check database setting
49
+ const dbValue = await c.var.services.settings.get("SITE_DESCRIPTION");
50
+ if (dbValue) {
51
+ return dbValue;
52
+ }
53
+ // 3. Default value
54
+ return "A microblog powered by Jant";
55
+ }
56
+ /**
57
+ * Get site language with fallback chain: ENV > DB > Default
58
+ *
59
+ * @param c - Hono context
60
+ * @returns Site language code
61
+ *
62
+ * @example
63
+ * ```typescript
64
+ * const lang = await getSiteLanguage(c);
65
+ * // Returns: c.env.SITE_LANGUAGE ?? (DB: SITE_LANGUAGE) ?? "en"
66
+ * ```
67
+ */ export async function getSiteLanguage(c) {
68
+ // 1. Check environment variable
69
+ if (c.env.SITE_LANGUAGE) {
70
+ return c.env.SITE_LANGUAGE;
71
+ }
72
+ // 2. Check database setting
73
+ const dbValue = await c.var.services.settings.get("SITE_LANGUAGE");
74
+ if (dbValue) {
75
+ return dbValue;
76
+ }
77
+ // 3. Default value
78
+ return "en";
79
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"collections.d.ts","sourceRoot":"","sources":["../../../src/routes/dash/collections.tsx"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAE5B,OAAO,KAAK,EAAE,QAAQ,EAAoB,MAAM,gBAAgB,CAAC;AACjE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAYjD,KAAK,GAAG,GAAG;IAAE,QAAQ,EAAE,QAAQ,CAAC;IAAC,SAAS,EAAE,YAAY,CAAA;CAAE,CAAC;AAE3D,eAAO,MAAM,iBAAiB,kDAAkB,CAAC"}
1
+ {"version":3,"file":"collections.d.ts","sourceRoot":"","sources":["../../../src/routes/dash/collections.tsx"],"names":[],"mappings":"AACA;;GAEG;AAEH,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAE5B,OAAO,KAAK,EAAE,QAAQ,EAAoB,MAAM,gBAAgB,CAAC;AACjE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAYjD,KAAK,GAAG,GAAG;IAAE,QAAQ,EAAE,QAAQ,CAAC;IAAC,SAAS,EAAE,YAAY,CAAA;CAAE,CAAC;AAE3D,eAAO,MAAM,iBAAiB,kDAAkB,CAAC"}
@@ -1,4 +1,5 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "hono/jsx/jsx-runtime";
2
+ import { getSiteName } from "../../lib/config.js";
2
3
  /**
3
4
  * Dashboard Collections Routes
4
5
  */ import { Hono } from "hono";
@@ -396,7 +397,7 @@ function EditCollectionContent({ collection }) {
396
397
  }
397
398
  // List collections
398
399
  collectionsRoutes.get("/", async (c)=>{
399
- const siteName = await c.var.services.settings.get("SITE_NAME") ?? "Jant";
400
+ const siteName = await getSiteName(c);
400
401
  const collections = await c.var.services.collections.list();
401
402
  return c.html(/*#__PURE__*/ _jsx(DashLayout, {
402
403
  c: c,
@@ -410,7 +411,7 @@ collectionsRoutes.get("/", async (c)=>{
410
411
  });
411
412
  // New collection form
412
413
  collectionsRoutes.get("/new", async (c)=>{
413
- const siteName = await c.var.services.settings.get("SITE_NAME") ?? "Jant";
414
+ const siteName = await getSiteName(c);
414
415
  return c.html(/*#__PURE__*/ _jsx(DashLayout, {
415
416
  c: c,
416
417
  title: "New Collection",
@@ -438,7 +439,7 @@ collectionsRoutes.get("/:id", async (c)=>{
438
439
  const collection = await c.var.services.collections.getById(id);
439
440
  if (!collection) return c.notFound();
440
441
  const posts = await c.var.services.collections.getPosts(id);
441
- const siteName = await c.var.services.settings.get("SITE_NAME") ?? "Jant";
442
+ const siteName = await getSiteName(c);
442
443
  return c.html(/*#__PURE__*/ _jsx(DashLayout, {
443
444
  c: c,
444
445
  title: collection.title,
@@ -456,7 +457,7 @@ collectionsRoutes.get("/:id/edit", async (c)=>{
456
457
  if (isNaN(id)) return c.notFound();
457
458
  const collection = await c.var.services.collections.getById(id);
458
459
  if (!collection) return c.notFound();
459
- const siteName = await c.var.services.settings.get("SITE_NAME") ?? "Jant";
460
+ const siteName = await getSiteName(c);
460
461
  return c.html(/*#__PURE__*/ _jsx(DashLayout, {
461
462
  c: c,
462
463
  title: `Edit: ${collection.title}`,
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/routes/dash/index.tsx"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAE5B,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAC/C,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAGjD,KAAK,GAAG,GAAG;IAAE,QAAQ,EAAE,QAAQ,CAAC;IAAC,SAAS,EAAE,YAAY,CAAA;CAAE,CAAC;AAE3D,eAAO,MAAM,eAAe,kDAAkB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/routes/dash/index.tsx"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAE5B,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAC/C,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAIjD,KAAK,GAAG,GAAG;IAAE,QAAQ,EAAE,QAAQ,CAAC;IAAC,SAAS,EAAE,YAAY,CAAA;CAAE,CAAC;AAE3D,eAAO,MAAM,eAAe,kDAAkB,CAAC"}
@@ -7,6 +7,7 @@ import { jsx as _jsx, jsxs as _jsxs } from "hono/jsx/jsx-runtime";
7
7
  import { useLingui as $_useLingui } from "@jant/core/i18n";
8
8
  import { Trans as Trans_ } from "@jant/core/i18n";
9
9
  import { DashLayout } from "../../theme/layouts/index.js";
10
+ import { getSiteName } from "../../lib/config.js";
10
11
  export const dashIndexRoutes = new Hono();
11
12
  /**
12
13
  * Dashboard content component
@@ -97,7 +98,7 @@ export const dashIndexRoutes = new Hono();
97
98
  });
98
99
  }
99
100
  dashIndexRoutes.get("/", async (c)=>{
100
- const siteName = await c.var.services.settings.get("SITE_NAME") ?? "Jant";
101
+ const siteName = await getSiteName(c);
101
102
  // Get some stats
102
103
  const allPosts = await c.var.services.posts.list({
103
104
  limit: 1000
@@ -1 +1 @@
1
- {"version":3,"file":"media.d.ts","sourceRoot":"","sources":["../../../src/routes/dash/media.tsx"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAE5B,OAAO,KAAK,EAAE,QAAQ,EAAS,MAAM,gBAAgB,CAAC;AACtD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAOjD,KAAK,GAAG,GAAG;IAAE,QAAQ,EAAE,QAAQ,CAAC;IAAC,SAAS,EAAE,YAAY,CAAA;CAAE,CAAC;AAE3D,eAAO,MAAM,WAAW,kDAAkB,CAAC"}
1
+ {"version":3,"file":"media.d.ts","sourceRoot":"","sources":["../../../src/routes/dash/media.tsx"],"names":[],"mappings":"AACA;;;;;GAKG;AAEH,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAE5B,OAAO,KAAK,EAAE,QAAQ,EAAS,MAAM,gBAAgB,CAAC;AACtD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAOjD,KAAK,GAAG,GAAG;IAAE,QAAQ,EAAE,QAAQ,CAAC;IAAC,SAAS,EAAE,YAAY,CAAA;CAAE,CAAC;AAE3D,eAAO,MAAM,WAAW,kDAAkB,CAAC"}
@@ -1,4 +1,5 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "hono/jsx/jsx-runtime";
2
+ import { getSiteName } from "../../lib/config.js";
2
3
  /**
3
4
  * Dashboard Media Routes
4
5
  *
@@ -530,7 +531,7 @@ function processSSEEvent(event) {
530
531
  // List media
531
532
  mediaRoutes.get("/", async (c)=>{
532
533
  const mediaList = await c.var.services.media.list(100);
533
- const siteName = await c.var.services.settings.get("SITE_NAME") ?? "Jant";
534
+ const siteName = await getSiteName(c);
534
535
  const r2PublicUrl = c.env.R2_PUBLIC_URL;
535
536
  const imageTransformUrl = c.env.IMAGE_TRANSFORM_URL;
536
537
  return c.html(/*#__PURE__*/ _jsx(DashLayout, {
@@ -550,7 +551,7 @@ mediaRoutes.get("/:id", async (c)=>{
550
551
  const id = c.req.param("id");
551
552
  const media = await c.var.services.media.getById(id);
552
553
  if (!media) return c.notFound();
553
- const siteName = await c.var.services.settings.get("SITE_NAME") ?? "Jant";
554
+ const siteName = await getSiteName(c);
554
555
  const r2PublicUrl = c.env.R2_PUBLIC_URL;
555
556
  const imageTransformUrl = c.env.IMAGE_TRANSFORM_URL;
556
557
  return c.html(/*#__PURE__*/ _jsx(DashLayout, {
@@ -1 +1 @@
1
- {"version":3,"file":"pages.d.ts","sourceRoot":"","sources":["../../../src/routes/dash/pages.tsx"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAE5B,OAAO,KAAK,EAAE,QAAQ,EAAQ,MAAM,gBAAgB,CAAC;AACrD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAejD,KAAK,GAAG,GAAG;IAAE,QAAQ,EAAE,QAAQ,CAAC;IAAC,SAAS,EAAE,YAAY,CAAA;CAAE,CAAC;AAE3D,eAAO,MAAM,WAAW,kDAAkB,CAAC"}
1
+ {"version":3,"file":"pages.d.ts","sourceRoot":"","sources":["../../../src/routes/dash/pages.tsx"],"names":[],"mappings":"AACA;;;;GAIG;AAEH,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAE5B,OAAO,KAAK,EAAE,QAAQ,EAAQ,MAAM,gBAAgB,CAAC;AACrD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAejD,KAAK,GAAG,GAAG;IAAE,QAAQ,EAAE,QAAQ,CAAC;IAAC,SAAS,EAAE,YAAY,CAAA;CAAE,CAAC;AAE3D,eAAO,MAAM,WAAW,kDAAkB,CAAC"}
@@ -1,4 +1,5 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "hono/jsx/jsx-runtime";
2
+ import { getSiteName } from "../../lib/config.js";
2
3
  /**
3
4
  * Dashboard Pages Routes
4
5
  *
@@ -191,7 +192,7 @@ pagesRoutes.get("/", async (c)=>{
191
192
  ],
192
193
  limit: 100
193
194
  });
194
- const siteName = await c.var.services.settings.get("SITE_NAME") ?? "Jant";
195
+ const siteName = await getSiteName(c);
195
196
  return c.html(/*#__PURE__*/ _jsx(DashLayout, {
196
197
  c: c,
197
198
  title: "Pages",
@@ -204,7 +205,7 @@ pagesRoutes.get("/", async (c)=>{
204
205
  });
205
206
  // New page form
206
207
  pagesRoutes.get("/new", async (c)=>{
207
- const siteName = await c.var.services.settings.get("SITE_NAME") ?? "Jant";
208
+ const siteName = await getSiteName(c);
208
209
  return c.html(/*#__PURE__*/ _jsx(DashLayout, {
209
210
  c: c,
210
211
  title: "New Page",
@@ -233,7 +234,7 @@ pagesRoutes.get("/:id", async (c)=>{
233
234
  if (!id) return c.notFound();
234
235
  const page = await c.var.services.posts.getById(id);
235
236
  if (!page || page.type !== "page") return c.notFound();
236
- const siteName = await c.var.services.settings.get("SITE_NAME") ?? "Jant";
237
+ const siteName = await getSiteName(c);
237
238
  return c.html(/*#__PURE__*/ _jsx(DashLayout, {
238
239
  c: c,
239
240
  title: page.title || "Page",
@@ -250,7 +251,7 @@ pagesRoutes.get("/:id/edit", async (c)=>{
250
251
  if (!id) return c.notFound();
251
252
  const page = await c.var.services.posts.getById(id);
252
253
  if (!page || page.type !== "page") return c.notFound();
253
- const siteName = await c.var.services.settings.get("SITE_NAME") ?? "Jant";
254
+ const siteName = await getSiteName(c);
254
255
  return c.html(/*#__PURE__*/ _jsx(DashLayout, {
255
256
  c: c,
256
257
  title: `Edit: ${page.title || "Page"}`,
@@ -1 +1 @@
1
- {"version":3,"file":"posts.d.ts","sourceRoot":"","sources":["../../../src/routes/dash/posts.tsx"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAE5B,OAAO,KAAK,EAAE,QAAQ,EAAQ,MAAM,gBAAgB,CAAC;AACrD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAWjD,KAAK,GAAG,GAAG;IAAE,QAAQ,EAAE,QAAQ,CAAC;IAAC,SAAS,EAAE,YAAY,CAAA;CAAE,CAAC;AAE3D,eAAO,MAAM,WAAW,kDAAkB,CAAC"}
1
+ {"version":3,"file":"posts.d.ts","sourceRoot":"","sources":["../../../src/routes/dash/posts.tsx"],"names":[],"mappings":"AACA;;GAEG;AAEH,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAE5B,OAAO,KAAK,EAAE,QAAQ,EAAQ,MAAM,gBAAgB,CAAC;AACrD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAWjD,KAAK,GAAG,GAAG;IAAE,QAAQ,EAAE,QAAQ,CAAC;IAAC,SAAS,EAAE,YAAY,CAAA;CAAE,CAAC;AAE3D,eAAO,MAAM,WAAW,kDAAkB,CAAC"}
@@ -1,4 +1,5 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "hono/jsx/jsx-runtime";
2
+ import { getSiteName } from "../../lib/config.js";
2
3
  /**
3
4
  * Dashboard Posts Routes
4
5
  */ import { Hono } from "hono";
@@ -56,7 +57,7 @@ postsRoutes.get("/", async (c)=>{
56
57
  "draft"
57
58
  ]
58
59
  });
59
- const siteName = await c.var.services.settings.get("SITE_NAME") ?? "Jant";
60
+ const siteName = await getSiteName(c);
60
61
  return c.html(/*#__PURE__*/ _jsx(DashLayout, {
61
62
  c: c,
62
63
  title: "Posts",
@@ -69,7 +70,7 @@ postsRoutes.get("/", async (c)=>{
69
70
  });
70
71
  // New post form
71
72
  postsRoutes.get("/new", async (c)=>{
72
- const siteName = await c.var.services.settings.get("SITE_NAME") ?? "Jant";
73
+ const siteName = await getSiteName(c);
73
74
  return c.html(/*#__PURE__*/ _jsx(DashLayout, {
74
75
  c: c,
75
76
  title: "New Post",
@@ -160,7 +161,7 @@ postsRoutes.get("/:id", async (c)=>{
160
161
  if (!id) return c.notFound();
161
162
  const post = await c.var.services.posts.getById(id);
162
163
  if (!post) return c.notFound();
163
- const siteName = await c.var.services.settings.get("SITE_NAME") ?? "Jant";
164
+ const siteName = await getSiteName(c);
164
165
  const pageTitle = post.title || "Post";
165
166
  return c.html(/*#__PURE__*/ _jsx(DashLayout, {
166
167
  c: c,
@@ -178,7 +179,7 @@ postsRoutes.get("/:id/edit", async (c)=>{
178
179
  if (!id) return c.notFound();
179
180
  const post = await c.var.services.posts.getById(id);
180
181
  if (!post) return c.notFound();
181
- const siteName = await c.var.services.settings.get("SITE_NAME") ?? "Jant";
182
+ const siteName = await getSiteName(c);
182
183
  return c.html(/*#__PURE__*/ _jsx(DashLayout, {
183
184
  c: c,
184
185
  title: `Edit: ${post.title || "Post"}`,
@@ -1 +1 @@
1
- {"version":3,"file":"redirects.d.ts","sourceRoot":"","sources":["../../../src/routes/dash/redirects.tsx"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAE5B,OAAO,KAAK,EAAE,QAAQ,EAAY,MAAM,gBAAgB,CAAC;AACzD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAUjD,KAAK,GAAG,GAAG;IAAE,QAAQ,EAAE,QAAQ,CAAC;IAAC,SAAS,EAAE,YAAY,CAAA;CAAE,CAAC;AAE3D,eAAO,MAAM,eAAe,kDAAkB,CAAC"}
1
+ {"version":3,"file":"redirects.d.ts","sourceRoot":"","sources":["../../../src/routes/dash/redirects.tsx"],"names":[],"mappings":"AACA;;GAEG;AAEH,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAE5B,OAAO,KAAK,EAAE,QAAQ,EAAY,MAAM,gBAAgB,CAAC;AACzD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAUjD,KAAK,GAAG,GAAG;IAAE,QAAQ,EAAE,QAAQ,CAAC;IAAC,SAAS,EAAE,YAAY,CAAA;CAAE,CAAC;AAE3D,eAAO,MAAM,eAAe,kDAAkB,CAAC"}
@@ -1,4 +1,5 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "hono/jsx/jsx-runtime";
2
+ import { getSiteName } from "../../lib/config.js";
2
3
  /**
3
4
  * Dashboard Redirects Routes
4
5
  */ import { Hono } from "hono";
@@ -196,7 +197,7 @@ function NewRedirectContent() {
196
197
  }
197
198
  // List redirects
198
199
  redirectsRoutes.get("/", async (c)=>{
199
- const siteName = await c.var.services.settings.get("SITE_NAME") ?? "Jant";
200
+ const siteName = await getSiteName(c);
200
201
  const redirects = await c.var.services.redirects.list();
201
202
  return c.html(/*#__PURE__*/ _jsx(DashLayout, {
202
203
  c: c,
@@ -210,7 +211,7 @@ redirectsRoutes.get("/", async (c)=>{
210
211
  });
211
212
  // New redirect form
212
213
  redirectsRoutes.get("/new", async (c)=>{
213
- const siteName = await c.var.services.settings.get("SITE_NAME") ?? "Jant";
214
+ const siteName = await getSiteName(c);
214
215
  return c.html(/*#__PURE__*/ _jsx(DashLayout, {
215
216
  c: c,
216
217
  title: "New Redirect",
@@ -1 +1 @@
1
- {"version":3,"file":"settings.d.ts","sourceRoot":"","sources":["../../../src/routes/dash/settings.tsx"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAE5B,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAC/C,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAIjD,KAAK,GAAG,GAAG;IAAE,QAAQ,EAAE,QAAQ,CAAC;IAAC,SAAS,EAAE,YAAY,CAAA;CAAE,CAAC;AAE3D,eAAO,MAAM,cAAc,kDAAkB,CAAC"}
1
+ {"version":3,"file":"settings.d.ts","sourceRoot":"","sources":["../../../src/routes/dash/settings.tsx"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAE5B,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAC/C,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AASjD,KAAK,GAAG,GAAG;IAAE,QAAQ,EAAE,QAAQ,CAAC;IAAC,SAAS,EAAE,YAAY,CAAA;CAAE,CAAC;AAE3D,eAAO,MAAM,cAAc,kDAAkB,CAAC"}
@@ -5,6 +5,7 @@ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "hono/jsx/jsx-
5
5
  import { useLingui as $_useLingui } from "@jant/core/i18n";
6
6
  import { DashLayout } from "../../theme/layouts/index.js";
7
7
  import { sse } from "../../lib/sse.js";
8
+ import { getSiteName, getSiteDescription, getSiteLanguage } from "../../lib/config.js";
8
9
  export const settingsRoutes = new Hono();
9
10
  function SettingsContent({ siteName, siteDescription, siteLanguage, saved }) {
10
11
  const { i18n: $__i18n, _: $__ } = $_useLingui();
@@ -241,10 +242,9 @@ function SettingsContent({ siteName, siteDescription, siteLanguage, saved }) {
241
242
  }
242
243
  // Settings page
243
244
  settingsRoutes.get("/", async (c)=>{
244
- const all = await c.var.services.settings.getAll();
245
- const siteName = all["SITE_NAME"] ?? "Jant";
246
- const siteDescription = all["SITE_DESCRIPTION"] ?? "";
247
- const siteLanguage = all["SITE_LANGUAGE"] ?? "en";
245
+ const siteName = await getSiteName(c);
246
+ const siteDescription = await getSiteDescription(c);
247
+ const siteLanguage = await getSiteLanguage(c);
248
248
  const saved = c.req.query("saved") !== undefined;
249
249
  return c.html(/*#__PURE__*/ _jsx(DashLayout, {
250
250
  c: c,
@@ -1 +1 @@
1
- {"version":3,"file":"archive.d.ts","sourceRoot":"","sources":["../../../src/routes/pages/archive.tsx"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAE5B,OAAO,KAAK,EAAE,QAAQ,EAAkB,MAAM,gBAAgB,CAAC;AAC/D,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAOjD,KAAK,GAAG,GAAG;IAAE,QAAQ,EAAE,QAAQ,CAAC;IAAC,SAAS,EAAE,YAAY,CAAA;CAAE,CAAC;AAI3D,eAAO,MAAM,aAAa,kDAAkB,CAAC"}
1
+ {"version":3,"file":"archive.d.ts","sourceRoot":"","sources":["../../../src/routes/pages/archive.tsx"],"names":[],"mappings":"AACA;;;;GAIG;AAEH,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAE5B,OAAO,KAAK,EAAE,QAAQ,EAAkB,MAAM,gBAAgB,CAAC;AAC/D,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAOjD,KAAK,GAAG,GAAG;IAAE,QAAQ,EAAE,QAAQ,CAAC;IAAC,SAAS,EAAE,YAAY,CAAA;CAAE,CAAC;AAI3D,eAAO,MAAM,aAAa,kDAAkB,CAAC"}
@@ -1,4 +1,5 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "hono/jsx/jsx-runtime";
2
+ import { getSiteName } from "../../lib/config.js";
2
3
  /**
3
4
  * Archive Page Route
4
5
  *
@@ -208,7 +209,7 @@ archiveRoutes.get("/", async (c)=>{
208
209
  // Parse cursor
209
210
  const cursorParam = c.req.query("cursor");
210
211
  const cursor = cursorParam ? parseInt(cursorParam, 10) : undefined;
211
- const siteName = await c.var.services.settings.get("SITE_NAME") ?? "Jant";
212
+ const siteName = await getSiteName(c);
212
213
  // Fetch one extra to check for more
213
214
  const posts = await c.var.services.posts.list({
214
215
  type,
@@ -1 +1 @@
1
- {"version":3,"file":"collection.d.ts","sourceRoot":"","sources":["../../../src/routes/pages/collection.tsx"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAE5B,OAAO,KAAK,EAAE,QAAQ,EAAoB,MAAM,gBAAgB,CAAC;AACjE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAKjD,KAAK,GAAG,GAAG;IAAE,QAAQ,EAAE,QAAQ,CAAC;IAAC,SAAS,EAAE,YAAY,CAAA;CAAE,CAAC;AAE3D,eAAO,MAAM,gBAAgB,kDAAkB,CAAC"}
1
+ {"version":3,"file":"collection.d.ts","sourceRoot":"","sources":["../../../src/routes/pages/collection.tsx"],"names":[],"mappings":"AACA;;GAEG;AAEH,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAE5B,OAAO,KAAK,EAAE,QAAQ,EAAoB,MAAM,gBAAgB,CAAC;AACjE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAKjD,KAAK,GAAG,GAAG;IAAE,QAAQ,EAAE,QAAQ,CAAC;IAAC,SAAS,EAAE,YAAY,CAAA;CAAE,CAAC;AAE3D,eAAO,MAAM,gBAAgB,kDAAkB,CAAC"}
@@ -1,4 +1,5 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "hono/jsx/jsx-runtime";
2
+ import { getSiteName } from "../../lib/config.js";
2
3
  /**
3
4
  * Collection Page Route
4
5
  */ import { Hono } from "hono";
@@ -80,7 +81,7 @@ collectionRoutes.get("/:path", async (c)=>{
80
81
  const collection = await c.var.services.collections.getByPath(path);
81
82
  if (!collection) return c.notFound();
82
83
  const posts = await c.var.services.collections.getPosts(collection.id);
83
- const siteName = await c.var.services.settings.get("SITE_NAME") ?? "Jant";
84
+ const siteName = await getSiteName(c);
84
85
  return c.html(/*#__PURE__*/ _jsx(BaseLayout, {
85
86
  title: `${collection.title} - ${siteName}`,
86
87
  description: collection.description ?? undefined,
@@ -1 +1 @@
1
- {"version":3,"file":"home.d.ts","sourceRoot":"","sources":["../../../src/routes/pages/home.tsx"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAE5B,OAAO,KAAK,EAAE,QAAQ,EAAQ,MAAM,gBAAgB,CAAC;AACrD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAKjD,KAAK,GAAG,GAAG;IAAE,QAAQ,EAAE,QAAQ,CAAC;IAAC,SAAS,EAAE,YAAY,CAAA;CAAE,CAAC;AAE3D,eAAO,MAAM,UAAU,kDAAkB,CAAC"}
1
+ {"version":3,"file":"home.d.ts","sourceRoot":"","sources":["../../../src/routes/pages/home.tsx"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAE5B,OAAO,KAAK,EAAE,QAAQ,EAAQ,MAAM,gBAAgB,CAAC;AACrD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAMjD,KAAK,GAAG,GAAG;IAAE,QAAQ,EAAE,QAAQ,CAAC;IAAC,SAAS,EAAE,YAAY,CAAA;CAAE,CAAC;AAE3D,eAAO,MAAM,UAAU,kDAAkB,CAAC"}
@@ -6,6 +6,7 @@ import { useLingui as $_useLingui } from "@jant/core/i18n";
6
6
  import { BaseLayout } from "../../theme/layouts/index.js";
7
7
  import * as sqid from "../../lib/sqid.js";
8
8
  import * as time from "../../lib/time.js";
9
+ import { getSiteName } from "../../lib/config.js";
9
10
  export const homeRoutes = new Hono();
10
11
  function HomeContent({ siteName, posts }) {
11
12
  const { i18n: $__i18n, _: $__ } = $_useLingui();
@@ -103,7 +104,7 @@ homeRoutes.get("/", async (c)=>{
103
104
  if (!isComplete) {
104
105
  return c.redirect("/setup");
105
106
  }
106
- const siteName = await c.var.services.settings.get("SITE_NAME") ?? "Jant";
107
+ const siteName = await getSiteName(c);
107
108
  const posts = await c.var.services.posts.list({
108
109
  visibility: [
109
110
  "featured",
@@ -1 +1 @@
1
- {"version":3,"file":"page.d.ts","sourceRoot":"","sources":["../../../src/routes/pages/page.tsx"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAE5B,OAAO,KAAK,EAAE,QAAQ,EAAQ,MAAM,gBAAgB,CAAC;AACrD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAGjD,KAAK,GAAG,GAAG;IAAE,QAAQ,EAAE,QAAQ,CAAC;IAAC,SAAS,EAAE,YAAY,CAAA;CAAE,CAAC;AAE3D,eAAO,MAAM,UAAU,kDAAkB,CAAC"}
1
+ {"version":3,"file":"page.d.ts","sourceRoot":"","sources":["../../../src/routes/pages/page.tsx"],"names":[],"mappings":"AACA;;;;GAIG;AAEH,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAE5B,OAAO,KAAK,EAAE,QAAQ,EAAQ,MAAM,gBAAgB,CAAC;AACrD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAGjD,KAAK,GAAG,GAAG;IAAE,QAAQ,EAAE,QAAQ,CAAC;IAAC,SAAS,EAAE,YAAY,CAAA;CAAE,CAAC;AAE3D,eAAO,MAAM,UAAU,kDAAkB,CAAC"}
@@ -1,4 +1,5 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "hono/jsx/jsx-runtime";
2
+ import { getSiteName } from "../../lib/config.js";
2
3
  /**
3
4
  * Custom Page Route
4
5
  *
@@ -58,7 +59,7 @@ pageRoutes.get("/:path", async (c)=>{
58
59
  if (page.visibility === "draft") {
59
60
  return c.notFound();
60
61
  }
61
- const siteName = await c.var.services.settings.get("SITE_NAME") ?? "Jant";
62
+ const siteName = await getSiteName(c);
62
63
  return c.html(/*#__PURE__*/ _jsx(BaseLayout, {
63
64
  title: `${page.title} - ${siteName}`,
64
65
  description: page.content?.slice(0, 160),
@@ -1 +1 @@
1
- {"version":3,"file":"post.d.ts","sourceRoot":"","sources":["../../../src/routes/pages/post.tsx"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAE5B,OAAO,KAAK,EAAE,QAAQ,EAAQ,MAAM,gBAAgB,CAAC;AACrD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAKjD,KAAK,GAAG,GAAG;IAAE,QAAQ,EAAE,QAAQ,CAAC;IAAC,SAAS,EAAE,YAAY,CAAA;CAAE,CAAC;AAE3D,eAAO,MAAM,UAAU,kDAAkB,CAAC"}
1
+ {"version":3,"file":"post.d.ts","sourceRoot":"","sources":["../../../src/routes/pages/post.tsx"],"names":[],"mappings":"AACA;;GAEG;AAEH,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAE5B,OAAO,KAAK,EAAE,QAAQ,EAAQ,MAAM,gBAAgB,CAAC;AACrD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAKjD,KAAK,GAAG,GAAG;IAAE,QAAQ,EAAE,QAAQ,CAAC;IAAC,SAAS,EAAE,YAAY,CAAA;CAAE,CAAC;AAE3D,eAAO,MAAM,UAAU,kDAAkB,CAAC"}
@@ -1,4 +1,5 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "hono/jsx/jsx-runtime";
2
+ import { getSiteName } from "../../lib/config.js";
2
3
  /**
3
4
  * Single Post Page Route
4
5
  */ import { Hono } from "hono";
@@ -77,7 +78,7 @@ postRoutes.get("/:id", async (c)=>{
77
78
  if (post.visibility === "draft") {
78
79
  return c.notFound();
79
80
  }
80
- const siteName = await c.var.services.settings.get("SITE_NAME") ?? "Jant";
81
+ const siteName = await getSiteName(c);
81
82
  const title = post.title || siteName;
82
83
  return c.html(/*#__PURE__*/ _jsx(BaseLayout, {
83
84
  title: title,
@@ -1 +1 @@
1
- {"version":3,"file":"search.d.ts","sourceRoot":"","sources":["../../../src/routes/pages/search.tsx"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAE5B,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAC/C,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAOjD,KAAK,GAAG,GAAG;IAAE,QAAQ,EAAE,QAAQ,CAAC;IAAC,SAAS,EAAE,YAAY,CAAA;CAAE,CAAC;AAI3D,eAAO,MAAM,YAAY,kDAAkB,CAAC"}
1
+ {"version":3,"file":"search.d.ts","sourceRoot":"","sources":["../../../src/routes/pages/search.tsx"],"names":[],"mappings":"AACA;;GAEG;AAEH,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAE5B,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAC/C,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAOjD,KAAK,GAAG,GAAG;IAAE,QAAQ,EAAE,QAAQ,CAAC;IAAC,SAAS,EAAE,YAAY,CAAA;CAAE,CAAC;AAI3D,eAAO,MAAM,YAAY,kDAAkB,CAAC"}
@@ -1,4 +1,5 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "hono/jsx/jsx-runtime";
2
+ import { getSiteName } from "../../lib/config.js";
2
3
  /**
3
4
  * Search Page Route
4
5
  */ import { Hono } from "hono";
@@ -140,7 +141,7 @@ searchRoutes.get("/", async (c)=>{
140
141
  const query = c.req.query("q") || "";
141
142
  const pageParam = c.req.query("page");
142
143
  const page = pageParam ? Math.max(1, parseInt(pageParam, 10) || 1) : 1;
143
- const siteName = await c.var.services.settings.get("SITE_NAME") ?? "Jant";
144
+ const siteName = await getSiteName(c);
144
145
  // Only search if there's a query
145
146
  let results = [];
146
147
  let error = null;
package/dist/types.d.ts CHANGED
@@ -14,6 +14,9 @@ export interface Bindings {
14
14
  IMAGE_TRANSFORM_URL?: string;
15
15
  DEMO_EMAIL?: string;
16
16
  DEMO_PASSWORD?: string;
17
+ SITE_NAME?: string;
18
+ SITE_DESCRIPTION?: string;
19
+ SITE_LANGUAGE?: string;
17
20
  }
18
21
  export interface Post {
19
22
  id: number;
@@ -141,41 +144,18 @@ export interface JantTheme {
141
144
  /** CSS variable overrides */
142
145
  cssVariables?: Record<string, string>;
143
146
  }
144
- /**
145
- * Site configuration
146
- */
147
- export interface SiteConfig {
148
- /** Site name */
149
- name?: string;
150
- /** Site description */
151
- description?: string;
152
- /** Default language */
153
- language?: string;
154
- /** Site URL (usually set via env) */
155
- url?: string;
156
- }
157
- /**
158
- * Feature toggles
159
- */
160
- export interface FeatureConfig {
161
- /** Enable search (default: true) */
162
- search?: boolean;
163
- /** Enable RSS feed (default: true) */
164
- rss?: boolean;
165
- /** Enable sitemap (default: true) */
166
- sitemap?: boolean;
167
- /** Enable i18n (default: true) */
168
- i18n?: boolean;
169
- }
170
147
  /**
171
148
  * Main Jant configuration
149
+ *
150
+ * Configuration Philosophy:
151
+ * - Use environment variables for runtime config (API keys, feature flags, site settings)
152
+ * - Use code config (this object) for compile-time customization (theme components)
153
+ *
154
+ * Site-level settings (name, description, language) are configured via
155
+ * environment variables, not here. See lib/config.ts for details.
172
156
  */
173
157
  export interface JantConfig {
174
- /** Site configuration */
175
- site?: SiteConfig;
176
- /** Theme configuration */
158
+ /** Theme configuration (components, CSS overrides) */
177
159
  theme?: JantTheme;
178
- /** Feature toggles */
179
- features?: FeatureConfig;
180
160
  }
181
161
  //# sourceMappingURL=types.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jant/core",
3
- "version": "0.2.15",
3
+ "version": "0.2.17",
4
4
  "description": "A modern, open-source microblogging platform built on Cloudflare Workers",
5
5
  "type": "module",
6
6
  "bin": {
package/src/app.tsx CHANGED
@@ -59,12 +59,15 @@ export type App = Hono<{ Bindings: Bindings; Variables: AppVariables }>;
59
59
  * @param config - Optional configuration
60
60
  * @returns Hono app instance
61
61
  *
62
+ * Site settings (name, description, language) should be configured via
63
+ * environment variables (SITE_NAME, SITE_DESCRIPTION, SITE_LANGUAGE).
64
+ * They can also be set in the dashboard, which stores them in the database.
65
+ *
62
66
  * @example
63
67
  * ```typescript
64
68
  * import { createApp } from "@jant/core";
65
69
  *
66
70
  * export default createApp({
67
- * site: { name: "My Blog" },
68
71
  * theme: { components: { PostCard: MyPostCard } },
69
72
  * });
70
73
  * ```
@@ -74,13 +77,20 @@ export function createApp(config: JantConfig = {}): App {
74
77
 
75
78
  // Initialize services, auth, and config middleware
76
79
  app.use("*", async (c, next) => {
77
- const db = createDatabase(c.env.DB);
78
- const services = createServices(db, c.env.DB);
80
+ // Use withSession() to enable D1 Read Replication
81
+ // Automatically routes read queries to the nearest replica for lower latency
82
+ // See: https://developers.cloudflare.com/d1/best-practices/read-replication/
83
+ const session = c.env.DB.withSession();
84
+
85
+ // Note: Drizzle ORM doesn't officially support D1DatabaseSession yet (issue #2226)
86
+ // but it works at runtime. We use type assertion as a temporary workaround.
87
+ const db = createDatabase(session as unknown as D1Database);
88
+ const services = createServices(db, session as unknown as D1Database);
79
89
  c.set("services", services);
80
90
  c.set("config", config);
81
91
 
82
92
  if (c.env.AUTH_SECRET) {
83
- const auth = createAuth(c.env.DB, {
93
+ const auth = createAuth(session as unknown as D1Database, {
84
94
  secret: c.env.AUTH_SECRET,
85
95
  baseURL: c.env.SITE_URL,
86
96
  });
package/src/index.ts CHANGED
@@ -25,8 +25,6 @@ export type {
25
25
  UpdatePost,
26
26
  JantConfig,
27
27
  JantTheme,
28
- SiteConfig,
29
- FeatureConfig,
30
28
  ThemeComponents,
31
29
  } from "./types.js";
32
30
 
@@ -0,0 +1,94 @@
1
+ /**
2
+ * Unified Configuration Helpers
3
+ *
4
+ * Configuration priority: Environment Variables > Database > Default Values
5
+ *
6
+ * This follows the 12-factor app methodology where configuration is stored
7
+ * in environment variables, while allowing runtime overrides via database.
8
+ */
9
+
10
+ import type { Context } from "hono";
11
+
12
+ /**
13
+ * Get site name with fallback chain: ENV > DB > Default
14
+ *
15
+ * @param c - Hono context
16
+ * @returns Site name
17
+ *
18
+ * @example
19
+ * ```typescript
20
+ * const siteName = await getSiteName(c);
21
+ * // Returns: c.env.SITE_NAME ?? (DB: SITE_NAME) ?? "Jant"
22
+ * ```
23
+ */
24
+ export async function getSiteName(c: Context): Promise<string> {
25
+ // 1. Check environment variable
26
+ if (c.env.SITE_NAME) {
27
+ return c.env.SITE_NAME;
28
+ }
29
+
30
+ // 2. Check database setting
31
+ const dbValue = await c.var.services.settings.get("SITE_NAME");
32
+ if (dbValue) {
33
+ return dbValue;
34
+ }
35
+
36
+ // 3. Default value
37
+ return "Jant";
38
+ }
39
+
40
+ /**
41
+ * Get site description with fallback chain: ENV > DB > Default
42
+ *
43
+ * @param c - Hono context
44
+ * @returns Site description
45
+ *
46
+ * @example
47
+ * ```typescript
48
+ * const description = await getSiteDescription(c);
49
+ * // Returns: c.env.SITE_DESCRIPTION ?? (DB: SITE_DESCRIPTION) ?? "A microblog powered by Jant"
50
+ * ```
51
+ */
52
+ export async function getSiteDescription(c: Context): Promise<string> {
53
+ // 1. Check environment variable
54
+ if (c.env.SITE_DESCRIPTION) {
55
+ return c.env.SITE_DESCRIPTION;
56
+ }
57
+
58
+ // 2. Check database setting
59
+ const dbValue = await c.var.services.settings.get("SITE_DESCRIPTION");
60
+ if (dbValue) {
61
+ return dbValue;
62
+ }
63
+
64
+ // 3. Default value
65
+ return "A microblog powered by Jant";
66
+ }
67
+
68
+ /**
69
+ * Get site language with fallback chain: ENV > DB > Default
70
+ *
71
+ * @param c - Hono context
72
+ * @returns Site language code
73
+ *
74
+ * @example
75
+ * ```typescript
76
+ * const lang = await getSiteLanguage(c);
77
+ * // Returns: c.env.SITE_LANGUAGE ?? (DB: SITE_LANGUAGE) ?? "en"
78
+ * ```
79
+ */
80
+ export async function getSiteLanguage(c: Context): Promise<string> {
81
+ // 1. Check environment variable
82
+ if (c.env.SITE_LANGUAGE) {
83
+ return c.env.SITE_LANGUAGE;
84
+ }
85
+
86
+ // 2. Check database setting
87
+ const dbValue = await c.var.services.settings.get("SITE_LANGUAGE");
88
+ if (dbValue) {
89
+ return dbValue;
90
+ }
91
+
92
+ // 3. Default value
93
+ return "en";
94
+ }
@@ -1,3 +1,4 @@
1
+ import { getSiteName } from "../../lib/config.js";
1
2
  /**
2
3
  * Dashboard Collections Routes
3
4
  */
@@ -363,7 +364,7 @@ function EditCollectionContent({ collection }: { collection: Collection }) {
363
364
 
364
365
  // List collections
365
366
  collectionsRoutes.get("/", async (c) => {
366
- const siteName = (await c.var.services.settings.get("SITE_NAME")) ?? "Jant";
367
+ const siteName = await getSiteName(c);
367
368
  const collections = await c.var.services.collections.list();
368
369
 
369
370
  return c.html(
@@ -380,7 +381,7 @@ collectionsRoutes.get("/", async (c) => {
380
381
 
381
382
  // New collection form
382
383
  collectionsRoutes.get("/new", async (c) => {
383
- const siteName = (await c.var.services.settings.get("SITE_NAME")) ?? "Jant";
384
+ const siteName = await getSiteName(c);
384
385
 
385
386
  return c.html(
386
387
  <DashLayout
@@ -422,7 +423,7 @@ collectionsRoutes.get("/:id", async (c) => {
422
423
  if (!collection) return c.notFound();
423
424
 
424
425
  const posts = await c.var.services.collections.getPosts(id);
425
- const siteName = (await c.var.services.settings.get("SITE_NAME")) ?? "Jant";
426
+ const siteName = await getSiteName(c);
426
427
 
427
428
  return c.html(
428
429
  <DashLayout
@@ -444,7 +445,7 @@ collectionsRoutes.get("/:id/edit", async (c) => {
444
445
  const collection = await c.var.services.collections.getById(id);
445
446
  if (!collection) return c.notFound();
446
447
 
447
- const siteName = (await c.var.services.settings.get("SITE_NAME")) ?? "Jant";
448
+ const siteName = await getSiteName(c);
448
449
 
449
450
  return c.html(
450
451
  <DashLayout
@@ -9,6 +9,7 @@ import { Trans, useLingui } from "@lingui/react/macro";
9
9
  import type { Bindings } from "../../types.js";
10
10
  import type { AppVariables } from "../../app.js";
11
11
  import { DashLayout } from "../../theme/layouts/index.js";
12
+ import { getSiteName } from "../../lib/config.js";
12
13
 
13
14
  type Env = { Bindings: Bindings; Variables: AppVariables };
14
15
 
@@ -86,7 +87,7 @@ function DashboardContent({
86
87
  }
87
88
 
88
89
  dashIndexRoutes.get("/", async (c) => {
89
- const siteName = (await c.var.services.settings.get("SITE_NAME")) ?? "Jant";
90
+ const siteName = await getSiteName(c);
90
91
 
91
92
  // Get some stats
92
93
  const allPosts = await c.var.services.posts.list({ limit: 1000 });
@@ -1,3 +1,4 @@
1
+ import { getSiteName } from "../../lib/config.js";
1
2
  /**
2
3
  * Dashboard Media Routes
3
4
  *
@@ -544,7 +545,7 @@ function ViewMediaContent({
544
545
  // List media
545
546
  mediaRoutes.get("/", async (c) => {
546
547
  const mediaList = await c.var.services.media.list(100);
547
- const siteName = (await c.var.services.settings.get("SITE_NAME")) ?? "Jant";
548
+ const siteName = await getSiteName(c);
548
549
  const r2PublicUrl = c.env.R2_PUBLIC_URL;
549
550
  const imageTransformUrl = c.env.IMAGE_TRANSFORM_URL;
550
551
 
@@ -570,7 +571,7 @@ mediaRoutes.get("/:id", async (c) => {
570
571
  const media = await c.var.services.media.getById(id);
571
572
  if (!media) return c.notFound();
572
573
 
573
- const siteName = (await c.var.services.settings.get("SITE_NAME")) ?? "Jant";
574
+ const siteName = await getSiteName(c);
574
575
  const r2PublicUrl = c.env.R2_PUBLIC_URL;
575
576
  const imageTransformUrl = c.env.IMAGE_TRANSFORM_URL;
576
577
 
@@ -1,3 +1,4 @@
1
+ import { getSiteName } from "../../lib/config.js";
1
2
  /**
2
3
  * Dashboard Pages Routes
3
4
  *
@@ -189,7 +190,7 @@ pagesRoutes.get("/", async (c) => {
189
190
  visibility: ["unlisted", "draft"],
190
191
  limit: 100,
191
192
  });
192
- const siteName = (await c.var.services.settings.get("SITE_NAME")) ?? "Jant";
193
+ const siteName = await getSiteName(c);
193
194
 
194
195
  return c.html(
195
196
  <DashLayout
@@ -205,7 +206,7 @@ pagesRoutes.get("/", async (c) => {
205
206
 
206
207
  // New page form
207
208
  pagesRoutes.get("/new", async (c) => {
208
- const siteName = (await c.var.services.settings.get("SITE_NAME")) ?? "Jant";
209
+ const siteName = await getSiteName(c);
209
210
 
210
211
  return c.html(
211
212
  <DashLayout
@@ -249,7 +250,7 @@ pagesRoutes.get("/:id", async (c) => {
249
250
  const page = await c.var.services.posts.getById(id);
250
251
  if (!page || page.type !== "page") return c.notFound();
251
252
 
252
- const siteName = (await c.var.services.settings.get("SITE_NAME")) ?? "Jant";
253
+ const siteName = await getSiteName(c);
253
254
 
254
255
  return c.html(
255
256
  <DashLayout
@@ -271,7 +272,7 @@ pagesRoutes.get("/:id/edit", async (c) => {
271
272
  const page = await c.var.services.posts.getById(id);
272
273
  if (!page || page.type !== "page") return c.notFound();
273
274
 
274
- const siteName = (await c.var.services.settings.get("SITE_NAME")) ?? "Jant";
275
+ const siteName = await getSiteName(c);
275
276
 
276
277
  return c.html(
277
278
  <DashLayout
@@ -1,3 +1,4 @@
1
+ import { getSiteName } from "../../lib/config.js";
1
2
  /**
2
3
  * Dashboard Posts Routes
3
4
  */
@@ -54,7 +55,7 @@ postsRoutes.get("/", async (c) => {
54
55
  const posts = await c.var.services.posts.list({
55
56
  visibility: ["featured", "quiet", "unlisted", "draft"],
56
57
  });
57
- const siteName = (await c.var.services.settings.get("SITE_NAME")) ?? "Jant";
58
+ const siteName = await getSiteName(c);
58
59
 
59
60
  return c.html(
60
61
  <DashLayout
@@ -70,7 +71,7 @@ postsRoutes.get("/", async (c) => {
70
71
 
71
72
  // New post form
72
73
  postsRoutes.get("/new", async (c) => {
73
- const siteName = (await c.var.services.settings.get("SITE_NAME")) ?? "Jant";
74
+ const siteName = await getSiteName(c);
74
75
 
75
76
  return c.html(
76
77
  <DashLayout
@@ -166,7 +167,7 @@ postsRoutes.get("/:id", async (c) => {
166
167
  const post = await c.var.services.posts.getById(id);
167
168
  if (!post) return c.notFound();
168
169
 
169
- const siteName = (await c.var.services.settings.get("SITE_NAME")) ?? "Jant";
170
+ const siteName = await getSiteName(c);
170
171
  const pageTitle = post.title || "Post";
171
172
 
172
173
  return c.html(
@@ -189,7 +190,7 @@ postsRoutes.get("/:id/edit", async (c) => {
189
190
  const post = await c.var.services.posts.getById(id);
190
191
  if (!post) return c.notFound();
191
192
 
192
- const siteName = (await c.var.services.settings.get("SITE_NAME")) ?? "Jant";
193
+ const siteName = await getSiteName(c);
193
194
 
194
195
  return c.html(
195
196
  <DashLayout
@@ -1,3 +1,4 @@
1
+ import { getSiteName } from "../../lib/config.js";
1
2
  /**
2
3
  * Dashboard Redirects Routes
3
4
  */
@@ -176,7 +177,7 @@ function NewRedirectContent() {
176
177
 
177
178
  // List redirects
178
179
  redirectsRoutes.get("/", async (c) => {
179
- const siteName = (await c.var.services.settings.get("SITE_NAME")) ?? "Jant";
180
+ const siteName = await getSiteName(c);
180
181
  const redirects = await c.var.services.redirects.list();
181
182
 
182
183
  return c.html(
@@ -193,7 +194,7 @@ redirectsRoutes.get("/", async (c) => {
193
194
 
194
195
  // New redirect form
195
196
  redirectsRoutes.get("/new", async (c) => {
196
- const siteName = (await c.var.services.settings.get("SITE_NAME")) ?? "Jant";
197
+ const siteName = await getSiteName(c);
197
198
 
198
199
  return c.html(
199
200
  <DashLayout
@@ -8,6 +8,11 @@ import type { Bindings } from "../../types.js";
8
8
  import type { AppVariables } from "../../app.js";
9
9
  import { DashLayout } from "../../theme/layouts/index.js";
10
10
  import { sse } from "../../lib/sse.js";
11
+ import {
12
+ getSiteName,
13
+ getSiteDescription,
14
+ getSiteLanguage,
15
+ } from "../../lib/config.js";
11
16
 
12
17
  type Env = { Bindings: Bindings; Variables: AppVariables };
13
18
 
@@ -207,10 +212,9 @@ function SettingsContent({
207
212
 
208
213
  // Settings page
209
214
  settingsRoutes.get("/", async (c) => {
210
- const all = await c.var.services.settings.getAll();
211
- const siteName = all["SITE_NAME"] ?? "Jant";
212
- const siteDescription = all["SITE_DESCRIPTION"] ?? "";
213
- const siteLanguage = all["SITE_LANGUAGE"] ?? "en";
215
+ const siteName = await getSiteName(c);
216
+ const siteDescription = await getSiteDescription(c);
217
+ const siteLanguage = await getSiteLanguage(c);
214
218
  const saved = c.req.query("saved") !== undefined;
215
219
 
216
220
  return c.html(
@@ -1,3 +1,4 @@
1
+ import { getSiteName } from "../../lib/config.js";
1
2
  /**
2
3
  * Archive Page Route
3
4
  *
@@ -225,7 +226,7 @@ archiveRoutes.get("/", async (c) => {
225
226
  const cursorParam = c.req.query("cursor");
226
227
  const cursor = cursorParam ? parseInt(cursorParam, 10) : undefined;
227
228
 
228
- const siteName = (await c.var.services.settings.get("SITE_NAME")) ?? "Jant";
229
+ const siteName = await getSiteName(c);
229
230
 
230
231
  // Fetch one extra to check for more
231
232
  const posts = await c.var.services.posts.list({
@@ -1,3 +1,4 @@
1
+ import { getSiteName } from "../../lib/config.js";
1
2
  /**
2
3
  * Collection Page Route
3
4
  */
@@ -89,7 +90,7 @@ collectionRoutes.get("/:path", async (c) => {
89
90
  if (!collection) return c.notFound();
90
91
 
91
92
  const posts = await c.var.services.collections.getPosts(collection.id);
92
- const siteName = (await c.var.services.settings.get("SITE_NAME")) ?? "Jant";
93
+ const siteName = await getSiteName(c);
93
94
 
94
95
  return c.html(
95
96
  <BaseLayout
@@ -9,6 +9,7 @@ import type { AppVariables } from "../../app.js";
9
9
  import { BaseLayout } from "../../theme/layouts/index.js";
10
10
  import * as sqid from "../../lib/sqid.js";
11
11
  import * as time from "../../lib/time.js";
12
+ import { getSiteName } from "../../lib/config.js";
12
13
 
13
14
  type Env = { Bindings: Bindings; Variables: AppVariables };
14
15
 
@@ -106,7 +107,7 @@ homeRoutes.get("/", async (c) => {
106
107
  return c.redirect("/setup");
107
108
  }
108
109
 
109
- const siteName = (await c.var.services.settings.get("SITE_NAME")) ?? "Jant";
110
+ const siteName = await getSiteName(c);
110
111
 
111
112
  const posts = await c.var.services.posts.list({
112
113
  visibility: ["featured", "quiet"],
@@ -1,3 +1,4 @@
1
+ import { getSiteName } from "../../lib/config.js";
1
2
  /**
2
3
  * Custom Page Route
3
4
  *
@@ -60,7 +61,7 @@ pageRoutes.get("/:path", async (c) => {
60
61
  return c.notFound();
61
62
  }
62
63
 
63
- const siteName = (await c.var.services.settings.get("SITE_NAME")) ?? "Jant";
64
+ const siteName = await getSiteName(c);
64
65
 
65
66
  return c.html(
66
67
  <BaseLayout
@@ -1,3 +1,4 @@
1
+ import { getSiteName } from "../../lib/config.js";
1
2
  /**
2
3
  * Single Post Page Route
3
4
  */
@@ -81,7 +82,7 @@ postRoutes.get("/:id", async (c) => {
81
82
  return c.notFound();
82
83
  }
83
84
 
84
- const siteName = (await c.var.services.settings.get("SITE_NAME")) ?? "Jant";
85
+ const siteName = await getSiteName(c);
85
86
  const title = post.title || siteName;
86
87
 
87
88
  return c.html(
@@ -1,3 +1,4 @@
1
+ import { getSiteName } from "../../lib/config.js";
1
2
  /**
2
3
  * Search Page Route
3
4
  */
@@ -155,7 +156,7 @@ searchRoutes.get("/", async (c) => {
155
156
  const pageParam = c.req.query("page");
156
157
  const page = pageParam ? Math.max(1, parseInt(pageParam, 10) || 1) : 1;
157
158
 
158
- const siteName = (await c.var.services.settings.get("SITE_NAME")) ?? "Jant";
159
+ const siteName = await getSiteName(c);
159
160
 
160
161
  // Only search if there's a query
161
162
  let results: Awaited<ReturnType<typeof c.var.services.search.search>> = [];
package/src/types.ts CHANGED
@@ -37,6 +37,10 @@ export interface Bindings {
37
37
  IMAGE_TRANSFORM_URL?: string;
38
38
  DEMO_EMAIL?: string;
39
39
  DEMO_PASSWORD?: string;
40
+ // Site configuration (optional - can be overridden in DB)
41
+ SITE_NAME?: string;
42
+ SITE_DESCRIPTION?: string;
43
+ SITE_LANGUAGE?: string;
40
44
  }
41
45
 
42
46
  // =============================================================================
@@ -193,42 +197,17 @@ export interface JantTheme {
193
197
  cssVariables?: Record<string, string>;
194
198
  }
195
199
 
196
- /**
197
- * Site configuration
198
- */
199
- export interface SiteConfig {
200
- /** Site name */
201
- name?: string;
202
- /** Site description */
203
- description?: string;
204
- /** Default language */
205
- language?: string;
206
- /** Site URL (usually set via env) */
207
- url?: string;
208
- }
209
-
210
- /**
211
- * Feature toggles
212
- */
213
- export interface FeatureConfig {
214
- /** Enable search (default: true) */
215
- search?: boolean;
216
- /** Enable RSS feed (default: true) */
217
- rss?: boolean;
218
- /** Enable sitemap (default: true) */
219
- sitemap?: boolean;
220
- /** Enable i18n (default: true) */
221
- i18n?: boolean;
222
- }
223
-
224
200
  /**
225
201
  * Main Jant configuration
202
+ *
203
+ * Configuration Philosophy:
204
+ * - Use environment variables for runtime config (API keys, feature flags, site settings)
205
+ * - Use code config (this object) for compile-time customization (theme components)
206
+ *
207
+ * Site-level settings (name, description, language) are configured via
208
+ * environment variables, not here. See lib/config.ts for details.
226
209
  */
227
210
  export interface JantConfig {
228
- /** Site configuration */
229
- site?: SiteConfig;
230
- /** Theme configuration */
211
+ /** Theme configuration (components, CSS overrides) */
231
212
  theme?: JantTheme;
232
- /** Feature toggles */
233
- features?: FeatureConfig;
234
213
  }