Created
December 2, 2025 06:30
-
-
Save daffl/d9ff6bcd7da5dc3b95b3e3f4563a289a to your computer and use it in GitHub Desktop.
A local-first Feathers app
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| <script lang="ts"> | |
| import { feathers } from 'feathers' | |
| import { Repo, type AnyDocumentId } from '@automerge/automerge-repo' | |
| import { BrowserWebSocketClientAdapter } from '@automerge/automerge-repo-network-websocket' | |
| import { IndexedDBStorageAdapter } from '@automerge/automerge-repo-storage-indexeddb' | |
| import type { SyncServiceDocument } from '@kalisio/feathers-automerge' | |
| import { AutomergeService } from '@kalisio/feathers-automerge' | |
| type Message = { | |
| id: string | |
| text: string | |
| createdAt: number | |
| } | |
| // Initialize Automerge Repo and point to public testing sync server | |
| const repo = new Repo({ | |
| network: [new BrowserWebSocketClientAdapter('wss://sync.automerge.org')], | |
| storage: new IndexedDBStorageAdapter(), | |
| }) | |
| // Load the Automerge document from the URL hash or create a new one and set the hash | |
| async function getDocument() { | |
| const hash = window.location.hash | |
| if (hash) { | |
| const url = hash.substring(1) | |
| return repo.find<SyncServiceDocument>(url as AnyDocumentId) | |
| } | |
| const doc = repo.create<SyncServiceDocument>({ | |
| __meta: {}, | |
| data: {}, | |
| }) | |
| window.location.hash = doc.url | |
| return doc | |
| } | |
| // Initialize Feathers 6 application | |
| const app = feathers<{ | |
| messages: AutomergeService<Message, Omit<Message, 'id'>> | |
| }>() | |
| // Register the Automerge service | |
| app.use('messages', new AutomergeService(await getDocument())) | |
| let text = $state('') | |
| let messages = $state(await app.service('messages').find()) | |
| // Render new messages on real-time events | |
| app.service('messages').on('created', (message: Message) => { | |
| messages.push(message) | |
| }) | |
| // Set up the application | |
| await app.setup() | |
| function createMessage(event: Event) { | |
| event.preventDefault() | |
| app.service('messages').create({ | |
| text, | |
| createdAt: Date.now(), | |
| }) | |
| text = '' | |
| } | |
| </script> | |
| <main> | |
| <link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/full.css" rel="stylesheet" type="text/css" /> | |
| <link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/tailwind.min.css" rel="stylesheet" type="text/css" /> | |
| <link rel="stylesheet" href="https://dove.feathersjs.com/feathers-chat.css" /> | |
| <div class="drawer drawer-mobile"> | |
| <input id="drawer-left" type="checkbox" class="drawer-toggle" /> | |
| <div class="drawer-content flex flex-col"> | |
| <div id="chat" class="h-full overflow-y-auto px-3"> | |
| {#each messages as message (message.id)} | |
| <div class={`chat py-2 chat-start`}> | |
| <div class="chat-image avatar"> | |
| <div class="w-10 rounded-full"> | |
| <img src="https://github.com/feathersdev.png" /> | |
| </div> | |
| </div> | |
| <div class="chat-header pb-1"> | |
| <time class="text-xs opacity-50">{new Date(message.createdAt).toLocaleString()}</time> | |
| </div> | |
| <div class="chat-bubble"> | |
| {message.text} | |
| </div> | |
| </div> | |
| {/each} | |
| <div id="message-end" /> | |
| </div> | |
| <div class="form-control w-full py-2 px-3"> | |
| <form class="input-group overflow-hidden" id="send-message" on:submit={createMessage}> | |
| <input | |
| name="text" | |
| type="text" | |
| placeholder="Compose message" | |
| class="input input-bordered w-full" | |
| bind:value={text} | |
| /> | |
| <button type="submit" class="btn">Send</button> | |
| </form> | |
| </div> | |
| </div> | |
| </div> | |
| </main> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| import { defineConfig } from 'vite' | |
| import { svelte } from '@sveltejs/vite-plugin-svelte' | |
| import wasm from 'vite-plugin-wasm' | |
| // https://vite.dev/config/ | |
| export default defineConfig({ | |
| plugins: [ | |
| wasm(), | |
| svelte({ | |
| compilerOptions: { | |
| experimental: { | |
| async: true, | |
| }, | |
| }, | |
| }), | |
| ], | |
| }) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment