Skip to content

Migrate to jazz for e2ee#5

Open
tionis wants to merge 2 commits intomainfrom
jazz
Open

Migrate to jazz for e2ee#5
tionis wants to merge 2 commits intomainfrom
jazz

Conversation

@tionis
Copy link
Copy Markdown
Owner

@tionis tionis commented Dec 31, 2025

No description provided.

tionis and others added 2 commits December 31, 2025 15:37
- Add Jazz schema (lib/schema.ts) with CoValue definitions for Todo, Sublist, TodoList, and Account
- Add Jazz provider with passphrase authentication (lib/jazz.tsx)
- Remove InstantDB dependencies and files (db.ts, transactions.ts, types.ts, instant.schema.ts, instant.perms.ts, instantdb.txt)
- Remove debug CLI tool (debug-cli.js, debug-examples.sh)
- Update dependencies: remove @instantdb/react, add jazz-react, jazz-tools, @scure/bip39

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Update layout.tsx to use JazzProvider
- Rewrite page.tsx with Jazz hooks, profile settings modal, and invite URL persistence
- Rewrite TodoListView.tsx with Jazz CoValue operations, drag-and-drop, and share modal with read/write invite links
- Simplify InvitationsView.tsx for Jazz invite acceptance flow
- Update HashRouter for Jazz CoValue IDs
- Fix textarea styling for passphrase visibility in globals.css
- Update utils.ts to remove slug generation (now using Jazz IDs)
- Update LLM.md documentation

Features:
- Passphrase-based authentication
- Profile settings (display name)
- Read-only and write access invite links
- Member list display in share modal
- Warning about permanent invite link access

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings December 31, 2025 14:42
@cloudflare-workers-and-pages
Copy link
Copy Markdown

Deploying tionis-todo with  Cloudflare Pages  Cloudflare Pages

Latest commit: ed09ca7
Status:🚫  Deploy failed.

View logs

Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR migrates the Smart Todos application from InstantDB to Jazz, introducing end-to-end encryption and fundamentally changing the authentication, data model, and sharing mechanisms.

Purpose: Replace InstantDB backend with Jazz to enable end-to-end encryption and local-first collaboration.

Key Changes:

  • Authentication switched from magic link (email + code) to passphrase-based recovery phrases
  • Data model migrated from InstantDB schema to Jazz CoValues with nested structures
  • Sharing changed from email-based invitations to cryptographic invite links
  • Direct property mutation replaces transaction-based updates

Reviewed changes

Copilot reviewed 18 out of 21 changed files in this pull request and generated 15 comments.

Show a summary per file
File Description
package.json Removed InstantDB dependencies, added jazz-react and jazz-tools; updated Next.js to 16.1.1
tsconfig.json Changed JSX transform to "react-jsx" for automatic JSX runtime
lib/schema.ts New Jazz CoValue schema with TodoList, Todo, Sublist, and Account structures
lib/jazz.tsx New Jazz provider with passphrase authentication and typed hooks
lib/utils.ts Updated to use Jazz IDs instead of custom slugs
lib/db.ts Deleted - InstantDB initialization removed
lib/types.ts Deleted - types moved to schema
lib/transactions.ts Deleted - direct mutations replace transactions
instant.schema.ts Deleted - replaced by lib/schema.ts
instant.perms.ts Deleted - permissions now handled by Jazz Groups
app/page.tsx Complete rewrite for Jazz authentication and CoValue management
app/layout.tsx Wrapped app in JazzProvider
app/components/InvitationsView.tsx Simplified to handle Jazz invite links via useAcceptInvite hook
app/components/HashRouter.tsx Updated routing to handle Jazz CoValue IDs and invite links
debug-cli.js Deleted - InstantDB debug tooling no longer applicable

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +8 to +9
// Get API key from environment or use email for development
const JAZZ_PEER = (process.env.NEXT_PUBLIC_JAZZ_PEER || "wss://cloud.jazz.tools/?key=todo@tionis.dev") as `wss://${string}`;
Copy link

Copilot AI Dec 31, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The hardcoded Jazz peer URL includes an email address "todo@tionis.dev". If this is meant to be production code, consider moving this to an environment variable without a default value to prevent unintended usage of someone else's Jazz cloud instance. This could lead to data being stored on the wrong server or potential security issues.

Suggested change
// Get API key from environment or use email for development
const JAZZ_PEER = (process.env.NEXT_PUBLIC_JAZZ_PEER || "wss://cloud.jazz.tools/?key=todo@tionis.dev") as `wss://${string}`;
// Get Jazz peer URL from environment; no hardcoded default to avoid using someone else's instance
const JAZZ_PEER_ENV = process.env.NEXT_PUBLIC_JAZZ_PEER;
if (!JAZZ_PEER_ENV) {
throw new Error("Environment variable NEXT_PUBLIC_JAZZ_PEER must be set to a valid Jazz peer wss:// URL.");
}
const JAZZ_PEER = JAZZ_PEER_ENV as `wss://${string}`;

Copilot uses AI. Check for mistakes.
import { ID } from "jazz-tools";

