@jant/core 0.3.27 → 0.3.29
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/reset-password.js +22 -0
- package/dist/client/client.css +1 -0
- package/dist/client/client.js +31561 -0
- package/dist/index.js +15209 -15
- package/package.json +25 -15
- package/src/__tests__/helpers/app.ts +19 -3
- package/src/__tests__/helpers/db.ts +44 -0
- package/src/__tests__/helpers/lingui-core-macro-mock.ts +33 -0
- package/src/app.tsx +111 -174
- package/src/client.ts +13 -0
- package/src/db/migrations/0007_post_collections_m2m.sql +94 -0
- package/src/db/migrations/0008_add_collection_dividers.sql +8 -0
- package/src/db/migrations/0009_drop_collection_show_divider.sql +2 -0
- package/src/db/migrations/0010_add_performance_indexes.sql +16 -0
- package/src/db/schema.ts +24 -4
- package/src/i18n/locales/en.po +810 -385
- package/src/i18n/locales/en.ts +1 -1
- package/src/i18n/locales/zh-Hans.po +733 -522
- package/src/i18n/locales/zh-Hans.ts +1 -1
- package/src/i18n/locales/zh-Hant.po +733 -522
- package/src/i18n/locales/zh-Hant.ts +1 -1
- package/src/i18n/middleware.ts +7 -11
- package/src/index.ts +1 -1
- package/src/lib/__tests__/icons.test.ts +178 -0
- package/src/lib/__tests__/resolve-config.test.ts +184 -0
- package/src/lib/__tests__/schemas.test.ts +12 -6
- package/src/lib/__tests__/theme.test.ts +62 -0
- package/src/lib/__tests__/timezones.test.ts +1 -1
- package/src/lib/__tests__/url.test.ts +12 -0
- package/src/lib/__tests__/view.test.ts +1 -5
- package/src/lib/avatar-upload.ts +18 -10
- package/src/lib/collection-form-bridge.ts +52 -0
- package/src/lib/collections-reorder.ts +28 -0
- package/src/lib/compose-bridge.ts +251 -0
- package/src/lib/errors.ts +116 -0
- package/src/lib/excerpt.ts +1 -1
- package/src/lib/favicon.ts +3 -5
- package/src/lib/html.ts +22 -0
- package/src/lib/icon-catalog.ts +181 -0
- package/src/lib/icons.ts +202 -0
- package/src/lib/navigation.ts +18 -33
- package/src/lib/pagination.ts +3 -2
- package/src/lib/post-form-bridge.ts +136 -0
- package/src/lib/render.tsx +11 -4
- package/src/lib/resolve-config.ts +157 -0
- package/src/lib/schemas.ts +76 -12
- package/src/lib/settings-bridge.ts +139 -0
- package/src/lib/storage.ts +37 -16
- package/src/lib/theme.ts +5 -7
- package/src/lib/timeline.ts +4 -8
- package/src/lib/toast.ts +134 -0
- package/src/lib/upload.ts +71 -0
- package/src/lib/url.ts +9 -1
- package/src/lib/version.ts +16 -0
- package/src/lib/view.ts +9 -10
- package/src/middleware/__tests__/auth.test.ts +6 -28
- package/src/middleware/__tests__/onboarding.test.ts +1 -1
- package/src/middleware/auth.ts +6 -12
- package/src/middleware/config.ts +51 -0
- package/src/middleware/error-handler.ts +56 -0
- package/src/middleware/onboarding.ts +1 -1
- package/src/preset.css +6 -0
- package/src/routes/__tests__/compose.test.ts +104 -17
- package/src/routes/api/__tests__/collections.test.ts +93 -2
- package/src/routes/api/__tests__/posts.test.ts +2 -1
- package/src/routes/api/__tests__/settings.test.ts +1 -1
- package/src/routes/api/collections.ts +64 -68
- package/src/routes/api/nav-items.ts +21 -59
- package/src/routes/api/pages.ts +18 -46
- package/src/routes/api/posts.ts +64 -86
- package/src/routes/api/search.ts +6 -4
- package/src/routes/api/settings.ts +8 -24
- package/src/routes/api/upload.ts +55 -53
- package/src/routes/auth/__tests__/setup.test.ts +118 -0
- package/src/routes/auth/reset.tsx +17 -66
- package/src/routes/auth/setup.tsx +67 -11
- package/src/routes/auth/signin.tsx +44 -8
- package/src/routes/compose.tsx +194 -0
- package/src/routes/dash/__tests__/font-theme.test.ts +110 -0
- package/src/routes/dash/__tests__/pages.test.ts +2 -2
- package/src/routes/dash/__tests__/settings-avatar.test.ts +23 -12
- package/src/routes/dash/appearance.tsx +173 -0
- package/src/routes/dash/collections.tsx +80 -14
- package/src/routes/dash/index.tsx +12 -14
- package/src/routes/dash/media.tsx +46 -49
- package/src/routes/dash/pages.tsx +85 -37
- package/src/routes/dash/posts.tsx +60 -23
- package/src/routes/dash/redirects.tsx +43 -33
- package/src/routes/dash/settings.tsx +234 -214
- package/src/routes/feed/__tests__/rss.test.ts +7 -3
- package/src/routes/feed/rss.ts +11 -16
- package/src/routes/feed/sitemap.ts +15 -9
- package/src/routes/pages/__tests__/collections.test.ts +9 -8
- package/src/routes/pages/archive.tsx +2 -2
- package/src/routes/pages/collection.tsx +76 -9
- package/src/routes/pages/collections.tsx +3 -1
- package/src/routes/pages/featured.tsx +2 -2
- package/src/routes/pages/home.tsx +3 -3
- package/src/routes/pages/latest.tsx +2 -2
- package/src/routes/pages/page.tsx +2 -2
- package/src/routes/pages/post.tsx +2 -2
- package/src/routes/pages/search.tsx +2 -2
- package/src/services/__tests__/collection.test.ts +324 -34
- package/src/services/__tests__/media.test.ts +1 -1
- package/src/services/__tests__/page.test.ts +116 -1
- package/src/services/auth.ts +88 -0
- package/src/services/collection.ts +169 -30
- package/src/services/index.ts +8 -3
- package/src/services/media.ts +39 -12
- package/src/services/navigation.ts +17 -5
- package/src/services/page.ts +24 -4
- package/src/services/post.ts +87 -19
- package/src/services/search.ts +0 -1
- package/src/services/settings.ts +21 -13
- package/src/style.css +3 -0
- package/src/styles/components.css +42 -1
- package/src/styles/tokens.css +4 -0
- package/src/styles/ui.css +902 -73
- package/src/types/app-context.ts +25 -0
- package/src/types/bindings.ts +1 -0
- package/src/types/config.ts +60 -23
- package/src/types/entities.ts +12 -2
- package/src/types/lingui-react-macro.d.ts +3 -3
- package/src/types/operations.ts +2 -4
- package/src/types/views.ts +1 -3
- package/src/ui/__tests__/font-themes.test.ts +27 -8
- package/src/ui/color-themes.ts +1 -1
- package/src/ui/components/__tests__/jant-collection-form.test.ts +153 -0
- package/src/ui/components/__tests__/jant-compose-dialog.test.ts +512 -0
- package/src/ui/components/__tests__/jant-compose-editor.test.ts +272 -0
- package/src/ui/components/__tests__/jant-post-form.test.ts +172 -0
- package/src/ui/components/__tests__/jant-settings-avatar.test.ts +235 -0
- package/src/ui/components/__tests__/jant-settings-general.test.ts +319 -0
- package/src/ui/components/collection-types.ts +45 -0
- package/src/ui/components/compose-types.ts +75 -0
- package/src/ui/components/jant-collection-form.ts +512 -0
- package/src/ui/components/jant-compose-dialog.ts +494 -0
- package/src/ui/components/jant-compose-editor.ts +799 -0
- package/src/ui/components/jant-post-form.ts +290 -0
- package/src/ui/components/jant-settings-avatar.ts +231 -0
- package/src/ui/components/jant-settings-general.ts +436 -0
- package/src/ui/components/post-form-template.ts +260 -0
- package/src/ui/components/post-form-types.ts +87 -0
- package/src/ui/components/settings-types.ts +62 -0
- package/src/ui/compose/ComposeDialog.tsx +141 -385
- package/src/ui/compose/ComposePrompt.tsx +3 -3
- package/src/ui/dash/PostList.tsx +55 -61
- package/src/ui/dash/appearance/AdvancedContent.tsx +80 -0
- package/src/ui/dash/appearance/AppearanceNav.tsx +56 -0
- package/src/ui/dash/appearance/ColorThemeContent.tsx +129 -0
- package/src/ui/dash/appearance/FontThemeContent.tsx +98 -0
- package/src/ui/dash/collections/CollectionForm.tsx +130 -117
- package/src/ui/dash/collections/CollectionsListContent.tsx +102 -41
- package/src/ui/dash/collections/IconPickerGrid.tsx +50 -0
- package/src/ui/dash/collections/ViewCollectionContent.tsx +14 -3
- package/src/ui/dash/index.ts +1 -1
- package/src/ui/dash/posts/PostForm.tsx +248 -0
- package/src/ui/dash/settings/AccountContent.tsx +69 -80
- package/src/ui/dash/settings/GeneralContent.tsx +159 -478
- package/src/ui/dash/settings/SettingsNav.tsx +4 -4
- package/src/ui/font-themes.ts +115 -32
- package/src/ui/layouts/BaseLayout.tsx +49 -19
- package/src/ui/layouts/DashLayout.tsx +14 -9
- package/src/ui/layouts/SiteLayout.tsx +38 -23
- package/src/ui/pages/CollectionPage.tsx +12 -2
- package/src/ui/pages/CollectionsPage.tsx +27 -27
- package/src/ui/pages/HomePage.tsx +15 -6
- package/src/ui/pages/SearchPage.tsx +1 -2
- package/src/ui/shared/CollectionsSidebar.tsx +59 -0
- package/src/ui/shared/Pagination.tsx +2 -2
- package/dist/app.js +0 -267
- package/dist/auth.js +0 -39
- package/dist/client.js +0 -13
- package/dist/db/index.js +0 -10
- package/dist/db/schema.js +0 -224
- package/dist/i18n/Trans.js +0 -24
- package/dist/i18n/context.js +0 -58
- package/dist/i18n/detect.js +0 -26
- package/dist/i18n/i18n.js +0 -49
- package/dist/i18n/index.js +0 -44
- package/dist/i18n/locales/en.js +0 -1
- package/dist/i18n/locales/zh-Hans.js +0 -1
- package/dist/i18n/locales/zh-Hant.js +0 -1
- package/dist/i18n/locales.js +0 -13
- package/dist/i18n/middleware.js +0 -30
- package/dist/lib/avatar-upload.js +0 -134
- package/dist/lib/config.js +0 -143
- package/dist/lib/constants.js +0 -50
- package/dist/lib/excerpt.js +0 -76
- package/dist/lib/favicon.js +0 -102
- package/dist/lib/feed.js +0 -123
- package/dist/lib/image-processor.js +0 -187
- package/dist/lib/image.js +0 -97
- package/dist/lib/index.js +0 -7
- package/dist/lib/markdown.js +0 -83
- package/dist/lib/media-helpers.js +0 -49
- package/dist/lib/media-upload.js +0 -104
- package/dist/lib/nav-reorder.js +0 -27
- package/dist/lib/navigation.js +0 -79
- package/dist/lib/pagination.js +0 -44
- package/dist/lib/render.js +0 -53
- package/dist/lib/schemas.js +0 -174
- package/dist/lib/sqid.js +0 -72
- package/dist/lib/sse.js +0 -218
- package/dist/lib/storage.js +0 -164
- package/dist/lib/theme.js +0 -65
- package/dist/lib/time.js +0 -159
- package/dist/lib/timeline.js +0 -95
- package/dist/lib/timezones.js +0 -388
- package/dist/lib/url.js +0 -89
- package/dist/lib/view.js +0 -217
- package/dist/middleware/auth.js +0 -52
- package/dist/middleware/onboarding.js +0 -41
- package/dist/routes/api/collections.js +0 -124
- package/dist/routes/api/nav-items.js +0 -104
- package/dist/routes/api/pages.js +0 -91
- package/dist/routes/api/posts.js +0 -218
- package/dist/routes/api/search.js +0 -48
- package/dist/routes/api/settings.js +0 -68
- package/dist/routes/api/upload.js +0 -246
- package/dist/routes/auth/reset.js +0 -221
- package/dist/routes/auth/setup.js +0 -194
- package/dist/routes/auth/signin.js +0 -176
- package/dist/routes/compose.js +0 -48
- package/dist/routes/dash/collections.js +0 -115
- package/dist/routes/dash/index.js +0 -118
- package/dist/routes/dash/media.js +0 -106
- package/dist/routes/dash/pages.js +0 -294
- package/dist/routes/dash/posts.js +0 -244
- package/dist/routes/dash/redirects.js +0 -257
- package/dist/routes/dash/settings.js +0 -379
- package/dist/routes/feed/rss.js +0 -62
- package/dist/routes/feed/sitemap.js +0 -49
- package/dist/routes/pages/archive.js +0 -62
- package/dist/routes/pages/collection.js +0 -34
- package/dist/routes/pages/collections.js +0 -28
- package/dist/routes/pages/featured.js +0 -36
- package/dist/routes/pages/home.js +0 -64
- package/dist/routes/pages/latest.js +0 -45
- package/dist/routes/pages/page.js +0 -68
- package/dist/routes/pages/post.js +0 -44
- package/dist/routes/pages/search.js +0 -54
- package/dist/services/collection.js +0 -109
- package/dist/services/index.js +0 -24
- package/dist/services/media.js +0 -117
- package/dist/services/navigation.js +0 -91
- package/dist/services/page.js +0 -84
- package/dist/services/post.js +0 -229
- package/dist/services/redirect.js +0 -48
- package/dist/services/search.js +0 -67
- package/dist/services/settings.js +0 -68
- package/dist/types/bindings.js +0 -3
- package/dist/types/config.js +0 -147
- package/dist/types/constants.js +0 -27
- package/dist/types/entities.js +0 -3
- package/dist/types/lingui-react-macro.d.js +0 -9
- package/dist/types/operations.js +0 -3
- package/dist/types/props.js +0 -3
- package/dist/types/sortablejs.d.js +0 -5
- package/dist/types/views.js +0 -5
- package/dist/types.js +0 -11
- package/dist/ui/color-themes.js +0 -268
- package/dist/ui/compose/ComposeDialog.js +0 -467
- package/dist/ui/compose/ComposePrompt.js +0 -55
- package/dist/ui/dash/ActionButtons.js +0 -46
- package/dist/ui/dash/CrudPageHeader.js +0 -22
- package/dist/ui/dash/DangerZone.js +0 -36
- package/dist/ui/dash/FormatBadge.js +0 -27
- package/dist/ui/dash/ListItemRow.js +0 -21
- package/dist/ui/dash/PageForm.js +0 -195
- package/dist/ui/dash/PostForm.js +0 -395
- package/dist/ui/dash/PostList.js +0 -83
- package/dist/ui/dash/StatusBadge.js +0 -46
- package/dist/ui/dash/collections/CollectionForm.js +0 -152
- package/dist/ui/dash/collections/CollectionsListContent.js +0 -68
- package/dist/ui/dash/collections/ViewCollectionContent.js +0 -96
- package/dist/ui/dash/index.js +0 -10
- package/dist/ui/dash/media/MediaListContent.js +0 -166
- package/dist/ui/dash/media/ViewMediaContent.js +0 -212
- package/dist/ui/dash/pages/LinkFormContent.js +0 -130
- package/dist/ui/dash/pages/UnifiedPagesContent.js +0 -193
- package/dist/ui/dash/settings/AccountContent.js +0 -209
- package/dist/ui/dash/settings/AppearanceContent.js +0 -259
- package/dist/ui/dash/settings/GeneralContent.js +0 -536
- package/dist/ui/dash/settings/SettingsNav.js +0 -41
- package/dist/ui/feed/LinkCard.js +0 -72
- package/dist/ui/feed/NoteCard.js +0 -58
- package/dist/ui/feed/QuoteCard.js +0 -63
- package/dist/ui/feed/ThreadPreview.js +0 -48
- package/dist/ui/feed/TimelineFeed.js +0 -41
- package/dist/ui/feed/TimelineItem.js +0 -27
- package/dist/ui/font-themes.js +0 -36
- package/dist/ui/layouts/BaseLayout.js +0 -153
- package/dist/ui/layouts/DashLayout.js +0 -141
- package/dist/ui/layouts/SiteLayout.js +0 -169
- package/dist/ui/pages/ArchivePage.js +0 -143
- package/dist/ui/pages/CollectionPage.js +0 -70
- package/dist/ui/pages/CollectionsPage.js +0 -76
- package/dist/ui/pages/FeaturedPage.js +0 -24
- package/dist/ui/pages/HomePage.js +0 -24
- package/dist/ui/pages/PostPage.js +0 -55
- package/dist/ui/pages/SearchPage.js +0 -122
- package/dist/ui/pages/SinglePage.js +0 -23
- package/dist/ui/shared/EmptyState.js +0 -27
- package/dist/ui/shared/MediaGallery.js +0 -35
- package/dist/ui/shared/Pagination.js +0 -195
- package/dist/ui/shared/ThreadView.js +0 -108
- package/dist/ui/shared/index.js +0 -5
- package/dist/vendor/datastar.js +0 -1606
- package/src/lib/__tests__/config.test.ts +0 -192
- package/src/lib/config.ts +0 -167
- package/src/routes/compose.ts +0 -63
- package/src/ui/dash/PostForm.tsx +0 -360
- package/src/ui/dash/settings/AppearanceContent.tsx +0 -254
package/dist/lib/timeline.js
DELETED
|
@@ -1,95 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Timeline Data Assembly
|
|
3
|
-
*
|
|
4
|
-
* Shared helper for assembling timeline items with media and thread previews.
|
|
5
|
-
* Used by page rendering with page-based pagination.
|
|
6
|
-
*/ import { buildMediaMap } from "./media-helpers.js";
|
|
7
|
-
import { createMediaContext, toPostView, toPostViews } from "./view.js";
|
|
8
|
-
const DEFAULT_PAGE_SIZE = 20;
|
|
9
|
-
/**
|
|
10
|
-
* Assembles a page of timeline items with media attachments and thread previews.
|
|
11
|
-
*
|
|
12
|
-
* Fetches posts using offset-based pagination, batch-loads media, identifies
|
|
13
|
-
* threads, and returns render-ready `TimelineItemView[]` with page info.
|
|
14
|
-
*
|
|
15
|
-
* @param c - Hono context (provides services + env)
|
|
16
|
-
* @param options - Optional page number (1-indexed, defaults to 1)
|
|
17
|
-
* @returns Assembled timeline items with pagination info
|
|
18
|
-
*
|
|
19
|
-
* @example
|
|
20
|
-
* ```ts
|
|
21
|
-
* const { items, currentPage, totalPages } = await assembleTimeline(c);
|
|
22
|
-
* const { items, currentPage, totalPages } = await assembleTimeline(c, { page: 2 });
|
|
23
|
-
* ```
|
|
24
|
-
*/ export async function assembleTimeline(c, options) {
|
|
25
|
-
const pageSize = parseInt(c.env.PAGE_SIZE ?? String(DEFAULT_PAGE_SIZE), 10) || DEFAULT_PAGE_SIZE;
|
|
26
|
-
const page = Math.max(1, options?.page ?? 1);
|
|
27
|
-
const offset = (page - 1) * pageSize;
|
|
28
|
-
// Get total count for pagination
|
|
29
|
-
const totalCount = await c.var.services.posts.count({
|
|
30
|
-
status: "published",
|
|
31
|
-
excludeReplies: true
|
|
32
|
-
});
|
|
33
|
-
const totalPages = Math.max(1, Math.ceil(totalCount / pageSize));
|
|
34
|
-
// Fetch posts for the current page
|
|
35
|
-
const posts = await c.var.services.posts.list({
|
|
36
|
-
status: "published",
|
|
37
|
-
excludeReplies: true,
|
|
38
|
-
limit: pageSize,
|
|
39
|
-
offset
|
|
40
|
-
});
|
|
41
|
-
if (posts.length === 0) {
|
|
42
|
-
return {
|
|
43
|
-
items: [],
|
|
44
|
-
currentPage: page,
|
|
45
|
-
totalPages
|
|
46
|
-
};
|
|
47
|
-
}
|
|
48
|
-
// Batch load media attachments
|
|
49
|
-
const postIds = posts.map((p)=>p.id);
|
|
50
|
-
const rawMediaMap = await c.var.services.media.getByPostIds(postIds);
|
|
51
|
-
const mediaCtx = createMediaContext(c);
|
|
52
|
-
const mediaMap = buildMediaMap(rawMediaMap, mediaCtx.r2PublicUrl, mediaCtx.imageTransformUrl, mediaCtx.s3PublicUrl);
|
|
53
|
-
// Get reply counts to identify thread roots
|
|
54
|
-
const replyCounts = await c.var.services.posts.getReplyCounts(postIds);
|
|
55
|
-
const threadRootIds = postIds.filter((id)=>(replyCounts.get(id) ?? 0) > 0);
|
|
56
|
-
// Batch load thread previews
|
|
57
|
-
const threadPreviews = await c.var.services.posts.getThreadPreviews(threadRootIds, 3);
|
|
58
|
-
// Batch load media for preview replies
|
|
59
|
-
const previewReplyIds = [];
|
|
60
|
-
for (const replies of threadPreviews.values()){
|
|
61
|
-
for (const reply of replies){
|
|
62
|
-
previewReplyIds.push(reply.id);
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
const previewMediaMap = previewReplyIds.length > 0 ? buildMediaMap(await c.var.services.media.getByPostIds(previewReplyIds), mediaCtx.r2PublicUrl, mediaCtx.imageTransformUrl, mediaCtx.s3PublicUrl) : new Map();
|
|
66
|
-
// Assemble timeline items with View Models
|
|
67
|
-
const items = posts.map((post)=>{
|
|
68
|
-
const postView = toPostView({
|
|
69
|
-
...post,
|
|
70
|
-
mediaAttachments: mediaMap.get(post.id) ?? []
|
|
71
|
-
}, mediaCtx);
|
|
72
|
-
const replyCount = replyCounts.get(post.id) ?? 0;
|
|
73
|
-
const previewReplies = threadPreviews.get(post.id);
|
|
74
|
-
if (replyCount > 0 && previewReplies) {
|
|
75
|
-
return {
|
|
76
|
-
post: postView,
|
|
77
|
-
threadPreview: {
|
|
78
|
-
replies: toPostViews(previewReplies.map((r)=>({
|
|
79
|
-
...r,
|
|
80
|
-
mediaAttachments: previewMediaMap.get(r.id) ?? []
|
|
81
|
-
})), mediaCtx),
|
|
82
|
-
totalReplyCount: replyCount
|
|
83
|
-
}
|
|
84
|
-
};
|
|
85
|
-
}
|
|
86
|
-
return {
|
|
87
|
-
post: postView
|
|
88
|
-
};
|
|
89
|
-
});
|
|
90
|
-
return {
|
|
91
|
-
items,
|
|
92
|
-
currentPage: page,
|
|
93
|
-
totalPages
|
|
94
|
-
};
|
|
95
|
-
}
|
package/dist/lib/timezones.js
DELETED
|
@@ -1,388 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Timezone List
|
|
3
|
-
*
|
|
4
|
-
* Provides a curated list of timezones for the settings UI
|
|
5
|
-
* and a helper to map IANA timezone names to our list entries.
|
|
6
|
-
*/ export const TIMEZONES = [
|
|
7
|
-
{
|
|
8
|
-
value: "International Date Line West",
|
|
9
|
-
label: "(UTC-12:00) International Date Line West",
|
|
10
|
-
offset: "-12:00",
|
|
11
|
-
iana: [
|
|
12
|
-
"Etc/GMT+12"
|
|
13
|
-
]
|
|
14
|
-
},
|
|
15
|
-
{
|
|
16
|
-
value: "American Samoa",
|
|
17
|
-
label: "(UTC-11:00) American Samoa",
|
|
18
|
-
offset: "-11:00",
|
|
19
|
-
iana: [
|
|
20
|
-
"Pacific/Pago_Pago",
|
|
21
|
-
"Pacific/Midway",
|
|
22
|
-
"Etc/GMT+11"
|
|
23
|
-
]
|
|
24
|
-
},
|
|
25
|
-
{
|
|
26
|
-
value: "Hawaii",
|
|
27
|
-
label: "(UTC-10:00) Hawaii",
|
|
28
|
-
offset: "-10:00",
|
|
29
|
-
iana: [
|
|
30
|
-
"Pacific/Honolulu",
|
|
31
|
-
"Etc/GMT+10"
|
|
32
|
-
]
|
|
33
|
-
},
|
|
34
|
-
{
|
|
35
|
-
value: "Alaska",
|
|
36
|
-
label: "(UTC-09:00) Alaska",
|
|
37
|
-
offset: "-09:00",
|
|
38
|
-
iana: [
|
|
39
|
-
"America/Anchorage",
|
|
40
|
-
"America/Juneau",
|
|
41
|
-
"America/Nome"
|
|
42
|
-
]
|
|
43
|
-
},
|
|
44
|
-
{
|
|
45
|
-
value: "Pacific Time (US & Canada)",
|
|
46
|
-
label: "(UTC-08:00) Pacific Time (US & Canada)",
|
|
47
|
-
offset: "-08:00",
|
|
48
|
-
iana: [
|
|
49
|
-
"America/Los_Angeles",
|
|
50
|
-
"America/Vancouver",
|
|
51
|
-
"America/Tijuana"
|
|
52
|
-
]
|
|
53
|
-
},
|
|
54
|
-
{
|
|
55
|
-
value: "Mountain Time (US & Canada)",
|
|
56
|
-
label: "(UTC-07:00) Mountain Time (US & Canada)",
|
|
57
|
-
offset: "-07:00",
|
|
58
|
-
iana: [
|
|
59
|
-
"America/Denver",
|
|
60
|
-
"America/Edmonton",
|
|
61
|
-
"America/Phoenix",
|
|
62
|
-
"America/Boise"
|
|
63
|
-
]
|
|
64
|
-
},
|
|
65
|
-
{
|
|
66
|
-
value: "Central Time (US & Canada)",
|
|
67
|
-
label: "(UTC-06:00) Central Time (US & Canada)",
|
|
68
|
-
offset: "-06:00",
|
|
69
|
-
iana: [
|
|
70
|
-
"America/Chicago",
|
|
71
|
-
"America/Winnipeg",
|
|
72
|
-
"America/Mexico_City",
|
|
73
|
-
"America/Guatemala"
|
|
74
|
-
]
|
|
75
|
-
},
|
|
76
|
-
{
|
|
77
|
-
value: "Eastern Time (US & Canada)",
|
|
78
|
-
label: "(UTC-05:00) Eastern Time (US & Canada)",
|
|
79
|
-
offset: "-05:00",
|
|
80
|
-
iana: [
|
|
81
|
-
"America/New_York",
|
|
82
|
-
"America/Toronto",
|
|
83
|
-
"America/Detroit",
|
|
84
|
-
"America/Indiana/Indianapolis",
|
|
85
|
-
"America/Bogota",
|
|
86
|
-
"America/Lima"
|
|
87
|
-
]
|
|
88
|
-
},
|
|
89
|
-
{
|
|
90
|
-
value: "Atlantic Time (Canada)",
|
|
91
|
-
label: "(UTC-04:00) Atlantic Time (Canada)",
|
|
92
|
-
offset: "-04:00",
|
|
93
|
-
iana: [
|
|
94
|
-
"America/Halifax",
|
|
95
|
-
"America/Caracas",
|
|
96
|
-
"America/Santiago",
|
|
97
|
-
"America/La_Paz"
|
|
98
|
-
]
|
|
99
|
-
},
|
|
100
|
-
{
|
|
101
|
-
value: "Newfoundland",
|
|
102
|
-
label: "(UTC-03:30) Newfoundland",
|
|
103
|
-
offset: "-03:30",
|
|
104
|
-
iana: [
|
|
105
|
-
"America/St_Johns"
|
|
106
|
-
]
|
|
107
|
-
},
|
|
108
|
-
{
|
|
109
|
-
value: "Buenos Aires",
|
|
110
|
-
label: "(UTC-03:00) Buenos Aires",
|
|
111
|
-
offset: "-03:00",
|
|
112
|
-
iana: [
|
|
113
|
-
"America/Argentina/Buenos_Aires",
|
|
114
|
-
"America/Sao_Paulo",
|
|
115
|
-
"America/Montevideo"
|
|
116
|
-
]
|
|
117
|
-
},
|
|
118
|
-
{
|
|
119
|
-
value: "Mid-Atlantic",
|
|
120
|
-
label: "(UTC-02:00) Mid-Atlantic",
|
|
121
|
-
offset: "-02:00",
|
|
122
|
-
iana: [
|
|
123
|
-
"Atlantic/South_Georgia",
|
|
124
|
-
"Etc/GMT+2"
|
|
125
|
-
]
|
|
126
|
-
},
|
|
127
|
-
{
|
|
128
|
-
value: "Azores",
|
|
129
|
-
label: "(UTC-01:00) Azores",
|
|
130
|
-
offset: "-01:00",
|
|
131
|
-
iana: [
|
|
132
|
-
"Atlantic/Azores",
|
|
133
|
-
"Atlantic/Cape_Verde"
|
|
134
|
-
]
|
|
135
|
-
},
|
|
136
|
-
{
|
|
137
|
-
value: "UTC",
|
|
138
|
-
label: "(UTC+00:00) UTC",
|
|
139
|
-
offset: "+00:00",
|
|
140
|
-
iana: [
|
|
141
|
-
"Etc/UTC",
|
|
142
|
-
"UTC",
|
|
143
|
-
"Etc/GMT",
|
|
144
|
-
"Africa/Accra"
|
|
145
|
-
]
|
|
146
|
-
},
|
|
147
|
-
{
|
|
148
|
-
value: "London",
|
|
149
|
-
label: "(UTC+00:00) London",
|
|
150
|
-
offset: "+00:00",
|
|
151
|
-
iana: [
|
|
152
|
-
"Europe/London",
|
|
153
|
-
"Europe/Dublin",
|
|
154
|
-
"Europe/Lisbon"
|
|
155
|
-
]
|
|
156
|
-
},
|
|
157
|
-
{
|
|
158
|
-
value: "Central European Time",
|
|
159
|
-
label: "(UTC+01:00) Central European Time",
|
|
160
|
-
offset: "+01:00",
|
|
161
|
-
iana: [
|
|
162
|
-
"Europe/Paris",
|
|
163
|
-
"Europe/Berlin",
|
|
164
|
-
"Europe/Amsterdam",
|
|
165
|
-
"Europe/Rome",
|
|
166
|
-
"Europe/Madrid",
|
|
167
|
-
"Europe/Brussels",
|
|
168
|
-
"Europe/Vienna",
|
|
169
|
-
"Europe/Warsaw",
|
|
170
|
-
"Europe/Prague",
|
|
171
|
-
"Europe/Stockholm",
|
|
172
|
-
"Europe/Oslo",
|
|
173
|
-
"Europe/Copenhagen",
|
|
174
|
-
"Europe/Zurich",
|
|
175
|
-
"Africa/Lagos"
|
|
176
|
-
]
|
|
177
|
-
},
|
|
178
|
-
{
|
|
179
|
-
value: "Eastern European Time",
|
|
180
|
-
label: "(UTC+02:00) Eastern European Time",
|
|
181
|
-
offset: "+02:00",
|
|
182
|
-
iana: [
|
|
183
|
-
"Europe/Helsinki",
|
|
184
|
-
"Europe/Athens",
|
|
185
|
-
"Europe/Bucharest",
|
|
186
|
-
"Europe/Istanbul",
|
|
187
|
-
"Africa/Cairo",
|
|
188
|
-
"Africa/Johannesburg",
|
|
189
|
-
"Asia/Jerusalem",
|
|
190
|
-
"Asia/Beirut"
|
|
191
|
-
]
|
|
192
|
-
},
|
|
193
|
-
{
|
|
194
|
-
value: "Moscow",
|
|
195
|
-
label: "(UTC+03:00) Moscow",
|
|
196
|
-
offset: "+03:00",
|
|
197
|
-
iana: [
|
|
198
|
-
"Europe/Moscow",
|
|
199
|
-
"Europe/Minsk",
|
|
200
|
-
"Asia/Baghdad",
|
|
201
|
-
"Asia/Riyadh",
|
|
202
|
-
"Africa/Nairobi",
|
|
203
|
-
"Asia/Kuwait"
|
|
204
|
-
]
|
|
205
|
-
},
|
|
206
|
-
{
|
|
207
|
-
value: "Tehran",
|
|
208
|
-
label: "(UTC+03:30) Tehran",
|
|
209
|
-
offset: "+03:30",
|
|
210
|
-
iana: [
|
|
211
|
-
"Asia/Tehran"
|
|
212
|
-
]
|
|
213
|
-
},
|
|
214
|
-
{
|
|
215
|
-
value: "Dubai",
|
|
216
|
-
label: "(UTC+04:00) Dubai",
|
|
217
|
-
offset: "+04:00",
|
|
218
|
-
iana: [
|
|
219
|
-
"Asia/Dubai",
|
|
220
|
-
"Asia/Muscat",
|
|
221
|
-
"Asia/Baku",
|
|
222
|
-
"Asia/Tbilisi"
|
|
223
|
-
]
|
|
224
|
-
},
|
|
225
|
-
{
|
|
226
|
-
value: "Kabul",
|
|
227
|
-
label: "(UTC+04:30) Kabul",
|
|
228
|
-
offset: "+04:30",
|
|
229
|
-
iana: [
|
|
230
|
-
"Asia/Kabul"
|
|
231
|
-
]
|
|
232
|
-
},
|
|
233
|
-
{
|
|
234
|
-
value: "Karachi",
|
|
235
|
-
label: "(UTC+05:00) Karachi",
|
|
236
|
-
offset: "+05:00",
|
|
237
|
-
iana: [
|
|
238
|
-
"Asia/Karachi",
|
|
239
|
-
"Asia/Tashkent",
|
|
240
|
-
"Asia/Yekaterinburg"
|
|
241
|
-
]
|
|
242
|
-
},
|
|
243
|
-
{
|
|
244
|
-
value: "Mumbai",
|
|
245
|
-
label: "(UTC+05:30) Mumbai",
|
|
246
|
-
offset: "+05:30",
|
|
247
|
-
iana: [
|
|
248
|
-
"Asia/Kolkata",
|
|
249
|
-
"Asia/Calcutta",
|
|
250
|
-
"Asia/Colombo"
|
|
251
|
-
]
|
|
252
|
-
},
|
|
253
|
-
{
|
|
254
|
-
value: "Kathmandu",
|
|
255
|
-
label: "(UTC+05:45) Kathmandu",
|
|
256
|
-
offset: "+05:45",
|
|
257
|
-
iana: [
|
|
258
|
-
"Asia/Kathmandu"
|
|
259
|
-
]
|
|
260
|
-
},
|
|
261
|
-
{
|
|
262
|
-
value: "Dhaka",
|
|
263
|
-
label: "(UTC+06:00) Dhaka",
|
|
264
|
-
offset: "+06:00",
|
|
265
|
-
iana: [
|
|
266
|
-
"Asia/Dhaka",
|
|
267
|
-
"Asia/Almaty",
|
|
268
|
-
"Asia/Omsk"
|
|
269
|
-
]
|
|
270
|
-
},
|
|
271
|
-
{
|
|
272
|
-
value: "Yangon",
|
|
273
|
-
label: "(UTC+06:30) Yangon",
|
|
274
|
-
offset: "+06:30",
|
|
275
|
-
iana: [
|
|
276
|
-
"Asia/Yangon",
|
|
277
|
-
"Asia/Rangoon"
|
|
278
|
-
]
|
|
279
|
-
},
|
|
280
|
-
{
|
|
281
|
-
value: "Bangkok",
|
|
282
|
-
label: "(UTC+07:00) Bangkok",
|
|
283
|
-
offset: "+07:00",
|
|
284
|
-
iana: [
|
|
285
|
-
"Asia/Bangkok",
|
|
286
|
-
"Asia/Jakarta",
|
|
287
|
-
"Asia/Ho_Chi_Minh",
|
|
288
|
-
"Asia/Krasnoyarsk"
|
|
289
|
-
]
|
|
290
|
-
},
|
|
291
|
-
{
|
|
292
|
-
value: "Beijing",
|
|
293
|
-
label: "(UTC+08:00) Beijing",
|
|
294
|
-
offset: "+08:00",
|
|
295
|
-
iana: [
|
|
296
|
-
"Asia/Shanghai",
|
|
297
|
-
"Asia/Hong_Kong",
|
|
298
|
-
"Asia/Taipei",
|
|
299
|
-
"Asia/Singapore",
|
|
300
|
-
"Asia/Kuala_Lumpur",
|
|
301
|
-
"Asia/Makassar",
|
|
302
|
-
"Asia/Irkutsk",
|
|
303
|
-
"Australia/Perth"
|
|
304
|
-
]
|
|
305
|
-
},
|
|
306
|
-
{
|
|
307
|
-
value: "Tokyo",
|
|
308
|
-
label: "(UTC+09:00) Tokyo",
|
|
309
|
-
offset: "+09:00",
|
|
310
|
-
iana: [
|
|
311
|
-
"Asia/Tokyo",
|
|
312
|
-
"Asia/Seoul",
|
|
313
|
-
"Asia/Yakutsk"
|
|
314
|
-
]
|
|
315
|
-
},
|
|
316
|
-
{
|
|
317
|
-
value: "Adelaide",
|
|
318
|
-
label: "(UTC+09:30) Adelaide",
|
|
319
|
-
offset: "+09:30",
|
|
320
|
-
iana: [
|
|
321
|
-
"Australia/Adelaide",
|
|
322
|
-
"Australia/Darwin"
|
|
323
|
-
]
|
|
324
|
-
},
|
|
325
|
-
{
|
|
326
|
-
value: "Sydney",
|
|
327
|
-
label: "(UTC+10:00) Sydney",
|
|
328
|
-
offset: "+10:00",
|
|
329
|
-
iana: [
|
|
330
|
-
"Australia/Sydney",
|
|
331
|
-
"Australia/Melbourne",
|
|
332
|
-
"Australia/Brisbane",
|
|
333
|
-
"Australia/Hobart",
|
|
334
|
-
"Pacific/Guam",
|
|
335
|
-
"Asia/Vladivostok"
|
|
336
|
-
]
|
|
337
|
-
},
|
|
338
|
-
{
|
|
339
|
-
value: "Noumea",
|
|
340
|
-
label: "(UTC+11:00) Noumea",
|
|
341
|
-
offset: "+11:00",
|
|
342
|
-
iana: [
|
|
343
|
-
"Pacific/Noumea",
|
|
344
|
-
"Asia/Magadan",
|
|
345
|
-
"Pacific/Guadalcanal"
|
|
346
|
-
]
|
|
347
|
-
},
|
|
348
|
-
{
|
|
349
|
-
value: "Auckland",
|
|
350
|
-
label: "(UTC+12:00) Auckland",
|
|
351
|
-
offset: "+12:00",
|
|
352
|
-
iana: [
|
|
353
|
-
"Pacific/Auckland",
|
|
354
|
-
"Pacific/Fiji",
|
|
355
|
-
"Asia/Kamchatka"
|
|
356
|
-
]
|
|
357
|
-
},
|
|
358
|
-
{
|
|
359
|
-
value: "Nuku'alofa",
|
|
360
|
-
label: "(UTC+13:00) Nuku'alofa",
|
|
361
|
-
offset: "+13:00",
|
|
362
|
-
iana: [
|
|
363
|
-
"Pacific/Tongatapu",
|
|
364
|
-
"Pacific/Apia"
|
|
365
|
-
]
|
|
366
|
-
}
|
|
367
|
-
];
|
|
368
|
-
/**
|
|
369
|
-
* Maps an IANA timezone name (e.g. "Asia/Shanghai") to our timezone list value
|
|
370
|
-
* (e.g. "Beijing"). Returns "UTC" if no match found.
|
|
371
|
-
*
|
|
372
|
-
* @param iana - IANA timezone identifier from Intl.DateTimeFormat
|
|
373
|
-
* @returns The matching timezone value from TIMEZONES
|
|
374
|
-
*
|
|
375
|
-
* @example
|
|
376
|
-
* ```ts
|
|
377
|
-
* mapIanaToTimezone("Asia/Shanghai"); // "Beijing"
|
|
378
|
-
* mapIanaToTimezone("America/New_York"); // "Eastern Time (US & Canada)"
|
|
379
|
-
* mapIanaToTimezone("Unknown/Zone"); // "UTC"
|
|
380
|
-
* ```
|
|
381
|
-
*/ export function mapIanaToTimezone(iana) {
|
|
382
|
-
for (const tz of TIMEZONES){
|
|
383
|
-
if (tz.iana.includes(iana)) {
|
|
384
|
-
return tz.value;
|
|
385
|
-
}
|
|
386
|
-
}
|
|
387
|
-
return "UTC";
|
|
388
|
-
}
|
package/dist/lib/url.js
DELETED
|
@@ -1,89 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* URL Utilities
|
|
3
|
-
*/ /**
|
|
4
|
-
* Extracts the hostname (domain) from a URL string.
|
|
5
|
-
*
|
|
6
|
-
* Parses a full URL and returns just the hostname portion (e.g., "example.com" from
|
|
7
|
-
* "https://example.com/path"). Returns `null` if the URL is malformed or cannot be parsed.
|
|
8
|
-
*
|
|
9
|
-
* @param url - The full URL string to extract the domain from
|
|
10
|
-
* @returns The hostname/domain if valid, or `null` if parsing fails
|
|
11
|
-
*
|
|
12
|
-
* @example
|
|
13
|
-
* ```ts
|
|
14
|
-
* const domain = extractDomain("https://www.example.com/path");
|
|
15
|
-
* // Returns: "www.example.com"
|
|
16
|
-
*
|
|
17
|
-
* const invalid = extractDomain("not-a-url");
|
|
18
|
-
* // Returns: null
|
|
19
|
-
* ```
|
|
20
|
-
*/ export function extractDomain(url) {
|
|
21
|
-
try {
|
|
22
|
-
const parsed = new URL(url);
|
|
23
|
-
return parsed.hostname;
|
|
24
|
-
} catch {
|
|
25
|
-
return null;
|
|
26
|
-
}
|
|
27
|
-
}
|
|
28
|
-
/**
|
|
29
|
-
* Normalizes a path by removing slashes and converting to lowercase.
|
|
30
|
-
*
|
|
31
|
-
* Trims whitespace, converts to lowercase, removes leading and trailing slashes,
|
|
32
|
-
* and collapses multiple consecutive slashes into single slashes. Used to create
|
|
33
|
-
* consistent path representations for routing and storage.
|
|
34
|
-
*
|
|
35
|
-
* @param path - The path string to normalize
|
|
36
|
-
* @returns The normalized path string
|
|
37
|
-
*
|
|
38
|
-
* @example
|
|
39
|
-
* ```ts
|
|
40
|
-
* const normalized = normalizePath(" /About/Contact// ");
|
|
41
|
-
* // Returns: "about/contact"
|
|
42
|
-
* ```
|
|
43
|
-
*/ export function normalizePath(path) {
|
|
44
|
-
return path.trim().toLowerCase().replace(/^\/+|\/+$/g, "").replace(/\/+/g, "/");
|
|
45
|
-
}
|
|
46
|
-
/**
|
|
47
|
-
* Checks if a string is a full URL with HTTP or HTTPS protocol.
|
|
48
|
-
*
|
|
49
|
-
* Validates whether a string starts with "http://" or "https://", indicating it's
|
|
50
|
-
* a full URL rather than a relative path. Useful for distinguishing between internal
|
|
51
|
-
* paths and external URLs.
|
|
52
|
-
*
|
|
53
|
-
* @param str - The string to check
|
|
54
|
-
* @returns `true` if the string starts with http:// or https://, `false` otherwise
|
|
55
|
-
*
|
|
56
|
-
* @example
|
|
57
|
-
* ```ts
|
|
58
|
-
* isFullUrl("https://example.com"); // Returns: true
|
|
59
|
-
* isFullUrl("/about"); // Returns: false
|
|
60
|
-
* isFullUrl("example.com"); // Returns: false
|
|
61
|
-
* ```
|
|
62
|
-
*/ export function isFullUrl(str) {
|
|
63
|
-
return str.startsWith("http://") || str.startsWith("https://");
|
|
64
|
-
}
|
|
65
|
-
/**
|
|
66
|
-
* Converts text to a URL-friendly slug.
|
|
67
|
-
*
|
|
68
|
-
* Transforms text into a lowercase, hyphen-separated slug by:
|
|
69
|
-
* - Converting to lowercase
|
|
70
|
-
* - Removing special characters (keeping only word characters, spaces, and hyphens)
|
|
71
|
-
* - Replacing whitespace and underscores with hyphens
|
|
72
|
-
* - Removing leading and trailing hyphens
|
|
73
|
-
*
|
|
74
|
-
* Used for generating clean URLs from titles and names.
|
|
75
|
-
*
|
|
76
|
-
* @param text - The text to convert to a slug
|
|
77
|
-
* @returns The slugified string
|
|
78
|
-
*
|
|
79
|
-
* @example
|
|
80
|
-
* ```ts
|
|
81
|
-
* const slug = slugify("Hello World! This is a Test.");
|
|
82
|
-
* // Returns: "hello-world-this-is-a-test"
|
|
83
|
-
*
|
|
84
|
-
* const slug = slugify(" Multiple Spaces ");
|
|
85
|
-
* // Returns: "multiple-spaces"
|
|
86
|
-
* ```
|
|
87
|
-
*/ export function slugify(text) {
|
|
88
|
-
return text.toLowerCase().trim().replace(/[^\w\s-]/g, "").replace(/[\s_-]+/g, "-").replace(/^-+|-+$/g, "");
|
|
89
|
-
}
|