publish(task 21): date-string-coercion + force-all migration erfolgreich
validatePost akzeptiert jetzt auch string-dates im YYYY-MM-DD- oder ISO-8601-format und coerced sie in ein Date-objekt in-place. vorher schlug die validation für 13 von 18 altposts fehl, weil deren yaml `date: "2023-02-26"` quoted war (hugo-konvention) und der yaml-parser strings statt Date-instanzen liefert. migration durchgelaufen (log in docs/publish-logs/): 18/18 success, 91 bilder auf beiden blossom-servern, 5 write-relays — bis auf relay.damus.io, der bei 6 posts nicht auf OK antwortet (üblich bei damus, rate-limiting). alle 7 multi-relay-posts haben weiter mindestens 4 acks (über MIN_RELAY_ACKS=2). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
db61149924
commit
0c6fdd15c3
|
|
@ -0,0 +1,372 @@
|
|||
{
|
||||
"run_id": "6356c2c9-37c6-4927-b906-7943bb59d3c0",
|
||||
"started_at": "2026-04-18T04:44:43.558Z",
|
||||
"ended_at": "2026-04-18T04:47:34.238Z",
|
||||
"mode": "force-all",
|
||||
"posts": [
|
||||
{
|
||||
"slug": "premium-freemium-mium-mium-mium",
|
||||
"status": "success",
|
||||
"action": "new",
|
||||
"event_id": "7f18e5fbc825f16d118281e4c56ce8a989d2647fedcd3d4e45a8df0e897a395c",
|
||||
"relays_ok": [
|
||||
"wss://nos.lol/",
|
||||
"wss://relay.damus.io/",
|
||||
"wss://relay.primal.net/",
|
||||
"wss://relay.tchncs.de/",
|
||||
"wss://relay.edufeed.org/"
|
||||
],
|
||||
"relays_failed": [],
|
||||
"blossom_servers_ok": [
|
||||
"https://blossom.edufeed.org",
|
||||
"https://blossom.primal.net"
|
||||
],
|
||||
"images_uploaded": 1,
|
||||
"duration_ms": 4294
|
||||
},
|
||||
{
|
||||
"slug": "erlebnispadagogik-im-handbuch-jugend-evangelische-perspektive",
|
||||
"status": "success",
|
||||
"action": "new",
|
||||
"event_id": "ee5ecc397b4bfbff268ec3c53187f0b2b4a03958e14df2728c27145a72b85941",
|
||||
"relays_ok": [
|
||||
"wss://nos.lol/",
|
||||
"wss://relay.damus.io/",
|
||||
"wss://relay.primal.net/",
|
||||
"wss://relay.tchncs.de/",
|
||||
"wss://relay.edufeed.org/"
|
||||
],
|
||||
"relays_failed": [],
|
||||
"blossom_servers_ok": [],
|
||||
"images_uploaded": 0,
|
||||
"duration_ms": 3111
|
||||
},
|
||||
{
|
||||
"slug": "telegram-octopi",
|
||||
"status": "success",
|
||||
"action": "new",
|
||||
"event_id": "bee5a9150ce2055e17d729772b4a998afbd3333e6224beb72fd2152ee2d0c05e",
|
||||
"relays_ok": [
|
||||
"wss://nos.lol/",
|
||||
"wss://relay.damus.io/",
|
||||
"wss://relay.primal.net/",
|
||||
"wss://relay.tchncs.de/",
|
||||
"wss://relay.edufeed.org/"
|
||||
],
|
||||
"relays_failed": [],
|
||||
"blossom_servers_ok": [
|
||||
"https://blossom.edufeed.org",
|
||||
"https://blossom.primal.net"
|
||||
],
|
||||
"images_uploaded": 4,
|
||||
"duration_ms": 5169
|
||||
},
|
||||
{
|
||||
"slug": "lutherkuerbis",
|
||||
"status": "success",
|
||||
"action": "new",
|
||||
"event_id": "7715c4359da95c0459a6e65fd25c17c3c8c169e83fe68acb9f98ed34dd44e4e6",
|
||||
"relays_ok": [
|
||||
"wss://nos.lol/",
|
||||
"wss://relay.damus.io/",
|
||||
"wss://relay.primal.net/",
|
||||
"wss://relay.tchncs.de/",
|
||||
"wss://relay.edufeed.org/"
|
||||
],
|
||||
"relays_failed": [],
|
||||
"blossom_servers_ok": [
|
||||
"https://blossom.edufeed.org",
|
||||
"https://blossom.primal.net"
|
||||
],
|
||||
"images_uploaded": 6,
|
||||
"duration_ms": 7921
|
||||
},
|
||||
{
|
||||
"slug": "pflanzenschild-qr-code",
|
||||
"status": "success",
|
||||
"action": "new",
|
||||
"event_id": "f66520b363e568bf2714b6d6bd63543dd4f79f8e834d40566656ea35d37ecdf2",
|
||||
"relays_ok": [
|
||||
"wss://nos.lol/",
|
||||
"wss://relay.damus.io/",
|
||||
"wss://relay.primal.net/",
|
||||
"wss://relay.tchncs.de/",
|
||||
"wss://relay.edufeed.org/"
|
||||
],
|
||||
"relays_failed": [],
|
||||
"blossom_servers_ok": [
|
||||
"https://blossom.edufeed.org",
|
||||
"https://blossom.primal.net"
|
||||
],
|
||||
"images_uploaded": 2,
|
||||
"duration_ms": 4436
|
||||
},
|
||||
{
|
||||
"slug": "virtual-reality",
|
||||
"status": "success",
|
||||
"action": "new",
|
||||
"event_id": "28b75d85774056e6e59097ebf58c44c9e8badadbd25084d0eebc3f95a9a90439",
|
||||
"relays_ok": [
|
||||
"wss://nos.lol/",
|
||||
"wss://relay.primal.net/",
|
||||
"wss://relay.tchncs.de/",
|
||||
"wss://relay.edufeed.org/"
|
||||
],
|
||||
"relays_failed": [
|
||||
"wss://relay.damus.io/"
|
||||
],
|
||||
"blossom_servers_ok": [
|
||||
"https://blossom.edufeed.org",
|
||||
"https://blossom.primal.net"
|
||||
],
|
||||
"images_uploaded": 7,
|
||||
"duration_ms": 14102
|
||||
},
|
||||
{
|
||||
"slug": "wordpress-werkstatt",
|
||||
"status": "success",
|
||||
"action": "new",
|
||||
"event_id": "5ff5ca9dcc4098e042c7bfe0808f05aea6d7ea871dbb69696594a7d7682b3115",
|
||||
"relays_ok": [
|
||||
"wss://nos.lol/",
|
||||
"wss://relay.damus.io/",
|
||||
"wss://relay.primal.net/",
|
||||
"wss://relay.tchncs.de/",
|
||||
"wss://relay.edufeed.org/"
|
||||
],
|
||||
"relays_failed": [],
|
||||
"blossom_servers_ok": [
|
||||
"https://blossom.edufeed.org",
|
||||
"https://blossom.primal.net"
|
||||
],
|
||||
"images_uploaded": 7,
|
||||
"duration_ms": 9300
|
||||
},
|
||||
{
|
||||
"slug": "bibelfussball",
|
||||
"status": "success",
|
||||
"action": "new",
|
||||
"event_id": "ee019e772f2c8e52a3d77041495508f5d65ab34bb46ccaff3a74f34173cc194f",
|
||||
"relays_ok": [
|
||||
"wss://nos.lol/",
|
||||
"wss://relay.primal.net/",
|
||||
"wss://relay.tchncs.de/",
|
||||
"wss://relay.edufeed.org/"
|
||||
],
|
||||
"relays_failed": [
|
||||
"wss://relay.damus.io/"
|
||||
],
|
||||
"blossom_servers_ok": [
|
||||
"https://blossom.edufeed.org",
|
||||
"https://blossom.primal.net"
|
||||
],
|
||||
"images_uploaded": 1,
|
||||
"duration_ms": 8627
|
||||
},
|
||||
{
|
||||
"slug": "moodle-iomad-linux",
|
||||
"status": "success",
|
||||
"action": "new",
|
||||
"event_id": "707e98d43993778d8e5ffb87a29262d32decc6d0518399991ed7e6c7b4dedf1d",
|
||||
"relays_ok": [
|
||||
"wss://nos.lol/",
|
||||
"wss://relay.primal.net/",
|
||||
"wss://relay.tchncs.de/",
|
||||
"wss://relay.edufeed.org/"
|
||||
],
|
||||
"relays_failed": [
|
||||
"wss://relay.damus.io/"
|
||||
],
|
||||
"blossom_servers_ok": [
|
||||
"https://blossom.edufeed.org",
|
||||
"https://blossom.primal.net"
|
||||
],
|
||||
"images_uploaded": 4,
|
||||
"duration_ms": 10653
|
||||
},
|
||||
{
|
||||
"slug": "ob-virtualcam",
|
||||
"status": "success",
|
||||
"action": "new",
|
||||
"event_id": "1e62cf1f6375fc3988024a3f3d02c041a3065ad69f53b32cb085858fff3c8ed0",
|
||||
"relays_ok": [
|
||||
"wss://nos.lol/",
|
||||
"wss://relay.damus.io/",
|
||||
"wss://relay.primal.net/",
|
||||
"wss://relay.tchncs.de/",
|
||||
"wss://relay.edufeed.org/"
|
||||
],
|
||||
"relays_failed": [],
|
||||
"blossom_servers_ok": [
|
||||
"https://blossom.edufeed.org",
|
||||
"https://blossom.primal.net"
|
||||
],
|
||||
"images_uploaded": 31,
|
||||
"duration_ms": 32549
|
||||
},
|
||||
{
|
||||
"slug": "jojos-schoko-zimt-schnecken",
|
||||
"status": "success",
|
||||
"action": "new",
|
||||
"event_id": "8561994ee97ebec8775e60106cd8c58b3b24df27c8c0f442e03c2ad384003df2",
|
||||
"relays_ok": [
|
||||
"wss://nos.lol/",
|
||||
"wss://relay.damus.io/",
|
||||
"wss://relay.primal.net/",
|
||||
"wss://relay.tchncs.de/",
|
||||
"wss://relay.edufeed.org/"
|
||||
],
|
||||
"relays_failed": [],
|
||||
"blossom_servers_ok": [
|
||||
"https://blossom.edufeed.org",
|
||||
"https://blossom.primal.net"
|
||||
],
|
||||
"images_uploaded": 6,
|
||||
"duration_ms": 9240
|
||||
},
|
||||
{
|
||||
"slug": "gleichnis-vom-saemann",
|
||||
"status": "success",
|
||||
"action": "new",
|
||||
"event_id": "a9b49cbf601b7dba4cb7b63e26c281308fee2f722b4c2c0bb7485d339cd9364e",
|
||||
"relays_ok": [
|
||||
"wss://nos.lol/",
|
||||
"wss://relay.damus.io/",
|
||||
"wss://relay.primal.net/",
|
||||
"wss://relay.tchncs.de/",
|
||||
"wss://relay.edufeed.org/"
|
||||
],
|
||||
"relays_failed": [],
|
||||
"blossom_servers_ok": [
|
||||
"https://blossom.edufeed.org",
|
||||
"https://blossom.primal.net"
|
||||
],
|
||||
"images_uploaded": 9,
|
||||
"duration_ms": 14335
|
||||
},
|
||||
{
|
||||
"slug": "dampfnudeln",
|
||||
"status": "success",
|
||||
"action": "new",
|
||||
"event_id": "51e032c62bc228ace874321f4bcb4f872fe4841258aba3d6d7208ce476664b43",
|
||||
"relays_ok": [
|
||||
"wss://nos.lol/",
|
||||
"wss://relay.damus.io/",
|
||||
"wss://relay.primal.net/",
|
||||
"wss://relay.tchncs.de/",
|
||||
"wss://relay.edufeed.org/"
|
||||
],
|
||||
"relays_failed": [],
|
||||
"blossom_servers_ok": [
|
||||
"https://blossom.edufeed.org",
|
||||
"https://blossom.primal.net"
|
||||
],
|
||||
"images_uploaded": 6,
|
||||
"duration_ms": 8128
|
||||
},
|
||||
{
|
||||
"slug": "wordpress-statt-padlet-oder-taskcards",
|
||||
"status": "success",
|
||||
"action": "update",
|
||||
"event_id": "8bd17088cb93d4b9868ac4764057f1963c9878a88abc528152649ff2d7b425ef",
|
||||
"relays_ok": [
|
||||
"wss://nos.lol/",
|
||||
"wss://relay.damus.io/",
|
||||
"wss://relay.primal.net/",
|
||||
"wss://relay.tchncs.de/",
|
||||
"wss://relay.edufeed.org/"
|
||||
],
|
||||
"relays_failed": [],
|
||||
"blossom_servers_ok": [
|
||||
"https://blossom.edufeed.org",
|
||||
"https://blossom.primal.net"
|
||||
],
|
||||
"images_uploaded": 3,
|
||||
"duration_ms": 7449
|
||||
},
|
||||
{
|
||||
"slug": "offenheit-das-wesentliche",
|
||||
"status": "success",
|
||||
"action": "update",
|
||||
"event_id": "45472a71074ed5fdb2c654c8500a9fb581bcf48221be3d565fb6b9ea088c9ab0",
|
||||
"relays_ok": [
|
||||
"wss://nos.lol/",
|
||||
"wss://relay.primal.net/",
|
||||
"wss://relay.tchncs.de/",
|
||||
"wss://relay.edufeed.org/"
|
||||
],
|
||||
"relays_failed": [
|
||||
"wss://relay.damus.io/"
|
||||
],
|
||||
"blossom_servers_ok": [
|
||||
"https://blossom.edufeed.org",
|
||||
"https://blossom.primal.net"
|
||||
],
|
||||
"images_uploaded": 1,
|
||||
"duration_ms": 8235
|
||||
},
|
||||
{
|
||||
"slug": "bottomup-markdown",
|
||||
"status": "success",
|
||||
"action": "update",
|
||||
"event_id": "a8030ba0f9c62a5787a84c607b11f3eaf9c0c694adcc245b9969522cff9f0e30",
|
||||
"relays_ok": [
|
||||
"wss://nos.lol/",
|
||||
"wss://relay.primal.net/",
|
||||
"wss://relay.tchncs.de/",
|
||||
"wss://relay.edufeed.org/"
|
||||
],
|
||||
"relays_failed": [
|
||||
"wss://relay.damus.io/"
|
||||
],
|
||||
"blossom_servers_ok": [
|
||||
"https://blossom.edufeed.org",
|
||||
"https://blossom.primal.net"
|
||||
],
|
||||
"images_uploaded": 1,
|
||||
"duration_ms": 7143
|
||||
},
|
||||
{
|
||||
"slug": "kibedenken-bewusstsein",
|
||||
"status": "success",
|
||||
"action": "update",
|
||||
"event_id": "a05458fc79f4192fef6902e8c55c465f3d9c26cede5772259d5f2d5879734dd2",
|
||||
"relays_ok": [
|
||||
"wss://nos.lol/",
|
||||
"wss://relay.damus.io/",
|
||||
"wss://relay.primal.net/",
|
||||
"wss://relay.tchncs.de/",
|
||||
"wss://relay.edufeed.org/"
|
||||
],
|
||||
"relays_failed": [],
|
||||
"blossom_servers_ok": [
|
||||
"https://blossom.edufeed.org",
|
||||
"https://blossom.primal.net"
|
||||
],
|
||||
"images_uploaded": 1,
|
||||
"duration_ms": 5147
|
||||
},
|
||||
{
|
||||
"slug": "dezentrale-oep-oer",
|
||||
"status": "success",
|
||||
"action": "update",
|
||||
"event_id": "4db003fd8c144fe1b0528c8cfbfb075ff6a8f203fd327c10c4c46e42fcac2a40",
|
||||
"relays_ok": [
|
||||
"wss://nos.lol/",
|
||||
"wss://relay.primal.net/",
|
||||
"wss://relay.tchncs.de/",
|
||||
"wss://relay.edufeed.org/"
|
||||
],
|
||||
"relays_failed": [
|
||||
"wss://relay.damus.io/"
|
||||
],
|
||||
"blossom_servers_ok": [
|
||||
"https://blossom.edufeed.org",
|
||||
"https://blossom.primal.net"
|
||||
],
|
||||
"images_uploaded": 1,
|
||||
"duration_ms": 8489
|
||||
}
|
||||
],
|
||||
"exit_code": 0
|
||||
}
|
||||
|
|
@ -1,6 +1,7 @@
|
|||
import type { Frontmatter } from './frontmatter.ts'
|
||||
|
||||
const SLUG_RE = /^[a-z0-9][a-z0-9-]*$/
|
||||
const DATE_STRING_RE = /^\d{4}-\d{2}-\d{2}(T\d{2}:\d{2}:\d{2}(\.\d+)?(Z|[+-]\d{2}:?\d{2})?)?$/
|
||||
|
||||
export function validateSlug(slug: string): void {
|
||||
if (!SLUG_RE.test(slug)) {
|
||||
|
|
@ -16,7 +17,14 @@ export function validatePost(fm: Frontmatter): void {
|
|||
throw new Error('missing/invalid slug')
|
||||
}
|
||||
validateSlug(fm.slug)
|
||||
// Coerce string-dates (YAML `date: "2023-02-26"`) in-place zu Date.
|
||||
// Native YAML-Dates (`date: 2023-02-26` ohne quotes) kommen bereits als
|
||||
// Date-instanz aus dem yaml-parser.
|
||||
if (typeof fm.date === 'string' && DATE_STRING_RE.test(fm.date)) {
|
||||
const coerced = new Date(fm.date)
|
||||
if (!isNaN(coerced.getTime())) fm.date = coerced
|
||||
}
|
||||
if (!(fm.date instanceof Date) || isNaN(fm.date.getTime())) {
|
||||
throw new Error('missing/invalid date (expected YAML date)')
|
||||
throw new Error('missing/invalid date (expected YAML date or ISO-string)')
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { assertThrows } from '@std/assert'
|
||||
import { assertEquals, assertThrows } from '@std/assert'
|
||||
import { validatePost, validateSlug } from '../src/core/validation.ts'
|
||||
import type { Frontmatter } from '../src/core/frontmatter.ts'
|
||||
|
||||
|
|
@ -35,7 +35,24 @@ Deno.test('validatePost: fehlt title', () => {
|
|||
assertThrows(() => validatePost(fm), Error, 'title')
|
||||
})
|
||||
|
||||
Deno.test('validatePost: date muss Date sein', () => {
|
||||
Deno.test('validatePost: lehnt beliebige strings als date ab', () => {
|
||||
const fm = { title: 'T', slug: 'ok', date: 'not-a-date' } as unknown as Frontmatter
|
||||
assertThrows(() => validatePost(fm), Error, 'date')
|
||||
})
|
||||
|
||||
Deno.test('validatePost: akzeptiert YYYY-MM-DD string-date (coerce zu Date)', () => {
|
||||
const fm = { title: 'T', slug: 'ok', date: '2023-02-26' } as unknown as Frontmatter
|
||||
validatePost(fm)
|
||||
assertEquals(fm.date instanceof Date, true)
|
||||
assertEquals((fm.date as Date).toISOString().startsWith('2023-02-26'), true)
|
||||
})
|
||||
|
||||
Deno.test('validatePost: akzeptiert ISO-string-date', () => {
|
||||
const fm = {
|
||||
title: 'T',
|
||||
slug: 'ok',
|
||||
date: '2024-01-15T10:30:00Z',
|
||||
} as unknown as Frontmatter
|
||||
validatePost(fm)
|
||||
assertEquals(fm.date instanceof Date, true)
|
||||
})
|
||||
|
|
|
|||
Loading…
Reference in New Issue