studiocms
Version:
Astro Native CMS for AstroDB. Built from the ground up by the Astro community.
837 lines (836 loc) • 36.6 kB
JavaScript
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
};