export function getListUrl(slug: string): string {
export function getListUrl(listId: ID<any>): string {
Copy link

Copilot AI Dec 31, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The function signature change from getListUrl(slug: string) to getListUrl(listId: ID<any>) uses a generic ID<any> type instead of a more specific type like ID<TodoList>. This loses type safety. Consider using ID<TodoList> to ensure only valid TodoList IDs are passed to this function.

Suggested change
export function getListUrl(listId: ID<any>): string {
export function getListUrl<T>(listId: ID<T>): string {

Copilot uses AI. Check for mistakes.
Comment on lines +51 to +58
sessionStorage.setItem(PENDING_INVITE_KEY, hash);
}

// If we just logged in and have a pending invite, restore it
if (me && me.root) {
const pendingInvite = sessionStorage.getItem(PENDING_INVITE_KEY);
if (pendingInvite) {
sessionStorage.removeItem(PENDING_INVITE_KEY);
Copy link

Copilot AI Dec 31, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The use of sessionStorage for storing pending invite links could lead to data loss if the user opens the invite link in a different tab or browser. Consider using localStorage instead for better persistence, or implement a more robust solution that handles cross-tab/cross-browser scenarios.

Suggested change
sessionStorage.setItem(PENDING_INVITE_KEY, hash);
}
// If we just logged in and have a pending invite, restore it
if (me && me.root) {
const pendingInvite = sessionStorage.getItem(PENDING_INVITE_KEY);
if (pendingInvite) {
sessionStorage.removeItem(PENDING_INVITE_KEY);
localStorage.setItem(PENDING_INVITE_KEY, hash);
}
// If we just logged in and have a pending invite, restore it
if (me && me.root) {
const pendingInvite = localStorage.getItem(PENDING_INVITE_KEY);
if (pendingInvite) {
localStorage.removeItem(PENDING_INVITE_KEY);

Copilot uses AI. Check for mistakes.
window.location.hash = `/list/${newList.id}`;
} catch (err) {
console.error("Failed to create list:", err);
setShowErrorModal({show: true, message: "Failed to create list. Please try again."});
Copy link

Copilot AI Dec 31, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The error handling for list creation only logs to console and shows a generic error modal. Users won't see the specific error that occurred. Consider passing the actual error message to the modal to help users understand what went wrong, especially for permission or network-related issues.

Suggested change
setShowErrorModal({show: true, message: "Failed to create list. Please try again."});
const errorMessage = err instanceof Error ? err.message : String(err);
setShowErrorModal({
show: true,
message: `Failed to create list: ${errorMessage}. Please try again.`,
});

Copilot uses AI. Check for mistakes.
Comment on lines +20 to +22
"jazz-react": "^0.14.28",
"jazz-tools": "^0.14.28",
"next": "^16.1.1",
Copy link

Copilot AI Dec 31, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This migration removes all existing user data and lists since there's no migration path from InstantDB to Jazz. Users will lose access to their existing todo lists and will need to re-authenticate. Consider documenting this breaking change prominently in the PR description and release notes, or implementing a data export/import tool to help users transition.

Copilot uses AI. Check for mistakes.
function App() {
const [mounted, setMounted] = useState(false);
const { isLoading, user, error } = db.useAuth();
const { me, logOut } = useAccount({ resolve: { root: { todoLists: { $each: true } } } });
Copy link

Copilot AI Dec 31, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unused variable logOut.

Suggested change
const { me, logOut } = useAccount({ resolve: { root: { todoLists: { $each: true } } } });
const { me } = useAccount({ resolve: { root: { todoLists: { $each: true } } } });

Copilot uses AI. Check for mistakes.
KeyboardSensor,
PointerSensor,
useSensor,
import { Group, ID, createInviteLink } from "jazz-tools";
Copy link

Copilot AI Dec 31, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unused import Group.

Suggested change
import { Group, ID, createInviteLink } from "jazz-tools";
import { ID, createInviteLink } from "jazz-tools";

Copilot uses AI. Check for mistakes.
closestCenter,
KeyboardSensor,
PointerSensor,
useSensor,
useSensors,
DragOverlay,
DragStartEvent,
DragEndEvent,
DragOverEvent,
Copy link

Copilot AI Dec 31, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unused import DragOverEvent.

Suggested change
DragOverEvent,

Copilot uses AI. Check for mistakes.
import { executeTransaction, canUserWrite, canUserView, transferListOwnership } from "../../lib/transactions";
import { useAccount, useCoState } from '../../lib/jazz';
import { Account } from "jazz-tools";
import { TodoList, Todo, Sublist, ListOfTodos, ListOfSublists } from '../../lib/schema';
Copy link

Copilot AI Dec 31, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unused imports ListOfSublists, ListOfTodos.

Suggested change
import { TodoList, Todo, Sublist, ListOfTodos, ListOfSublists } from '../../lib/schema';
import { TodoList, Todo, Sublist } from '../../lib/schema';

Copilot uses AI. Check for mistakes.
import { useAccount, useCoState } from '../../lib/jazz';
import { Account } from "jazz-tools";
import { TodoList, Todo, Sublist, ListOfTodos, ListOfSublists } from '../../lib/schema';
import { copyToClipboard } from "../../lib/utils";
import LoadingSpinner from './LoadingSpinner';
import ErrorDisplay from './ErrorDisplay';
Copy link

Copilot AI Dec 31, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unused import ErrorDisplay.

Suggested change
import ErrorDisplay from './ErrorDisplay';

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants