Merge branch 'dev'

This commit is contained in:
Jeff Emmett 2026-03-21 15:24:23 -07:00
commit 18cf1194d5
4 changed files with 18 additions and 12 deletions

View File

@ -23,7 +23,7 @@ export function normalizeVisibility(v: string): SpaceVisibility {
if (v === 'public_read' || v === 'public') return 'public'; if (v === 'public_read' || v === 'public') return 'public';
if (v === 'authenticated' || v === 'permissioned') return 'permissioned'; if (v === 'authenticated' || v === 'permissioned') return 'permissioned';
if (v === 'members_only' || v === 'private') return 'private'; if (v === 'members_only' || v === 'private') return 'private';
return 'public'; return 'private'; // sovereign by default — unknown values treated as private
} }
// ── Nest Permissions & Policy ── // ── Nest Permissions & Policy ──
@ -237,7 +237,13 @@ function migrateVisibility(
slug: string, slug: string,
): Automerge.Doc<CommunityDoc> { ): Automerge.Doc<CommunityDoc> {
const v = doc.meta?.visibility as string; const v = doc.meta?.visibility as string;
if (!v) return doc; if (!v) {
// Missing visibility — default to private (sovereign by default)
console.log(`[Store] Migrating missing visibility→private in ${slug}`);
return Automerge.change(doc, `Set default visibility to private in ${slug}`, (d) => {
d.meta.visibility = 'private';
});
}
const normalized = normalizeVisibility(v); const normalized = normalizeVisibility(v);
if (v === normalized) return doc; if (v === normalized) return doc;
console.log(`[Store] Migrating visibility ${v}${normalized} in ${slug}`); console.log(`[Store] Migrating visibility ${v}${normalized} in ${slug}`);

View File

@ -464,7 +464,7 @@ async function getSpaceConfig(slug: string): Promise<SpaceAuthConfig | null> {
if (!doc) return null; if (!doc) return null;
return { return {
spaceSlug: slug, spaceSlug: slug,
visibility: (doc.meta.visibility || "public") as SpaceVisibility, visibility: (doc.meta.visibility || "private") as SpaceVisibility,
ownerDID: doc.meta.ownerDID || undefined, ownerDID: doc.meta.ownerDID || undefined,
app: "rspace", app: "rspace",
}; };
@ -1960,12 +1960,12 @@ app.use("/:space/*", async (c, next) => {
const space = c.req.param("space"); const space = c.req.param("space");
if (!space || space === "api" || space.includes(".")) return; if (!space || space === "api" || space.includes(".")) return;
const config = await getSpaceConfig(space); const config = await getSpaceConfig(space);
const vis = config?.visibility || "public"; const vis = config?.visibility || "private";
if (vis === "public") return; if (vis === "private") return; // Shell already defaults to private
const html = await c.res.text(); const html = await c.res.text();
c.res = new Response( c.res = new Response(
html.replace( html.replace(
'data-space-visibility="public"', 'data-space-visibility="private"',
`data-space-visibility="${vis}"`, `data-space-visibility="${vis}"`,
), ),
{ status: c.res.status, headers: c.res.headers }, { status: c.res.status, headers: c.res.headers },
@ -2179,7 +2179,7 @@ app.get("/admin-data", async (c) => {
spacesList.push({ spacesList.push({
slug: data.meta.slug, slug: data.meta.slug,
name: data.meta.name, name: data.meta.name,
visibility: data.meta.visibility || "public", visibility: data.meta.visibility || "private",
createdAt: data.meta.createdAt, createdAt: data.meta.createdAt,
ownerDID: data.meta.ownerDID, ownerDID: data.meta.ownerDID,
shapeCount, shapeCount,

View File

@ -149,7 +149,7 @@ export function renderShell(opts: ShellOptions): string {
modules, modules,
theme = "dark", theme = "dark",
head = "", head = "",
spaceVisibility = "public", spaceVisibility = "private",
} = opts; } = opts;
// Auto-populate from space data when not explicitly provided // Auto-populate from space data when not explicitly provided

View File

@ -240,7 +240,7 @@ spaces.get("/", async (c) => {
if (seenSlugs.has(slug)) continue; if (seenSlugs.has(slug)) continue;
seenSlugs.add(slug); seenSlugs.add(slug);
let vis = data.meta.visibility || "public"; let vis = data.meta.visibility || "private";
// Check both claims.sub (raw userId) and did:key: format for // Check both claims.sub (raw userId) and did:key: format for
// compatibility — auto-provisioned spaces store ownerDID as did:key: // compatibility — auto-provisioned spaces store ownerDID as did:key:
const callerDid = claims ? ((claims.did as string) || `did:key:${(claims.sub as string).slice(0, 32)}`) : ""; const callerDid = claims ? ((claims.did as string) || `did:key:${(claims.sub as string).slice(0, 32)}`) : "";
@ -298,8 +298,8 @@ spaces.get("/", async (c) => {
// Within each group: user's own spaces first, then alphabetically // Within each group: user's own spaces first, then alphabetically
const visOrder: Record<string, number> = { private: 0, permissioned: 1, public: 2 }; const visOrder: Record<string, number> = { private: 0, permissioned: 1, public: 2 };
spacesList.sort((a, b) => { spacesList.sort((a, b) => {
const va = visOrder[a.visibility || "public"] ?? 2; const va = visOrder[a.visibility || "private"] ?? 0;
const vb = visOrder[b.visibility || "public"] ?? 2; const vb = visOrder[b.visibility || "private"] ?? 0;
if (va !== vb) return va - vb; if (va !== vb) return va - vb;
if (a.role && !b.role) return -1; if (a.role && !b.role) return -1;
if (!a.role && b.role) return 1; if (!a.role && b.role) return 1;
@ -522,7 +522,7 @@ spaces.get("/admin", async (c) => {
spacesList.push({ spacesList.push({
slug: data.meta.slug, slug: data.meta.slug,
name: data.meta.name, name: data.meta.name,
visibility: data.meta.visibility || "public", visibility: data.meta.visibility || "private",
createdAt: data.meta.createdAt, createdAt: data.meta.createdAt,
ownerDID: data.meta.ownerDID, ownerDID: data.meta.ownerDID,
shapeCount, shapeCount,