### Clone and Setup Automerge Tutorial Project Source: https://automerge.org/docs/tutorial/setup Clone the automerge-repo-quickstart repository, switch to the 'without-automerge' branch, install dependencies, and start the local development server. ```bash $ git clone https://github.com/automerge/automerge-repo-quickstart# Cloning into 'automerge-repo-quickstart'... $ cd automerge-repo-quickstart $ git checkout without-automerge $ npm install # ...installing dependencies... $ npm run dev ``` -------------------------------- ### Initialize Automerge Repo with Storage and Network Adapters Source: https://automerge.org/docs/tutorial/local-sync Configure a Repo with IndexedDBStorageAdapter for persistence and BroadcastChannelNetworkAdapter for local sync. This setup allows data to be saved in the browser and synchronized across tabs. ```typescript import React, { Suspense } from "react";import ReactDOM from "react-dom/client";import App from "./components/App.tsx";import "./index.css";import { initTaskList } from "./components/TaskList.tsx";import { Repo, BroadcastChannelNetworkAdapter, IndexedDBStorageAdapter, } from "@automerge/react";const repo = new Repo({ network: [new BroadcastChannelNetworkAdapter()], storage: new IndexedDBStorageAdapter(), });// Add the repo to the global window object so it can be accessed in the browser console// This is useful for debugging and testing purposes.declare global { interface Window { repo: Repo; } } window.repo = repo; ReactDOM.createRoot(document.getElementById("root")!).render( Loading a document...}> , ); ``` -------------------------------- ### Initialize Automerge Repo with Storage and Network Source: https://automerge.org/docs/cookbook/rich-text-prosemirror-vanilla Sets up the Automerge repository with IndexedDB for local storage and a WebSocket adapter for network synchronization. Ensure the necessary packages are installed. ```javascript import { DocHandle, Repo, isValidAutomergeUrl } from "@automerge/automerge-repo" import { IndexedDBStorageAdapter } from "@automerge/automerge-repo-storage-indexeddb" import { BrowserWebSocketClientAdapter } from "@automerge/automerge-repo-network-websocket" import { init } from "@automerge/automerge-prosemirror" const repo = new Repo({ storage: new IndexedDBStorageAdapter("automerge"), network: [new BrowserWebSocketClientAdapter("wss://sync.automerge.org")], }) ``` -------------------------------- ### Create a Repo with WebSocket and File System Adapters Source: https://automerge.org/docs/reference/repositories Initializes a Repo instance, configuring it to use a WebSocket server for network communication and the Node.js file system for local storage. This setup is suitable for server-side applications or environments where direct file system access is available. ```javascript import { Repo } from "@automerge/automerge-repo" import { WebSocketServer } from "ws" import { NodeWSServerAdapter } from "@automerge/automerge-repo-network-websocket" import { NodeFSStorageAdapter } from "@automerge/automerge-repo-storage-nodefs" const wss = new WebSocketServer({ noServer: true }) const repo = new Repo({ network: [new NodeWSServerAdapter(wss)], storage: new NodeFSStorageAdapter(dir), }) ``` -------------------------------- ### Val.town Automerge Initialization and Document Retrieval Source: https://automerge.org/docs/reference/library-initialization A Val.town example demonstrating manual WebAssembly initialization and setting up a Repo to retrieve document contents by ID. It uses the slim variants of Automerge and the repo, and a WebSocket client for network synchronization. ```typescript import { BrowserWebSocketClientAdapter } from "npm:@automerge/automerge-repo-network-websocket";import { isValidAutomergeUrl, Repo } from "npm:@automerge/automerge-repo/slim";/* set up Automerge's internal wasm guts manually */import { automergeWasmBase64 } from "npm:@automerge/automerge/automerge.wasm.base64.js";import * as automerge from "npm:@automerge/automerge/slim";await automerge.initializeBase64Wasm(automergeWasmBase64);/* This example will return the contents of a documentID passed in as the path as JSON. */export default async function (req: Request): Promise { const docId = new URL(req.url).pathname.substring(1); if (!isValidAutomergeUrl("automerge:" + docId)) { return Response.error(); } const repo = new Repo({ network: [new BrowserWebSocketClientAdapter("wss://sync.automerge.org")], }); const handle = await repo.find(docId); const contents = handle.doc(); return Response.json(contents); } ``` -------------------------------- ### Install @automerge/react Source: https://automerge.org/docs/tutorial/local-sync Install the @automerge/react package to your project to begin using Automerge functionalities. ```bash $ npm install @automerge/react# ...installing dependencies... ``` -------------------------------- ### Setup MessageChannel Network Adapters for Two Repos Source: https://automerge.org/docs/reference/repositories/networking Configure two Repos to communicate within the same browser using MessageChannel. This involves creating a MessageChannel and wrapping each port with a MessageChannelNetworkAdapter. ```javascript import { MessageChannelNetworkAdapter } from "@automerge/automerge-repo-network-messagechannel"; import { Repo } from "@automerge/automerge-repo"; const { port1: leftToRight, port2: rightToLeft } = new MessageChannel(); const rightToLeft = new MessageChannelNetworkAdapter(rightToLeft); const leftToRight = new MessageChannelNetworkAdapter(leftToRight); const left = new Repo({ network: [leftToRight], }); const right = new Repo({ network: [rightToLeft], }); ``` -------------------------------- ### Hard-code Initial Change for Independent Schema Setup Source: https://automerge.org/docs/cookbook/modeling-data Use this method to initialize a document with a pre-defined schema by hard-coding an initial change as a byte array. This allows independent schema setup on different devices while ensuring merge compatibility. ```javascript // hard-code the initial change here const initChange = new Uint8Array([133, 111, 74, 131, ...]) let [doc] = Automerge.load(initChange) ``` -------------------------------- ### Create a Ref and Get its Value Source: https://automerge.org/docs/reference/repositories/refs Create a document, then obtain a reference to a specific field within a list item. You can then retrieve the value at that reference. ```javascript const handle = repo.create({ todos: [ { title: "First", done: false }, { title: "Second", done: true }, ] }) const doneRef = handle.ref("todos", 0, "done") // Logs false console.log("first todo done:", doneRef.value()) ``` -------------------------------- ### Setup RepoContext in React App Source: https://automerge.org/docs/tutorial/react Wrap your App component with RepoContext.Provider to make the Automerge repo available to child components via hooks. Ensure Suspense is used for asynchronous document loading. ```tsx import { Repo, BroadcastChannelNetworkAdapter, IndexedDBStorageAdapter, RepoContext, isValidAutomergeUrl, DocHandle, } from "@automerge/react"; // ... ReactDOM.createRoot(document.getElementById("root")!).render( Loading a document...}> , ); ``` -------------------------------- ### Vite Configuration Source: https://automerge.org/docs/reference/library-initialization Vite requires specific plugins, `vite-plugin-wasm` and `vite-plugin-top-level-await`, to handle WebAssembly and top-level await. Install them and add them to your `vite.config.js`. ```javascript yarn add vite-plugin-wasm vite-plugin-top-level-await ``` ```javascript import { defineConfig } from 'vite' import wasm from 'vite-plugin-wasm' import topLevelAwait from 'vite-plugin-top-level-await' export default defineConfig({ ..., plugins: [wasm(), topLevelAwait()], ... }) ``` -------------------------------- ### Example Rich Text Document Spans Source: https://automerge.org/docs/reference/under-the-hood/rich-text-schema An example array of spans representing a rich text document, including text, blockquotes, ordered lists, and inline formatting like bold and links. ```typescript [ { type: "text", value: "From the automerge docs:" }, { type: "block", value: { parents: ["blockquote"], type: "paragraph" }, }, { type: "text", value: "The requirements we have for this schema are:" }, { type: "block", value: { parents: ["blockquote", "ordered-list"], type: "paragraph"}, }, { type: "text": value: "The ability to represent inline text decoration such as bold spans, as well as semantic information like hyperlinks or code spans" }, { type: "block", value: { parents: ["blockquote", "ordered-list"], type: "paragraph"}, }, { type: "text": value: "A way of representing hierarchical structure which merges well - or, alternatively, which results in patches which are commensurate in size with the editing action the user took (inserting a paragraph is a single user action, we would like it to not result in a large patch which is hard to interpret)" }, { type: "block", value: {parents: ["blockquote"], type: "paragraph"} }, { type: "text", value: "..." } { type: "block", value: { parents: [], type: "paragraph"} }, { type: "text", value: "From: ", marks: { strong: true } }, { type: "text", value: "Rich Text Schema", marks: { link: '{\"href\": \"/\", title: \"\"}', em: true} } ] ``` -------------------------------- ### Create and Get Root Document Management Functions Source: https://automerge.org/docs/tutorial/persist-root-doc This function checks local storage for an existing root document URL. If found, it returns the URL; otherwise, it creates a new root document, stores its URL in local storage, and then returns the URL. This ensures the root document is persisted across browser sessions. ```typescript import { AutomergeUrl, Repo } from "@automerge/react"; const ROOT_DOC_URL_KEY = "root-doc-url"; export type RootDocument = { taskLists: AutomergeUrl[]; }; export const getOrCreateRoot = (repo: Repo): AutomergeUrl => { // Check if we already have a root document const existingUrl = localStorage.getItem(ROOT_DOC_URL_KEY); if (existingUrl) { return existingUrl as AutomergeUrl; } // Otherwise create one and (synchronously) store it const root = repo.create({ taskLists: [] }); localStorage.setItem(ROOT_DOC_URL_KEY, root.url); return root.url; }; ``` -------------------------------- ### Create and Modify a Document Handle Source: https://automerge.org/docs/reference/repositories Demonstrates how to create a new document handle using a Repo instance and make an initial change to it. It also shows how to subscribe to 'change' events to log updates received from other peers. ```javascript let doc = repo.create() // Make a change ourselves and send that to everyone else doc.change((d) => (d.text = "hello world")) // Listen for changes from other peers doc.on("change", ({ doc }) => { console.log("new text is ", doc.text) }) ``` -------------------------------- ### Initialize Automerge Repo and Root Document Source: https://automerge.org/docs/tutorial/persist-root-doc Sets up the Automerge repository with network and storage adapters, initializes the root document, and makes the repo and handle globally accessible for debugging. ```typescript import React, { Suspense } from "react"; import ReactDOM from "react-dom/client"; import App from "./components/App.tsx"; import "./index.css"; import { Repo, BroadcastChannelNetworkAdapter, WebSocketClientAdapter, IndexedDBStorageAdapter, RepoContext, DocHandle, } from "@automerge/react"; import { getOrCreateRoot, RootDocument } from "./rootDoc.ts"; const repo = new Repo({ network: [ new BroadcastChannelNetworkAdapter(), new WebSocketClientAdapter("wss://sync.automerge.org"), ], storage: new IndexedDBStorageAdapter(), }); // Add the repo to the global window object so it can be accessed in the browser console // This is useful for debugging and testing purposes. declare global { interface Window { repo: Repo; // We also add the handle to the global window object for debugging handle: DocHandle; } } window.repo = repo; const rootDocUrl = getOrCreateRoot(repo); window.handle = await repo.find(rootDocUrl); ReactDOM.createRoot(document.getElementById("root")!).render( Loading a document...}> , ); ``` -------------------------------- ### Initialize WebSocket Client Adapter Source: https://automerge.org/docs/reference/repositories/networking Instantiate the WebSocketClientAdapter to connect to a WebSocket server. Ensure the server is running at the specified URL. ```javascript import { WebSocketClientAdapter } from "@automerge/automerge-repo-network-websocket"; const network = new WebSocketClientAdapter("ws://localhost:3030"); ``` -------------------------------- ### Initialize and Merge Documents Source: https://automerge.org/docs/cookbook/modeling-data Demonstrates initializing a document with a schema and merging changes from another document. Ensure schema initialization is done once before merging. ```javascript let doc1 = Automerge.change(Automerge.init(), (doc) => { doc.cards = []; }); let doc2 = Automerge.merge(Automerge.init(), doc1); doc1 = Automerge.change(doc1, (doc) => { doc.cards.push({ title: "card1" }); }); doc2 = Automerge.change(doc2, (doc) => { doc.cards.push({ title: "card2" }); }); doc1 = Automerge.merge(doc1, doc2); doc2 = Automerge.merge(doc2, doc1); ``` -------------------------------- ### initSyncState Source: https://automerge.org/automerge/api-docs/js Initializes a new sync state. ```APIDOC ## initSyncState ### Description Initializes a new sync state. ### Function Signature `initSyncState(): SyncState` ``` -------------------------------- ### Initialize Root Document Source: https://automerge.org/docs/tutorial/multiple-task-lists This code snippet shows how to initialize the root document, creating it if it doesn't exist and setting up an initial task list. It also sets the location hash to the new document's URL. ```typescript if (isValidAutomergeUrl(locationHash)) { const taskList = await repo.find(locationHash); window.handle = repo.create({ taskLists: [taskList.url] });} else { const taskList = repo.create(initTaskList()); window.handle = repo.create({ taskLists: [taskList.url] }); // Set the location hash to the new document we just made. document.location.hash = taskList.url;}window.handle = repo.create({ taskLists: [] }); ``` -------------------------------- ### React Component for ProseMirror Editor Source: https://automerge.org/docs/cookbook/rich-text-prosemirror-react This React component integrates Automerge with ProseMirror to create a collaborative rich text editor. It handles editor initialization, state management, and cleanup. Ensure Automerge and ProseMirror are installed. ```jsx import { AutomergeUrl } from "@automerge/automerge-repo" import { useHandle } from "@automerge/automerge-repo-react-hooks" import { useEffect, useRef, useState } from "react" import {EditorState} from "prosemirror-state" import {EditorView} from "prosemirror-view" import {exampleSetup} from "prosemirror-example-setup" import { init } from "@automerge/prosemirror" import "prosemirror-example-setup/style/style.css" import "prosemirror-menu/style/menu.css" import "prosemirror-view/style/prosemirror.css" import "./App.css" function App({ docUrl }: { docUrl: AutomergeUrl }) { const editorRoot = useRef(null) const handle = useHandle<{text: string}>(docUrl) const [loaded, setLoaded] = useState(handle && handle.docSync() != null) useEffect(() => { if (handle != null) { handle.whenReady().then(() => { if (handle.docSync() != null) { setLoaded(true) } }) } }, [handle]) const [view, setView] = useState(null) useEffect(() => { if (editorRoot.current != null && loaded) { // This is the integration with automerge const { pmDoc: doc, schema, plugin } = init(handle!, ["text"]) const plugins = exampleSetup({schema}) plugins.push(plugin) const view = new EditorView(editorRoot.current, { state: EditorState.create({ schema, plugins, doc, }), }) setView(view) } return () => { if (view) { view.destroy() setView(null) } } }, [editorRoot, loaded]) return
} export default App ``` -------------------------------- ### Apply Bold Mark to Text in Automerge Source: https://automerge.org/docs/reference/documents/rich-text Use Automerge.mark to apply formatting to a range of text. Specify the start and end of the range, an expand option, the mark name, and its value. Retrieve active marks using Automerge.marks. ```javascript import * as Automerge from "@automerge/automerge" let doc = Automerge.from({text: "hello world"}) Automerge.change(doc, d => { Automerge.mark(d, ["text"], {start: 0, end: 5, expand: "both"}, "bold", true) }) console.log(Automerge.marks(doc, ["text"])) >> [ { name: 'bold', value: true, start: 0, end: 5 } ] ``` -------------------------------- ### Creating and Using Refs Source: https://automerge.org/docs/reference/repositories/refs Demonstrates how to create a Ref to a specific property within a document and how to read its value. ```APIDOC ## Creating and Using Refs ### Description This example shows how to create a reference to a specific field within a document and retrieve its current value. ### Method Implicitly through document handle methods. ### Endpoint N/A (SDK method) ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body None ### Request Example ```javascript const handle = repo.create({ todos: [ { title: "First", done: false }, { title: "Second", done: true }, ] }); const doneRef = handle.ref("todos", 0, "done"); ``` ### Response #### Success Response (200) N/A (SDK method returns a Ref object) #### Response Example ```javascript // Logs false console.log("first todo done:", doneRef.value()); ``` ``` -------------------------------- ### Registering Selected Document in Root Document Source: https://automerge.org/docs/tutorial/multiple-task-lists This effect hook in `DocumentList` ensures that if a selected document URL is valid and not already present in the root document's `taskLists`, it gets added. This is crucial for persisting the selection across reloads. ```typescript import { useEffect } from "react"; export const DocumentList: React.FC<{ docUrl: AutomergeUrl; selectedDocument: AutomergeUrl | null; onSelectDocument: (docUrl: AutomergeUrl | null) => void; }> = ({ docUrl, selectedDocument, onSelectDocument }) => { const repo = useRepo(); const [doc, changeDoc] = useDocument(docUrl, { suspense: true, }); useEffect(() => { changeDoc((d) => { if (selectedDocument && !d.taskLists.includes(selectedDocument)) { // If the selected document is not in the list, add it d.taskLists.push(selectedDocument); } }); }, [selectedDocument, changeDoc]); const handleNewDocument = () => { const newTaskList = repo.create(initTaskList()); changeDoc((d) => d.taskLists.push(newTaskList.url)); onSelectDocument(newTaskList.url); }; return ( // .. ); }; ``` -------------------------------- ### Initialize BroadcastChannel Network Adapter Source: https://automerge.org/docs/reference/repositories/networking Create a BroadcastChannelNetworkAdapter for inter-process communication within the same browser. Note that this can be less efficient than MessageChannel due to the sync protocol's point-to-point nature. ```javascript import { BroadcastChannelNetworkAdapter } from "@automerge/automerge-repo-network-broadcastchannel"; const network = new BroadcastChannelNetworkAdapter(); ``` -------------------------------- ### Creating and Manipulating Refs Source: https://automerge.org/docs/reference/repositories/refs Demonstrates how to create a document, obtain references to specific fields or array elements, and perform operations like removal. It also shows how to log the document state after modifications. ```APIDOC ## Create and Manipulate Refs ### Description This section illustrates the creation of Automerge documents and the subsequent use of the Refs API to target and modify specific data within those documents. It covers referencing fields, array elements, and using pattern matching for selections. ### Method N/A (SDK Example) ### Endpoint N/A (SDK Example) ### Parameters N/A (SDK Example) ### Request Example ```javascript handle = repo.create({ user: { name: "Alice", age: 30, hobbies: ["biking", "spelunking", "weaving"] }}) const ageRef = handle.ref("user", "age") ageRef.remove() // Logs undefined console.log("age is", handle.doc().user.age) const nameRef = handle.ref("user", "name", cursor(2,5)) nameRef.remove() // Logs Al console.log("name is", handle.doc().user.name) const bikingHobbyRef = handle.ref("user", "hobbies", 0) bikingHobbyRef.remove() // logs ['spelunking', 'weaving'] console.log("hobbies are ", handle.doc().user.hobbies) ``` ### Response N/A (SDK Example) ``` -------------------------------- ### Initialize Node.js File System Storage Adapter Source: https://automerge.org/docs/reference/repositories/storage Instantiate the NodeFSStorageAdapter to store Automerge documents in a directory on the local file system. This adapter is safe for concurrent use by multiple processes. ```javascript import { NodeFSStorageAdapter } from "@automerge/automerge-repo-storage-nodefs"; const storage = new NodeFSStorageAdapter(); ``` -------------------------------- ### Connect to Sync Server via WebSocket Source: https://automerge.org/docs/tutorial/network-sync Add WebSocketClientAdapter to your Repo's network subsystem during creation to enable syncing with a remote server. This allows other processes to connect to the server and retrieve your changes. ```typescript //...import { WebSocketClientAdapter } from "@automerge/react"; const repo = new Repo({ network: [ new BroadcastChannelNetworkAdapter(), new WebSocketClientAdapter("wss://sync.automerge.org"), ], storage: new IndexedDBStorageAdapter(), }); ``` -------------------------------- ### Create a new Automerge document Source: https://automerge.org/docs/tutorial/local-sync Use `repo.create` to make a new document, save it to storage, and announce it to the network. This returns a `DocHandle` for accessing the document and its URL. ```javascript const handle = window.repo.create({foo: "bar"}) console.log(handle.url) ``` -------------------------------- ### Configure Repo with IndexedDBStorageAdapter Source: https://automerge.org/docs/reference/under-the-hood/storage Modify the Repo initialization to use IndexedDBStorageAdapter for persistence. This configuration disables live network synchronization but allows for data to be saved and reloaded across browser refreshes or tab closures. ```typescript const repo = new Repo({ network: [], // This part means that we're not sending live changes anywhere storage: new IndexedDBStorageAdapter(), }); ``` -------------------------------- ### Initialize WebSocketServerAdapter with ws Source: https://automerge.org/docs/reference/repositories/networking Instantiate the WebSocketServerAdapter using the 'ws' library. This adapter is used on the server side for WebSocket communication. ```javascript import { WebSocketServer } from "ws"; import { WebSocketServerAdapter } from "@automerge/automerge-repo-network-websocket"; const wss = new WebSocketServer({ port: 8080 }); const adapter = new WebSocketServerAdapter(wss); ``` -------------------------------- ### Initialize Document Structure with Automerge.change() Source: https://automerge.org/docs/cookbook/modeling-data Use Automerge.change() to set up the initial schema for a new document. This ensures a consistent structure across devices before users begin making changes. ```javascript let doc = Automerge.init() doc = Automerge.change(doc, doc => { doc.users = [] doc.channels = {} doc.messages = [] }) ``` -------------------------------- ### Initialize Root Document in main.tsx Source: https://automerge.org/docs/tutorial/multiple-task-lists Sets up the Automerge repository and initializes a root document. It checks the URL for an existing task list or creates a new one, storing its URL in the root document. The root document handle is made available globally for debugging. ```typescript import { RootDocument } from "./rootDoc.ts" // ..// Add the repo to the global window object so it can be accessed in the browser console// This is useful for debugging and testing purposes. declare global { interface Window { repo: Repo; // We also add the handle to the global window object for debugging handle: DocHandle; } } window.repo = repo; // Check the URL for a document to load const locationHash = document.location.hash.substring(1); // Depending if we have an AutomergeUrl, either find or create the document if (isValidAutomergeUrl(locationHash)) { const taskList = await repo.find(locationHash); window.handle = repo.create({ taskLists: [taskList.url] }); } else { const taskList = repo.create(initTaskList()); window.handle = repo.create({ taskLists: [taskList.url] }); // Set the location hash to the new document we just made. document.location.hash = taskList.url; } ReactDOM.createRoot(document.getElementById("root")!).render( Loading a document...}> , ); ``` -------------------------------- ### Unbundled Vanilla JS Initialization Source: https://automerge.org/docs/reference/library-initialization For use in unbundled vanilla JavaScript, manually initialize the WASM module by fetching the `.wasm` file and then setting up the Automerge Repo. This approach may require wrapping in an async function if top-level await is not supported. ```javascript import * as AutomergeRepo from "https://esm.sh/@automerge/[email protected]/slim?bundle-deps"; await AutomergeRepo.initializeWasm( fetch("https://esm.sh/@automerge/automerge/dist/automerge.wasm") ); // Then set up an automerge repo (loading with our annoying WASM hack) const repo = new AutomergeRepo.Repo({ storage: new AutomergeRepo.IndexedDBStorageAdapter(), network: [ new AutomergeRepo.WebSocketClientAdapter("wss://sync.automerge.org"), ], }); ``` -------------------------------- ### Initialize Automerge Repo with Text Document Source: https://automerge.org/docs/cookbook/rich-text-prosemirror-react Modify the handle initialization logic in `main.tsx` to create a document with a 'text' field instead of a 'Counter'. This ensures the document is ready to store rich text. ```typescript import { AutomergeUrl } from "@automerge/automerge-repo" import { useHandle } from "@automerge/automerge-repo-react-hooks" import { useEffect, useState } from "react" function App({ docUrl }: { docUrl: AutomergeUrl }) { const handle = useHandle<{text: string}>(docUrl) const [loaded, setLoaded] = useState(handle && handle.docSync() != null) useEffect(() => { if (handle != null) { handle.whenReady().then(() => { if (handle.docSync() != null) { setLoaded(true) } }) } }, [handle]) return
} export default App ``` -------------------------------- ### Handle Document URL and Initialize Handle Source: https://automerge.org/docs/cookbook/rich-text-prosemirror-vanilla Retrieves the Automerge document URL from the browser's hash. If a valid URL exists, it finds the document; otherwise, it creates a new document and updates the URL hash. ```javascript // Get the document ID from the URL fragment if it's there. Otherwise, create// a new document and update the URL fragment to match. const docUrl = window.location.hash.slice(1) if (docUrl && isValidAutomergeUrl(docUrl)) { handle = await repo.find(docUrl) } else { handle = repo.create({ text: "" }) window.location.hash = handle.url } ``` -------------------------------- ### Importing Automerge (Recommended) Source: https://automerge.org/docs/guides/migrating-from-automerge-2-to-automerge-3 Change your imports to use the main Automerge module. This is recommended as the `next` module is deprecated. ```javascript import * as Automerge from "@automerge/automerge" ``` -------------------------------- ### wasmInitialized Source: https://automerge.org/automerge/api-docs/js Returns true if the WebAssembly module has been initialized. ```APIDOC ## wasmInitialized ### Description Returns true if the WebAssembly module has been initialized. ### Function Signature `wasmInitialized(): boolean` ``` -------------------------------- ### Initialize IndexedDB Storage Adapter Source: https://automerge.org/docs/reference/repositories/storage Instantiate the IndexedDBStorageAdapter to store Automerge documents in the browser's IndexedDB. This adapter is safe for concurrent use across multiple tabs. ```javascript import { IndexedDBStorageAdapter } from "@automerge/automerge-repo-storage-indexeddb" const storage = new IndexedDBStorageAdapter() ``` -------------------------------- ### load Source: https://automerge.org/automerge/api-docs/js Loads an Automerge document from a Uint8Array. ```APIDOC ## load ### Description Loads an Automerge document from a Uint8Array. ### Function Signature `load(data: Uint8Array): Doc` ``` -------------------------------- ### Update Text to string in Automerge Source: https://automerge.org/docs/guides/migrating-from-automerge-2-to-automerge-3 Shows how to migrate from using Automerge.Text to plain strings. This involves changing the initialization and update methods. ```javascript import * as Automerge from "@automerge/automerge" let doc = Automerge.from({ content: new Automerge.Text() }) doc = Automerge.change(doc, d => { d.content.insertAt(0, "Hello ") }) ``` ```javascript import * as Automerge from "@automerge/automerge" let doc = Automerge.from({ content: "" }) doc = Automerge.change(doc, d => { Automerge.splice(d, ["content"], 0, 0, "Hello") }) ``` -------------------------------- ### Find an Automerge document by URL Source: https://automerge.org/docs/tutorial/local-sync Use `repo.find` to retrieve a document using its URL. It checks local storage and connected peers. This is useful for loading existing documents. ```javascript const handle = await window.repo.find("") console.log(handle.doc()) ``` -------------------------------- ### isWasmInitialized Source: https://automerge.org/automerge/api-docs/js Checks if the WebAssembly module has been initialized. ```APIDOC ## isWasmInitialized ### Description Checks if the WebAssembly module has been initialized. ### Function Signature `isWasmInitialized(): boolean` ``` -------------------------------- ### Webpack Configuration Source: https://automerge.org/docs/reference/library-initialization For Webpack projects, enable the `asyncWebAssembly` experiment in your `webpack.config.js` to properly load the WebAssembly module. ```javascript { experiments: { asyncWebAssembly: true; } } ``` -------------------------------- ### Importing Automerge (Deprecated) Source: https://automerge.org/docs/guides/migrating-from-automerge-2-to-automerge-3 If you are using the `next` API, it is recommended to switch to the main Automerge import. The `next` module still works but is deprecated. ```javascript import { next as Automerge } from "@automerge/automerge" ``` -------------------------------- ### Debugging Root Document in Browser Console Source: https://automerge.org/docs/tutorial/persist-root-doc Demonstrates how to inspect the root document stored in local storage using the browser's developer console. This helps verify that the root document is correctly persisted. ```javascript const rootDocUrl = localStorage.getItem("root-doc-url") const root = await window.repo.find(rootDocUrl); console.log("Root document:", root.doc()); ``` -------------------------------- ### Load or Create Automerge Document Handle Source: https://automerge.org/docs/tutorial/load-by-url Add this code to your main application file to load a document by URL or create a new one. It initializes the Automerge repository and sets up global access to the repository and document handle for debugging. ```typescript import React, { Suspense } from "react"; import ReactDOM from "react-dom/client"; import App from "./components/App.tsx"; import "./index.css"; import { initTaskList, TaskList } from "./components/TaskList.tsx"; import { Repo, BroadcastChannelNetworkAdapter, IndexedDBStorageAdapter, isValidAutomergeUrl, DocHandle, } from "@automerge/react"; const repo = new Repo({ network: [new BroadcastChannelNetworkAdapter()], storage: new IndexedDBStorageAdapter(), }); // Add the repo to the global window object so it can be accessed in the browser console // This is useful for debugging and testing purposes. declare global { interface Window { repo: Repo; // We also add the handle to the global window object for debugging handle: DocHandle; } } window.repo = repo; // Check the URL for a document to load const locationHash = document.location.hash.substring(1); // Depending if we have an AutomergeUrl, either find or create the document if (isValidAutomergeUrl(locationHash)) { window.handle = await repo.find(locationHash); } else { window.handle = repo.create(initTaskList()); // Set the location hash to the new document we just made. document.location.hash = window.handle.url; } ReactDOM.createRoot(document.getElementById("root")!).render( Loading a document...}> , ); ``` -------------------------------- ### Integrating SyncControls into App.tsx Source: https://automerge.org/docs/tutorial/multi-device-root-doc Demonstrates how to integrate the SyncControls component into the main App component to provide multi-device synchronization capabilities. Ensure necessary imports are present. ```typescript // ..import { useHash } from "react-use";import { SyncControls } from "./SyncControls"; // ..

