@deepsel/cms-utils 1.1.3 → 1.1.5

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 (40) hide show
  1. package/dist/blog/fetchBlogList.d.ts +15 -0
  2. package/dist/blog/fetchBlogList.js +51 -0
  3. package/dist/blog/fetchBlogPost.d.ts +14 -0
  4. package/dist/blog/fetchBlogPost.js +61 -0
  5. package/dist/blog/index.d.ts +3 -0
  6. package/dist/blog/index.js +3 -0
  7. package/dist/blog/types.d.ts +45 -0
  8. package/dist/blog/types.js +1 -0
  9. package/dist/constants/index.d.ts +1 -0
  10. package/dist/constants/index.js +1 -0
  11. package/dist/constants/websiteDataTypes.d.ts +7 -0
  12. package/dist/constants/websiteDataTypes.js +6 -0
  13. package/dist/index.d.ts +2 -1
  14. package/dist/index.js +2 -1
  15. package/dist/menus/isActiveMenu.d.ts +2 -2
  16. package/dist/menus/isActiveMenu.js +2 -2
  17. package/dist/page/fetchPageData.d.ts +9 -1
  18. package/dist/page/fetchPageData.js +22 -22
  19. package/dist/page/fetchSearchResults.d.ts +31 -0
  20. package/dist/page/fetchSearchResults.js +73 -0
  21. package/dist/page/getPathType.d.ts +9 -0
  22. package/dist/page/getPathType.js +46 -0
  23. package/dist/page/index.d.ts +3 -2
  24. package/dist/page/index.js +3 -2
  25. package/dist/page/isCrossingTemplateBoundary.d.ts +1 -0
  26. package/dist/page/isCrossingTemplateBoundary.js +6 -0
  27. package/dist/page/parseSlug.d.ts +12 -0
  28. package/dist/page/{parseSlugForLangAndPath.js → parseSlug.js} +8 -6
  29. package/dist/page/types.d.ts +2 -30
  30. package/dist/types.d.ts +8 -0
  31. package/package.json +6 -65
  32. package/dist/language/index.d.ts +0 -1
  33. package/dist/language/index.js +0 -1
  34. package/dist/page/constants.d.ts +0 -0
  35. package/dist/page/constants.js +0 -1
  36. package/dist/page/fetchFormData.d.ts +0 -4
  37. package/dist/page/fetchFormData.js +0 -38
  38. package/dist/page/parseSlugForLangAndPath.d.ts +0 -5
  39. /package/dist/{language → page}/isValidLanguageCode.d.ts +0 -0
  40. /package/dist/{language → page}/isValidLanguageCode.js +0 -0
@@ -0,0 +1,15 @@
1
+ import type { BlogListData } from './types';
2
+ import type { Pagination } from '../page/getPathType';
3
+ interface FetchBlogListProps {
4
+ lang?: string;
5
+ pagination?: Pagination;
6
+ astroRequest?: Request;
7
+ authToken?: string;
8
+ backendHost?: string;
9
+ }
10
+ /**
11
+ * Fetches blog list from the backend by language
12
+ * Corresponds to GET /blog_post/website/{lang}
13
+ */
14
+ export declare function fetchBlogList({ astroRequest, pagination, authToken, lang, backendHost, }: FetchBlogListProps): Promise<BlogListData>;
15
+ export {};
@@ -0,0 +1,51 @@
1
+ /**
2
+ * Fetches blog list from the backend by language
3
+ * Corresponds to GET /blog_post/website/{lang}
4
+ */
5
+ export async function fetchBlogList({ astroRequest, pagination, authToken, lang = 'default', backendHost = 'http://localhost:8000/api/v1', }) {
6
+ try {
7
+ let url = `${backendHost}/blog_post/list/${lang}`;
8
+ if (pagination) {
9
+ const searchParams = new URLSearchParams();
10
+ if (pagination.page)
11
+ searchParams.append('page', pagination.page.toString());
12
+ if (pagination.pageSize)
13
+ searchParams.append('page_size', pagination.pageSize.toString());
14
+ url += `?${searchParams.toString()}`;
15
+ }
16
+ const fetchOptions = {
17
+ method: 'GET',
18
+ headers: {
19
+ 'Content-Type': 'application/json',
20
+ },
21
+ };
22
+ let hostname = null;
23
+ if (astroRequest) {
24
+ const url = new URL(astroRequest.url);
25
+ hostname = url.hostname;
26
+ }
27
+ else if (typeof window !== 'undefined') {
28
+ hostname = window.location.hostname;
29
+ }
30
+ if (hostname) {
31
+ fetchOptions.headers['X-Original-Host'] = hostname;
32
+ fetchOptions.headers['X-Frontend-Host'] = hostname;
33
+ }
34
+ if (authToken) {
35
+ fetchOptions.headers['Authorization'] = `Bearer ${authToken}`;
36
+ }
37
+ const response = await fetch(url, fetchOptions);
38
+ if (response.status === 401) {
39
+ throw new Error('Authentication required');
40
+ }
41
+ if (!response.ok) {
42
+ throw new Error(`Failed to fetch blog list: ${response.statusText}`);
43
+ }
44
+ const jsonData = await response.json();
45
+ return jsonData;
46
+ }
47
+ catch (error) {
48
+ console.error('Error fetching blog list:', error);
49
+ throw error;
50
+ }
51
+ }
@@ -0,0 +1,14 @@
1
+ import type { BlogPostData } from './types';
2
+ interface FetchBlogPostProps {
3
+ path: string;
4
+ lang?: string;
5
+ astroRequest?: Request;
6
+ authToken?: string;
7
+ backendHost?: string;
8
+ }
9
+ /**
10
+ * Fetches a single blog post from the backend by language and path
11
+ * Corresponds to GET /blog_post/website/{lang}/{path}
12
+ */
13
+ export declare function fetchBlogPost({ path, lang, astroRequest, authToken, backendHost, }: FetchBlogPostProps): Promise<BlogPostData>;
14
+ export {};
@@ -0,0 +1,61 @@
1
+ import { fetchPublicSettings } from '../page';
2
+ /**
3
+ * Fetches a single blog post from the backend by language and path
4
+ * Corresponds to GET /blog_post/website/{lang}/{path}
5
+ */
6
+ export async function fetchBlogPost({ path, lang = 'default', astroRequest, authToken, backendHost = 'http://localhost:8000/api/v1', }) {
7
+ try {
8
+ const cleanPath = path.startsWith('/') ? path.substring(1) : path;
9
+ let postSlug = cleanPath;
10
+ // rm the blog/ prefix
11
+ if (cleanPath.startsWith('blog/')) {
12
+ postSlug = cleanPath.substring('blog/'.length);
13
+ }
14
+ const url = `${backendHost}/blog_post/single/${lang}/${postSlug}`;
15
+ const fetchOptions = {
16
+ method: 'GET',
17
+ headers: {
18
+ 'Content-Type': 'application/json',
19
+ },
20
+ };
21
+ let hostname = null;
22
+ if (astroRequest) {
23
+ const url = new URL(astroRequest.url);
24
+ hostname = url.hostname;
25
+ }
26
+ else if (typeof window !== 'undefined') {
27
+ hostname = window.location.hostname;
28
+ }
29
+ if (hostname) {
30
+ fetchOptions.headers['X-Original-Host'] = hostname;
31
+ fetchOptions.headers['X-Frontend-Host'] = hostname;
32
+ }
33
+ if (authToken) {
34
+ fetchOptions.headers['Authorization'] = `Bearer ${authToken}`;
35
+ }
36
+ const response = await fetch(url, fetchOptions);
37
+ if (response.status === 401) {
38
+ throw new Error('Authentication required');
39
+ }
40
+ if (response.status === 404) {
41
+ try {
42
+ const { detail } = (await response.json());
43
+ console.warn('404', url, { detail });
44
+ }
45
+ catch {
46
+ console.warn('404', url);
47
+ }
48
+ const siteSettings = await fetchPublicSettings(null, astroRequest, lang, backendHost);
49
+ return {
50
+ notFound: true,
51
+ public_settings: siteSettings,
52
+ };
53
+ }
54
+ const jsonData = await response.json();
55
+ return jsonData;
56
+ }
57
+ catch (error) {
58
+ console.error('Error fetching blog post:', error);
59
+ throw error;
60
+ }
61
+ }
@@ -0,0 +1,3 @@
1
+ export * from './fetchBlogList';
2
+ export * from './fetchBlogPost';
3
+ export * from './types';
@@ -0,0 +1,3 @@
1
+ export * from './fetchBlogList';
2
+ export * from './fetchBlogPost';
3
+ export * from './types';
@@ -0,0 +1,45 @@
1
+ import type { SiteSettings } from '../types';
2
+ import type { SeoMetadata, LanguageAlternative } from '../page/types';
3
+ export interface BlogPostAuthor {
4
+ id: number;
5
+ display_name?: string;
6
+ username: string;
7
+ image?: string;
8
+ }
9
+ export interface BlogPostListItem {
10
+ id: number;
11
+ title: string;
12
+ slug: string;
13
+ excerpt?: string;
14
+ featured_image_id?: number;
15
+ featured_image_name?: string;
16
+ publish_date?: string;
17
+ author?: BlogPostAuthor;
18
+ lang: string;
19
+ }
20
+ export interface BlogListData {
21
+ lang: string;
22
+ public_settings: SiteSettings;
23
+ blog_posts: BlogPostListItem[];
24
+ page: number;
25
+ page_size: number;
26
+ total_count: number;
27
+ total_pages: number;
28
+ }
29
+ export interface BlogPostData {
30
+ id?: number;
31
+ title?: string;
32
+ content?: string;
33
+ lang?: string;
34
+ public_settings: SiteSettings;
35
+ seo_metadata?: SeoMetadata;
36
+ custom_code?: string | null;
37
+ page_custom_code?: string | null;
38
+ require_login?: boolean | null;
39
+ featured_image_id?: number | null;
40
+ featured_image_name?: string | null;
41
+ publish_date?: string | null;
42
+ author?: BlogPostAuthor | null;
43
+ language_alternatives?: LanguageAlternative[];
44
+ notFound?: boolean;
45
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1 @@
1
+ export * from './websiteDataTypes';
@@ -0,0 +1 @@
1
+ export * from './websiteDataTypes';
@@ -0,0 +1,7 @@
1
+ export declare const WebsiteDataTypes: {
2
+ readonly Page: "Page";
3
+ readonly BlogList: "BlogList";
4
+ readonly BlogPost: "BlogPost";
5
+ readonly SearchResults: "SearchResults";
6
+ };
7
+ export type WebsiteDataType = (typeof WebsiteDataTypes)[keyof typeof WebsiteDataTypes];
@@ -0,0 +1,6 @@
1
+ export const WebsiteDataTypes = {
2
+ Page: 'Page',
3
+ BlogList: 'BlogList',
4
+ BlogPost: 'BlogPost',
5
+ SearchResults: 'SearchResults',
6
+ };
package/dist/index.d.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  export * from './page';
2
- export * from './language';
3
2
  export * from './menus';
3
+ export * from './blog';
4
4
  export * from './types';
5
+ export * from './constants';
package/dist/index.js CHANGED
@@ -1,4 +1,5 @@
1
1
  export * from './page';
2
- export * from './language';
3
2
  export * from './menus';
3
+ export * from './blog';
4
4
  export * from './types';
5
+ export * from './constants';
@@ -1,3 +1,3 @@
1
1
  import type { MenuItem } from './types';
2
- import type { PageData } from '../page';
3
- export declare const isActiveMenu: (menuItem: MenuItem, pageData: PageData) => boolean;
2
+ import type { WebsiteData } from '../types';
3
+ export declare const isActiveMenu: (menuItem: MenuItem, websiteData: WebsiteData) => boolean;
@@ -1,11 +1,11 @@
1
1
  // Check if a menu item should be marked as active
2
- export const isActiveMenu = (menuItem, pageData) => {
2
+ export const isActiveMenu = (menuItem, websiteData) => {
3
3
  // return if not browser
4
4
  if (typeof window === 'undefined') {
5
5
  return false;
6
6
  }
7
7
  const location = window.location;
8
- const currentLang = pageData.lang;
8
+ const currentLang = websiteData.data.lang;
9
9
  let result;
10
10
  if (menuItem.url === '/') {
11
11
  result =
@@ -1,5 +1,13 @@
1
1
  import type { PageData } from './types';
2
+ interface FetchPageDataProps {
3
+ path: string;
4
+ lang?: string;
5
+ astroRequest?: Request;
6
+ authToken?: string;
7
+ backendHost?: string;
8
+ }
2
9
  /**
3
10
  * Fetches page data from the backend by language and slug
4
11
  */
5
- export declare function fetchPageData(lang: string | null, slug: string, isPreview?: boolean, authToken?: string | null, astroRequest?: Request | null, backendHost?: string): Promise<PageData>;
12
+ export declare function fetchPageData({ path, lang, astroRequest, authToken, backendHost, }: FetchPageDataProps): Promise<PageData>;
13
+ export {};
@@ -2,25 +2,23 @@ import { fetchPublicSettings } from './fetchPublicSettings';
2
2
  /**
3
3
  * Fetches page data from the backend by language and slug
4
4
  */
5
- export async function fetchPageData(lang, slug, isPreview = false, authToken = null, astroRequest = null, backendHost = 'http://localhost:8000') {
5
+ export async function fetchPageData({ path, lang, astroRequest, authToken, backendHost = 'http://localhost:8000/api/v1', }) {
6
6
  try {
7
- // Format the slug properly, make sure it starts with a slash
8
- let formattedSlug = slug.startsWith('/') ? slug : `/${slug}`;
7
+ // Format the path properly, make sure it starts with a slash
8
+ let formattedPath = path.startsWith('/') ? path : `/${path}`;
9
9
  // Backend will consider 'default' as the home slug
10
- if (formattedSlug === '/') {
11
- formattedSlug = '/default';
10
+ if (formattedPath === '/') {
11
+ formattedPath = '/default';
12
12
  }
13
13
  // Determine the URL based on whether a language is provided
14
- let url;
15
- if (lang && lang !== 'default') {
16
- url = `${backendHost}/page/website/${lang}${formattedSlug}`;
17
- }
18
- else {
19
- url = `${backendHost}/page/website/default${formattedSlug}`;
20
- }
14
+ const langPrefix = lang || 'default';
15
+ let url = `${backendHost}/page/website/${langPrefix}${formattedPath}`;
21
16
  // Add preview parameter if enabled
22
- if (isPreview) {
23
- url += '?preview=true';
17
+ if (astroRequest) {
18
+ const previewParam = new URL(astroRequest.url).searchParams.get('preview');
19
+ if (previewParam === 'true') {
20
+ url += `?preview=true`;
21
+ }
24
22
  }
25
23
  // Prepare fetch options
26
24
  const fetchOptions = {
@@ -33,8 +31,8 @@ export async function fetchPageData(lang, slug, isPreview = false, authToken = n
33
31
  let hostname = null;
34
32
  // Server-side: Extract hostname from Astro request
35
33
  if (astroRequest) {
36
- const url = new URL(astroRequest.url);
37
- hostname = url.hostname;
34
+ const requestUrl = new URL(astroRequest.url);
35
+ hostname = requestUrl.hostname;
38
36
  }
39
37
  // Client-side: Extract hostname from window
40
38
  else if (typeof window !== 'undefined') {
@@ -57,22 +55,24 @@ export async function fetchPageData(lang, slug, isPreview = false, authToken = n
57
55
  }
58
56
  // Only treat actual 404 as not found
59
57
  if (response.status === 404) {
60
- const { detail } = await response.json();
61
- console.warn('404', url, { detail });
58
+ try {
59
+ const { detail } = await response.json();
60
+ console.warn('404', url, { detail });
61
+ }
62
+ catch {
63
+ console.warn('404', url);
64
+ }
62
65
  // When page is not found, still fetch menus and site settings
63
66
  try {
64
67
  const siteSettings = await fetchPublicSettings(null, astroRequest, lang, backendHost);
65
68
  return {
66
69
  notFound: true,
67
- status: 404,
68
- detail,
69
70
  public_settings: siteSettings,
70
- lang: lang || siteSettings.default_language?.iso_code || 'en',
71
71
  };
72
72
  }
73
73
  catch (settingsError) {
74
74
  console.warn('Could not fetch site settings for 404 page:', settingsError);
75
- throw new Error(`Page not found: ${detail}`);
75
+ throw new Error(`Page not found`);
76
76
  }
77
77
  }
78
78
  try {
@@ -0,0 +1,31 @@
1
+ import type { SiteSettings } from '../types';
2
+ export interface SearchResultItem {
3
+ id: string;
4
+ title: string;
5
+ url: string;
6
+ publishDate: string | null;
7
+ contentType: string;
8
+ relevanceScore: number;
9
+ }
10
+ export interface SearchResultsData {
11
+ lang: string;
12
+ query: string;
13
+ public_settings: SiteSettings;
14
+ results: SearchResultItem[];
15
+ total: number;
16
+ suggestions: string[];
17
+ }
18
+ interface FetchSearchResultsProps {
19
+ lang?: string;
20
+ q: string;
21
+ limit?: number;
22
+ astroRequest?: Request;
23
+ authToken?: string;
24
+ backendHost?: string;
25
+ }
26
+ /**
27
+ * Fetches search results from the backend.
28
+ * Calls GET /api/v1/page/website_search/{lang}?q=...&limit=...
29
+ */
30
+ export declare function fetchSearchResults({ lang, q, limit, astroRequest, authToken, backendHost, }: FetchSearchResultsProps): Promise<SearchResultsData>;
31
+ export {};
@@ -0,0 +1,73 @@
1
+ import { fetchPublicSettings } from './fetchPublicSettings';
2
+ /**
3
+ * Fetches search results from the backend.
4
+ * Calls GET /api/v1/page/website_search/{lang}?q=...&limit=...
5
+ */
6
+ export async function fetchSearchResults({ lang = 'default', q, limit = 100, astroRequest, authToken, backendHost = 'http://localhost:8000/api/v1', }) {
7
+ // Build hostname for headers
8
+ let hostname = null;
9
+ if (astroRequest) {
10
+ const requestUrl = new URL(astroRequest.url);
11
+ hostname = requestUrl.hostname;
12
+ }
13
+ else if (typeof window !== 'undefined') {
14
+ hostname = window.location.hostname;
15
+ }
16
+ const headers = {
17
+ 'Content-Type': 'application/json',
18
+ };
19
+ if (hostname) {
20
+ headers['X-Original-Host'] = hostname;
21
+ headers['X-Frontend-Host'] = hostname;
22
+ }
23
+ if (authToken) {
24
+ headers['Authorization'] = `Bearer ${authToken}`;
25
+ }
26
+ // Always fetch public_settings alongside the search call
27
+ const settingsPromise = fetchPublicSettings(null, astroRequest ?? null, lang, `http://localhost:8000`);
28
+ // If no query, skip the search call and return empty results
29
+ if (!q.trim()) {
30
+ const public_settings = await settingsPromise;
31
+ // Normalize lang: replace 'default' with the actual ISO code from settings
32
+ const resolvedLang = lang === 'default' ? public_settings.default_language?.iso_code || lang : lang;
33
+ return {
34
+ lang: resolvedLang,
35
+ query: q,
36
+ public_settings,
37
+ results: [],
38
+ total: 0,
39
+ suggestions: [],
40
+ };
41
+ }
42
+ const searchParams = new URLSearchParams({ q, limit: String(limit) });
43
+ const searchUrl = `${backendHost}/page/website_search/${lang}?${searchParams.toString()}`;
44
+ const [public_settings, searchResponse] = await Promise.allSettled([
45
+ settingsPromise,
46
+ fetch(searchUrl, { method: 'GET', headers }),
47
+ ]);
48
+ const resolvedSettings = public_settings.status === 'fulfilled' ? public_settings.value : {};
49
+ // Normalize lang: replace 'default' with the actual ISO code from settings
50
+ const resolvedLang = lang === 'default' ? resolvedSettings.default_language?.iso_code || lang : lang;
51
+ if (searchResponse.status === 'rejected' || !searchResponse.value.ok) {
52
+ console.error('Error fetching search results:', searchResponse.status === 'rejected'
53
+ ? searchResponse.reason
54
+ : searchResponse.value.statusText);
55
+ return {
56
+ lang: resolvedLang,
57
+ query: q,
58
+ public_settings: resolvedSettings,
59
+ results: [],
60
+ total: 0,
61
+ suggestions: [],
62
+ };
63
+ }
64
+ const apiData = await searchResponse.value.json();
65
+ return {
66
+ lang: resolvedLang,
67
+ query: q,
68
+ public_settings: resolvedSettings,
69
+ results: apiData.results ?? [],
70
+ total: apiData.total ?? 0,
71
+ suggestions: apiData.suggestions ?? [],
72
+ };
73
+ }
@@ -0,0 +1,9 @@
1
+ import { type WebsiteDataType } from '../constants';
2
+ export interface Pagination {
3
+ page?: number;
4
+ pageSize?: number;
5
+ }
6
+ export declare function getPathType(path: string): {
7
+ pathType: WebsiteDataType;
8
+ pagination?: Pagination;
9
+ };
@@ -0,0 +1,46 @@
1
+ import { WebsiteDataTypes } from '../constants';
2
+ export function getPathType(path) {
3
+ let pathType = WebsiteDataTypes.Page;
4
+ let pagination = undefined;
5
+ // delete forward at the beginning
6
+ if (path.startsWith('/')) {
7
+ path = path.slice(1);
8
+ }
9
+ if (path === 'search' || path.startsWith('search?') || path.startsWith('search/')) {
10
+ return { pathType: WebsiteDataTypes.SearchResults };
11
+ }
12
+ if (path.startsWith('blog')) {
13
+ // split
14
+ const parts = path.split('/');
15
+ let pageSize = undefined;
16
+ // extract query parameters if any
17
+ const queryString = path.split('?')[1];
18
+ if (queryString) {
19
+ const params = new URLSearchParams(queryString);
20
+ const size = params.get('pageSize');
21
+ if (size && !isNaN(Number(size))) {
22
+ pageSize = Number(size);
23
+ }
24
+ }
25
+ // check which blog list format, either /blog, /blog/page/2, or /blog/{slug}
26
+ if (parts.length > 1 && parts[1] !== '') {
27
+ // /blog/page/2
28
+ if (parts[1] === 'page' && parts[2] && !isNaN(Number(parts[2]))) {
29
+ pathType = WebsiteDataTypes.BlogList;
30
+ pagination = { page: Number(parts[2]), pageSize };
31
+ }
32
+ // /blog/{slug}
33
+ else {
34
+ pathType = WebsiteDataTypes.BlogPost;
35
+ }
36
+ }
37
+ else {
38
+ // /blog
39
+ pathType = WebsiteDataTypes.BlogList;
40
+ if (pageSize) {
41
+ pagination = { pageSize };
42
+ }
43
+ }
44
+ }
45
+ return { pathType, pagination };
46
+ }
@@ -1,6 +1,7 @@
1
- export * from './fetchFormData';
2
1
  export * from './fetchPageData';
3
2
  export * from './fetchPublicSettings';
3
+ export * from './fetchSearchResults';
4
4
  export * from './getAuthToken';
5
- export * from './parseSlugForLangAndPath';
5
+ export * from './parseSlug';
6
6
  export * from './types';
7
+ export * from './isCrossingTemplateBoundary';
@@ -1,6 +1,7 @@
1
- export * from './fetchFormData';
2
1
  export * from './fetchPageData';
3
2
  export * from './fetchPublicSettings';
3
+ export * from './fetchSearchResults';
4
4
  export * from './getAuthToken';
5
- export * from './parseSlugForLangAndPath';
5
+ export * from './parseSlug';
6
6
  export * from './types';
7
+ export * from './isCrossingTemplateBoundary';
@@ -0,0 +1 @@
1
+ export declare const isCrossingTemplateBoundary: (fromPath: string, toPath: string) => boolean;
@@ -0,0 +1,6 @@
1
+ import { getPathType } from './getPathType';
2
+ export const isCrossingTemplateBoundary = (fromPath, toPath) => {
3
+ const fromPathType = getPathType(fromPath).pathType;
4
+ const toPathType = getPathType(toPath).pathType;
5
+ return fromPathType !== toPathType;
6
+ };
@@ -0,0 +1,12 @@
1
+ import type { Pagination } from './getPathType';
2
+ import type { WebsiteDataType } from '../constants';
3
+ export interface SlugParseResult {
4
+ lang?: string;
5
+ path: string;
6
+ pathType: WebsiteDataType;
7
+ pagination?: Pagination;
8
+ }
9
+ /**
10
+ * Parses a slug to determine language and path
11
+ */
12
+ export declare function parseSlug(slug: string | null): SlugParseResult;
@@ -1,10 +1,11 @@
1
- import { isValidLanguageCode } from '../language';
1
+ import { isValidLanguageCode } from './isValidLanguageCode';
2
+ import { getPathType } from './getPathType';
2
3
  /**
3
4
  * Parses a slug to determine language and path
4
5
  */
5
- export function parseSlugForLangAndPath(slug) {
6
+ export function parseSlug(slug) {
6
7
  const slugParts = slug ? slug.split('/').filter(Boolean) : [];
7
- let lang = null;
8
+ let lang;
8
9
  let path = '/';
9
10
  // Check if the first part is a valid language code
10
11
  if (slugParts.length > 0 && isValidLanguageCode(slugParts[0])) {
@@ -15,8 +16,9 @@ export function parseSlugForLangAndPath(slug) {
15
16
  }
16
17
  }
17
18
  else {
18
- // No language in URL, use the path as is with a leading slash
19
- path = slugParts.length > 0 ? '/' + slugParts.join('/') : '/';
19
+ // No language in URL, use the path as is
20
+ path = slugParts.length > 0 ? slugParts.join('/') : '/';
20
21
  }
21
- return { lang, path };
22
+ const { pathType, pagination } = getPathType(path);
23
+ return { lang, path, pathType, pagination };
22
24
  }
@@ -1,9 +1,5 @@
1
1
  import type { SiteSettings } from '../types';
2
2
  import type { MenuItem } from '../menus/types';
3
- export interface SlugParseResult {
4
- lang: string | null;
5
- path: string;
6
- }
7
3
  export interface Language {
8
4
  id: number;
9
5
  name: string;
@@ -35,41 +31,17 @@ export interface LanguageAlternative {
35
31
  slug: string;
36
32
  locale: Language;
37
33
  }
38
- export interface BlogPostAuthor {
39
- id: number;
40
- display_name?: string;
41
- username: string;
42
- image?: string;
43
- }
44
- export interface BlogPostListItem {
45
- id: number;
46
- title: string;
47
- slug: string;
48
- excerpt?: string;
49
- featured_image_id?: number;
50
- publish_date?: string;
51
- author?: BlogPostAuthor;
52
- lang: string;
53
- }
54
34
  export interface PageData {
55
35
  id?: number;
56
36
  title?: string;
57
37
  content?: Content;
58
- lang: string;
38
+ slug?: string;
39
+ lang?: string;
59
40
  public_settings: SiteSettings;
60
41
  seo_metadata?: SeoMetadata;
61
42
  language_alternatives?: LanguageAlternative[];
62
- is_frontend_page?: boolean | null;
63
- string_id?: string | null;
64
- contents?: unknown;
65
43
  page_custom_code?: string | null;
66
44
  custom_code?: string | null;
67
45
  require_login?: boolean;
68
- blog_posts?: BlogPostListItem[];
69
- featured_image_id?: number;
70
- publish_date?: string;
71
- author?: BlogPostAuthor;
72
46
  notFound?: boolean;
73
- status?: number;
74
- detail?: string;
75
47
  }
package/dist/types.d.ts CHANGED
@@ -1,5 +1,13 @@
1
1
  import type { MenuItem } from './menus/types';
2
2
  import type { SpecialTemplate } from './page/types';
3
+ import type { WebsiteDataType } from './constants';
4
+ import type { PageData, SearchResultsData } from './page';
5
+ import type { BlogListData, BlogPostData } from './blog';
6
+ export type WebsiteData = {
7
+ type: WebsiteDataType;
8
+ data: PageData | BlogListData | BlogPostData | SearchResultsData;
9
+ settings?: SiteSettings;
10
+ };
3
11
  export interface SiteSettings {
4
12
  id: number;
5
13
  name: string;
package/package.json CHANGED
@@ -1,7 +1,12 @@
1
1
  {
2
2
  "name": "@deepsel/cms-utils",
3
- "version": "1.1.3",
3
+ "version": "1.1.5",
4
4
  "description": "Helper utilities for Deepsel CMS",
5
+ "repository": {
6
+ "type": "git",
7
+ "url": "https://github.com/DeepselSystems/deepsel-cms",
8
+ "directory": "packages/cms-utils"
9
+ },
5
10
  "publishConfig": {
6
11
  "access": "public"
7
12
  },
@@ -20,70 +25,6 @@
20
25
  ".": {
21
26
  "import": "./dist/index.js",
22
27
  "types": "./dist/index.d.ts"
23
- },
24
- "./types": {
25
- "import": "./dist/types.js",
26
- "types": "./dist/types.d.ts"
27
- },
28
- "./language": {
29
- "import": "./dist/language/index.js",
30
- "types": "./dist/language/index.d.ts"
31
- },
32
- "./language/isValidLanguageCode": {
33
- "import": "./dist/language/isValidLanguageCode.js",
34
- "types": "./dist/language/isValidLanguageCode.d.ts"
35
- },
36
- "./menus": {
37
- "import": "./dist/menus/index.js",
38
- "types": "./dist/menus/index.d.ts"
39
- },
40
- "./menus/isActiveMenu": {
41
- "import": "./dist/menus/isActiveMenu.js",
42
- "types": "./dist/menus/isActiveMenu.d.ts"
43
- },
44
- "./menus/types": {
45
- "import": "./dist/menus/types.js",
46
- "types": "./dist/menus/types.d.ts"
47
- },
48
- "./page": {
49
- "import": "./dist/page/index.js",
50
- "types": "./dist/page/index.d.ts"
51
- },
52
- "./page/constants": {
53
- "import": "./dist/page/constants.js",
54
- "types": "./dist/page/constants.d.ts"
55
- },
56
- "./page/types": {
57
- "import": "./dist/page/types.js",
58
- "types": "./dist/page/types.d.ts"
59
- },
60
- "./page/fetchBlogListData": {
61
- "import": "./dist/page/fetchBlogListData.js",
62
- "types": "./dist/page/fetchBlogListData.d.ts"
63
- },
64
- "./page/fetchBlogPostData": {
65
- "import": "./dist/page/fetchBlogPostData.js",
66
- "types": "./dist/page/fetchBlogPostData.d.ts"
67
- },
68
- "./page/fetchFormData": {
69
- "import": "./dist/page/fetchFormData.js",
70
- "types": "./dist/page/fetchFormData.d.ts"
71
- },
72
- "./page/fetchPageData": {
73
- "import": "./dist/page/fetchPageData.js",
74
- "types": "./dist/page/fetchPageData.d.ts"
75
- },
76
- "./page/fetchPublicSettings": {
77
- "import": "./dist/page/fetchPublicSettings.js",
78
- "types": "./dist/page/fetchPublicSettings.d.ts"
79
- },
80
- "./page/getAuthToken": {
81
- "import": "./dist/page/getAuthToken.js",
82
- "types": "./dist/page/getAuthToken.d.ts"
83
- },
84
- "./page/parseSlugForLangAndPath": {
85
- "import": "./dist/page/parseSlugForLangAndPath.js",
86
- "types": "./dist/page/parseSlugForLangAndPath.d.ts"
87
28
  }
88
29
  },
89
30
  "files": [
@@ -1 +0,0 @@
1
- export * from './isValidLanguageCode';
@@ -1 +0,0 @@
1
- export * from './isValidLanguageCode';
File without changes
@@ -1 +0,0 @@
1
- "use strict";
@@ -1,4 +0,0 @@
1
- /**
2
- * Fetches Form data from the backend by language and slug
3
- */
4
- export declare function fetchFormData(lang: string, slug: string, backendHost?: string): Promise<Record<string, unknown>>;
@@ -1,38 +0,0 @@
1
- /**
2
- * Fetches Form data from the backend by language and slug
3
- */
4
- export async function fetchFormData(lang, slug, backendHost = 'http://localhost:8000') {
5
- try {
6
- // Format the slug properly
7
- const formattedSlug = slug.replace(/^\/forms\//, '');
8
- // Determine the URL based on whether a language is provided
9
- const url = `${backendHost}/form/website/${lang}/${formattedSlug}`;
10
- // Prepare fetch options
11
- const fetchOptions = {
12
- method: 'GET',
13
- headers: {
14
- 'Content-Type': 'application/json',
15
- },
16
- };
17
- // Fetch the page data from the backend
18
- const response = await fetch(url, fetchOptions);
19
- // Only treat actual 404 as not found
20
- if (response.status === 404) {
21
- const { detail } = await response.json();
22
- console.warn('404', url, { detail });
23
- return { notFound: true, status: 404, detail };
24
- }
25
- try {
26
- // Parse the JSON
27
- return await response.json();
28
- }
29
- catch (parseError) {
30
- console.error(`Failed to parse response: ${parseError.message}`);
31
- return { error: true, parseError: parseError.message };
32
- }
33
- }
34
- catch (error) {
35
- console.error('Error fetching page data:', error);
36
- return { error: true, message: error.message };
37
- }
38
- }
@@ -1,5 +0,0 @@
1
- import type { SlugParseResult } from './types';
2
- /**
3
- * Parses a slug to determine language and path
4
- */
5
- export declare function parseSlugForLangAndPath(slug: string | null): SlugParseResult;
File without changes