Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -117,9 +117,9 @@ jobs:

- name: Lighthouse CI
id: lhci
timeout-minutes: 5
run: |
npm install -g @lhci/cli
lhci autorun
timeout 5m bash -lc 'npm install -g @lhci/cli && lhci autorun'
continue-on-error: true

- name: Upload Lighthouse results
Expand Down
25 changes: 18 additions & 7 deletions docs/tinyland-static-post-pulse-ingest-2026-05-10.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,13 @@
Date: 2026-05-10

This repo is the static consumer for `transscendsurvival.org`. Tinyland owns the
reviewed source projection; this site keeps rendering ordinary frontmatter posts
and a checked-in Pulse snapshot.
reviewed source projection.

2026-05-19 correction: this checked-in ingest path is fallback and migration
evidence only. The intended Cloudflare Pages display path is runtime broker
fetch from `hub.tinyland.dev`, with Tinyland-managed greymatter as the source of
truth. Checked-in snapshots must not be treated as the live blog federation
mechanism.

## Checked-In Inputs

Expand All @@ -20,8 +25,13 @@ Pulse projection snapshot:
static/data/pulse/public-snapshot.v1.json
```

Both are copied from Tinyland reviewed static artifacts. They are not fetched
from a live broker at runtime.
Both are copied from Tinyland reviewed static artifacts. They remain useful as
first-paint and regression fixtures, but canonical blog display now hydrates
from:

```text
https://hub.tinyland.dev/projections/jesssullivan-github-io/blog/broker-stream.v1.json
```

## Post Ingest

Expand Down Expand Up @@ -85,13 +95,14 @@ index and validating Pulse.

Allowed:

- checked-in static snapshots;
- ordinary Markdown/frontmatter posts in `src/posts`;
- checked-in static snapshots as fallback/regression fixtures;
- ordinary Markdown/frontmatter posts in `src/posts` for legacy/static
first-paint content;
- runtime display fetches from the public `hub.tinyland.dev` broker stream;
- the existing `PublicPulseSnapshot` validator and `/pulse` renderer.

Blocked:

- live broker fetches during SvelteKit render;
- mutations back into Tinyland;
- ActivityPub delivery, inbox, follower, retry, tombstone, or moderation claims;
- private storage refs, exact location payloads, credentials, or payment data.
Expand Down
13 changes: 6 additions & 7 deletions e2e/pulse-brokered-stream.spec.ts
Original file line number Diff line number Diff line change
@@ -1,20 +1,19 @@
import { test, expect } from '@playwright/test';

const endpoint = 'https://tinyland.dev/projections/jesssullivan-github-io/pulse/ap-stream-demo.v1.json';
const endpointPattern = '**/projections/jesssullivan-github-io/pulse/ap-stream-demo.v1.json**';
const endpoint = 'https://hub.tinyland.dev/projections/jesssullivan-github-io/pulse/ap-stream-demo.v1.json';

const liveDemo = {
schemaVersion: 'tinyland.pulse.ap-stream-demo.v1',
generatedAt: '2026-05-10T13:00:00.000Z',
sourceAuthority: 'tinyland.dev',
sourceAuthorityUrl: 'https://tinyland.dev',
sourceAuthorityUrl: 'https://hub.tinyland.dev',
sourceSnapshotId: 'tinyland-jesssullivan-pulse-static-seed-2026-05-10',
contentHash: 'sha256:fc3b04ec97946d6777e5245040b09a3ead296a9bf4614d0fea7df2d3cfb2ccb7',
policyVersion: 'm1-2026-04-27',
projectionKind: 'pulse-ap-stream-demo',
demoStatus: 'controlled-static-source-live-broker-demo',
demoStatus: 'controlled-broker-source-demo',
publicFediverseDelivery: false,
activityPubStatus: 'ap-shaped-projection-only',
activityPubStatus: 'broker-projection-only',
spokeRef: 'jesssullivan-github-io',
spokeTarget: 'transscendsurvival.org',
routePath: '/projections/jesssullivan-github-io/pulse/ap-stream-demo.v1.json',
Expand All @@ -39,7 +38,7 @@ const liveDemo = {

test.describe('Pulse brokered stream lab', () => {
test('renders AP-shaped broker data from the live Tinyland endpoint', async ({ page }) => {
await page.route(endpointPattern, (route) =>
await page.route(endpoint, (route) =>
route.fulfill({
status: 200,
contentType: 'application/json',
Expand All @@ -61,7 +60,7 @@ test.describe('Pulse brokered stream lab', () => {
});

test('shows unavailable instead of falling back to checked-in static data', async ({ page }) => {
await page.route(endpointPattern, (route) =>
await page.route(endpoint, (route) =>
route.fulfill({
status: 503,
contentType: 'application/json',
Expand Down
2 changes: 2 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,9 @@
"@skeletonlabs/skeleton": "^4.15.2",
"@skeletonlabs/skeleton-svelte": "^4.15.2",
"@tummycrypt/tinyvectors": "^0.2.3",
"dompurify": "^3.3.3",
"flexsearch": "^0.8.212",
"marked": "^4.3.0",
"mdsvex": "^0.12.7",
"shiki": "^4.0.2",
"tailwindcss": "^4.2.2"
Expand Down
6 changes: 3 additions & 3 deletions packages/pulse-core/src/schema/ap-stream-demo.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { z } from 'zod';
import { IsoTimestampSchema } from './event.js';

export const PULSE_AP_STREAM_DEMO_SCHEMA_VERSION = 'tinyland.pulse.ap-stream-demo.v1';
export const PULSE_AP_STREAM_DEMO_STATUS = 'controlled-static-source-live-broker-demo';
export const PULSE_AP_STREAM_DEMO_STATUS = 'controlled-broker-source-demo';

export const PulseApStreamDemoTagSchema = z
.object({
Expand Down Expand Up @@ -38,14 +38,14 @@ export const PulseApStreamDemoSchema = z
schemaVersion: z.literal(PULSE_AP_STREAM_DEMO_SCHEMA_VERSION),
generatedAt: IsoTimestampSchema,
sourceAuthority: z.literal('tinyland.dev'),
sourceAuthorityUrl: z.literal('https://tinyland.dev'),
sourceAuthorityUrl: z.literal('https://hub.tinyland.dev'),
sourceSnapshotId: z.string().min(1),
contentHash: z.string().regex(/^sha256:[0-9a-f]{64}$/),
policyVersion: z.string().min(1),
projectionKind: z.literal('pulse-ap-stream-demo'),
demoStatus: z.literal(PULSE_AP_STREAM_DEMO_STATUS),
publicFediverseDelivery: z.literal(false),
activityPubStatus: z.literal('ap-shaped-projection-only'),
activityPubStatus: z.literal('broker-projection-only'),
spokeRef: z.string().min(1),
spokeTarget: z.string().min(1),
routePath: z.string().regex(/^\/projections\/[^/]+\/pulse\/ap-stream-demo\.v1\.json$/),
Expand Down
8 changes: 4 additions & 4 deletions packages/pulse-core/test/schema.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -155,22 +155,22 @@ describe('schema/ap-stream-demo', () => {
schemaVersion: PULSE_AP_STREAM_DEMO_SCHEMA_VERSION,
generatedAt: '2026-05-10T13:00:00.000Z',
sourceAuthority: 'tinyland.dev',
sourceAuthorityUrl: 'https://tinyland.dev',
sourceAuthorityUrl: 'https://hub.tinyland.dev',
sourceSnapshotId: 'tinyland-jesssullivan-pulse-static-seed-2026-05-10',
contentHash: `sha256:${'b'.repeat(64)}`,
policyVersion: PUBLIC_SNAPSHOT_POLICY_VERSION,
projectionKind: 'pulse-ap-stream-demo',
demoStatus: PULSE_AP_STREAM_DEMO_STATUS,
publicFediverseDelivery: false,
activityPubStatus: 'ap-shaped-projection-only',
activityPubStatus: 'broker-projection-only',
spokeRef: 'jesssullivan-github-io',
spokeTarget: 'transscendsurvival.org',
routePath: '/projections/jesssullivan-github-io/pulse/ap-stream-demo.v1.json',
publicUrl: 'https://tinyland.dev/projections/jesssullivan-github-io/pulse/ap-stream-demo.v1.json',
publicUrl: 'https://hub.tinyland.dev/projections/jesssullivan-github-io/pulse/ap-stream-demo.v1.json',
itemCount: 1,
orderedItems: [
{
id: 'https://tinyland.dev/projections/jesssullivan-github-io/pulse/ap-stream-demo.v1.json#note-1',
id: 'https://hub.tinyland.dev/projections/jesssullivan-github-io/pulse/ap-stream-demo.v1.json#note-1',
type: 'Note',
published: '2026-05-10T12:30:00.000Z',
summary: 'hello',
Expand Down
7 changes: 4 additions & 3 deletions scripts/ingest-tinyland-posts.mts
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
#!/usr/bin/env tsx
// Materializes reviewed tinyland.dev post projections into the existing
// src/posts/*.md frontmatter flow. The static site remains a read-only
// consumer: this script only reads a checked-in snapshot.
// Fallback/migration only. The canonical blog display path is the CF Pages
// runtime fetch from the public Tinyland broker stream, not checked-in posts.
// This script materializes reviewed snapshot evidence into the legacy
// src/posts/*.md frontmatter flow when explicitly invoked.

import { createHash } from 'node:crypto';
import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';
Expand Down
2 changes: 1 addition & 1 deletion src/app.html
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
<meta charset="utf-8" />
<link rel="icon" href="%sveltekit.assets%/favicon.png" />
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover" />
<meta http-equiv="Content-Security-Policy" content="default-src 'self'; script-src 'self' 'unsafe-inline' https://giscus.app; style-src 'self' 'unsafe-inline' https://giscus.app; img-src 'self' data: https:; font-src 'self'; frame-src 'self' https://w.soundcloud.com https://www.youtube-nocookie.com https://giscus.app; connect-src 'self' https://*.pagefind.app https://tinyland.dev; media-src 'self' https:" />
<meta http-equiv="Content-Security-Policy" content="default-src 'self'; script-src 'self' 'unsafe-inline' https://giscus.app; style-src 'self' 'unsafe-inline' https://giscus.app; img-src 'self' data: https:; font-src 'self'; frame-src 'self' https://w.soundcloud.com https://www.youtube-nocookie.com https://giscus.app; connect-src 'self' https://*.pagefind.app https://tinyland.dev https://hub.tinyland.dev; media-src 'self' https:" />
<meta name="referrer" content="strict-origin-when-cross-origin" />
<link rel="alternate" type="application/feed+json" title="transscendsurvival.org JSON Feed" href="/feed.json" />
<link rel="alternate" type="application/rss+xml" title="RSS" href="/feed.xml" />
Expand Down
30 changes: 30 additions & 0 deletions src/lib/app-csp.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import { readFileSync } from 'node:fs';
import { describe, expect, it } from 'vitest';

const appHtml = readFileSync(new URL('../app.html', import.meta.url), 'utf8');

function cspDirective(name: string): string[] {
const content = appHtml.match(/http-equiv="Content-Security-Policy" content="([^"]+)"/)?.[1];
if (!content) {
throw new Error('Content-Security-Policy meta tag not found');
}

const directive = content
.split(';')
.map((part) => part.trim())
.find((part) => part.startsWith(`${name} `));

if (!directive) {
throw new Error(`${name} directive not found`);
}

return directive.split(/\s+/).slice(1);
}

describe('app CSP', () => {
it('allows the Tinyland hub broker origin for runtime Pulse/blog streams', () => {
expect(cspDirective('connect-src')).toEqual(
expect.arrayContaining(['https://hub.tinyland.dev', 'https://tinyland.dev']),
);
});
});
6 changes: 3 additions & 3 deletions src/lib/components/pulse/PulseApStreamDemoPanel.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,14 @@ const readyState: PulseApStreamDemoPanelState = {
schemaVersion: 'tinyland.pulse.ap-stream-demo.v1',
generatedAt: '2026-05-10T13:00:00.000Z',
sourceAuthority: 'tinyland.dev',
sourceAuthorityUrl: 'https://tinyland.dev',
sourceAuthorityUrl: 'https://hub.tinyland.dev',
sourceSnapshotId: 'tinyland-jesssullivan-pulse-static-seed-2026-05-10',
contentHash: 'sha256:fc3b04ec97946d6777e5245040b09a3ead296a9bf4614d0fea7df2d3cfb2ccb7',
policyVersion: 'm1-2026-04-27',
projectionKind: 'pulse-ap-stream-demo',
demoStatus: 'controlled-static-source-live-broker-demo',
demoStatus: 'controlled-broker-source-demo',
publicFediverseDelivery: false,
activityPubStatus: 'ap-shaped-projection-only',
activityPubStatus: 'broker-projection-only',
spokeRef: 'jesssullivan-github-io',
spokeTarget: 'transscendsurvival.org',
routePath: '/projections/jesssullivan-github-io/pulse/ap-stream-demo.v1.json',
Expand Down
6 changes: 3 additions & 3 deletions src/lib/pulse/apStreamDemo.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,14 @@ const validDemo: PulseApStreamDemo = {
schemaVersion: 'tinyland.pulse.ap-stream-demo.v1',
generatedAt: '2026-05-10T13:00:00.000Z',
sourceAuthority: 'tinyland.dev',
sourceAuthorityUrl: 'https://tinyland.dev',
sourceAuthorityUrl: 'https://hub.tinyland.dev',
sourceSnapshotId: 'tinyland-jesssullivan-pulse-static-seed-2026-05-10',
contentHash: 'sha256:fc3b04ec97946d6777e5245040b09a3ead296a9bf4614d0fea7df2d3cfb2ccb7',
policyVersion: 'm1-2026-04-27',
projectionKind: 'pulse-ap-stream-demo',
demoStatus: 'controlled-static-source-live-broker-demo',
demoStatus: 'controlled-broker-source-demo',
publicFediverseDelivery: false,
activityPubStatus: 'ap-shaped-projection-only',
activityPubStatus: 'broker-projection-only',
spokeRef: 'jesssullivan-github-io',
spokeTarget: 'transscendsurvival.org',
routePath: '/projections/jesssullivan-github-io/pulse/ap-stream-demo.v1.json',
Expand Down
2 changes: 1 addition & 1 deletion src/lib/pulse/apStreamDemo.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { PulseApStreamDemoSchema, type PulseApStreamDemo } from '@blog/pulse-core/schema';

export const TINYLAND_PULSE_AP_STREAM_DEMO_URL =
'https://tinyland.dev/projections/jesssullivan-github-io/pulse/ap-stream-demo.v1.json';
'https://hub.tinyland.dev/projections/jesssullivan-github-io/pulse/ap-stream-demo.v1.json';

export type PulseApStreamFetch = (input: RequestInfo | URL, init?: RequestInit) => Promise<Response>;

Expand Down
4 changes: 2 additions & 2 deletions src/lib/tinyland-post-snapshot.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ function snapshotHash(snapshot: TinylandPostSnapshot): string {
}

describe('Tinyland post projection snapshot', () => {
it('keeps transscendsurvival.org as a checked-in static consumer', () => {
it('keeps checked-in post snapshots fallback-only and non-authoritative', () => {
const snapshot = readJson<TinylandPostSnapshot>('static/data/tinyland/posts/public-snapshot.v1.json');

expect(snapshot.schemaVersion).toBe('tinyland.static-spoke.snapshot.v1');
Expand All @@ -60,7 +60,7 @@ describe('Tinyland post projection snapshot', () => {
);
});

it('materializes reviewed posts into the extant frontmatter flow', () => {
it('materializes reviewed snapshot evidence into the legacy frontmatter flow', () => {
const snapshot = readJson<TinylandPostSnapshot>('static/data/tinyland/posts/public-snapshot.v1.json');

for (const post of snapshot.posts) {
Expand Down
Loading
Loading