fix(rnotes): resolve global scope for notebook docIds and seeding
The rnotes module has defaultScope: 'global' but several code paths used the raw space slug instead of the resolved scope: - subscribeNotebook() built docIds with space slug (e.g. jeff🎶...) instead of resolved scope (global🎶...), breaking Automerge sync - seedDemoIfEmpty() seeded notebooks under space-scoped paths, orphaning them when the API queries global-scoped prefix - onSpaceCreate() created default notebook under space scope Also migrated 3 orphaned jeff-scoped notebook files to global/ on server. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
f5388ecc2c
commit
fe031094a4
|
|
@ -423,8 +423,12 @@ Gear: EUR 400 (10%)</code></pre><p><em>Maya is tracking expenses in rF
|
||||||
// ── Sync (via shared runtime) ──
|
// ── Sync (via shared runtime) ──
|
||||||
|
|
||||||
private async subscribeNotebook(notebookId: string) {
|
private async subscribeNotebook(notebookId: string) {
|
||||||
this.subscribedDocId = `${this.space}:notes:notebooks:${notebookId}`;
|
|
||||||
const runtime = (window as any).__rspaceOfflineRuntime;
|
const runtime = (window as any).__rspaceOfflineRuntime;
|
||||||
|
// Resolve scope: rnotes is globally-scoped, so use 'global' prefix
|
||||||
|
const dataSpace = runtime?.isInitialized
|
||||||
|
? (runtime.resolveDocSpace?.('rnotes') || this.space)
|
||||||
|
: this.space;
|
||||||
|
this.subscribedDocId = `${dataSpace}:notes:notebooks:${notebookId}`;
|
||||||
|
|
||||||
if (runtime?.isInitialized) {
|
if (runtime?.isInitialized) {
|
||||||
try {
|
try {
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,7 @@ import * as Automerge from "@automerge/automerge";
|
||||||
import { renderShell } from "../../server/shell";
|
import { renderShell } from "../../server/shell";
|
||||||
import { getModuleInfoList } from "../../shared/module";
|
import { getModuleInfoList } from "../../shared/module";
|
||||||
import type { RSpaceModule, SpaceLifecycleContext } from "../../shared/module";
|
import type { RSpaceModule, SpaceLifecycleContext } from "../../shared/module";
|
||||||
|
import { resolveDataSpace } from "../../shared/scope-resolver";
|
||||||
import { verifyEncryptIDToken, extractToken } from "@encryptid/sdk/server";
|
import { verifyEncryptIDToken, extractToken } from "@encryptid/sdk/server";
|
||||||
import { renderLanding } from "./landing";
|
import { renderLanding } from "./landing";
|
||||||
import { notebookSchema, notebookDocId, connectionsDocId, createNoteItem } from "./schemas";
|
import { notebookSchema, notebookDocId, connectionsDocId, createNoteItem } from "./schemas";
|
||||||
|
|
@ -127,16 +128,19 @@ function findNote(space: string, noteId: string): { docId: string; doc: Notebook
|
||||||
function seedDemoIfEmpty(space: string) {
|
function seedDemoIfEmpty(space: string) {
|
||||||
if (!_syncServer) return;
|
if (!_syncServer) return;
|
||||||
|
|
||||||
|
// Resolve effective data space (global for rnotes by default)
|
||||||
|
const dataSpace = resolveDataSpace("rnotes", space);
|
||||||
|
|
||||||
// If the space already has notebooks, skip
|
// If the space already has notebooks, skip
|
||||||
if (listNotebooks(space).length > 0) return;
|
if (listNotebooks(dataSpace).length > 0) return;
|
||||||
|
|
||||||
const now = Date.now();
|
const now = Date.now();
|
||||||
|
|
||||||
// Notebook 1: Project Ideas
|
// Notebook 1: Project Ideas
|
||||||
const nb1Id = newId();
|
const nb1Id = newId();
|
||||||
const nb1DocId = notebookDocId(space, nb1Id);
|
const nb1DocId = notebookDocId(dataSpace, nb1Id);
|
||||||
const nb1Doc = Automerge.change(Automerge.init<NotebookDoc>(), "Seed: Project Ideas", (d) => {
|
const nb1Doc = Automerge.change(Automerge.init<NotebookDoc>(), "Seed: Project Ideas", (d) => {
|
||||||
d.meta = { module: "notes", collection: "notebooks", version: 1, spaceSlug: space, createdAt: now };
|
d.meta = { module: "notes", collection: "notebooks", version: 1, spaceSlug: dataSpace, createdAt: now };
|
||||||
d.notebook = { id: nb1Id, title: "Project Ideas", slug: "project-ideas", description: "Brainstorms and design notes for the r* ecosystem", coverColor: "#6366f1", isPublic: true, createdAt: now, updatedAt: now };
|
d.notebook = { id: nb1Id, title: "Project Ideas", slug: "project-ideas", description: "Brainstorms and design notes for the r* ecosystem", coverColor: "#6366f1", isPublic: true, createdAt: now, updatedAt: now };
|
||||||
d.items = {};
|
d.items = {};
|
||||||
});
|
});
|
||||||
|
|
@ -144,9 +148,9 @@ function seedDemoIfEmpty(space: string) {
|
||||||
|
|
||||||
// Notebook 2: Meeting Notes
|
// Notebook 2: Meeting Notes
|
||||||
const nb2Id = newId();
|
const nb2Id = newId();
|
||||||
const nb2DocId = notebookDocId(space, nb2Id);
|
const nb2DocId = notebookDocId(dataSpace, nb2Id);
|
||||||
const nb2Doc = Automerge.change(Automerge.init<NotebookDoc>(), "Seed: Meeting Notes", (d) => {
|
const nb2Doc = Automerge.change(Automerge.init<NotebookDoc>(), "Seed: Meeting Notes", (d) => {
|
||||||
d.meta = { module: "notes", collection: "notebooks", version: 1, spaceSlug: space, createdAt: now };
|
d.meta = { module: "notes", collection: "notebooks", version: 1, spaceSlug: dataSpace, createdAt: now };
|
||||||
d.notebook = { id: nb2Id, title: "Meeting Notes", slug: "meeting-notes", description: "Weekly standups, design reviews, and retrospectives", coverColor: "#f59e0b", isPublic: true, createdAt: now, updatedAt: now };
|
d.notebook = { id: nb2Id, title: "Meeting Notes", slug: "meeting-notes", description: "Weekly standups, design reviews, and retrospectives", coverColor: "#f59e0b", isPublic: true, createdAt: now, updatedAt: now };
|
||||||
d.items = {};
|
d.items = {};
|
||||||
});
|
});
|
||||||
|
|
@ -154,9 +158,9 @@ function seedDemoIfEmpty(space: string) {
|
||||||
|
|
||||||
// Notebook 3: How-To Guides
|
// Notebook 3: How-To Guides
|
||||||
const nb3Id = newId();
|
const nb3Id = newId();
|
||||||
const nb3DocId = notebookDocId(space, nb3Id);
|
const nb3DocId = notebookDocId(dataSpace, nb3Id);
|
||||||
const nb3Doc = Automerge.change(Automerge.init<NotebookDoc>(), "Seed: How-To Guides", (d) => {
|
const nb3Doc = Automerge.change(Automerge.init<NotebookDoc>(), "Seed: How-To Guides", (d) => {
|
||||||
d.meta = { module: "notes", collection: "notebooks", version: 1, spaceSlug: space, createdAt: now };
|
d.meta = { module: "notes", collection: "notebooks", version: 1, spaceSlug: dataSpace, createdAt: now };
|
||||||
d.notebook = { id: nb3Id, title: "How-To Guides", slug: "how-to-guides", description: "Tutorials and onboarding guides for contributors", coverColor: "#10b981", isPublic: true, createdAt: now, updatedAt: now };
|
d.notebook = { id: nb3Id, title: "How-To Guides", slug: "how-to-guides", description: "Tutorials and onboarding guides for contributors", coverColor: "#10b981", isPublic: true, createdAt: now, updatedAt: now };
|
||||||
d.items = {};
|
d.items = {};
|
||||||
});
|
});
|
||||||
|
|
@ -1043,9 +1047,10 @@ export const notesModule: RSpaceModule = {
|
||||||
async onSpaceCreate(ctx: SpaceLifecycleContext) {
|
async onSpaceCreate(ctx: SpaceLifecycleContext) {
|
||||||
if (!_syncServer) return;
|
if (!_syncServer) return;
|
||||||
|
|
||||||
// Create a default "My Notes" notebook doc for the new space
|
// Create a default "My Notes" notebook doc, using resolved scope
|
||||||
|
const dataSpace = resolveDataSpace("rnotes", ctx.spaceSlug);
|
||||||
const notebookId = "default";
|
const notebookId = "default";
|
||||||
const docId = notebookDocId(ctx.spaceSlug, notebookId);
|
const docId = notebookDocId(dataSpace, notebookId);
|
||||||
|
|
||||||
if (_syncServer.getDoc(docId)) return; // already exists
|
if (_syncServer.getDoc(docId)) return; // already exists
|
||||||
|
|
||||||
|
|
@ -1055,7 +1060,7 @@ export const notesModule: RSpaceModule = {
|
||||||
module: "notes",
|
module: "notes",
|
||||||
collection: "notebooks",
|
collection: "notebooks",
|
||||||
version: 1,
|
version: 1,
|
||||||
spaceSlug: ctx.spaceSlug,
|
spaceSlug: dataSpace,
|
||||||
createdAt: Date.now(),
|
createdAt: Date.now(),
|
||||||
};
|
};
|
||||||
d.notebook = {
|
d.notebook = {
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue