UNPKG

studiocms

Version:

Astro Native CMS for AstroDB. Built from the ground up by the Astro community.

837 lines (836 loc) 36.6 kB
import { asc, eq, or } from "astro:db"; import config from "studiocms:config"; import { CMSNotificationSettingsId, GhostUserDefaults, versionCacheLifetime } from "../../../consts.js"; import { Effect, genLogger } from "../../../effect.js"; import { FolderListMapID, FolderTreeMapID, PageFolderTreeMapID, SiteConfigMapID, StudioCMSPkgId, VersionMapID } from "../consts.js"; import { AstroDB, GetVersionFromNPM, SDKCore_Collectors, SDKCore_FolderTree, SDKCore_Users } from "../effect/index.js"; import { SDKCoreError, StudioCMS_SDK_Error } from "../errors.js"; import { tsDiffTracking, tsEmailVerificationTokens, tsNotificationSettings, tsOAuthAccounts, tsPageContent, tsPageData, tsPageDataCategories, tsPageDataTags, tsPageFolderStructure, tsPermissions, tsSessionTable, tsUsers } from "../tables.js"; import { _ClearUnknownError, _clearLibSQLError, CacheContext, convertCombinedPageDataToMetaOnly, filterPagesByDraftAndIndex, folderListReturn, folderTreeReturn, isCacheEnabled, isCacheExpired, pageDataReturn, siteConfigReturn, versionReturn } from "../utils.js"; import { SDKCore_CONFIG } from "./config.js"; class SDKCore_GET extends Effect.Service()( "studiocms/sdk/SDKCore/modules/get", { dependencies: [ AstroDB.Default, SDKCore_FolderTree.Default, GetVersionFromNPM.Default, SDKCore_Users.Default, SDKCore_Collectors.Default, SDKCore_CONFIG.Default ], effect: genLogger("studiocms/sdk/SDKCore/modules/get/effect")(function* () { const [ dbService, { FolderList, pages, folderTree, version, siteConfig, pageFolderTree }, { buildFolderTree, getAvailableFolders, addPageToFolderTree }, getVersionFromNPM, { combineRanks, verifyRank }, { collectUserData, collectPageData }, { siteConfig: sdkSiteConfig } ] = yield* Effect.all([ AstroDB, CacheContext, SDKCore_FolderTree, GetVersionFromNPM, SDKCore_Users, SDKCore_Collectors, SDKCore_CONFIG ]); const validatePagination = Effect.fn(function* (paginate) { if (paginate.limit < 0 || paginate.offset < 0) { return yield* Effect.fail( new SDKCoreError({ type: "UNKNOWN", cause: new StudioCMS_SDK_Error( "Pagination limit and offset must be non-negative values" ) }) ); } if (paginate.limit === 0) { paginate.limit = 10; } return paginate; }); const getFolderByNameOrId = Effect.fn(function* (idOrName) { const data = yield* dbService.execute( (db) => db.select().from(tsPageFolderStructure).where( or(eq(tsPageFolderStructure.id, idOrName), eq(tsPageFolderStructure.name, idOrName)) ).get() ); if (!data) { return yield* Effect.fail( new SDKCoreError({ type: "LibSQLDatabaseError", cause: new StudioCMS_SDK_Error(`Folder not found in Database: ${idOrName}`) }) ); } return data; }); function _getPackagesPages(packageName, tree, metaOnly = false) { return Effect.gen(function* () { const pagesRaw = yield* dbService.execute( (db) => db.select().from(tsPageData).where(eq(tsPageData.package, packageName)) ); const folders = tree || (yield* buildFolderTree); const pages2 = []; for (const page of pagesRaw) { const data = yield* collectPageData(page, folders, metaOnly); pages2.push(data); } if (metaOnly) { return pages2; } return pages2; }).pipe( Effect.catchTags({ LibSQLClientError: (cause) => _clearLibSQLError("GET.packagePages", cause) }) ); } function _getPageById(id, metaOnly = false) { const getPage = (id2, tree) => Effect.gen(function* () { const page = yield* dbService.execute( (db) => db.select().from(tsPageData).where(eq(tsPageData.id, id2)).get() ); if (!page) return void 0; const folders = tree || (yield* buildFolderTree); return yield* collectPageData(page, folders); }); return Effect.gen(function* () { const status = yield* isCacheEnabled; if (!status) { const page = yield* getPage(id); if (!page) { return void 0; } const pageData = pageDataReturn(page); return metaOnly ? convertCombinedPageDataToMetaOnly(pageData) : pageData; } const { data: tree } = yield* GET.folderTree(); const cachedPage = pages.get(id); if (!cachedPage || isCacheExpired(cachedPage)) { const page = yield* getPage(id, tree); if (!page) { return void 0; } const returnPage = pageDataReturn(page); pages.set(id, returnPage); return metaOnly ? convertCombinedPageDataToMetaOnly(returnPage) : returnPage; } return metaOnly ? convertCombinedPageDataToMetaOnly(cachedPage) : cachedPage; }).pipe( Effect.catchTags({ UnknownException: (cause) => _clearLibSQLError("GET.page.byId", cause), LibSQLClientError: (cause) => _clearLibSQLError("GET.page.byId", cause) }) ); } function _getPageBySlug(slug, metaOnly = false) { const getPage = (iSlug, tree) => Effect.gen(function* () { const page = yield* dbService.execute( (db) => db.select().from(tsPageData).where(eq(tsPageData.slug, iSlug)).get() ); if (!page) return void 0; const folders = tree || (yield* buildFolderTree); return yield* collectPageData(page, folders); }); return Effect.gen(function* () { const status = yield* isCacheEnabled; if (!status) { const page = yield* getPage(slug); if (!page) { return void 0; } const pageData = pageDataReturn(page); return metaOnly ? convertCombinedPageDataToMetaOnly(pageData) : pageData; } const { data: tree } = yield* GET.folderTree(); const cachedPage = Array.from(pages.values()).find((page) => page.data.slug === slug); if (!cachedPage || isCacheExpired(cachedPage)) { const page = yield* getPage(slug, tree); if (!page) { return void 0; } const pageData = pageDataReturn(page); pages.set(page.id, pageData); return metaOnly ? convertCombinedPageDataToMetaOnly(pageData) : pageData; } return metaOnly ? convertCombinedPageDataToMetaOnly(cachedPage) : cachedPage; }).pipe( Effect.catchTags({ UnknownException: (cause) => _clearLibSQLError("GET.page.bySlug", cause), LibSQLClientError: (cause) => _clearLibSQLError("GET.page.bySlug", cause) }) ); } function _getAllPages(includeDrafts = false, hideDefaultIndex = false, metaOnly = false, paginate) { const getPages = (includeDrafts2 = false, hideDefaultIndex2 = false, tree, paginate2) => Effect.gen(function* () { let pagesRaw = []; if (paginate2) { const paginateData = yield* validatePagination(paginate2); pagesRaw = yield* dbService.execute( (db) => db.select().from(tsPageData).orderBy(asc(tsPageData.title)).limit(paginateData.limit).offset(paginateData.offset) ); } else { pagesRaw = yield* dbService.execute( (db) => db.select().from(tsPageData).orderBy(asc(tsPageData.title)) ); } const pagesFiltered = filterPagesByDraftAndIndex( pagesRaw, includeDrafts2, hideDefaultIndex2 ); const folders = tree || (yield* buildFolderTree); const pages2 = []; for (const page of pagesFiltered) { const data = yield* collectPageData(page, folders); pages2.push(data); } return pages2; }); return Effect.gen(function* () { const status = yield* isCacheEnabled; if (!status) { const dbPages = yield* getPages(includeDrafts, hideDefaultIndex, void 0, paginate); const data2 = dbPages.map((page) => pageDataReturn(page)); return metaOnly ? convertCombinedPageDataToMetaOnly(data2) : data2; } const { data: tree } = yield* GET.folderTree(); if (pages.size === 0) { const newData = yield* getPages(includeDrafts, hideDefaultIndex, tree); for (const data3 of newData) { pages.set(data3.id, pageDataReturn(data3)); } const data2 = newData.map((data3) => pageDataReturn(data3)); if (paginate) { const sortedData = data2.sort((a, b) => a.data.title.localeCompare(b.data.title)); const paginatedData = sortedData.slice( paginate.offset, paginate.offset + paginate.limit ); return metaOnly ? convertCombinedPageDataToMetaOnly(paginatedData) : paginatedData; } return metaOnly ? convertCombinedPageDataToMetaOnly(data2) : data2; } const cacheMap = Array.from(pages.values()); for (const item of cacheMap) { if (isCacheExpired(item)) { const updated = yield* GET.page.byId(item.data.id); if (!updated) { pages.delete(item.data.id); continue; } pages.set(updated.data.id, updated); } } const data = Array.from(pages.values()); if (paginate) { const sortedData = data.sort((a, b) => a.data.title.localeCompare(b.data.title)); const paginatedData = sortedData.slice( paginate.offset, paginate.offset + paginate.limit ); return metaOnly ? convertCombinedPageDataToMetaOnly(paginatedData) : paginatedData; } return metaOnly ? convertCombinedPageDataToMetaOnly(data) : data; }).pipe( Effect.catchTags({ UnknownException: (cause) => _clearLibSQLError("GET.pages", cause), LibSQLClientError: (cause) => _clearLibSQLError("GET.pages", cause) }) ); } function _folderPages(idOrName, includeDrafts = false, hideDefaultIndex = false, metaOnly = false, paginate) { const getAllPages = (includeDrafts2 = false, hideDefaultIndex2 = false, tree, paginate2) => Effect.gen(function* () { let pagesRaw = []; if (paginate2) { const paginateData = yield* validatePagination(paginate2); pagesRaw = yield* dbService.execute( (db) => db.select().from(tsPageData).orderBy(asc(tsPageData.title)).limit(paginateData.limit).offset(paginateData.offset) ); } else { pagesRaw = yield* dbService.execute( (db) => db.select().from(tsPageData).orderBy(asc(tsPageData.title)) ); } const pagesFiltered = filterPagesByDraftAndIndex( pagesRaw, includeDrafts2, hideDefaultIndex2 ); const folders = tree || (yield* buildFolderTree); const pages2 = []; for (const page of pagesFiltered) { const data = yield* collectPageData(page, folders); pages2.push(data); } return pages2; }); const getPages = (id, includeDrafts2 = false, hideDefaultIndex2 = false, tree) => Effect.gen(function* () { const pagesRaw = yield* dbService.execute( (db) => db.select().from(tsPageData).where(eq(tsPageData.parentFolder, id)).orderBy(asc(tsPageData.title)) ); const pagesFiltered = filterPagesByDraftAndIndex( pagesRaw, includeDrafts2, hideDefaultIndex2 ); const folders = tree || (yield* buildFolderTree); const pages2 = []; for (const page of pagesFiltered) { pages2.push(yield* collectPageData(page, folders)); } return pages2; }); return Effect.gen(function* () { const status = yield* isCacheEnabled; const folderData = yield* getFolderByNameOrId(idOrName); if (!status) { const dbPages = yield* getPages(folderData.id, includeDrafts, hideDefaultIndex); const data2 = dbPages.map((page) => pageDataReturn(page)); return metaOnly ? convertCombinedPageDataToMetaOnly(data2) : data2; } const { data: tree } = yield* GET.folderTree(); if (pages.size === 0) { const updatedData = yield* getAllPages(includeDrafts, hideDefaultIndex, tree); for (const data3 of updatedData) { pages.set(data3.id, pageDataReturn(data3)); } const data2 = updatedData.filter(({ parentFolder }) => parentFolder === folderData.id).map((data3) => pageDataReturn(data3)); if (paginate) { const sortedData = data2.sort((a, b) => a.data.title.localeCompare(b.data.title)); const paginatedData = sortedData.slice( paginate.offset, paginate.offset + paginate.limit ); return metaOnly ? convertCombinedPageDataToMetaOnly(paginatedData) : paginatedData; } return metaOnly ? convertCombinedPageDataToMetaOnly(data2) : data2; } const cacheMap = Array.from(pages.values()); for (const item of cacheMap) { if (isCacheExpired(item)) { const updated = yield* GET.page.byId(item.data.id); if (!updated) { pages.delete(item.data.id); continue; } pages.set(updated.data.id, updated); } } const data = Array.from(pages.values()).filter( ({ data: { parentFolder } }) => parentFolder === folderData.id ); if (paginate) { const sortedData = data.sort((a, b) => a.data.title.localeCompare(b.data.title)); const paginatedData = sortedData.slice( paginate.offset, paginate.offset + paginate.limit ); return metaOnly ? convertCombinedPageDataToMetaOnly(paginatedData) : paginatedData; } return metaOnly ? convertCombinedPageDataToMetaOnly(data) : data; }).pipe( Effect.catchTags({ UnknownException: (cause) => _clearLibSQLError("GET.pages", cause), LibSQLClientError: (cause) => _clearLibSQLError("GET.pages", cause) }) ); } const getPermissionsByRank = (rank) => Effect.gen(function* () { const currentPermittedUsers = yield* dbService.execute( (db) => db.select().from(tsPermissions) ); const existingUsers = yield* dbService.execute((db) => db.select().from(tsUsers)); return yield* verifyRank(existingUsers, currentPermittedUsers, rank); }).pipe( Effect.catchTags({ LibSQLClientError: (cause) => _clearLibSQLError(`GET.permissionsLists.${rank}s`, cause) }) ); const GET = { databaseTable: { users: () => dbService.execute((db) => db.select().from(tsUsers)), oAuthAccounts: () => dbService.execute((db) => db.select().from(tsOAuthAccounts)), sessionTable: () => dbService.execute((db) => db.select().from(tsSessionTable)), permissions: () => dbService.execute((db) => db.select().from(tsPermissions)), pageData: () => dbService.execute((db) => db.select().from(tsPageData)), pageDataTags: () => dbService.execute((db) => db.select().from(tsPageDataTags)), pageDataCategories: () => dbService.execute((db) => db.select().from(tsPageDataCategories)), pageContent: () => dbService.execute((db) => db.select().from(tsPageContent)), diffTracking: () => dbService.execute((db) => db.select().from(tsDiffTracking)), pageFolderStructure: () => dbService.execute((db) => db.select().from(tsPageFolderStructure)), notificationSettings: () => dbService.execute( (db) => db.select().from(tsNotificationSettings).where(eq(tsNotificationSettings.id, CMSNotificationSettingsId)).get() ), emailVerificationTokens: () => dbService.execute((db) => db.select().from(tsEmailVerificationTokens)) }, permissionsLists: { /** * Retrieves all permissions for users in the database. * * @returns A promise that resolves to an array of combined rank data. * @throws {StudioCMS_SDK_Error} If an error occurs while getting the permissions. */ all: () => Effect.gen(function* () { const currentPermittedUsers = yield* dbService.execute( (db) => db.select().from(tsPermissions) ); const existingUsers = yield* dbService.execute((db) => db.select().from(tsUsers)); const owners = yield* verifyRank(existingUsers, currentPermittedUsers, "owner"); const admins = yield* verifyRank(existingUsers, currentPermittedUsers, "admin"); const editors = yield* verifyRank(existingUsers, currentPermittedUsers, "editor"); const visitors = yield* verifyRank(existingUsers, currentPermittedUsers, "visitor"); return [ ...yield* combineRanks("owner", owners), ...yield* combineRanks("admin", admins), ...yield* combineRanks("editor", editors), ...yield* combineRanks("visitor", visitors) ]; }).pipe( Effect.catchTags({ LibSQLClientError: (cause) => _clearLibSQLError("GET.permissionsLists.all", cause) }) ), /** * Retrieves all owners in the database. * * @returns A promise that resolves to an array of combined rank data. * @throws {StudioCMS_SDK_Error} If an error occurs while getting the owners. */ owners: () => getPermissionsByRank("owner"), /** * Retrieves all admins in the database. * * @returns A promise that resolves to an array of combined rank data. * @throws {StudioCMS_SDK_Error} If an error occurs while getting the admins. */ admins: () => getPermissionsByRank("admin"), /** * Retrieves all editors in the database. * * @returns A promise that resolves to an array of combined rank data. * @throws {StudioCMS_SDK_Error} If an error occurs while getting the editors. */ editors: () => getPermissionsByRank("editor"), /** * Retrieves all visitors in the database. * * @returns A promise that resolves to an array of combined rank data. * @throws {StudioCMS_SDK_Error} If an error occurs while getting the visitors. */ visitors: () => getPermissionsByRank("visitor") }, users: { /** * Retrieves all users from the database. * * @returns A promise that resolves to an array of combined user data. * @throws {StudioCMS_SDK_Error} If an error occurs while getting the users. */ all: () => Effect.gen(function* () { const combinedUserData = []; const users = yield* dbService.execute((db) => db.select().from(tsUsers)); for (const user of users) { if (user.id === GhostUserDefaults.id) { continue; } const UserData = yield* collectUserData(user); combinedUserData.push(UserData); } return combinedUserData; }).pipe( Effect.catchTags({ LibSQLClientError: (cause) => _clearLibSQLError("GET.users.all", cause) }) ), /** * Retrieves a user by ID. * * @param id - The ID of the user to retrieve. * @returns A promise that resolves to the user data. * @throws {StudioCMS_SDK_Error} If an error occurs while getting the user. */ byId: (id) => Effect.gen(function* () { const user = yield* dbService.execute( (db) => db.select().from(tsUsers).where(eq(tsUsers.id, id)).get() ); if (!user) return void 0; return yield* collectUserData(user); }).pipe( Effect.catchTags({ LibSQLClientError: (cause) => _clearLibSQLError("GET.users.byId", cause) }) ), /** * Retrieves a user by username. * * @param username - The username of the user to retrieve. * @returns A promise that resolves to the user data. * @throws {StudioCMS_SDK_Error} If an error occurs while getting the user. */ byUsername: (username) => Effect.gen(function* () { const user = yield* dbService.execute( (db) => db.select().from(tsUsers).where(eq(tsUsers.username, username)).get() ); if (!user) return void 0; return yield* collectUserData(user); }).pipe( Effect.catchTags({ LibSQLClientError: (cause) => _clearLibSQLError("GET.users.byId", cause) }) ), /** * Retrieves a user by email. * * @param email - The email of the user to retrieve. * @returns A promise that resolves to the user data. * @throws {StudioCMS_SDK_Error} If an error occurs while getting the user. */ byEmail: (email) => Effect.gen(function* () { const user = yield* dbService.execute( (db) => db.select().from(tsUsers).where(eq(tsUsers.email, email)).get() ); if (!user) return void 0; return yield* collectUserData(user); }).pipe( Effect.catchTags({ LibSQLClientError: (cause) => _clearLibSQLError("GET.users.byId", cause) }) ) }, /** * Retrieves a folder by ID. * * @param id - The ID of the folder to retrieve. * @returns A promise that resolves to the folder data. * @throws {StudioCMS_SDK_Error} If an error occurs while getting the folder. */ folder: dbService.makeQuery( (ex, id) => ex( (db) => db.select().from(tsPageFolderStructure).where(eq(tsPageFolderStructure.id, id)).get() ).pipe( Effect.catchTags({ LibSQLClientError: (cause) => _clearLibSQLError("GET.folder", cause) }) ) ), /** * Retrieves the site configuration, with caching support. * If caching is enabled, it checks the cache for an existing site config. * If the cache is expired or not available, it fetches the site config from the database * and updates the cache. * @returns An `Effect` that yields the site config. * @throws UnknownException - If an unknown error occurs during retrieval. * @throws LibSQLDatabaseError - If a database error occurs during retrieval. */ siteConfig: () => Effect.gen(function* () { const status = yield* isCacheEnabled; if (config.dbStartPage) { return void 0; } if (!status) { const newConfig = yield* sdkSiteConfig.get(); if (!newConfig) { return yield* Effect.fail( new SDKCoreError({ type: "UNKNOWN", cause: new StudioCMS_SDK_Error("Site config not found in database") }) ); } return siteConfigReturn(newConfig.data); } const currentSiteConfig = siteConfig.get(SiteConfigMapID); if (!currentSiteConfig || isCacheExpired(currentSiteConfig)) { const newConfig = yield* sdkSiteConfig.get(); if (!newConfig) { return yield* Effect.fail( new SDKCoreError({ type: "UNKNOWN", cause: new StudioCMS_SDK_Error("Site config not found in database") }) ); } const returnConfig = siteConfigReturn(newConfig.data); siteConfig.set(SiteConfigMapID, returnConfig); return returnConfig; } return currentSiteConfig; }).pipe( Effect.catchTags({ UnknownException: (cause) => _clearLibSQLError("GET.siteConfig", cause), LibSQLClientError: (cause) => _clearLibSQLError("GET.siteConfig", cause) }) ), /** * Retrieves the folder tree structure, with caching support. * If caching is enabled, it checks the cache for an existing folder tree. * If the cache is expired or not available, it fetches the folder tree from the database * and updates the cache. * @returns An `Effect` that yields the folder tree. * @throws UnknownException - If an unknown error occurs during retrieval. * @throws LibSQLDatabaseError - If a database error occurs during retrieval. */ folderTree: () => Effect.gen(function* () { const status = yield* isCacheEnabled; if (!status) { return folderTreeReturn(yield* buildFolderTree); } const tree = folderTree.get(FolderTreeMapID); if (!tree || isCacheExpired(tree)) { const newFolderTree = yield* buildFolderTree; const returnable = folderTreeReturn(newFolderTree); folderTree.set(FolderTreeMapID, returnable); return returnable; } return tree; }).pipe( Effect.catchTags({ UnknownException: (cause) => _clearLibSQLError("GET.folderTree", cause), LibSQLClientError: (cause) => _clearLibSQLError("GET.folderTree", cause) }) ), /** * Retrieves the folder tree structure, with caching support. * If caching is enabled, it checks the cache for an existing folder tree. * If the cache is expired or not available, it fetches the folder tree from the database * and updates the cache. * @returns An `Effect` that yields the folder tree. * @throws UnknownException - If an unknown error occurs during retrieval. * @throws LibSQLDatabaseError - If a database error occurs during retrieval. */ pageFolderTree: (hideDefaultIndex = false) => Effect.gen(function* () { const status = yield* isCacheEnabled; if (!status) { const folderTree2 = yield* buildFolderTree; const pages2 = yield* GET.pages(true, hideDefaultIndex); for (const { data: page } of pages2) { if (page.parentFolder) { yield* addPageToFolderTree(folderTree2, page.parentFolder, { id: page.id, name: page.title, page: true, pageData: page, children: [] }); } else { folderTree2.push({ id: page.id, name: page.title, page: true, pageData: page, children: [] }); } } return folderTreeReturn(folderTree2); } const tree = pageFolderTree.get(PageFolderTreeMapID); if (!tree || isCacheExpired(tree)) { const newFolderTree = yield* buildFolderTree; const pages2 = yield* GET.pages(true, hideDefaultIndex); for (const { data: page } of pages2) { if (page.parentFolder) { yield* addPageToFolderTree(newFolderTree, page.parentFolder, { id: page.id, name: page.title, page: true, pageData: page, children: [] }); } else { newFolderTree.push({ id: page.id, name: page.title, page: true, pageData: page, children: [] }); } } pageFolderTree.set(PageFolderTreeMapID, folderTreeReturn(newFolderTree)); return folderTreeReturn(newFolderTree); } return tree; }).pipe( Effect.catchTags({ UnknownException: (cause) => _clearLibSQLError("GET.pageFolderTree", cause), LibSQLClientError: (cause) => _clearLibSQLError("GET.pageFolderTree", cause) }) ), /** * Retrieves a list of available folders, with caching support. * If caching is enabled, it checks the cache for an existing folder list. * If the cache is expired or not available, it fetches the folder list from the database * and updates the cache. * @returns An `Effect` that yields the folder list. * @throws UnknownException - If an unknown error occurs during retrieval. * @throws LibSQLDatabaseError - If a database error occurs during retrieval. */ folderList: () => Effect.gen(function* () { const status = yield* isCacheEnabled; if (!status) { const folderList = yield* getAvailableFolders; return folderListReturn(folderList); } const list = FolderList.get(FolderListMapID); if (!list || isCacheExpired(list)) { const folderList = yield* getAvailableFolders; FolderList.set(FolderListMapID, folderListReturn(folderList)); return folderListReturn(folderList); } return list; }).pipe( Effect.catchTags({ UnknownException: (cause) => _clearLibSQLError("GET.folderList", cause), LibSQLClientError: (cause) => _clearLibSQLError("GET.folderList", cause) }) ), /** * Retrieves the latest version of StudioCMS from NPM, with caching support. * @returns An `Effect` that yields the latest version of StudioCMS. * @throws UnknownException - If an unknown error occurs during retrieval. */ latestVersion: () => Effect.gen(function* () { const status = yield* isCacheEnabled; if (!status) { const version2 = yield* getVersionFromNPM.get(StudioCMSPkgId); return versionReturn(version2); } const latestVersion = version.get(VersionMapID); if (!latestVersion || isCacheExpired(latestVersion, versionCacheLifetime)) { const newVersion = yield* getVersionFromNPM.get(StudioCMSPkgId); const latestVersion2 = versionReturn(newVersion); version.set(VersionMapID, latestVersion2); return latestVersion2; } return latestVersion; }).pipe( Effect.catchTags({ UnknownException: (cause) => _ClearUnknownError("GET.latestVersion", cause) }) ), page: { /** * Retrieves a page by its ID, with an option to return only metadata. * * @param id - The ID of the page to retrieve. * @param metaOnly - If `true`, returns only metadata for the page. Defaults to `false`. * @returns An `Effect` that yields the page data or metadata, depending on `metaOnly`. * * @throws UnknownException - If an unknown error occurs during retrieval. * @throws LibSQLDatabaseError - If a database error occurs during retrieval. */ byId: _getPageById, /** * Retrieves a page by its slug, with an option to return only metadata. * * @param slug - The slug of the page to retrieve. * @param metaOnly - If `true`, returns only metadata for the page. Defaults to `false`. * @returns An `Effect` that yields the page data or metadata, depending on `metaOnly`. * * @throws UnknownException - If an unknown error occurs during retrieval. * @throws LibSQLDatabaseError - If a database error occurs during retrieval. */ bySlug: _getPageBySlug }, /** * Retrieves pages within a specified folder by its ID or name, supporting various filtering and pagination options. * * This function handles both cached and non-cached scenarios, fetching pages from the database or cache as appropriate. * It supports filtering drafts, hiding default index pages, returning only metadata, and paginating results. * * @param idOrName - The ID or name of the folder to retrieve pages from. * @param includeDrafts - Whether to include draft pages in the results. Defaults to `false`. * @param hideDefaultIndex - Whether to exclude default index pages from the results. Defaults to `false`. * @param metaOnly - If `true`, returns only metadata for each page. Defaults to `false`. * @param paginate - Optional pagination input specifying `limit` and `offset`. * @returns An `Effect` that yields an array of page data or metadata, depending on `metaOnly`. * * @throws UnknownException - If an unknown error occurs during retrieval. * @throws LibSQLDatabaseError - If a database error occurs during retrieval. */ folderPages: _folderPages, /** * Retrieves all pages associated with a given package name, optionally using a provided folder tree and returning only metadata if specified. * * @param packageName - The name of the package to fetch pages for. * @param tree - Optional. A pre-built folder tree to use for organizing pages. If not provided, the folder tree will be built automatically. * @param metaOnly - Optional. If true, returns only metadata for each page; otherwise, returns combined page data. Defaults to false. * @returns An Effect that resolves to an array of page data, either as `MetaOnlyPageData[]` or `CombinedPageData[]` depending on `metaOnly`. */ packagePages: _getPackagesPages, /** * Retrieves all pages from the database or cache, with options for including drafts, * hiding the default index page, returning only metadata, and paginating results. * * - If caching is enabled, attempts to return cached pages and updates expired cache entries. * - If caching is disabled, fetches pages directly from the database. * - Supports filtering by draft status and default index visibility. * - Can return either full page data or metadata only. * - Supports pagination via the `paginate` parameter. * * @param includeDrafts - Whether to include draft pages in the results. Defaults to `false`. * @param hideDefaultIndex - Whether to exclude the default index page from the results. Defaults to `false`. * @param metaOnly - Whether to return only metadata for each page. Defaults to `false`. * @param paginate - Optional pagination input specifying `limit` and `offset`. * @returns An `Effect` that yields an array of page data or metadata, depending on `metaOnly`. */ pages: _getAllPages }; return GET; }) } ) { } export { SDKCore_GET };