@commonpub/layer 0.57.0 → 0.59.0
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/components/LayoutRow.vue +8 -8
- package/components/LayoutSection.vue +8 -8
- package/components/LayoutSlot.vue +3 -3
- package/components/MirrorDetailModal.vue +3 -3
- package/components/MirrorRequestApproveModal.vue +3 -3
- package/components/PollDisplay.vue +1 -1
- package/components/RegistryDirectory.vue +2 -2
- package/components/admin/layouts/AdminLayoutsAutoForm.vue +1 -1
- package/components/admin/layouts/AdminLayoutsCanvas.vue +2 -2
- package/components/admin/layouts/AdminLayoutsConflictModal.vue +1 -1
- package/components/admin/layouts/AdminLayoutsHelpOverlay.vue +1 -1
- package/components/admin/layouts/AdminLayoutsInspectorPage.vue +1 -1
- package/components/admin/layouts/AdminLayoutsToolbar.vue +5 -5
- package/components/admin/theme/AdminThemeSceneGallery.vue +3 -3
- package/components/admin/theme/AdminThemeSceneProse.vue +3 -3
- package/components/admin/theme/AdminThemeTokenInput.vue +1 -1
- package/components/blocks/BlockCodeView.vue +2 -2
- package/components/blocks/BlockDividerView.vue +1 -1
- package/components/blocks/BlockPartsListView.vue +1 -1
- package/components/blocks/BlockQuizView.vue +1 -1
- package/components/blocks/BlockQuoteView.vue +1 -1
- package/components/contest/ContestHero.vue +2 -2
- package/components/contest/ContestStagesEditor.vue +4 -4
- package/components/editors/ArticleEditor.vue +1 -1
- package/components/editors/ExplainerEditor.vue +1 -1
- package/components/sections/SectionLearning.vue +1 -1
- package/components/views/ArticleView.vue +2 -2
- package/components/views/ProjectView.vue +3 -3
- package/composables/useAdminSidebar.ts +3 -3
- package/composables/useLayoutEditor.ts +1 -1
- package/composables/useLayoutHotkeys.ts +1 -1
- package/composables/useLayoutResize.ts +1 -1
- package/composables/usePublishValidation.ts +1 -1
- package/composables/useThemeAdmin.ts +2 -2
- package/error.vue +1 -1
- package/layouts/admin.vue +2 -2
- package/layouts/default.vue +2 -2
- package/package.json +6 -6
- package/pages/[type]/index.vue +1 -1
- package/pages/about.vue +3 -3
- package/pages/admin/api-keys.vue +5 -5
- package/pages/admin/audit.vue +2 -2
- package/pages/admin/categories.vue +1 -1
- package/pages/admin/content.vue +2 -2
- package/pages/admin/features.vue +1 -1
- package/pages/admin/federation.vue +9 -9
- package/pages/admin/homepage.vue +4 -4
- package/pages/admin/index.vue +1 -1
- package/pages/admin/layouts/[id].vue +18 -18
- package/pages/admin/layouts/index.vue +4 -4
- package/pages/admin/navigation.vue +1 -1
- package/pages/admin/reports.vue +1 -1
- package/pages/admin/settings.vue +2 -2
- package/pages/admin/theme/edit/[id].vue +2 -2
- package/pages/admin/theme/index.vue +5 -5
- package/pages/admin/users.vue +1 -1
- package/pages/auth/forgot-password.vue +1 -1
- package/pages/auth/login.vue +3 -3
- package/pages/auth/register.vue +1 -1
- package/pages/auth/reset-password.vue +1 -1
- package/pages/auth/verify-email.vue +1 -1
- package/pages/cert/[code].vue +1 -1
- package/pages/contests/[slug]/edit.vue +78 -19
- package/pages/contests/[slug]/index.vue +7 -7
- package/pages/contests/[slug]/judge.vue +15 -3
- package/pages/contests/[slug]/results.vue +5 -5
- package/pages/contests/create.vue +15 -15
- package/pages/contests/index.vue +2 -2
- package/pages/cookies.vue +1 -1
- package/pages/create.vue +2 -2
- package/pages/dashboard.vue +1 -1
- package/pages/docs/[siteSlug]/[...pagePath].vue +1 -1
- package/pages/docs/[siteSlug]/edit.vue +1 -1
- package/pages/docs/[siteSlug]/index.vue +1 -1
- package/pages/docs/create.vue +1 -1
- package/pages/docs/index.vue +1 -1
- package/pages/events/[slug]/edit.vue +1 -1
- package/pages/events/[slug]/index.vue +2 -2
- package/pages/events/create.vue +1 -1
- package/pages/events/index.vue +1 -1
- package/pages/explore.vue +1 -1
- package/pages/federated-hubs/[id]/index.vue +3 -3
- package/pages/federated-hubs/[id]/posts/[postId].vue +1 -1
- package/pages/federation/search.vue +1 -1
- package/pages/feed.vue +1 -1
- package/pages/hubs/[slug]/members.vue +1 -1
- package/pages/hubs/[slug]/posts/[postId].vue +1 -1
- package/pages/hubs/[slug]/settings.vue +5 -5
- package/pages/hubs/create.vue +6 -6
- package/pages/hubs/index.vue +1 -1
- package/pages/index.vue +2 -2
- package/pages/learn/[slug]/[lessonSlug]/edit.vue +1 -1
- package/pages/learn/[slug]/[lessonSlug]/index.vue +4 -4
- package/pages/learn/[slug]/edit.vue +1 -1
- package/pages/learn/[slug]/index.vue +1 -1
- package/pages/learn/create.vue +1 -1
- package/pages/learn/index.vue +2 -2
- package/pages/messages/[conversationId].vue +1 -1
- package/pages/messages/index.vue +1 -1
- package/pages/notifications.vue +1 -1
- package/pages/privacy.vue +5 -5
- package/pages/products/[slug].vue +1 -1
- package/pages/products/index.vue +1 -1
- package/pages/search.vue +1 -1
- package/pages/settings/profile.vue +1 -1
- package/pages/settings.vue +1 -1
- package/pages/tags/[slug].vue +1 -1
- package/pages/tags/index.vue +1 -1
- package/pages/terms.vue +1 -1
- package/pages/u/[username]/[type]/[slug]/edit.vue +3 -3
- package/pages/u/[username]/[type]/[slug]/index.vue +1 -1
- package/pages/u/[username]/followers.vue +1 -1
- package/pages/u/[username]/following.vue +1 -1
- package/pages/u/[username]/index.vue +3 -3
- package/pages/videos/[id].vue +1 -1
- package/pages/videos/index.vue +1 -1
- package/pages/videos/submit.vue +2 -2
- package/sections/builtin/hero.ts +1 -1
- package/sections/builtin/markdown.ts +1 -1
- package/server/api/admin/homepage/sections.put.ts +1 -1
- package/server/api/admin/layouts/[id].put.ts +1 -1
- package/server/api/contests/[slug]/entries.post.ts +3 -3
- package/server/api/hubs/[slug]/feed.xml.get.ts +1 -1
- package/server/api/users/[username]/feed.xml.get.ts +1 -1
- package/server/middleware/content-redirect.ts +1 -1
- package/server/plugins/federation-delivery.ts +1 -1
- package/server/plugins/federation-hub-sync.ts +1 -1
- package/server/plugins/registry-heartbeat.ts +3 -3
- package/server/plugins/search-index.ts +1 -1
- package/server/utils/email.ts +3 -3
- package/server/utils/instanceTheme.ts +1 -1
- package/utils/contestStages.ts +3 -3
|
@@ -86,7 +86,7 @@ export default defineEventHandler(async (event) => {
|
|
|
86
86
|
try {
|
|
87
87
|
const result = await migrateHomepageSectionsToLayout(db, {
|
|
88
88
|
adminId: user.id,
|
|
89
|
-
force: false, // changed from true
|
|
89
|
+
force: false, // changed from true, see comment above
|
|
90
90
|
});
|
|
91
91
|
if (result.migrated) {
|
|
92
92
|
invalidateLayoutsByRouteCache();
|
|
@@ -103,7 +103,7 @@ export default defineEventHandler(async (event) => {
|
|
|
103
103
|
) {
|
|
104
104
|
throw createError({
|
|
105
105
|
statusCode: 400,
|
|
106
|
-
statusMessage: 'Cannot change layout scope via PUT
|
|
106
|
+
statusMessage: 'Cannot change layout scope via PUT, POST a new layout instead',
|
|
107
107
|
});
|
|
108
108
|
}
|
|
109
109
|
|
|
@@ -27,7 +27,7 @@ export default defineEventHandler(async (event): Promise<ContestEntryItem> => {
|
|
|
27
27
|
const detail = contest.status === 'upcoming'
|
|
28
28
|
? 'Entries open once the contest is active.'
|
|
29
29
|
: contest.status === 'judging'
|
|
30
|
-
? 'Submissions are closed
|
|
30
|
+
? 'Submissions are closed, the contest is being judged.'
|
|
31
31
|
: `The contest is ${contest.status}.`;
|
|
32
32
|
throw createError({ statusCode: 400, statusMessage: `This contest isn't accepting entries right now. ${detail}` });
|
|
33
33
|
}
|
|
@@ -38,7 +38,7 @@ export default defineEventHandler(async (event): Promise<ContestEntryItem> => {
|
|
|
38
38
|
.limit(1);
|
|
39
39
|
if (!content) throw createError({ statusCode: 400, statusMessage: 'That content no longer exists.' });
|
|
40
40
|
if (content.authorId !== user.id) throw createError({ statusCode: 403, statusMessage: 'You can only submit your own content.' });
|
|
41
|
-
if (content.status !== 'published') throw createError({ statusCode: 400, statusMessage: 'That project isn’t published yet
|
|
41
|
+
if (content.status !== 'published') throw createError({ statusCode: 400, statusMessage: 'That project isn’t published yet, publish it first, then submit.' });
|
|
42
42
|
const eligible = contest.eligibleContentTypes ?? null;
|
|
43
43
|
if (eligible && eligible.length > 0 && !eligible.includes(content.type)) {
|
|
44
44
|
throw createError({ statusCode: 400, statusMessage: `This contest only accepts: ${eligible.join(', ')}.` });
|
|
@@ -48,7 +48,7 @@ export default defineEventHandler(async (event): Promise<ContestEntryItem> => {
|
|
|
48
48
|
// cap + dedupes; a null here means already-entered or over the entry limit.
|
|
49
49
|
const entry = await submitContestEntry(db, contest.id, input.contentId, user.id);
|
|
50
50
|
if (!entry) {
|
|
51
|
-
throw createError({ statusCode: 400, statusMessage: 'Couldn’t submit
|
|
51
|
+
throw createError({ statusCode: 400, statusMessage: 'Couldn’t submit, you may have already entered this project, or reached the contest’s entry limit.' });
|
|
52
52
|
}
|
|
53
53
|
return entry;
|
|
54
54
|
});
|
|
@@ -44,7 +44,7 @@ export default defineEventHandler(async (event) => {
|
|
|
44
44
|
const xml = `<?xml version="1.0" encoding="UTF-8"?>
|
|
45
45
|
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
|
|
46
46
|
<channel>
|
|
47
|
-
<title>${escapeXml(hub.name)}
|
|
47
|
+
<title>${escapeXml(hub.name)}, CommonPub</title>
|
|
48
48
|
<link>${escapeXml(siteUrl)}/hubs/${escapeXml(slug)}</link>
|
|
49
49
|
<description>${escapeXml(hub.description ?? `Content from ${hub.name}`)}</description>
|
|
50
50
|
<language>en</language>
|
|
@@ -49,7 +49,7 @@ export default defineEventHandler(async (event) => {
|
|
|
49
49
|
const xml = `<?xml version="1.0" encoding="UTF-8"?>
|
|
50
50
|
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
|
|
51
51
|
<channel>
|
|
52
|
-
<title>${escapeXml(displayName)}
|
|
52
|
+
<title>${escapeXml(displayName)}, CommonPub</title>
|
|
53
53
|
<link>${escapeXml(siteUrl)}/u/${escapeXml(username)}</link>
|
|
54
54
|
<description>Content by ${escapeXml(displayName)}</description>
|
|
55
55
|
<language>en</language>
|
|
@@ -43,7 +43,7 @@ export default defineEventHandler(async (event) => {
|
|
|
43
43
|
.where(and(eq(contentItems.slug, slug), isNull(contentItems.deletedAt)))
|
|
44
44
|
.limit(1);
|
|
45
45
|
|
|
46
|
-
if (!row) return; // Content not found
|
|
46
|
+
if (!row) return; // Content not found, let the page handler show 404
|
|
47
47
|
|
|
48
48
|
const newPath = isEdit
|
|
49
49
|
? `/u/${row.username}/${row.type}/${row.slug}/edit`
|
|
@@ -15,7 +15,7 @@ export default defineNitroPlugin((nitro) => {
|
|
|
15
15
|
try {
|
|
16
16
|
const config = useConfig();
|
|
17
17
|
if (!config.features.federation) {
|
|
18
|
-
console.log('[federation] Federation disabled
|
|
18
|
+
console.log('[federation] Federation disabled, delivery worker not started');
|
|
19
19
|
return;
|
|
20
20
|
}
|
|
21
21
|
|
|
@@ -23,7 +23,7 @@ export default defineNitroPlugin((nitro) => {
|
|
|
23
23
|
try {
|
|
24
24
|
const config = useConfig();
|
|
25
25
|
if (!config.features.federateHubs) {
|
|
26
|
-
console.log('[hub-sync] Hub federation disabled
|
|
26
|
+
console.log('[hub-sync] Hub federation disabled, sync worker not started');
|
|
27
27
|
return;
|
|
28
28
|
}
|
|
29
29
|
|
|
@@ -15,12 +15,12 @@ export default defineNitroPlugin((nitro) => {
|
|
|
15
15
|
try {
|
|
16
16
|
const config = useConfig();
|
|
17
17
|
if (!config.features.announceToRegistry) {
|
|
18
|
-
return; // opt-in
|
|
18
|
+
return; // opt-in, silent when off
|
|
19
19
|
}
|
|
20
20
|
// The registry verifies our ping by resolving `https://{instance.domain}/actor`, which is
|
|
21
21
|
// only served when federation is on. Without it every ping 401s — warn + skip.
|
|
22
22
|
if (!config.features.federation) {
|
|
23
|
-
console.warn('[registry] announceToRegistry is on but federation is off
|
|
23
|
+
console.warn('[registry] announceToRegistry is on but federation is off, pings would be unverifiable (our /actor is not served). Skipping.');
|
|
24
24
|
return;
|
|
25
25
|
}
|
|
26
26
|
const registryUrl = config.federation?.registryUrl ?? 'https://commonpub.io';
|
|
@@ -32,7 +32,7 @@ export default defineNitroPlugin((nitro) => {
|
|
|
32
32
|
// Don't announce a registry to itself.
|
|
33
33
|
const registryDomain = registryUrl.replace(/^https?:\/\//, '').replace(/[:/].*$/, '');
|
|
34
34
|
if (registryDomain === domain) {
|
|
35
|
-
console.log('[registry] Skipping heartbeat
|
|
35
|
+
console.log('[registry] Skipping heartbeat, this instance is its own registry');
|
|
36
36
|
return;
|
|
37
37
|
}
|
|
38
38
|
|
|
@@ -13,7 +13,7 @@ export default defineNitroPlugin(async () => {
|
|
|
13
13
|
const meiliKey = process.env.MEILI_MASTER_KEY;
|
|
14
14
|
|
|
15
15
|
if (!meiliUrl) {
|
|
16
|
-
console.log('[search-index] Meilisearch not configured
|
|
16
|
+
console.log('[search-index] Meilisearch not configured, search uses Postgres FTS fallback');
|
|
17
17
|
return;
|
|
18
18
|
}
|
|
19
19
|
|
package/server/utils/email.ts
CHANGED
|
@@ -21,7 +21,7 @@ export function useEmailAdapter(): EmailAdapter {
|
|
|
21
21
|
const from = runtimeConfig.smtpFrom as string;
|
|
22
22
|
|
|
23
23
|
if (!host || !user || !pass || !from) {
|
|
24
|
-
console.warn('[email] SMTP configured but missing credentials
|
|
24
|
+
console.warn('[email] SMTP configured but missing credentials, falling back to console');
|
|
25
25
|
cachedAdapter = new ConsoleEmailAdapter();
|
|
26
26
|
return cachedAdapter;
|
|
27
27
|
}
|
|
@@ -35,7 +35,7 @@ export function useEmailAdapter(): EmailAdapter {
|
|
|
35
35
|
const from = runtimeConfig.resendFrom as string;
|
|
36
36
|
|
|
37
37
|
if (!apiKey || !from) {
|
|
38
|
-
console.warn('[email] Resend configured but missing API key or from address
|
|
38
|
+
console.warn('[email] Resend configured but missing API key or from address, falling back to console');
|
|
39
39
|
cachedAdapter = new ConsoleEmailAdapter();
|
|
40
40
|
return cachedAdapter;
|
|
41
41
|
}
|
|
@@ -45,7 +45,7 @@ export function useEmailAdapter(): EmailAdapter {
|
|
|
45
45
|
}
|
|
46
46
|
|
|
47
47
|
if (process.env.NODE_ENV === 'production') {
|
|
48
|
-
console.warn('[email] ⚠ Using console email adapter in production
|
|
48
|
+
console.warn('[email] ⚠ Using console email adapter in production, emails will be logged, not sent. Set NUXT_EMAIL_ADAPTER to "smtp" or "resend".');
|
|
49
49
|
}
|
|
50
50
|
cachedAdapter = new ConsoleEmailAdapter();
|
|
51
51
|
return cachedAdapter;
|
|
@@ -12,7 +12,7 @@ import {
|
|
|
12
12
|
} from '@commonpub/server';
|
|
13
13
|
import { THEME_TO_FAMILY, FAMILY_VARIANTS, IS_DARK, VALID_THEME_IDS } from '../../utils/themeConfig';
|
|
14
14
|
|
|
15
|
-
const CACHE_TTL = 60_000; // 1 minute
|
|
15
|
+
const CACHE_TTL = 60_000; // 1 minute, admin changes propagate fast
|
|
16
16
|
|
|
17
17
|
interface CachedThemeState {
|
|
18
18
|
/** The admin's chosen default theme (built-in id, custom data-attr, or registered id) */
|
package/utils/contestStages.ts
CHANGED
|
@@ -118,8 +118,8 @@ export const STAGE_KIND_LABEL: Record<ContestStage['kind'], string> = {
|
|
|
118
118
|
export const STAGE_KIND_HELP: Record<ContestStage['kind'], string> = {
|
|
119
119
|
submission: 'Entrants submit (or, in a later round, refine) entries. The hero countdown targets this stage’s end date.',
|
|
120
120
|
review: 'Judges score entries on a rubric. End a review stage with an Advancement cut (Top-N) to pick who continues. Add per-round criteria below for multi-round contests.',
|
|
121
|
-
interim: 'A working period
|
|
121
|
+
interim: 'A working period, e.g. a build sprint. The surviving cohort refines their existing entries; no new entrants.',
|
|
122
122
|
results: 'Final standings are published (ranks calculated from the latest judging round).',
|
|
123
|
-
event: 'A real-world milestone or showcase (date + location). Informational
|
|
124
|
-
custom: 'An arbitrary dated milestone. No behaviour
|
|
123
|
+
event: 'A real-world milestone or showcase (date + location). Informational, no entry/judging behaviour.',
|
|
124
|
+
custom: 'An arbitrary dated milestone. No behaviour, just appears on the timeline.',
|
|
125
125
|
};
|