@tetherto/dev-websites-core 0.3.5 → 0.3.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cache/handler.d.mts.map +1 -1
- package/dist/cms/index.d.mts +2 -2
- package/dist/cms/index.mjs +2 -2
- package/dist/cms.mjs +545 -10
- package/dist/cms.mjs.map +1 -1
- package/dist/i18n/index.mjs +1 -2
- package/dist/index.d.mts +118 -3
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +2 -2
- package/dist/index5.d.mts +2 -2
- package/dist/ui/carousel/index.mjs +1 -2
- package/dist/ui/components/Accordion/index.mjs +1 -2
- package/dist/ui/components/Avatar/index.mjs +1 -2
- package/dist/ui/components/Badge/index.mjs +1 -2
- package/dist/ui/components/BadgeVersion/index.mjs +1 -2
- package/dist/ui/components/Button/index.mjs +1 -2
- package/dist/ui/components/Card/index.mjs +1 -2
- package/dist/ui/components/Carousel/index.mjs +1 -2
- package/dist/ui/components/Checkbox/index.mjs +1 -2
- package/dist/ui/components/CodeBlock/index.mjs +1 -2
- package/dist/ui/components/CodeBlockTabs/index.mjs +1 -2
- package/dist/ui/components/CollapsibleSection/index.mjs +1 -2
- package/dist/ui/components/CopyButton/index.mjs +1 -2
- package/dist/ui/components/CustomHtml/CustomHtml.d.mts +8 -0
- package/dist/ui/components/CustomHtml/CustomHtml.d.mts.map +1 -0
- package/dist/ui/components/CustomHtml/CustomHtml.mjs +31 -0
- package/dist/ui/components/CustomHtml/CustomHtml.mjs.map +1 -0
- package/dist/ui/components/CustomHtml/converters.d.mts +14 -0
- package/dist/ui/components/CustomHtml/converters.d.mts.map +1 -0
- package/dist/ui/components/CustomHtml/converters.mjs +9 -0
- package/dist/ui/components/CustomHtml/converters.mjs.map +1 -0
- package/dist/ui/components/CustomHtml/index.d.mts +3 -0
- package/dist/ui/components/CustomHtml/index.mjs +3 -0
- package/dist/ui/components/Dialog/index.mjs +1 -2
- package/dist/ui/components/EmptyState/index.mjs +1 -2
- package/dist/ui/components/FieldError/index.mjs +1 -2
- package/dist/ui/components/FormattedDate/index.mjs +1 -2
- package/dist/ui/components/GoogleOAuthButton/index.mjs +1 -2
- package/dist/ui/components/IconButton/index.mjs +1 -2
- package/dist/ui/components/Input/index.mjs +1 -2
- package/dist/ui/components/Label/index.mjs +1 -2
- package/dist/ui/components/LazyVideo/index.mjs +1 -2
- package/dist/ui/components/Pagination/index.mjs +1 -2
- package/dist/ui/components/PaginationItem/index.mjs +1 -2
- package/dist/ui/components/PasswordInput/index.mjs +1 -2
- package/dist/ui/components/ProgressStepper/index.mjs +1 -2
- package/dist/ui/components/Prose/index.mjs +1 -2
- package/dist/ui/components/Radio/index.mjs +1 -2
- package/dist/ui/components/Reveal/index.mjs +1 -2
- package/dist/ui/components/SearchInput/index.mjs +1 -2
- package/dist/ui/components/Select/index.mjs +1 -2
- package/dist/ui/components/Sheet/index.mjs +1 -2
- package/dist/ui/components/StaggerReveal/index.mjs +1 -2
- package/dist/ui/components/Stepper/index.mjs +1 -2
- package/dist/ui/components/Switch/index.mjs +1 -2
- package/dist/ui/components/TextButton/index.mjs +1 -2
- package/dist/ui/components/Textarea/index.mjs +1 -2
- package/dist/ui/components/Toast/index.mjs +1 -2
- package/dist/ui/components/Tooltip/index.mjs +1 -2
- package/dist/ui/components/VisuallyHidden/index.mjs +1 -2
- package/dist/ui/hooks/index.mjs +1 -2
- package/dist/ui/index.d.mts +4 -1
- package/dist/ui/index.mjs +1 -0
- package/dist/ui/utils/index.mjs +1 -2
- package/package.json +18 -10
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"handler.d.mts","names":[],"sources":["../../src/cache/types.ts","../../src/cache/createMongoCacheHandler.ts","../../src/cache/handler.ts"],"mappings":";;;;;;KAgCY;EACV;EACA;EACA;EACA,UAAU;;EAEV,cAAc,0BAA0B;GACvC;;KAWS;EACV;EACA,OAAO;;;KAIG;EACV;;;;KCtBU;EACV,IAAI,cAAc,QAAQ;EAC1B,IAAI,aAAa,OAAO,oBAAoB,MAAM,kBAAkB;EACpE,OAAO,cAAc;EACrB;EACA,cAAc,yBAAyB,sBAAsB;;;;;;KAOnD,oCAAoC,kBAAkB"}
|
|
1
|
+
{"version":3,"file":"handler.d.mts","names":["_$__createMongoCacheHandler_js0.MongoCacheHandlerConstructor"],"sources":["../../src/cache/types.ts","../../src/cache/createMongoCacheHandler.ts","../../src/cache/handler.ts"],"mappings":";;;;;;KAgCY;EACV;EACA;EACA;EACA,UAAU;;EAEV,cAAc,0BAA0B;GACvC;;KAWS;EACV;EACA,OAAO;;;KAIG;EACV;;;;KCtBU;EACV,IAAI,cAAc,QAAQ;EAC1B,IAAI,aAAa,OAAO,oBAAoB,MAAM,kBAAkB;EACpE,OAAO,cAAc;EACrB;EACA,cAAc,yBAAyB,sBAAsB;;;;;;KAOnD,oCAAoC,kBAAkB"}
|
package/dist/cms/index.d.mts
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import { $ as
|
|
1
|
+
import { $ as AccessOptions, A as downloadCtaBlock, B as slugify, C as codeBlockLanguages, D as sectionHeadingBlock, E as leafBlocks, F as codeBlock, G as Overrides, H as draftsWithAutosave, I as richTextBlock, J as CollectionOverride, K as STOCK_COLLECTION_SLUGS, L as coerceBlogPostCategoriesOnRead, M as videoBlock, N as imageBlock, O as accordionBlock, P as codeTabsBlock, Q as AccessHelpers, R as coerceBlogPostCategoriesOnWrite, S as showcaseContentBlocks, T as languageOptions, U as BuildCmsConfigOptions, V as seoFields, W as buildCmsConfig, X as applyCollectionOverride, Y as GlobalOverride, Z as applyGlobalOverride, _ as requireEnvAtRuntime, _t as withRoles, a as createChangelog, at as RoleOption, b as blogContentBlocks, c as createPages, ct as adminRoleAccess, d as createAuthors, dt as globalRoleRule, et as createAccessHelpers, f as createMedia, ft as hiddenUnless, g as createS3MediaPlugin, gt as userHasAnyRole, h as CreateS3MediaPluginOptions, ht as resolveRoleOptions, i as createEventTags, it as DEFAULT_ROLES, j as customHtmlBlock, k as stepsBlock, l as createBlogPosts, lt as collectionRoleRule, m as createUsers, mt as publishedOrRoleRead, n as createSiteSettings, nt as DEFAULT_COLLECTION_ROLES, o as createChangelogTags, ot as RoleRule, p as createApiTokens, pt as isCmsAdmin, q as StockCollectionSlug, r as createEvents, rt as DEFAULT_GLOBAL_ROLES, s as createLegalPages, st as RolesOptions, t as createAnnouncementBanner, tt as ADMIN_ROLE, u as createCategories, ut as effectiveRoles, v as getRichTextEditorConfig, vt as writeAccess, w as defaultCodeLanguage, x as pageContentBlocks, y as richTextEditor, z as setPublishedAt } from "../index.mjs";
|
|
2
2
|
import { n as readPayloadMediaAsDataUrl, r as readPayloadMediaBuffer, t as PayloadMedia } from "../readMediaBuffer.mjs";
|
|
3
|
-
export { type AccessHelpers, type AccessOptions, type BuildCmsConfigOptions, type CollectionOverride, type CreateS3MediaPluginOptions, type GlobalOverride, type Overrides, type PayloadMedia, STOCK_COLLECTION_SLUGS, type StockCollectionSlug, accordionBlock, applyCollectionOverride, applyGlobalOverride, blogContentBlocks, buildCmsConfig, codeBlock, codeBlockLanguages, codeTabsBlock, coerceBlogPostCategoriesOnRead, coerceBlogPostCategoriesOnWrite, createAccessHelpers, createAnnouncementBanner, createApiTokens, createAuthors, createBlogPosts, createCategories, createChangelog, createChangelogTags, createEventTags, createEvents, createLegalPages, createMedia, createPages, createS3MediaPlugin, createSiteSettings, createUsers, defaultCodeLanguage, downloadCtaBlock, draftsWithAutosave, getRichTextEditorConfig, imageBlock, languageOptions, leafBlocks, pageContentBlocks, readPayloadMediaAsDataUrl, readPayloadMediaBuffer, requireEnvAtRuntime, richTextBlock, richTextEditor, sectionHeadingBlock, seoFields, setPublishedAt, showcaseContentBlocks, slugify, stepsBlock, videoBlock };
|
|
3
|
+
export { ADMIN_ROLE, type AccessHelpers, type AccessOptions, type BuildCmsConfigOptions, type CollectionOverride, type CreateS3MediaPluginOptions, DEFAULT_COLLECTION_ROLES, DEFAULT_GLOBAL_ROLES, DEFAULT_ROLES, type GlobalOverride, type Overrides, type PayloadMedia, type RoleOption, type RoleRule, type RolesOptions, STOCK_COLLECTION_SLUGS, type StockCollectionSlug, accordionBlock, adminRoleAccess, applyCollectionOverride, applyGlobalOverride, blogContentBlocks, buildCmsConfig, codeBlock, codeBlockLanguages, codeTabsBlock, coerceBlogPostCategoriesOnRead, coerceBlogPostCategoriesOnWrite, collectionRoleRule, createAccessHelpers, createAnnouncementBanner, createApiTokens, createAuthors, createBlogPosts, createCategories, createChangelog, createChangelogTags, createEventTags, createEvents, createLegalPages, createMedia, createPages, createS3MediaPlugin, createSiteSettings, createUsers, customHtmlBlock, defaultCodeLanguage, downloadCtaBlock, draftsWithAutosave, effectiveRoles, getRichTextEditorConfig, globalRoleRule, hiddenUnless, imageBlock, isCmsAdmin, languageOptions, leafBlocks, pageContentBlocks, publishedOrRoleRead, readPayloadMediaAsDataUrl, readPayloadMediaBuffer, requireEnvAtRuntime, resolveRoleOptions, richTextBlock, richTextEditor, sectionHeadingBlock, seoFields, setPublishedAt, showcaseContentBlocks, slugify, stepsBlock, userHasAnyRole, videoBlock, withRoles, writeAccess };
|
package/dist/cms/index.mjs
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import { A as richTextBlock, B as
|
|
1
|
+
import { $ as globalRoleRule, A as richTextBlock, B as defaultCodeLanguage, C as blogContentBlocks, D as accordionBlock, E as sectionHeadingBlock, F as downloadCtaBlock, G as createApiTokens, H as createAuthors, I as customHtmlBlock, J as DEFAULT_GLOBAL_ROLES, K as ADMIN_ROLE, L as codeTabsBlock, M as richTextEditor, N as videoBlock, O as leafBlocks, P as imageBlock, Q as effectiveRoles, R as codeBlock, S as coerceBlogPostCategoriesOnWrite, T as showcaseContentBlocks, U as seoFields, V as languageOptions, W as slugify, X as adminRoleAccess, Y as DEFAULT_ROLES, Z as collectionRoleRule, _ as createCategories, a as STOCK_COLLECTION_SLUGS, at as withRoles, b as setPublishedAt, c as createSiteSettings, d as createPages, et as hiddenUnless, f as createMedia, g as createChangelog, h as createChangelogTags, i as buildCmsConfig, it as userHasAnyRole, j as getRichTextEditorConfig, k as stepsBlock, l as createUsers, m as createEventTags, n as createS3MediaPlugin, nt as publishedOrRoleRead, o as applyCollectionOverride, ot as writeAccess, p as createEvents, q as DEFAULT_COLLECTION_ROLES, r as requireEnvAtRuntime, rt as resolveRoleOptions, s as applyGlobalOverride, st as createAccessHelpers, t as createAnnouncementBanner, tt as isCmsAdmin, u as createLegalPages, v as createBlogPosts, w as pageContentBlocks, x as coerceBlogPostCategoriesOnRead, y as draftsWithAutosave, z as codeBlockLanguages } from "../cms.mjs";
|
|
2
2
|
import { n as readPayloadMediaBuffer, t as readPayloadMediaAsDataUrl } from "../readMediaBuffer.mjs";
|
|
3
|
-
export { STOCK_COLLECTION_SLUGS, accordionBlock, applyCollectionOverride, applyGlobalOverride, blogContentBlocks, buildCmsConfig, codeBlock, codeBlockLanguages, codeTabsBlock, coerceBlogPostCategoriesOnRead, coerceBlogPostCategoriesOnWrite, createAccessHelpers, createAnnouncementBanner, createApiTokens, createAuthors, createBlogPosts, createCategories, createChangelog, createChangelogTags, createEventTags, createEvents, createLegalPages, createMedia, createPages, createS3MediaPlugin, createSiteSettings, createUsers, defaultCodeLanguage, downloadCtaBlock, draftsWithAutosave, getRichTextEditorConfig, imageBlock, languageOptions, leafBlocks, pageContentBlocks, readPayloadMediaAsDataUrl, readPayloadMediaBuffer, requireEnvAtRuntime, richTextBlock, richTextEditor, sectionHeadingBlock, seoFields, setPublishedAt, showcaseContentBlocks, slugify, stepsBlock, videoBlock };
|
|
3
|
+
export { ADMIN_ROLE, DEFAULT_COLLECTION_ROLES, DEFAULT_GLOBAL_ROLES, DEFAULT_ROLES, STOCK_COLLECTION_SLUGS, accordionBlock, adminRoleAccess, applyCollectionOverride, applyGlobalOverride, blogContentBlocks, buildCmsConfig, codeBlock, codeBlockLanguages, codeTabsBlock, coerceBlogPostCategoriesOnRead, coerceBlogPostCategoriesOnWrite, collectionRoleRule, createAccessHelpers, createAnnouncementBanner, createApiTokens, createAuthors, createBlogPosts, createCategories, createChangelog, createChangelogTags, createEventTags, createEvents, createLegalPages, createMedia, createPages, createS3MediaPlugin, createSiteSettings, createUsers, customHtmlBlock, defaultCodeLanguage, downloadCtaBlock, draftsWithAutosave, effectiveRoles, getRichTextEditorConfig, globalRoleRule, hiddenUnless, imageBlock, isCmsAdmin, languageOptions, leafBlocks, pageContentBlocks, publishedOrRoleRead, readPayloadMediaAsDataUrl, readPayloadMediaBuffer, requireEnvAtRuntime, resolveRoleOptions, richTextBlock, richTextEditor, sectionHeadingBlock, seoFields, setPublishedAt, showcaseContentBlocks, slugify, stepsBlock, userHasAnyRole, videoBlock, withRoles, writeAccess };
|
package/dist/cms.mjs
CHANGED
|
@@ -30,6 +30,370 @@ function createAccessHelpers(options = {}) {
|
|
|
30
30
|
};
|
|
31
31
|
}
|
|
32
32
|
//#endregion
|
|
33
|
+
//#region src/cms/shared/roles.ts
|
|
34
|
+
const ADMIN_ROLE = "admin";
|
|
35
|
+
const CMS_ROLES_SLUG = "cms-roles";
|
|
36
|
+
const moderator = ["moderator"];
|
|
37
|
+
const developer = ["developer"];
|
|
38
|
+
const moderatorAndDeveloper = ["moderator", "developer"];
|
|
39
|
+
const DEFAULT_ROLES = [
|
|
40
|
+
{
|
|
41
|
+
label: "Admin",
|
|
42
|
+
value: ADMIN_ROLE
|
|
43
|
+
},
|
|
44
|
+
{
|
|
45
|
+
label: "Moderator",
|
|
46
|
+
value: "moderator"
|
|
47
|
+
},
|
|
48
|
+
{
|
|
49
|
+
label: "Developer",
|
|
50
|
+
value: "developer"
|
|
51
|
+
}
|
|
52
|
+
];
|
|
53
|
+
const DEFAULT_COLLECTION_ROLES = {
|
|
54
|
+
"api-tokens": false,
|
|
55
|
+
"media": { roles: moderatorAndDeveloper },
|
|
56
|
+
"authors": { roles: moderator },
|
|
57
|
+
"categories": { roles: moderator },
|
|
58
|
+
"blog-posts": {
|
|
59
|
+
roles: moderator,
|
|
60
|
+
drafts: true
|
|
61
|
+
},
|
|
62
|
+
"pages": {
|
|
63
|
+
roles: moderator,
|
|
64
|
+
drafts: true
|
|
65
|
+
},
|
|
66
|
+
"legal-pages": {
|
|
67
|
+
roles: moderator,
|
|
68
|
+
drafts: true
|
|
69
|
+
},
|
|
70
|
+
"changelog-tags": { roles: developer },
|
|
71
|
+
"changelog": {
|
|
72
|
+
roles: developer,
|
|
73
|
+
drafts: true
|
|
74
|
+
},
|
|
75
|
+
"event-tags": { roles: moderator },
|
|
76
|
+
"events": {
|
|
77
|
+
roles: moderator,
|
|
78
|
+
drafts: true
|
|
79
|
+
}
|
|
80
|
+
};
|
|
81
|
+
const DEFAULT_GLOBAL_ROLES = {
|
|
82
|
+
"site-settings": false,
|
|
83
|
+
"announcement-banner": { roles: moderator }
|
|
84
|
+
};
|
|
85
|
+
let roleCache = null;
|
|
86
|
+
function asCmsUser(user) {
|
|
87
|
+
if (!user || typeof user !== "object") return null;
|
|
88
|
+
const record = user;
|
|
89
|
+
if (record.collection !== "users") return null;
|
|
90
|
+
return record;
|
|
91
|
+
}
|
|
92
|
+
function roleRefs(roles) {
|
|
93
|
+
if (!Array.isArray(roles)) return {
|
|
94
|
+
ids: [],
|
|
95
|
+
slugs: []
|
|
96
|
+
};
|
|
97
|
+
const ids = [];
|
|
98
|
+
const slugs = [];
|
|
99
|
+
roles.forEach((role) => {
|
|
100
|
+
if (typeof role === "string" || typeof role === "number") {
|
|
101
|
+
const value = String(role);
|
|
102
|
+
if (/^[a-f0-9]{24}$/i.test(value)) ids.push(value);
|
|
103
|
+
else if (value) slugs.push(value);
|
|
104
|
+
return;
|
|
105
|
+
}
|
|
106
|
+
if (role && typeof role === "object" && "id" in role && role.id != null) ids.push(String(role.id));
|
|
107
|
+
});
|
|
108
|
+
return {
|
|
109
|
+
ids,
|
|
110
|
+
slugs
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
function readPermissions(value) {
|
|
114
|
+
if (!Array.isArray(value)) return [];
|
|
115
|
+
return value.flatMap((entry) => {
|
|
116
|
+
if (!entry || typeof entry !== "object" || !("target" in entry)) return [];
|
|
117
|
+
const row = entry;
|
|
118
|
+
if (!row.target) return [];
|
|
119
|
+
return [{
|
|
120
|
+
target: row.target,
|
|
121
|
+
create: Boolean(row.create),
|
|
122
|
+
update: Boolean(row.update),
|
|
123
|
+
delete: Boolean(row.delete),
|
|
124
|
+
drafts: Boolean(row.drafts)
|
|
125
|
+
}];
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
async function refreshRoleCache(payload) {
|
|
129
|
+
const found = await payload.find({
|
|
130
|
+
collection: CMS_ROLES_SLUG,
|
|
131
|
+
depth: 0,
|
|
132
|
+
limit: 500,
|
|
133
|
+
pagination: false,
|
|
134
|
+
overrideAccess: true
|
|
135
|
+
});
|
|
136
|
+
const byId = /* @__PURE__ */ new Map();
|
|
137
|
+
const bySlug = /* @__PURE__ */ new Map();
|
|
138
|
+
found.docs.forEach((doc) => {
|
|
139
|
+
const record = doc;
|
|
140
|
+
if (!record.slug) return;
|
|
141
|
+
const role = {
|
|
142
|
+
id: String(record.id),
|
|
143
|
+
name: record.name ?? record.slug,
|
|
144
|
+
slug: record.slug,
|
|
145
|
+
fullAccess: Boolean(record.fullAccess) || record.slug === "admin",
|
|
146
|
+
permissions: readPermissions(record.permissions)
|
|
147
|
+
};
|
|
148
|
+
byId.set(role.id, role);
|
|
149
|
+
bySlug.set(role.slug, role);
|
|
150
|
+
});
|
|
151
|
+
roleCache = {
|
|
152
|
+
byId,
|
|
153
|
+
bySlug
|
|
154
|
+
};
|
|
155
|
+
}
|
|
156
|
+
async function ensureRoleCache(payload) {
|
|
157
|
+
if (!roleCache) await refreshRoleCache(payload);
|
|
158
|
+
return roleCache ?? {
|
|
159
|
+
byId: /* @__PURE__ */ new Map(),
|
|
160
|
+
bySlug: /* @__PURE__ */ new Map()
|
|
161
|
+
};
|
|
162
|
+
}
|
|
163
|
+
function lookupRoles(refs, cache) {
|
|
164
|
+
return [...refs.ids.map((id) => cache.byId.get(id)), ...refs.slugs.map((slug) => cache.bySlug.get(slug))].filter((role) => Boolean(role));
|
|
165
|
+
}
|
|
166
|
+
function syncAssignment(user) {
|
|
167
|
+
const record = asCmsUser(user);
|
|
168
|
+
if (!record) return "guest";
|
|
169
|
+
const refs = roleRefs(record.roles);
|
|
170
|
+
if (refs.ids.length === 0 && refs.slugs.length === 0) return "admin";
|
|
171
|
+
if (!roleCache) return "unknown";
|
|
172
|
+
return lookupRoles(refs, roleCache);
|
|
173
|
+
}
|
|
174
|
+
async function loadAssignment(req) {
|
|
175
|
+
const record = asCmsUser(req.user);
|
|
176
|
+
if (!record) return "guest";
|
|
177
|
+
const refs = roleRefs(record.roles);
|
|
178
|
+
if (refs.ids.length === 0 && refs.slugs.length === 0) return "admin";
|
|
179
|
+
return lookupRoles(refs, await ensureRoleCache(req.payload));
|
|
180
|
+
}
|
|
181
|
+
function hasPermission(roles, target, action) {
|
|
182
|
+
if (roles.some((role) => role.fullAccess)) return true;
|
|
183
|
+
return roles.some((role) => role.permissions.some((permission) => permission.target === target && permission[action]));
|
|
184
|
+
}
|
|
185
|
+
/**
|
|
186
|
+
* `null` means this user has no roles yet and is treated as admin.
|
|
187
|
+
* `true` / `false` is the cached decision. A cold cache returns `null` so the
|
|
188
|
+
* nav stays visible until startup finishes loading roles.
|
|
189
|
+
*/
|
|
190
|
+
function cachedPermission(user, target, action) {
|
|
191
|
+
const assigned = syncAssignment(user);
|
|
192
|
+
if (assigned === "guest") return false;
|
|
193
|
+
if (assigned === "admin") return true;
|
|
194
|
+
if (assigned === "unknown") return null;
|
|
195
|
+
return hasPermission(assigned, target, action);
|
|
196
|
+
}
|
|
197
|
+
async function userIsFullAdmin(req) {
|
|
198
|
+
const assigned = await loadAssignment(req);
|
|
199
|
+
if (assigned === "guest") return false;
|
|
200
|
+
if (assigned === "admin") return true;
|
|
201
|
+
return assigned.some((role) => role.fullAccess);
|
|
202
|
+
}
|
|
203
|
+
async function userCan(req, target, action) {
|
|
204
|
+
const assigned = await loadAssignment(req);
|
|
205
|
+
if (assigned === "guest") return false;
|
|
206
|
+
if (assigned === "admin") return true;
|
|
207
|
+
return hasPermission(assigned, target, action);
|
|
208
|
+
}
|
|
209
|
+
/**
|
|
210
|
+
* Users created before the roles field existed have none stored.
|
|
211
|
+
* Treat that as admin so turning roles on does not lock the panel.
|
|
212
|
+
*/
|
|
213
|
+
function effectiveRoles(user) {
|
|
214
|
+
const assigned = syncAssignment(user);
|
|
215
|
+
if (assigned === "admin") return [ADMIN_ROLE];
|
|
216
|
+
if (assigned === "guest" || assigned === "unknown") return [];
|
|
217
|
+
return assigned.map((role) => role.slug);
|
|
218
|
+
}
|
|
219
|
+
function userHasAnyRole(user, roles) {
|
|
220
|
+
const assigned = effectiveRoles(user);
|
|
221
|
+
if (assigned.includes("admin")) return true;
|
|
222
|
+
return roles.some((role) => assigned.includes(role));
|
|
223
|
+
}
|
|
224
|
+
function isCmsAdmin(user) {
|
|
225
|
+
const assigned = syncAssignment(user);
|
|
226
|
+
if (assigned === "admin") return true;
|
|
227
|
+
if (assigned === "guest" || assigned === "unknown") return false;
|
|
228
|
+
return assigned.some((role) => role.fullAccess);
|
|
229
|
+
}
|
|
230
|
+
const adminRoleAccess = ({ req }) => userIsFullAdmin(req);
|
|
231
|
+
function hiddenUnless(roles) {
|
|
232
|
+
return ({ user }) => !userHasAnyRole(user, roles);
|
|
233
|
+
}
|
|
234
|
+
function writeAccess(roles) {
|
|
235
|
+
return ({ req }) => userHasAnyRole(req.user, roles);
|
|
236
|
+
}
|
|
237
|
+
function publishedOrRoleRead(roles) {
|
|
238
|
+
return ({ req }) => {
|
|
239
|
+
if (userHasAnyRole(req.user, roles)) return true;
|
|
240
|
+
return { _status: { equals: "published" } };
|
|
241
|
+
};
|
|
242
|
+
}
|
|
243
|
+
const selfOrAdminAccess = async ({ req }) => {
|
|
244
|
+
if (await userIsFullAdmin(req)) return true;
|
|
245
|
+
const record = asCmsUser(req.user);
|
|
246
|
+
if (record?.id == null) return false;
|
|
247
|
+
return { id: { equals: record.id } };
|
|
248
|
+
};
|
|
249
|
+
const manageRolesAccess = ({ req }) => userIsFullAdmin(req);
|
|
250
|
+
function hiddenFor(target) {
|
|
251
|
+
return ({ user }) => {
|
|
252
|
+
const create = cachedPermission(user, target, "create");
|
|
253
|
+
const update = cachedPermission(user, target, "update");
|
|
254
|
+
const drafts = cachedPermission(user, target, "drafts");
|
|
255
|
+
if (create == null || update == null || drafts == null) return false;
|
|
256
|
+
return !(create || update || drafts);
|
|
257
|
+
};
|
|
258
|
+
}
|
|
259
|
+
function hiddenUnlessFullAdmin() {
|
|
260
|
+
return ({ user }) => {
|
|
261
|
+
const assigned = syncAssignment(user);
|
|
262
|
+
if (assigned === "unknown" || assigned === "admin") return false;
|
|
263
|
+
if (assigned === "guest") return true;
|
|
264
|
+
return !assigned.some((role) => role.fullAccess);
|
|
265
|
+
};
|
|
266
|
+
}
|
|
267
|
+
function resolveRoleOptions(options = {}) {
|
|
268
|
+
const custom = options.roles?.filter((role) => role.value !== "admin") ?? DEFAULT_ROLES.filter((role) => role.value !== "admin");
|
|
269
|
+
const merged = /* @__PURE__ */ new Map([[ADMIN_ROLE, {
|
|
270
|
+
label: "Admin",
|
|
271
|
+
value: ADMIN_ROLE
|
|
272
|
+
}]]);
|
|
273
|
+
[...custom, ...options.extraRoles ?? []].forEach((role) => {
|
|
274
|
+
if (!role.value || role.value === "admin") return;
|
|
275
|
+
merged.set(role.value, {
|
|
276
|
+
label: role.label,
|
|
277
|
+
value: role.value
|
|
278
|
+
});
|
|
279
|
+
});
|
|
280
|
+
return [...merged.values()];
|
|
281
|
+
}
|
|
282
|
+
function collectionRoleRule(options, slug, fallback) {
|
|
283
|
+
return roleRule(options, "collections", slug, fallback);
|
|
284
|
+
}
|
|
285
|
+
function globalRoleRule(options, slug, fallback) {
|
|
286
|
+
return roleRule(options, "globals", slug, fallback);
|
|
287
|
+
}
|
|
288
|
+
function roleRule(options, kind, slug, fallback) {
|
|
289
|
+
const overrides = (options === true || options == null ? {} : options)[kind];
|
|
290
|
+
if (overrides && Object.prototype.hasOwnProperty.call(overrides, slug)) return overrides[slug];
|
|
291
|
+
const defaults = kind === "collections" ? DEFAULT_COLLECTION_ROLES : DEFAULT_GLOBAL_ROLES;
|
|
292
|
+
if (Object.prototype.hasOwnProperty.call(defaults, slug)) return defaults[slug];
|
|
293
|
+
return fallback;
|
|
294
|
+
}
|
|
295
|
+
function rolesField() {
|
|
296
|
+
return {
|
|
297
|
+
name: "roles",
|
|
298
|
+
type: "relationship",
|
|
299
|
+
relationTo: CMS_ROLES_SLUG,
|
|
300
|
+
hasMany: true,
|
|
301
|
+
saveToJWT: true,
|
|
302
|
+
access: {
|
|
303
|
+
create: manageRolesAccess,
|
|
304
|
+
update: manageRolesAccess
|
|
305
|
+
},
|
|
306
|
+
admin: {
|
|
307
|
+
position: "sidebar",
|
|
308
|
+
description: "Only an admin can change roles. Several roles can be combined. Empty means Admin until a role is saved. The user must sign in again before a change applies."
|
|
309
|
+
}
|
|
310
|
+
};
|
|
311
|
+
}
|
|
312
|
+
function permissionFor(target, rule, role, collection) {
|
|
313
|
+
if (rule == null || rule === false || !rule.roles.includes(role)) return null;
|
|
314
|
+
return {
|
|
315
|
+
target,
|
|
316
|
+
create: collection,
|
|
317
|
+
update: true,
|
|
318
|
+
delete: false,
|
|
319
|
+
drafts: collection && rule.drafts === true
|
|
320
|
+
};
|
|
321
|
+
}
|
|
322
|
+
/** Targets shown in the Roles editor: stock defaults plus anything the app configures. */
|
|
323
|
+
function roleTargetSlugs(options = {}) {
|
|
324
|
+
const targets = /* @__PURE__ */ new Set([
|
|
325
|
+
...Object.keys(DEFAULT_COLLECTION_ROLES),
|
|
326
|
+
...Object.keys(DEFAULT_GLOBAL_ROLES),
|
|
327
|
+
...Object.keys(options.collections ?? {}),
|
|
328
|
+
...Object.keys(options.globals ?? {})
|
|
329
|
+
]);
|
|
330
|
+
targets.delete("users");
|
|
331
|
+
targets.delete(CMS_ROLES_SLUG);
|
|
332
|
+
return [...targets].sort();
|
|
333
|
+
}
|
|
334
|
+
/**
|
|
335
|
+
* Default role documents. Existing documents with the same slug are left alone,
|
|
336
|
+
* so edits made in the admin survive a restart.
|
|
337
|
+
*/
|
|
338
|
+
function buildRoleSeeds(options = {}) {
|
|
339
|
+
const roles = resolveRoleOptions(options);
|
|
340
|
+
const targets = roleTargetSlugs(options);
|
|
341
|
+
return roles.map((role) => {
|
|
342
|
+
if (role.value === "admin") return {
|
|
343
|
+
name: role.label,
|
|
344
|
+
slug: role.value,
|
|
345
|
+
fullAccess: true,
|
|
346
|
+
permissions: []
|
|
347
|
+
};
|
|
348
|
+
const permissions = targets.flatMap((target) => {
|
|
349
|
+
const collection = collectionRoleRule(options, target);
|
|
350
|
+
const global = globalRoleRule(options, target);
|
|
351
|
+
const row = permissionFor(target, collection !== void 0 ? collection : global, role.value, collection !== void 0);
|
|
352
|
+
return row ? [row] : [];
|
|
353
|
+
});
|
|
354
|
+
return {
|
|
355
|
+
name: role.label,
|
|
356
|
+
slug: role.value,
|
|
357
|
+
fullAccess: false,
|
|
358
|
+
permissions
|
|
359
|
+
};
|
|
360
|
+
});
|
|
361
|
+
}
|
|
362
|
+
function isCollectionConfig(config) {
|
|
363
|
+
if ("auth" in config || "upload" in config || "labels" in config || "defaultSort" in config) return true;
|
|
364
|
+
return Boolean(config.access && ("create" in config.access || "delete" in config.access));
|
|
365
|
+
}
|
|
366
|
+
/** Limits create, update, and delete from the Roles collection. Admin is always allowed. */
|
|
367
|
+
function withRoles(config) {
|
|
368
|
+
const collection = isCollectionConfig(config);
|
|
369
|
+
const users = collection && Boolean(config.auth);
|
|
370
|
+
const slug = config.slug;
|
|
371
|
+
const versioned = "versions" in config && Boolean(config.versions);
|
|
372
|
+
return {
|
|
373
|
+
...config,
|
|
374
|
+
admin: {
|
|
375
|
+
...config.admin,
|
|
376
|
+
...users ? { hidden: hiddenUnlessFullAdmin() } : { hidden: hiddenFor(slug) }
|
|
377
|
+
},
|
|
378
|
+
access: {
|
|
379
|
+
...config.access,
|
|
380
|
+
...collection ? {
|
|
381
|
+
create: users ? adminRoleAccess : ({ req }) => userCan(req, slug, "create"),
|
|
382
|
+
delete: users ? adminRoleAccess : ({ req }) => userCan(req, slug, "delete")
|
|
383
|
+
} : {},
|
|
384
|
+
...users ? {
|
|
385
|
+
read: selfOrAdminAccess,
|
|
386
|
+
update: selfOrAdminAccess
|
|
387
|
+
} : { update: ({ req }) => userCan(req, slug, "update") },
|
|
388
|
+
...versioned && !users ? { read: async ({ req }) => {
|
|
389
|
+
if (await userCan(req, slug, "update") || await userCan(req, slug, "drafts")) return true;
|
|
390
|
+
return { _status: { equals: "published" } };
|
|
391
|
+
} } : {}
|
|
392
|
+
},
|
|
393
|
+
...users && !(config.fields ?? []).some((field) => "name" in field && field.name === "roles") ? { fields: [...config.fields ?? [], rolesField()] } : {}
|
|
394
|
+
};
|
|
395
|
+
}
|
|
396
|
+
//#endregion
|
|
33
397
|
//#region src/cms/collections/createApiTokens.ts
|
|
34
398
|
const adminOrSelf = ({ req }) => {
|
|
35
399
|
if (req.user?.collection === "users") return true;
|
|
@@ -96,6 +460,133 @@ function createApiTokens(access) {
|
|
|
96
460
|
//#region src/cms/hooks/slugify.ts
|
|
97
461
|
const slugify = ({ value }) => typeof value === "string" ? value.toLowerCase().replace(/\s+/g, "-").replace(/[^a-z0-9-]/g, "") : value;
|
|
98
462
|
//#endregion
|
|
463
|
+
//#region src/cms/collections/createCmsRoles.ts
|
|
464
|
+
const refresh = ({ req }) => refreshRoleCache(req.payload);
|
|
465
|
+
const refreshAfterDelete = ({ req }) => refreshRoleCache(req.payload);
|
|
466
|
+
const keepAdminRole = ({ data, originalDoc }) => {
|
|
467
|
+
if (originalDoc?.slug === "admin" || data?.slug === "admin") return {
|
|
468
|
+
...data,
|
|
469
|
+
slug: ADMIN_ROLE,
|
|
470
|
+
fullAccess: true
|
|
471
|
+
};
|
|
472
|
+
return data;
|
|
473
|
+
};
|
|
474
|
+
const blockAdminDelete = async ({ id, req }) => {
|
|
475
|
+
if ((await req.payload.findByID({
|
|
476
|
+
collection: "cms-roles",
|
|
477
|
+
id,
|
|
478
|
+
depth: 0,
|
|
479
|
+
overrideAccess: true
|
|
480
|
+
})).slug === "admin") throw new Error("The Admin role cannot be deleted.");
|
|
481
|
+
};
|
|
482
|
+
const fullAdmin = ({ req }) => userIsFullAdmin(req);
|
|
483
|
+
function createCmsRoles(targets) {
|
|
484
|
+
return {
|
|
485
|
+
slug: CMS_ROLES_SLUG,
|
|
486
|
+
labels: {
|
|
487
|
+
singular: "Role",
|
|
488
|
+
plural: "Roles"
|
|
489
|
+
},
|
|
490
|
+
admin: {
|
|
491
|
+
useAsTitle: "name",
|
|
492
|
+
hidden: hiddenUnlessFullAdmin(),
|
|
493
|
+
description: "Who can edit each collection and global. Only an admin can change this."
|
|
494
|
+
},
|
|
495
|
+
access: {
|
|
496
|
+
read: fullAdmin,
|
|
497
|
+
create: fullAdmin,
|
|
498
|
+
update: fullAdmin,
|
|
499
|
+
delete: fullAdmin
|
|
500
|
+
},
|
|
501
|
+
hooks: {
|
|
502
|
+
beforeChange: [keepAdminRole],
|
|
503
|
+
beforeDelete: [blockAdminDelete],
|
|
504
|
+
afterChange: [refresh],
|
|
505
|
+
afterDelete: [refreshAfterDelete]
|
|
506
|
+
},
|
|
507
|
+
fields: [
|
|
508
|
+
{
|
|
509
|
+
name: "name",
|
|
510
|
+
type: "text",
|
|
511
|
+
required: true
|
|
512
|
+
},
|
|
513
|
+
{
|
|
514
|
+
name: "slug",
|
|
515
|
+
type: "text",
|
|
516
|
+
required: true,
|
|
517
|
+
unique: true,
|
|
518
|
+
index: true,
|
|
519
|
+
hooks: { beforeValidate: [slugify] },
|
|
520
|
+
admin: { description: "Stable id. Do not change it after users are assigned this role." }
|
|
521
|
+
},
|
|
522
|
+
{
|
|
523
|
+
name: "fullAccess",
|
|
524
|
+
type: "checkbox",
|
|
525
|
+
defaultValue: false,
|
|
526
|
+
admin: { description: "Can edit every collection, including Roles and Users." }
|
|
527
|
+
},
|
|
528
|
+
{
|
|
529
|
+
name: "permissions",
|
|
530
|
+
type: "array",
|
|
531
|
+
admin: {
|
|
532
|
+
condition: (data) => !data?.fullAccess,
|
|
533
|
+
description: "One row per collection or global. No row means no access."
|
|
534
|
+
},
|
|
535
|
+
fields: [
|
|
536
|
+
{
|
|
537
|
+
name: "target",
|
|
538
|
+
type: "select",
|
|
539
|
+
required: true,
|
|
540
|
+
options: targets.map((slug) => ({
|
|
541
|
+
label: slug,
|
|
542
|
+
value: slug
|
|
543
|
+
}))
|
|
544
|
+
},
|
|
545
|
+
{
|
|
546
|
+
name: "create",
|
|
547
|
+
type: "checkbox",
|
|
548
|
+
defaultValue: false
|
|
549
|
+
},
|
|
550
|
+
{
|
|
551
|
+
name: "update",
|
|
552
|
+
type: "checkbox",
|
|
553
|
+
defaultValue: false
|
|
554
|
+
},
|
|
555
|
+
{
|
|
556
|
+
name: "delete",
|
|
557
|
+
type: "checkbox",
|
|
558
|
+
defaultValue: false
|
|
559
|
+
},
|
|
560
|
+
{
|
|
561
|
+
name: "drafts",
|
|
562
|
+
type: "checkbox",
|
|
563
|
+
defaultValue: false,
|
|
564
|
+
admin: { description: "Can open unpublished documents. Update also allows this." }
|
|
565
|
+
}
|
|
566
|
+
]
|
|
567
|
+
}
|
|
568
|
+
]
|
|
569
|
+
};
|
|
570
|
+
}
|
|
571
|
+
/** Creates each default role once. Documents that already exist are left as edited. */
|
|
572
|
+
async function seedDefaultCmsRoles(payload, options = {}) {
|
|
573
|
+
const seeds = buildRoleSeeds(options);
|
|
574
|
+
await Promise.all(seeds.map(async (role) => {
|
|
575
|
+
if ((await payload.find({
|
|
576
|
+
collection: "cms-roles",
|
|
577
|
+
where: { slug: { equals: role.slug } },
|
|
578
|
+
limit: 1,
|
|
579
|
+
depth: 0,
|
|
580
|
+
overrideAccess: true
|
|
581
|
+
})).docs.length > 0) return;
|
|
582
|
+
await payload.create({
|
|
583
|
+
collection: CMS_ROLES_SLUG,
|
|
584
|
+
data: role,
|
|
585
|
+
overrideAccess: true
|
|
586
|
+
});
|
|
587
|
+
}));
|
|
588
|
+
}
|
|
589
|
+
//#endregion
|
|
99
590
|
//#region src/cms/shared/seo-fields.ts
|
|
100
591
|
const MAX_META_TITLE = 60;
|
|
101
592
|
const MAX_META_DESCRIPTION = 160;
|
|
@@ -398,6 +889,25 @@ const codeTabsBlock = {
|
|
|
398
889
|
}]
|
|
399
890
|
};
|
|
400
891
|
//#endregion
|
|
892
|
+
//#region src/cms/blocks/custom-html.ts
|
|
893
|
+
const customHtmlBlock = {
|
|
894
|
+
slug: "custom-html",
|
|
895
|
+
labels: {
|
|
896
|
+
singular: "Custom HTML",
|
|
897
|
+
plural: "Custom HTML"
|
|
898
|
+
},
|
|
899
|
+
fields: [{
|
|
900
|
+
name: "html",
|
|
901
|
+
type: "code",
|
|
902
|
+
required: true,
|
|
903
|
+
localized: true,
|
|
904
|
+
admin: {
|
|
905
|
+
language: "html",
|
|
906
|
+
description: "Raw HTML, CSS, and scripts. Rendered as-is. Inline scripts run in the browser, same as a WordPress Custom HTML block."
|
|
907
|
+
}
|
|
908
|
+
}]
|
|
909
|
+
};
|
|
910
|
+
//#endregion
|
|
401
911
|
//#region src/cms/blocks/download-cta.ts
|
|
402
912
|
const downloadCtaBlock = {
|
|
403
913
|
slug: "download-cta",
|
|
@@ -552,17 +1062,21 @@ const richTextFeatures = ({ defaultFeatures }) => [
|
|
|
552
1062
|
name: "caption",
|
|
553
1063
|
type: "text"
|
|
554
1064
|
}] } } }),
|
|
555
|
-
BlocksFeature({ blocks: [
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
1065
|
+
BlocksFeature({ blocks: [
|
|
1066
|
+
CodeBlock({
|
|
1067
|
+
languages: codeBlockLanguages,
|
|
1068
|
+
defaultLanguage: defaultCodeLanguage
|
|
1069
|
+
}),
|
|
1070
|
+
videoBlock,
|
|
1071
|
+
customHtmlBlock
|
|
1072
|
+
] }),
|
|
559
1073
|
EXPERIMENTAL_TableFeature()
|
|
560
1074
|
];
|
|
561
1075
|
/**
|
|
562
1076
|
* Shared Lexical editor for every `richText` field.
|
|
563
1077
|
*
|
|
564
|
-
* Adds `CodeBlock`, inline `video`
|
|
565
|
-
* `EXPERIMENTAL_TableFeature` on top of Payload defaults.
|
|
1078
|
+
* Adds `CodeBlock`, inline `video` and `custom-html` blocks, media upload
|
|
1079
|
+
* captions, and `EXPERIMENTAL_TableFeature` on top of Payload defaults.
|
|
566
1080
|
*/
|
|
567
1081
|
const richTextEditor = () => lexicalEditor({ features: richTextFeatures });
|
|
568
1082
|
/** Resolve Lexical editor config for seed scripts / markdown conversion. */
|
|
@@ -630,6 +1144,7 @@ const leafBlocks = [
|
|
|
630
1144
|
imageBlock,
|
|
631
1145
|
videoBlock,
|
|
632
1146
|
downloadCtaBlock,
|
|
1147
|
+
customHtmlBlock,
|
|
633
1148
|
stepsBlock
|
|
634
1149
|
];
|
|
635
1150
|
//#endregion
|
|
@@ -690,6 +1205,7 @@ const blogContentBlocks = [
|
|
|
690
1205
|
imageBlock,
|
|
691
1206
|
videoBlock,
|
|
692
1207
|
downloadCtaBlock,
|
|
1208
|
+
customHtmlBlock,
|
|
693
1209
|
stepsBlock,
|
|
694
1210
|
accordionBlock
|
|
695
1211
|
];
|
|
@@ -1693,12 +2209,31 @@ function buildCmsConfig(options) {
|
|
|
1693
2209
|
"event-tags": createEventTags(access),
|
|
1694
2210
|
"events": createEvents(access)
|
|
1695
2211
|
};
|
|
1696
|
-
const
|
|
1697
|
-
const
|
|
2212
|
+
const rolesSetting = options.access?.roles;
|
|
2213
|
+
const rolesEnabled = rolesSetting != null;
|
|
2214
|
+
const rolesConfig = rolesSetting === true || rolesSetting == null ? {} : rolesSetting;
|
|
2215
|
+
if (rolesEnabled) Object.keys(stock).forEach((slug) => {
|
|
2216
|
+
stock[slug] = withRoles(stock[slug]);
|
|
2217
|
+
});
|
|
2218
|
+
const collections = [
|
|
2219
|
+
...rolesEnabled ? [createCmsRoles(roleTargetSlugs(rolesConfig))] : [],
|
|
2220
|
+
...STOCK_COLLECTION_SLUGS.map((slug) => applyCollectionOverride(stock[slug], overrides[slug])).filter((c) => c !== null),
|
|
2221
|
+
...options.extraCollections ?? []
|
|
2222
|
+
];
|
|
2223
|
+
const siteSettingsBase = createSiteSettings(access);
|
|
2224
|
+
const siteSettingsWithRoles = rolesEnabled ? withRoles(siteSettingsBase) : siteSettingsBase;
|
|
2225
|
+
const siteSettings = applyGlobalOverride(siteSettingsWithRoles, overrides["site-settings"]);
|
|
1698
2226
|
const globals = [...siteSettings ? [siteSettings] : [], ...options.extraGlobals ?? []];
|
|
1699
|
-
const { jobs: jobsOverride, ...payloadRest } = options.payload ?? {};
|
|
2227
|
+
const { jobs: jobsOverride, onInit: callerOnInit, ...payloadRest } = options.payload ?? {};
|
|
1700
2228
|
return buildConfig({
|
|
1701
2229
|
...payloadRest,
|
|
2230
|
+
onInit: async (payload) => {
|
|
2231
|
+
if (rolesEnabled) {
|
|
2232
|
+
await seedDefaultCmsRoles(payload, rolesConfig);
|
|
2233
|
+
await refreshRoleCache(payload);
|
|
2234
|
+
}
|
|
2235
|
+
if (callerOnInit) await callerOnInit(payload);
|
|
2236
|
+
},
|
|
1702
2237
|
jobs: {
|
|
1703
2238
|
autoRun: [{ cron: "* * * * *" }],
|
|
1704
2239
|
...jobsOverride
|
|
@@ -1843,6 +2378,6 @@ function createAnnouncementBanner(access) {
|
|
|
1843
2378
|
};
|
|
1844
2379
|
}
|
|
1845
2380
|
//#endregion
|
|
1846
|
-
export { richTextBlock as A,
|
|
2381
|
+
export { globalRoleRule as $, richTextBlock as A, defaultCodeLanguage as B, blogContentBlocks as C, accordionBlock as D, sectionHeadingBlock as E, downloadCtaBlock as F, createApiTokens as G, createAuthors as H, customHtmlBlock as I, DEFAULT_GLOBAL_ROLES as J, ADMIN_ROLE as K, codeTabsBlock as L, richTextEditor as M, videoBlock as N, leafBlocks as O, imageBlock as P, effectiveRoles as Q, codeBlock as R, coerceBlogPostCategoriesOnWrite as S, showcaseContentBlocks as T, seoFields as U, languageOptions as V, slugify as W, adminRoleAccess as X, DEFAULT_ROLES as Y, collectionRoleRule as Z, createCategories as _, STOCK_COLLECTION_SLUGS as a, withRoles as at, setPublishedAt as b, createSiteSettings as c, createPages as d, hiddenUnless as et, createMedia as f, createChangelog as g, createChangelogTags as h, buildCmsConfig as i, userHasAnyRole as it, getRichTextEditorConfig as j, stepsBlock as k, createUsers as l, createEventTags as m, createS3MediaPlugin as n, publishedOrRoleRead as nt, applyCollectionOverride as o, writeAccess as ot, createEvents as p, DEFAULT_COLLECTION_ROLES as q, requireEnvAtRuntime as r, resolveRoleOptions as rt, applyGlobalOverride as s, createAccessHelpers as st, createAnnouncementBanner as t, isCmsAdmin as tt, createLegalPages as u, createBlogPosts as v, pageContentBlocks as w, coerceBlogPostCategoriesOnRead as x, draftsWithAutosave as y, codeBlockLanguages as z };
|
|
1847
2382
|
|
|
1848
2383
|
//# sourceMappingURL=cms.mjs.map
|