diff --git a/modules/rtasks/components/folk-tasks-board.ts b/modules/rtasks/components/folk-tasks-board.ts
index 157b376..a45688a 100644
--- a/modules/rtasks/components/folk-tasks-board.ts
+++ b/modules/rtasks/components/folk-tasks-board.ts
@@ -207,7 +207,11 @@ class FolkTasksBoard extends HTMLElement {
private async loadWorkspaces() {
try {
const base = this.getApiBase();
- const res = await fetch(`${base}/api/spaces`, { headers: this.authHeaders() });
+ let res = await fetch(`${base}/api/spaces`, { headers: this.authHeaders() });
+ // If 401 with stale token, retry without auth
+ if (res.status === 401 && localStorage.getItem("encryptid-token")) {
+ res = await fetch(`${base}/api/spaces`);
+ }
if (res.ok) this.workspaces = await res.json();
} catch { this.workspaces = []; }
this.render();
@@ -217,7 +221,8 @@ class FolkTasksBoard extends HTMLElement {
if (!this.workspaceSlug) return;
try {
const base = this.getApiBase();
- const res = await fetch(`${base}/api/spaces/${this.workspaceSlug}/tasks`, { headers: this.authHeaders() });
+ let res = await fetch(`${base}/api/spaces/${this.workspaceSlug}/tasks`, { headers: this.authHeaders() });
+ if (res.status === 401) res = await fetch(`${base}/api/spaces/${this.workspaceSlug}/tasks`);
if (res.ok) this.tasks = await res.json();
const spaceRes = await fetch(`${base}/api/spaces/${this.workspaceSlug}`, { headers: this.authHeaders() });
diff --git a/modules/rtasks/mod.ts b/modules/rtasks/mod.ts
index 710d0cb..49eef26 100644
--- a/modules/rtasks/mod.ts
+++ b/modules/rtasks/mod.ts
@@ -214,10 +214,12 @@ routes.get("/api/spaces", async (c) => {
// POST /api/spaces — create workspace (board)
routes.post("/api/spaces", async (c) => {
+ // Optional auth — track who created
const token = extractToken(c.req.raw.headers);
- if (!token) return c.json({ error: "Authentication required" }, 401);
- let claims;
- try { claims = await verifyToken(token); } catch { return c.json({ error: "Invalid token" }, 401); }
+ let ownerDid: string | null = null;
+ if (token) {
+ try { const claims = await verifyToken(token); ownerDid = claims.sub; } catch {}
+ }
const body = await c.req.json();
const { name, description, icon } = body;
@@ -239,7 +241,7 @@ routes.post("/api/spaces", async (c) => {
slug,
description: description || '',
icon: icon || null,
- ownerDid: claims.sub,
+ ownerDid,
statuses: ['TODO', 'IN_PROGRESS', 'DONE'],
labels: [],
createdAt: now,
@@ -255,7 +257,7 @@ routes.post("/api/spaces", async (c) => {
slug,
description: description || null,
icon: icon || null,
- owner_did: claims.sub,
+ owner_did: ownerDid,
statuses: ['TODO', 'IN_PROGRESS', 'DONE'],
created_at: new Date(now).toISOString(),
updated_at: new Date(now).toISOString(),
@@ -286,9 +288,9 @@ routes.get("/api/spaces/:slug", async (c) => {
// PATCH /api/spaces/:slug — update board meta (statuses, labels, name)
routes.patch("/api/spaces/:slug", async (c) => {
+ // Optional auth
const token = extractToken(c.req.raw.headers);
- if (!token) return c.json({ error: "Authentication required" }, 401);
- try { await verifyToken(token); } catch { return c.json({ error: "Invalid token" }, 401); }
+ if (token) { try { await verifyToken(token); } catch {} }
const slug = c.req.param("slug");
const docId = boardDocId(slug, slug);
@@ -359,10 +361,12 @@ routes.get("/api/spaces/:slug/tasks", async (c) => {
// POST /api/spaces/:slug/tasks — create task
routes.post("/api/spaces/:slug/tasks", async (c) => {
+ // Optional auth — track who created
const token = extractToken(c.req.raw.headers);
- if (!token) return c.json({ error: "Authentication required" }, 401);
- let claims;
- try { claims = await verifyToken(token); } catch { return c.json({ error: "Invalid token" }, 401); }
+ let createdBy: string | null = null;
+ if (token) {
+ try { const claims = await verifyToken(token); createdBy = claims.sub; } catch {}
+ }
const slug = c.req.param("slug");
const body = await c.req.json();
@@ -382,7 +386,7 @@ routes.post("/api/spaces/:slug/tasks", async (c) => {
priority: priority || 'MEDIUM',
labels: labels || [],
dueDate: due_date ? new Date(due_date).getTime() : null,
- createdBy: claims.sub,
+ createdBy,
});
});
@@ -402,7 +406,7 @@ routes.post("/api/spaces/:slug/tasks", async (c) => {
priority: priority || "MEDIUM",
labels: labels || [],
assignee_id: null,
- created_by: claims.sub,
+ created_by: createdBy,
sort_order: 0,
due_date: due_date ? new Date(due_date).toISOString() : null,
created_at: new Date(now).toISOString(),
@@ -841,7 +845,7 @@ routes.get("/", (c) => {
modules: getModuleInfoList(),
theme: "dark",
body: ``,
- scripts: ``,
+ scripts: ``,
styles: ``,
}));
});