Powered by Automerge + Vite + React + TypeScript

``` -------------------------------- ### Initialize Automerge WASM with Base64 in Deno Source: https://automerge.org/docs/reference/library-initialization Manually initialize the Automerge WebAssembly module in Deno using a base64 encoded string when filesystem access is restricted. Ensure the `automergeWasmBase64` is imported. ```typescript import { automergeWasmBase64 } from "npm:@automerge/automerge";import * as Am from "npm:@automerge/automerge";await Am.initializeBase64Wasm(automergeWasmBase64); ``` -------------------------------- ### Using Refs with Cursors for Strings Source: https://automerge.org/docs/reference/repositories/refs Demonstrates how to use Refs with cursors to reference and modify specific substrings within a text document. ```APIDOC ## Using Refs with Cursors for Strings ### Description This example shows how to use Automerge Refs in conjunction with cursors to pinpoint and manipulate specific ranges within a string value in the document. ### Method Implicitly through document handle methods and the `change` method of a Ref object. ### Endpoint N/A (SDK method) ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body None ### Request Example ```javascript // Assuming 'cursor' is imported or available let handle = repo.create({ message: "Hello world" }); const rangeRef = handle.ref("message", cursor(0, 5)); // References 'Hello' // Logs 'Hello' console.log(rangeRef.value()); rangeRef.change(() => "Hi"); // Replaces the referenced text with 'Hi' ``` ### Response #### Success Response (200) N/A (SDK method modifies the document in place) #### Response Example ```javascript // The text is replaced at the range; logs "Hi world" console.log(handle.doc().message); ``` ``` -------------------------------- ### Integrate Automerge with ProseMirror Editor Source: https://automerge.org/docs/cookbook/rich-text-prosemirror-vanilla Initializes the ProseMirror editor state and plugins using the Automerge document handle. This sets up the schema, document mirror, and the Automerge plugin for the editor. ```javascript // This is the integration with automerge. const { schema, doc, plugin } = init(handle, ["text"]) const editorConfig = { schema, plugins: [plugin], }// This is the prosemirror editor. const view = new EditorView(document.querySelector("#editor"), { state: EditorState.create({ doc, // Note that we initialize using the mirror plugins: exampleSetup({ schema, plugins: [plugin] }), }), }) ``` -------------------------------- ### releaseInfo Source: https://automerge.org/automerge/api-docs/js Retrieves information about the Automerge release. ```APIDOC ## releaseInfo ### Description Retrieves information about the Automerge release. ### Function Signature `releaseInfo(): JsReleaseInfo` ``` -------------------------------- ### HTML Structure for ProseMirror + Automerge App Source: https://automerge.org/docs/cookbook/rich-text-prosemirror-vanilla Basic HTML file structure required for the ProseMirror and Automerge integration. Includes a div for the editor and a script tag for the main JavaScript file. ```html Prosemirror + Automerge
``` -------------------------------- ### Remove Properties via Ref Source: https://automerge.org/docs/reference/repositories/refs Demonstrates how Refs can be used to remove properties, substrings, or array elements they point to. ```javascript const firstTodoRef = handle.ref("todos", 0) firstTodoRef.remove() // The first todo object is removed from the list ``` -------------------------------- ### Pattern Matching with Refs Source: https://automerge.org/docs/reference/repositories/refs Shows how to use pattern matching within refs to select elements from an array based on their properties, and then remove the matched element. ```APIDOC ## Pattern Matching with Refs ### Description This example demonstrates using pattern matching with the `ref` function to select an object within an array based on a specific property value (e.g., `id: "b"`). The selected object can then be manipulated, such as being removed from the document. ### Method N/A (SDK Example) ### Endpoint N/A (SDK Example) ### Parameters N/A (SDK Example) ### Request Example ```javascript handle = repo.create({ users: [ { id: "a", name: "Alice" }, { id: "b", name: "Bob" }, { id: "c", name: "Charlie" }, ] }) const bobRef = handle.ref("users", { id: "b" }) bobRef.remove() // Logs the objects for Alice and Charlie console.log(handle.doc().users) ``` ### Response N/A (SDK Example) ``` -------------------------------- ### Listen for changes on an Automerge document Source: https://automerge.org/docs/tutorial/local-sync Attach a 'change' event listener to a `DocHandle` to log updates to the document. This allows observing real-time modifications. ```javascript handle.on("change", evt => console.log(evt.doc)) ``` -------------------------------- ### save Source: https://automerge.org/automerge/api-docs/js Saves the entire Automerge document to a Uint8Array. ```APIDOC ## save ### Description Saves the entire Automerge document to a Uint8Array. ### Function Signature `save(doc: Doc): Uint8Array` ``` -------------------------------- ### Create and Modify Automerge Document with Various Data Types Source: https://automerge.org/docs/reference/documents Demonstrates creating an Automerge document with different data types like maps, lists, text, strings, numbers, booleans, bytes, dates, counters, and null. It also shows how to modify these values and nested structures using the `change` function and specific Automerge methods like `splice` and `increment`. ```javascript import * as A from "@automerge/automerge";let doc = A.from({ map: { key: "value", nested_map: { key: "value" }, nested_list: [1], }, list: ["a", "b", "c", { nested: "map" }, ["nested list"]], text: "world", raw_string: new A.ImmutableString("immutablestring"), integer: 1, float: 2.3, boolean: true, bytes: new Uint8Array([1, 2, 3]), date: new Date(), counter: new A.Counter(1), none: null, }); doc = A.change(doc, (d) => { // Insert 'Hello' at the beginning of the string A.splice(d, ["text"], 0, 0, "Hello "); d.counter.increment(20); d.map.key = "new value"; d.map.nested_map.key = "new nested value"; d.list[0] = "A"; d.list.insertAt(0, "Z"); d.list[4].nested = "MAP"; d.list[5][0] = "NESTED LIST"; }); console.log(doc); ``` -------------------------------- ### loadIncremental Source: https://automerge.org/automerge/api-docs/js Loads changes incrementally into an existing Automerge document. ```APIDOC ## loadIncremental ### Description Loads changes incrementally into an existing Automerge document. ### Function Signature `loadIncremental(doc: Doc, data: Uint8Array): Doc` ``` -------------------------------- ### readBundle Source: https://automerge.org/automerge/api-docs/js Reads a bundle of changes from a Uint8Array. ```APIDOC ## readBundle ### Description Reads a bundle of changes from a Uint8Array. ### Function Signature `readBundle(data: Uint8Array): DecodedChange[]` ``` -------------------------------- ### Create DocumentList Component Source: https://automerge.org/docs/tutorial/multiple-task-lists A React component that displays a list of task lists. It takes the URL of the root document, fetches it using `useDocument`, and then maps over the `taskLists` array to render each task list's title. ```typescript import React from "react"; import { useDocument, AutomergeUrl } from "@automerge/react"; import { TaskList } from "./TaskList"; export interface DocumentList { taskLists: AutomergeUrl[]; } export const DocumentList: React.FC<{ docUrl: AutomergeUrl; }> = ({ docUrl }) => { const [doc, changeDoc] = useDocument(docUrl, { suspense: true, }); return (
{doc.taskLists.map((docUrl) => (
))}
); }; // Component to display document title const DocumentTitle: React.FC<{ docUrl: AutomergeUrl }> = ({ docUrl }) => { const [doc] = useDocument(docUrl, { suspense: true }); // Get the first task's title or use a default const title = doc.title || "Untitled Task List"; return
{title}
; }; ``` -------------------------------- ### Initialize Automerge WASM with URL in Vite Source: https://automerge.org/docs/reference/library-initialization Initialize the Automerge WebAssembly module in a Vite application using a URL obtained via the `?url` suffix. This method is suitable for environments where direct WASM module imports are not supported. ```javascript // Note the ?url suffix import wasmUrl from "@automerge/automerge/automerge.wasm?url"; // Note the `/slim` suffixes import * as Automerge from "@automerge/automerge/slim"; import { Repo } from "@automerge/automerge-repo/slim"; await Automerge.initializeWasm(wasmUrl) // Now we can get on with our lives const repo = new Repo({..}) ``` -------------------------------- ### App Component for Task List Management Source: https://automerge.org/docs/tutorial/multiple-task-lists The main App component orchestrates the display of document lists and task lists. It uses react-use's `useHash` to manage the selected document's URL in the browser's hash, ensuring that the correct task list is displayed. ```typescript import { type AutomergeUrl, isValidAutomergeUrl } from "@automerge/react"; import { useHash } from "react-use"; function App({ docUrl }: { docUrl: AutomergeUrl }) { const [hash, setHash] = useHash(); const cleanHash = hash.slice(1); // Remove the leading '#' const selectedDocUrl = cleanHash && isValidAutomergeUrl(cleanHash) ? (cleanHash as AutomergeUrl) : null; return ( <>

Automerge Task List

{ if (url) { setHash(url); } else { setHash(""); } }} selectedDocument={selectedDocUrl} />
{selectedDocUrl ? : null}
); } export default App; ``` -------------------------------- ### Apply Hard-coded Migration to Upgrade Document Source: https://automerge.org/docs/cookbook/modeling-data Safely upgrade a document from one schema version to another by applying a hard-coded migration change. This ensures compatibility when multiple devices might perform the same migration independently. ```javascript type DocV1 = { version: 1, cards: Card[] } type DocV2 = { version: 2, title: Automerge.Text, cards: Card[] } // This change creates the `title` property required in V2, // and updates the `version` property from 1 to 2 const migrateV1toV2 = new Uint8Array([133, 111, 74, 131, ...]) let doc = getDocumentFromNetwork() if (doc.version === 1) { [doc] = Automerge.applyChange(doc, [migrateV1toV2]) } ``` -------------------------------- ### Node.js Import Source: https://automerge.org/docs/reference/library-initialization In Node.js, Automerge can be imported directly using standard ES module syntax. ```javascript import * as A from "@automerge/automerge" ```