@jant/core 0.2.11 → 0.2.13
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/dist/app.d.ts.map +1 -1
- package/dist/app.js +112 -85
- package/dist/auth.d.ts +1 -0
- package/dist/auth.d.ts.map +1 -1
- package/dist/auth.js +2 -1
- package/dist/client.js +1 -1
- package/dist/db/schema.d.ts.map +1 -1
- package/dist/i18n/context.d.ts.map +1 -1
- package/dist/i18n/context.js +0 -3
- package/dist/i18n/detect.d.ts +0 -11
- package/dist/i18n/detect.d.ts.map +1 -1
- package/dist/i18n/detect.js +1 -52
- package/dist/i18n/i18n.d.ts +4 -14
- package/dist/i18n/i18n.d.ts.map +1 -1
- package/dist/i18n/i18n.js +19 -25
- package/dist/i18n/index.d.ts +1 -1
- package/dist/i18n/index.d.ts.map +1 -1
- package/dist/i18n/index.js +1 -1
- package/dist/i18n/middleware.d.ts +2 -5
- package/dist/i18n/middleware.d.ts.map +1 -1
- package/dist/i18n/middleware.js +12 -23
- package/dist/lib/constants.d.ts.map +1 -1
- package/dist/lib/schemas.d.ts.map +1 -1
- package/dist/lib/sse.d.ts +45 -17
- package/dist/lib/sse.d.ts.map +1 -1
- package/dist/lib/sse.js +77 -37
- package/dist/middleware/auth.d.ts.map +1 -1
- package/dist/routes/api/posts.js +0 -1
- package/dist/routes/api/upload.js +13 -3
- package/dist/routes/dash/collections.d.ts.map +1 -1
- package/dist/routes/dash/collections.js +134 -142
- package/dist/routes/dash/index.js +25 -25
- package/dist/routes/dash/media.d.ts.map +1 -1
- package/dist/routes/dash/media.js +60 -56
- package/dist/routes/dash/pages.d.ts.map +1 -1
- package/dist/routes/dash/pages.js +64 -66
- package/dist/routes/dash/posts.d.ts.map +1 -1
- package/dist/routes/dash/posts.js +50 -59
- package/dist/routes/dash/redirects.d.ts.map +1 -1
- package/dist/routes/dash/redirects.js +63 -60
- package/dist/routes/dash/settings.d.ts.map +1 -1
- package/dist/routes/dash/settings.js +249 -93
- package/dist/routes/feed/rss.js +6 -4
- package/dist/routes/pages/archive.js +60 -62
- package/dist/routes/pages/collection.js +8 -8
- package/dist/routes/pages/home.js +14 -14
- package/dist/routes/pages/page.js +7 -6
- package/dist/routes/pages/post.js +8 -8
- package/dist/routes/pages/search.js +25 -27
- package/dist/services/collection.d.ts.map +1 -1
- package/dist/services/index.d.ts.map +1 -1
- package/dist/services/media.d.ts.map +1 -1
- package/dist/services/post.d.ts.map +1 -1
- package/dist/services/redirect.d.ts.map +1 -1
- package/dist/services/settings.d.ts.map +1 -1
- package/dist/theme/components/ActionButtons.d.ts +1 -1
- package/dist/theme/components/ActionButtons.d.ts.map +1 -1
- package/dist/theme/components/ActionButtons.js +17 -21
- package/dist/theme/components/CrudPageHeader.d.ts.map +1 -1
- package/dist/theme/components/DangerZone.d.ts.map +1 -1
- package/dist/theme/components/DangerZone.js +12 -15
- package/dist/theme/components/EmptyState.d.ts.map +1 -1
- package/dist/theme/components/PageForm.d.ts.map +1 -1
- package/dist/theme/components/PageForm.js +58 -56
- package/dist/theme/components/Pagination.d.ts.map +1 -1
- package/dist/theme/components/Pagination.js +22 -25
- package/dist/theme/components/PostForm.d.ts +0 -1
- package/dist/theme/components/PostForm.d.ts.map +1 -1
- package/dist/theme/components/PostForm.js +85 -77
- package/dist/theme/components/PostList.d.ts.map +1 -1
- package/dist/theme/components/PostList.js +17 -17
- package/dist/theme/components/ThreadView.d.ts.map +1 -1
- package/dist/theme/components/ThreadView.js +15 -18
- package/dist/theme/components/TypeBadge.d.ts.map +1 -1
- package/dist/theme/components/TypeBadge.js +20 -20
- package/dist/theme/components/VisibilityBadge.d.ts.map +1 -1
- package/dist/theme/components/VisibilityBadge.js +14 -14
- package/dist/theme/components/index.d.ts +2 -2
- package/dist/theme/components/index.d.ts.map +1 -1
- package/dist/theme/layouts/BaseLayout.d.ts.map +1 -1
- package/dist/theme/layouts/BaseLayout.js +4 -2
- package/dist/theme/layouts/DashLayout.d.ts.map +1 -1
- package/dist/theme/layouts/DashLayout.js +29 -29
- package/dist/types/lingui-react-macro.d.js +9 -0
- package/dist/types.d.ts +2 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/vendor/datastar.js +1606 -0
- package/package.json +7 -15
- package/src/app.tsx +222 -59
- package/src/auth.ts +5 -1
- package/src/client.ts +1 -1
- package/src/db/migrations/meta/0000_snapshot.json +16 -47
- package/src/db/migrations/meta/_journal.json +1 -1
- package/src/db/schema.ts +22 -7
- package/src/i18n/EXAMPLES.md +45 -23
- package/src/i18n/README.md +39 -25
- package/src/i18n/context.tsx +1 -4
- package/src/i18n/detect.ts +1 -67
- package/src/i18n/i18n.ts +15 -19
- package/src/i18n/index.ts +0 -3
- package/src/i18n/middleware.ts +12 -24
- package/src/lib/constants.ts +2 -1
- package/src/lib/image-processor.ts +14 -6
- package/src/lib/image.ts +2 -2
- package/src/lib/schemas.ts +7 -3
- package/src/lib/sse.ts +133 -51
- package/src/middleware/auth.ts +6 -2
- package/src/routes/api/posts.ts +9 -9
- package/src/routes/api/upload.ts +39 -10
- package/src/routes/dash/collections.tsx +249 -81
- package/src/routes/dash/index.tsx +22 -7
- package/src/routes/dash/media.tsx +94 -24
- package/src/routes/dash/pages.tsx +132 -54
- package/src/routes/dash/posts.tsx +99 -57
- package/src/routes/dash/redirects.tsx +117 -36
- package/src/routes/dash/settings.tsx +268 -55
- package/src/routes/feed/rss.ts +6 -4
- package/src/routes/pages/archive.tsx +78 -24
- package/src/routes/pages/collection.tsx +32 -8
- package/src/routes/pages/home.tsx +38 -10
- package/src/routes/pages/page.tsx +15 -5
- package/src/routes/pages/post.tsx +17 -6
- package/src/routes/pages/search.tsx +50 -13
- package/src/services/collection.ts +29 -8
- package/src/services/index.ts +4 -1
- package/src/services/media.ts +15 -3
- package/src/services/post.ts +37 -10
- package/src/services/redirect.ts +4 -1
- package/src/services/settings.ts +14 -3
- package/src/theme/components/ActionButtons.tsx +31 -15
- package/src/theme/components/CrudPageHeader.tsx +3 -4
- package/src/theme/components/DangerZone.tsx +19 -13
- package/src/theme/components/EmptyState.tsx +1 -5
- package/src/theme/components/PageForm.tsx +80 -25
- package/src/theme/components/Pagination.tsx +34 -31
- package/src/theme/components/PostForm.tsx +91 -27
- package/src/theme/components/PostList.tsx +23 -6
- package/src/theme/components/ThreadView.tsx +25 -10
- package/src/theme/components/TypeBadge.tsx +13 -4
- package/src/theme/components/VisibilityBadge.tsx +17 -5
- package/src/theme/components/index.ts +12 -2
- package/src/theme/layouts/BaseLayout.tsx +6 -5
- package/src/theme/layouts/DashLayout.tsx +71 -18
- package/src/types/lingui-react-macro.d.ts +34 -0
- package/src/types.ts +16 -4
- package/src/vendor/datastar.js +9 -0
- package/src/vendor/datastar.js.map +7 -0
- package/dist/plugin.d.ts +0 -3
- package/dist/plugin.d.ts.map +0 -1
- package/dist/plugin.js +0 -20
- package/dist/tailwind.d.ts +0 -12
- package/dist/tailwind.d.ts.map +0 -1
- package/dist/tailwind.js +0 -15
package/dist/i18n/i18n.js
CHANGED
|
@@ -1,42 +1,36 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* i18n Runtime using @lingui/core
|
|
2
|
+
* i18n Runtime using @lingui/core
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
* const { i18n } = bindI18n(c.get("i18n"));
|
|
9
|
-
*
|
|
10
|
-
* // Simple message
|
|
11
|
-
* i18n._(msg({ message: "Hello", comment: "@context: Greeting" }))
|
|
12
|
-
*
|
|
13
|
-
* // With interpolation
|
|
14
|
-
* i18n._(msg({ message: "Welcome, {name}!", comment: "@context: Welcome" }), { name })
|
|
15
|
-
*
|
|
16
|
-
* The msg macro generates hash-based IDs at compile time, which match the compiled catalogs.
|
|
4
|
+
* The SWC Lingui plugin adds hash-based IDs to t() calls when imports come
|
|
5
|
+
* from @lingui/react/macro. The runtimeConfigModule setting rewrites those
|
|
6
|
+
* imports to our custom Hono JSX implementation at build time.
|
|
17
7
|
*/ import { I18n } from "@lingui/core";
|
|
18
8
|
import { locales, baseLocale, isLocale } from "./locales.js";
|
|
19
9
|
import { messages as messagesEn } from "./locales/en.js";
|
|
20
10
|
import { messages as messagesZhHans } from "./locales/zh-Hans.js";
|
|
21
11
|
import { messages as messagesZhHant } from "./locales/zh-Hant.js";
|
|
22
12
|
export { locales, baseLocale, isLocale };
|
|
13
|
+
// Pre-compute merged catalogs at module load time (done once, not per request)
|
|
14
|
+
// For non-English locales, merge English as fallback so missing translations
|
|
15
|
+
// fall back to English rather than showing hash IDs.
|
|
16
|
+
const catalogEn = messagesEn;
|
|
17
|
+
const catalogZhHans = {
|
|
18
|
+
...messagesEn,
|
|
19
|
+
...messagesZhHans
|
|
20
|
+
};
|
|
21
|
+
const catalogZhHant = {
|
|
22
|
+
...messagesEn,
|
|
23
|
+
...messagesZhHant
|
|
24
|
+
};
|
|
23
25
|
/**
|
|
24
26
|
* Create a new i18n instance for a specific locale.
|
|
25
27
|
* IMPORTANT: In Cloudflare Workers (concurrent environment), we must create
|
|
26
28
|
* a new instance per request to avoid race conditions. Never use a global instance!
|
|
27
29
|
*/ export function createI18n(locale) {
|
|
28
30
|
const i18n = new I18n({});
|
|
29
|
-
|
|
30
|
-
i18n.load("
|
|
31
|
-
i18n.load("zh-
|
|
32
|
-
...messagesEn,
|
|
33
|
-
...messagesZhHans
|
|
34
|
-
});
|
|
35
|
-
i18n.load("zh-Hant", {
|
|
36
|
-
...messagesEn,
|
|
37
|
-
...messagesZhHant
|
|
38
|
-
});
|
|
39
|
-
// Activate locale after loading messages to avoid warnings
|
|
31
|
+
i18n.load("en", catalogEn);
|
|
32
|
+
i18n.load("zh-Hans", catalogZhHans);
|
|
33
|
+
i18n.load("zh-Hant", catalogZhHant);
|
|
40
34
|
i18n.activate(locale);
|
|
41
35
|
return i18n;
|
|
42
36
|
}
|
package/dist/i18n/index.d.ts
CHANGED
|
@@ -36,6 +36,6 @@
|
|
|
36
36
|
export { createI18n, getI18n, locales, baseLocale, isLocale, type Locale, type I18n, } from "./i18n.js";
|
|
37
37
|
export { I18nProvider, useLingui } from "./context.js";
|
|
38
38
|
export { Trans } from "./Trans.js";
|
|
39
|
-
export {
|
|
39
|
+
export { isValidLanguage, getLanguageDisplayName, getSupportedLanguages, } from "./detect.js";
|
|
40
40
|
export { i18nMiddleware } from "./middleware.js";
|
|
41
41
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/i18n/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/i18n/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AAGH,OAAO,EACL,UAAU,EACV,OAAO,EACP,OAAO,EACP,UAAU,EACV,QAAQ,EACR,KAAK,MAAM,EACX,KAAK,IAAI,GACV,MAAM,WAAW,CAAC;AAGnB,OAAO,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAGvD,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AAGnC,OAAO,EACL,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/i18n/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AAGH,OAAO,EACL,UAAU,EACV,OAAO,EACP,OAAO,EACP,UAAU,EACV,QAAQ,EACR,KAAK,MAAM,EACX,KAAK,IAAI,GACV,MAAM,WAAW,CAAC;AAGnB,OAAO,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAGvD,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AAGnC,OAAO,EACL,eAAe,EACf,sBAAsB,EACtB,qBAAqB,GACtB,MAAM,aAAa,CAAC;AAGrB,OAAO,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC"}
|
package/dist/i18n/index.js
CHANGED
|
@@ -39,6 +39,6 @@ export { I18nProvider, useLingui } from "./context.js";
|
|
|
39
39
|
// Trans component (simplified for Hono JSX)
|
|
40
40
|
export { Trans } from "./Trans.js";
|
|
41
41
|
// Language detection utilities
|
|
42
|
-
export {
|
|
42
|
+
export { isValidLanguage, getLanguageDisplayName, getSupportedLanguages } from "./detect.js";
|
|
43
43
|
// Hono middleware
|
|
44
44
|
export { i18nMiddleware } from "./middleware.js";
|
|
@@ -14,11 +14,8 @@ declare module "hono" {
|
|
|
14
14
|
* Hono middleware for internationalization.
|
|
15
15
|
* Creates a per-request i18n instance to avoid race conditions in concurrent environments.
|
|
16
16
|
*
|
|
17
|
-
* Language
|
|
18
|
-
*
|
|
19
|
-
* 2. Database SITE_LANGUAGE setting (site default)
|
|
20
|
-
* 3. Accept-Language header
|
|
21
|
-
* 4. Default locale (en)
|
|
17
|
+
* Language is determined by the database SITE_LANGUAGE setting (single source of truth).
|
|
18
|
+
* Falls back to the default locale (en) if not set.
|
|
22
19
|
*/
|
|
23
20
|
export declare function i18nMiddleware(): MiddlewareHandler;
|
|
24
21
|
//# sourceMappingURL=middleware.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"middleware.d.ts","sourceRoot":"","sources":["../../src/i18n/middleware.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,MAAM,CAAC;AAC9C,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,cAAc,CAAC;
|
|
1
|
+
{"version":3,"file":"middleware.d.ts","sourceRoot":"","sources":["../../src/i18n/middleware.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,MAAM,CAAC;AAC9C,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,cAAc,CAAC;AACzC,OAAO,EAAoC,KAAK,MAAM,EAAE,MAAM,WAAW,CAAC;AAG1E,OAAO,QAAQ,MAAM,CAAC;IACpB,UAAU,kBAAkB;QAC1B,IAAI,EAAE,MAAM,CAAC;QACb,IAAI,EAAE,IAAI,CAAC;KACZ;CACF;AAED;;;;;;GAMG;AACH,wBAAgB,cAAc,IAAI,iBAAiB,CAuBlD"}
|
package/dist/i18n/middleware.js
CHANGED
|
@@ -1,35 +1,24 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* i18n Hono Middleware
|
|
3
|
-
*/ import {
|
|
4
|
-
import { createI18n, isLocale } from "./i18n.js";
|
|
3
|
+
*/ import { createI18n, isLocale, baseLocale } from "./i18n.js";
|
|
5
4
|
/**
|
|
6
5
|
* Hono middleware for internationalization.
|
|
7
6
|
* Creates a per-request i18n instance to avoid race conditions in concurrent environments.
|
|
8
7
|
*
|
|
9
|
-
* Language
|
|
10
|
-
*
|
|
11
|
-
* 2. Database SITE_LANGUAGE setting (site default)
|
|
12
|
-
* 3. Accept-Language header
|
|
13
|
-
* 4. Default locale (en)
|
|
8
|
+
* Language is determined by the database SITE_LANGUAGE setting (single source of truth).
|
|
9
|
+
* Falls back to the default locale (en) if not set.
|
|
14
10
|
*/ export function i18nMiddleware() {
|
|
15
11
|
return async (c, next)=>{
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
const services = c.get("services");
|
|
24
|
-
if (services) {
|
|
25
|
-
try {
|
|
26
|
-
const siteLang = await services.settings.get("SITE_LANGUAGE");
|
|
27
|
-
if (siteLang && isLocale(siteLang)) {
|
|
28
|
-
lang = siteLang;
|
|
29
|
-
}
|
|
30
|
-
} catch {
|
|
31
|
-
// Ignore errors, fall back to detected language
|
|
12
|
+
let lang = baseLocale;
|
|
13
|
+
const services = c.get("services");
|
|
14
|
+
if (services) {
|
|
15
|
+
try {
|
|
16
|
+
const siteLang = await services.settings.get("SITE_LANGUAGE");
|
|
17
|
+
if (siteLang && isLocale(siteLang)) {
|
|
18
|
+
lang = siteLang;
|
|
32
19
|
}
|
|
20
|
+
} catch {
|
|
21
|
+
// Ignore errors, fall back to default locale
|
|
33
22
|
}
|
|
34
23
|
}
|
|
35
24
|
// Create a new i18n instance for this request to avoid race conditions
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../../src/lib/constants.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH;;GAEG;AACH,eAAO,MAAM,cAAc,mMAqBjB,CAAC;AAEX,MAAM,MAAM,YAAY,GAAG,CAAC,OAAO,cAAc,CAAC,CAAC,MAAM,CAAC,CAAC;AAE3D;;GAEG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAGpD;AAED;;GAEG;AACH,eAAO,MAAM,iBAAiB,MAAM,CAAC;AAErC;;GAEG;AACH,eAAO,MAAM,aAAa;;;;;;CAMhB,CAAC;AAEX,MAAM,MAAM,WAAW,GAAG,CAAC,OAAO,aAAa,CAAC,CAAC,MAAM,OAAO,aAAa,CAAC,CAAC;AAE7E;;GAEG;AACH,eAAO,MAAM,iBAAiB;;;CAGpB,CAAC;AAEX,MAAM,MAAM,gBAAgB,
|
|
1
|
+
{"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../../src/lib/constants.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH;;GAEG;AACH,eAAO,MAAM,cAAc,mMAqBjB,CAAC;AAEX,MAAM,MAAM,YAAY,GAAG,CAAC,OAAO,cAAc,CAAC,CAAC,MAAM,CAAC,CAAC;AAE3D;;GAEG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAGpD;AAED;;GAEG;AACH,eAAO,MAAM,iBAAiB,MAAM,CAAC;AAErC;;GAEG;AACH,eAAO,MAAM,aAAa;;;;;;CAMhB,CAAC;AAEX,MAAM,MAAM,WAAW,GAAG,CAAC,OAAO,aAAa,CAAC,CAAC,MAAM,OAAO,aAAa,CAAC,CAAC;AAE7E;;GAEG;AACH,eAAO,MAAM,iBAAiB;;;CAGpB,CAAC;AAEX,MAAM,MAAM,gBAAgB,GAC1B,CAAC,OAAO,iBAAiB,CAAC,CAAC,MAAM,OAAO,iBAAiB,CAAC,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"schemas.d.ts","sourceRoot":"","sources":["../../src/lib/schemas.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAGxB;;;GAGG;AACH,eAAO,MAAM,cAAc;;;;;;;EAAqB,CAAC;AAEjD;;;GAGG;AACH,eAAO,MAAM,gBAAgB;;;;;EAA4B,CAAC;AAE1D;;;GAGG;AACH,eAAO,MAAM,kBAAkB;;;EAAyB,CAAC;AAEzD;;GAEG;AACH,eAAO,MAAM,gBAAgB;;;;;;;;;;;;;;;;;;;;;;
|
|
1
|
+
{"version":3,"file":"schemas.d.ts","sourceRoot":"","sources":["../../src/lib/schemas.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAGxB;;;GAGG;AACH,eAAO,MAAM,cAAc;;;;;;;EAAqB,CAAC;AAEjD;;;GAGG;AACH,eAAO,MAAM,gBAAgB;;;;;EAA4B,CAAC;AAE1D;;;GAGG;AACH,eAAO,MAAM,kBAAkB;;;EAAyB,CAAC;AAEzD;;GAEG;AACH,eAAO,MAAM,gBAAgB;;;;;;;;;;;;;;;;;;;;;;iBAc3B,CAAC;AAEH;;GAEG;AACH,eAAO,MAAM,gBAAgB;;;;;;;;;;;;;;;;;;;;;;iBAA6B,CAAC;AAE3D;;;;;;;;GAQG;AACH,wBAAgB,aAAa,CAAC,CAAC,EAC7B,QAAQ,EAAE,QAAQ,EAClB,GAAG,EAAE,MAAM,EACX,MAAM,EAAE,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,GACrB,CAAC,CAMH;AAED;;;;;;;;GAQG;AACH,wBAAgB,qBAAqB,CAAC,CAAC,EACrC,QAAQ,EAAE,QAAQ,EAClB,GAAG,EAAE,MAAM,EACX,MAAM,EAAE,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,GACrB,CAAC,GAAG,SAAS,CAMf"}
|
package/dist/lib/sse.d.ts
CHANGED
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Server-Sent Events (SSE) utilities for Datastar
|
|
2
|
+
* Server-Sent Events (SSE) utilities for Datastar v1.0.0-RC.7
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
* Datastar uses SSE for real-time UI updates without page reloads.
|
|
4
|
+
* Generates SSE events compatible with the Datastar client's expected format.
|
|
6
5
|
*
|
|
7
6
|
* @see https://data-star.dev/
|
|
8
7
|
*
|
|
@@ -11,16 +10,19 @@
|
|
|
11
10
|
* app.post("/api/example", (c) => {
|
|
12
11
|
* return sse(c, async (stream) => {
|
|
13
12
|
* await stream.patchSignals({ loading: false });
|
|
14
|
-
* await stream.patchElements("
|
|
13
|
+
* await stream.patchElements('<div id="result">Done!</div>');
|
|
14
|
+
* await stream.redirect("/success");
|
|
15
15
|
* });
|
|
16
16
|
* });
|
|
17
17
|
* ```
|
|
18
18
|
*/
|
|
19
19
|
import type { Context } from "hono";
|
|
20
20
|
/**
|
|
21
|
-
* Patch modes for DOM updates
|
|
21
|
+
* Patch modes for DOM element updates
|
|
22
|
+
*
|
|
23
|
+
* @see https://data-star.dev/reference/action_plugins/backend/sse
|
|
22
24
|
*/
|
|
23
|
-
export type PatchMode = "
|
|
25
|
+
export type PatchMode = "outer" | "inner" | "replace" | "prepend" | "append" | "before" | "after" | "remove";
|
|
24
26
|
/**
|
|
25
27
|
* SSE stream writer for Datastar events
|
|
26
28
|
*/
|
|
@@ -29,22 +31,25 @@ export interface SSEStream {
|
|
|
29
31
|
* Update reactive signals on the client
|
|
30
32
|
*
|
|
31
33
|
* @param signals - Object containing signal values to update
|
|
34
|
+
* @param options - Optional settings (e.g. onlyIfMissing)
|
|
32
35
|
*
|
|
33
36
|
* @example
|
|
34
37
|
* ```ts
|
|
35
38
|
* await stream.patchSignals({ count: 42, loading: false });
|
|
36
39
|
* ```
|
|
37
40
|
*/
|
|
38
|
-
patchSignals(signals: Record<string, unknown
|
|
41
|
+
patchSignals(signals: Record<string, unknown>, options?: {
|
|
42
|
+
onlyIfMissing?: boolean;
|
|
43
|
+
}): void;
|
|
39
44
|
/**
|
|
40
|
-
* Update DOM elements
|
|
45
|
+
* Update DOM elements via patching
|
|
41
46
|
*
|
|
42
47
|
* @param html - HTML content (must include element with id for targeting)
|
|
43
|
-
* @param options - Optional mode and
|
|
48
|
+
* @param options - Optional patch mode, selector, and view transition
|
|
44
49
|
*
|
|
45
50
|
* @example
|
|
46
51
|
* ```ts
|
|
47
|
-
* //
|
|
52
|
+
* // Outer patch element with matching id (default)
|
|
48
53
|
* await stream.patchElements('<div id="content">New content</div>');
|
|
49
54
|
*
|
|
50
55
|
* // Append to a container
|
|
@@ -57,31 +62,45 @@ export interface SSEStream {
|
|
|
57
62
|
patchElements(html: string, options?: {
|
|
58
63
|
mode?: PatchMode;
|
|
59
64
|
selector?: string;
|
|
60
|
-
|
|
65
|
+
useViewTransition?: boolean;
|
|
66
|
+
}): void;
|
|
67
|
+
/**
|
|
68
|
+
* Redirect the client to a new URL
|
|
69
|
+
*
|
|
70
|
+
* Uses patchElements internally to inject a script that navigates the client.
|
|
71
|
+
*
|
|
72
|
+
* @param url - The URL to redirect to
|
|
73
|
+
*
|
|
74
|
+
* @example
|
|
75
|
+
* ```ts
|
|
76
|
+
* await stream.redirect('/dash/posts');
|
|
77
|
+
* ```
|
|
78
|
+
*/
|
|
79
|
+
redirect(url: string): void;
|
|
61
80
|
/**
|
|
62
|
-
*
|
|
81
|
+
* Remove elements matching a CSS selector
|
|
63
82
|
*
|
|
64
|
-
* @param
|
|
83
|
+
* @param selector - CSS selector for elements to remove
|
|
65
84
|
*
|
|
66
85
|
* @example
|
|
67
86
|
* ```ts
|
|
68
|
-
* await stream.
|
|
87
|
+
* await stream.remove('#placeholder');
|
|
69
88
|
* ```
|
|
70
89
|
*/
|
|
71
|
-
|
|
90
|
+
remove(selector: string): void;
|
|
72
91
|
}
|
|
73
92
|
/**
|
|
74
93
|
* Create an SSE response for Datastar
|
|
75
94
|
*
|
|
76
95
|
* @param c - Hono context
|
|
77
96
|
* @param handler - Async function that writes to the SSE stream
|
|
97
|
+
* @param options - Optional response options (e.g. headers for cookie forwarding)
|
|
78
98
|
* @returns Response with SSE content-type
|
|
79
99
|
*
|
|
80
100
|
* @example
|
|
81
101
|
* ```ts
|
|
82
102
|
* app.post("/api/upload", (c) => {
|
|
83
103
|
* return sse(c, async (stream) => {
|
|
84
|
-
* // Process upload...
|
|
85
104
|
* await stream.patchSignals({ uploading: false });
|
|
86
105
|
* await stream.patchElements('<div id="new-item">...</div>', {
|
|
87
106
|
* mode: 'append',
|
|
@@ -89,7 +108,16 @@ export interface SSEStream {
|
|
|
89
108
|
* });
|
|
90
109
|
* });
|
|
91
110
|
* });
|
|
111
|
+
*
|
|
112
|
+
* // With cookie forwarding (for auth)
|
|
113
|
+
* app.post("/signin", (c) => {
|
|
114
|
+
* return sse(c, async (stream) => {
|
|
115
|
+
* await stream.redirect('/dash');
|
|
116
|
+
* }, { headers: { 'Set-Cookie': cookieValue } });
|
|
117
|
+
* });
|
|
92
118
|
* ```
|
|
93
119
|
*/
|
|
94
|
-
export declare function sse(c: Context, handler: (stream: SSEStream) => Promise<void
|
|
120
|
+
export declare function sse(c: Context, handler: (stream: SSEStream) => Promise<void>, options?: {
|
|
121
|
+
headers?: Record<string, string>;
|
|
122
|
+
}): Response;
|
|
95
123
|
//# sourceMappingURL=sse.d.ts.map
|
package/dist/lib/sse.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sse.d.ts","sourceRoot":"","sources":["../../src/lib/sse.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,MAAM,CAAC;AAEpC
|
|
1
|
+
{"version":3,"file":"sse.d.ts","sourceRoot":"","sources":["../../src/lib/sse.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,MAAM,CAAC;AAEpC;;;;GAIG;AACH,MAAM,MAAM,SAAS,GACjB,OAAO,GACP,OAAO,GACP,SAAS,GACT,SAAS,GACT,QAAQ,GACR,QAAQ,GACR,OAAO,GACP,QAAQ,CAAC;AAEb;;GAEG;AACH,MAAM,WAAW,SAAS;IACxB;;;;;;;;;;OAUG;IACH,YAAY,CACV,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAChC,OAAO,CAAC,EAAE;QAAE,aAAa,CAAC,EAAE,OAAO,CAAA;KAAE,GACpC,IAAI,CAAC;IAER;;;;;;;;;;;;;;;;;OAiBG;IACH,aAAa,CACX,IAAI,EAAE,MAAM,EACZ,OAAO,CAAC,EAAE;QACR,IAAI,CAAC,EAAE,SAAS,CAAC;QACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;QAClB,iBAAiB,CAAC,EAAE,OAAO,CAAC;KAC7B,GACA,IAAI,CAAC;IAER;;;;;;;;;;;OAWG;IACH,QAAQ,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;IAE5B;;;;;;;;;OASG;IACH,MAAM,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;CAChC;AAkBD;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,wBAAgB,GAAG,CACjB,CAAC,EAAE,OAAO,EACV,OAAO,EAAE,CAAC,MAAM,EAAE,SAAS,KAAK,OAAO,CAAC,IAAI,CAAC,EAC7C,OAAO,CAAC,EAAE;IAAE,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;CAAE,GAC7C,QAAQ,CA2EV"}
|
package/dist/lib/sse.js
CHANGED
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Server-Sent Events (SSE) utilities for Datastar
|
|
2
|
+
* Server-Sent Events (SSE) utilities for Datastar v1.0.0-RC.7
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
* Datastar uses SSE for real-time UI updates without page reloads.
|
|
4
|
+
* Generates SSE events compatible with the Datastar client's expected format.
|
|
6
5
|
*
|
|
7
6
|
* @see https://data-star.dev/
|
|
8
7
|
*
|
|
@@ -11,22 +10,37 @@
|
|
|
11
10
|
* app.post("/api/example", (c) => {
|
|
12
11
|
* return sse(c, async (stream) => {
|
|
13
12
|
* await stream.patchSignals({ loading: false });
|
|
14
|
-
* await stream.patchElements("
|
|
13
|
+
* await stream.patchElements('<div id="result">Done!</div>');
|
|
14
|
+
* await stream.redirect("/success");
|
|
15
15
|
* });
|
|
16
16
|
* });
|
|
17
17
|
* ```
|
|
18
18
|
*/ /**
|
|
19
|
+
* Format a single SSE event string
|
|
20
|
+
*
|
|
21
|
+
* @param eventType - The Datastar event type (e.g. "datastar-patch-elements")
|
|
22
|
+
* @param dataLines - Array of "key value" data lines
|
|
23
|
+
* @returns Formatted SSE event string
|
|
24
|
+
*/ function formatEvent(eventType, dataLines) {
|
|
25
|
+
let event = `event: ${eventType}\n`;
|
|
26
|
+
for (const line of dataLines){
|
|
27
|
+
event += `data: ${line}\n`;
|
|
28
|
+
}
|
|
29
|
+
event += "\n";
|
|
30
|
+
return event;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
19
33
|
* Create an SSE response for Datastar
|
|
20
34
|
*
|
|
21
35
|
* @param c - Hono context
|
|
22
36
|
* @param handler - Async function that writes to the SSE stream
|
|
37
|
+
* @param options - Optional response options (e.g. headers for cookie forwarding)
|
|
23
38
|
* @returns Response with SSE content-type
|
|
24
39
|
*
|
|
25
40
|
* @example
|
|
26
41
|
* ```ts
|
|
27
42
|
* app.post("/api/upload", (c) => {
|
|
28
43
|
* return sse(c, async (stream) => {
|
|
29
|
-
* // Process upload...
|
|
30
44
|
* await stream.patchSignals({ uploading: false });
|
|
31
45
|
* await stream.patchElements('<div id="new-item">...</div>', {
|
|
32
46
|
* mode: 'append',
|
|
@@ -34,48 +48,74 @@
|
|
|
34
48
|
* });
|
|
35
49
|
* });
|
|
36
50
|
* });
|
|
51
|
+
*
|
|
52
|
+
* // With cookie forwarding (for auth)
|
|
53
|
+
* app.post("/signin", (c) => {
|
|
54
|
+
* return sse(c, async (stream) => {
|
|
55
|
+
* await stream.redirect('/dash');
|
|
56
|
+
* }, { headers: { 'Set-Cookie': cookieValue } });
|
|
57
|
+
* });
|
|
37
58
|
* ```
|
|
38
|
-
*/ export function sse(c, handler) {
|
|
59
|
+
*/ export function sse(c, handler, options) {
|
|
39
60
|
const encoder = new TextEncoder();
|
|
40
|
-
const
|
|
61
|
+
const body = new ReadableStream({
|
|
41
62
|
async start (controller) {
|
|
42
|
-
const
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
63
|
+
const stream = {
|
|
64
|
+
patchSignals (signals, opts) {
|
|
65
|
+
const dataLines = [
|
|
66
|
+
`signals ${JSON.stringify(signals)}`
|
|
67
|
+
];
|
|
68
|
+
if (opts?.onlyIfMissing) {
|
|
69
|
+
dataLines.push("onlyIfMissing true");
|
|
70
|
+
}
|
|
71
|
+
controller.enqueue(encoder.encode(formatEvent("datastar-patch-signals", dataLines)));
|
|
49
72
|
},
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
73
|
+
patchElements (html, opts) {
|
|
74
|
+
const dataLines = [];
|
|
75
|
+
// Each line of HTML gets its own "elements <line>" data line
|
|
76
|
+
for (const line of html.split("\n")){
|
|
77
|
+
dataLines.push(`elements ${line}`);
|
|
78
|
+
}
|
|
79
|
+
if (opts?.mode) {
|
|
80
|
+
dataLines.push(`mode ${opts.mode}`);
|
|
54
81
|
}
|
|
55
|
-
if (
|
|
56
|
-
|
|
82
|
+
if (opts?.selector) {
|
|
83
|
+
dataLines.push(`selector ${opts.selector}`);
|
|
57
84
|
}
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
85
|
+
if (opts?.useViewTransition) {
|
|
86
|
+
dataLines.push("useViewTransition true");
|
|
87
|
+
}
|
|
88
|
+
controller.enqueue(encoder.encode(formatEvent("datastar-patch-elements", dataLines)));
|
|
89
|
+
},
|
|
90
|
+
redirect (url) {
|
|
91
|
+
const escapedUrl = url.replace(/\\/g, "\\\\").replace(/'/g, "\\'");
|
|
92
|
+
const script = `<script data-effect="el.remove()">window.location.href='${escapedUrl}'</script>`;
|
|
93
|
+
const dataLines = [
|
|
94
|
+
`elements ${script}`,
|
|
95
|
+
"mode append",
|
|
96
|
+
"selector body"
|
|
97
|
+
];
|
|
98
|
+
controller.enqueue(encoder.encode(formatEvent("datastar-patch-elements", dataLines)));
|
|
61
99
|
},
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
100
|
+
remove (selector) {
|
|
101
|
+
controller.enqueue(encoder.encode(formatEvent("datastar-patch-elements", [
|
|
102
|
+
"elements ",
|
|
103
|
+
`mode remove`,
|
|
104
|
+
`selector ${selector}`
|
|
105
|
+
])));
|
|
65
106
|
}
|
|
66
107
|
};
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
} finally{
|
|
70
|
-
controller.close();
|
|
71
|
-
}
|
|
108
|
+
await handler(stream);
|
|
109
|
+
controller.close();
|
|
72
110
|
}
|
|
73
111
|
});
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
112
|
+
const headers = {
|
|
113
|
+
"Content-Type": "text/event-stream",
|
|
114
|
+
"Cache-Control": "no-cache",
|
|
115
|
+
Connection: "keep-alive",
|
|
116
|
+
...options?.headers
|
|
117
|
+
};
|
|
118
|
+
return new Response(body, {
|
|
119
|
+
headers
|
|
80
120
|
});
|
|
81
121
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../../src/middleware/auth.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,MAAM,CAAC;AAC9C,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AAE9C,KAAK,GAAG,GAAG;IAAE,QAAQ,EAAE,QAAQ,CAAC;IAAC,SAAS,EAAE,YAAY,CAAA;CAAE,CAAC;AAE3D;;;GAGG;AACH,wBAAgB,WAAW,CAAC,UAAU,SAAY,GAAG,iBAAiB,CAAC,GAAG,CAAC,
|
|
1
|
+
{"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../../src/middleware/auth.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,MAAM,CAAC;AAC9C,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AAE9C,KAAK,GAAG,GAAG;IAAE,QAAQ,EAAE,QAAQ,CAAC;IAAC,SAAS,EAAE,YAAY,CAAA;CAAE,CAAC;AAE3D;;;GAGG;AACH,wBAAgB,WAAW,CAAC,UAAU,SAAY,GAAG,iBAAiB,CAAC,GAAG,CAAC,CAoB1E;AAED;;;GAGG;AACH,wBAAgB,cAAc,IAAI,iBAAiB,CAAC,GAAG,CAAC,CAoBvD"}
|
package/dist/routes/api/posts.js
CHANGED
|
@@ -27,7 +27,6 @@ postsApiRoutes.get("/", async (c)=>{
|
|
|
27
27
|
...p,
|
|
28
28
|
sqid: sqid.encode(p.id)
|
|
29
29
|
})),
|
|
30
|
-
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion -- Array length check guarantees element exists
|
|
31
30
|
nextCursor: posts.length === limit ? sqid.encode(posts[posts.length - 1].id) : null
|
|
32
31
|
});
|
|
33
32
|
});
|
|
@@ -39,7 +39,11 @@ uploadApiRoutes.use("*", requireAuthApi());
|
|
|
39
39
|
loading="lazy"
|
|
40
40
|
/>
|
|
41
41
|
</button>
|
|
42
|
-
<a
|
|
42
|
+
<a
|
|
43
|
+
href="/dash/media/${media.id}"
|
|
44
|
+
class="block mt-2 text-xs truncate hover:underline"
|
|
45
|
+
title="${media.originalName}"
|
|
46
|
+
>
|
|
43
47
|
${media.originalName}
|
|
44
48
|
</a>
|
|
45
49
|
<div class="text-xs text-muted-foreground">${sizeStr}</div>
|
|
@@ -52,11 +56,17 @@ uploadApiRoutes.use("*", requireAuthApi());
|
|
|
52
56
|
href="/dash/media/${media.id}"
|
|
53
57
|
class="block aspect-square bg-muted rounded-lg overflow-hidden border hover:border-primary"
|
|
54
58
|
>
|
|
55
|
-
<div
|
|
59
|
+
<div
|
|
60
|
+
class="w-full h-full flex items-center justify-center text-muted-foreground"
|
|
61
|
+
>
|
|
56
62
|
<span class="text-xs">${media.mimeType}</span>
|
|
57
63
|
</div>
|
|
58
64
|
</a>
|
|
59
|
-
<a
|
|
65
|
+
<a
|
|
66
|
+
href="/dash/media/${media.id}"
|
|
67
|
+
class="block mt-2 text-xs truncate hover:underline"
|
|
68
|
+
title="${media.originalName}"
|
|
69
|
+
>
|
|
60
70
|
${media.originalName}
|
|
61
71
|
</a>
|
|
62
72
|
<div class="text-xs text-muted-foreground">${sizeStr}</div>
|
|
@@ -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;
|
|
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"}
|