@abraca/nuxt 0.1.0 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,84 +1,244 @@
1
- <!--
2
- Get your module up and running quickly.
3
-
4
- Find and replace all on all files (CMD+SHIFT+F):
5
- - Name: My Module
6
- - Package name: my-module
7
- - Description: My new Nuxt module
8
- -->
9
-
10
- # My Module
1
+ # @abraca/nuxt
11
2
 
12
3
  [![npm version][npm-version-src]][npm-version-href]
13
4
  [![npm downloads][npm-downloads-src]][npm-downloads-href]
14
5
  [![License][license-src]][license-href]
15
6
  [![Nuxt][nuxt-src]][nuxt-href]
16
7
 
17
- My new Nuxt module for doing amazing things.
8
+ First-class Nuxt 4 module for the [Abracadabra](https://abra.cou.sh) CRDT collaboration platform. Drop real-time collaborative documents, multi-user awareness, offline-first sync, and a full rich-text editor into any Nuxt app.
18
9
 
19
- - [✨ &nbsp;Release Notes](/CHANGELOG.md)
20
- <!-- - [🏀 Online playground](https://stackblitz.com/github/your-org/my-module?file=playground%2Fapp.vue) -->
21
- <!-- - [📖 &nbsp;Documentation](https://example.com) -->
10
+ - [Release Notes](/CHANGELOG.md)
22
11
 
23
12
  ## Features
24
13
 
25
- <!-- Highlight some of the features your module provide here -->
26
- - &nbsp;Foo
27
- - 🚠 &nbsp;Bar
28
- - 🌲 &nbsp;Baz
14
+ - Real-time collaborative editing via WebSocket + Yjs CRDT
15
+ - Offline-first with IndexedDB persistence and background sync queue
16
+ - Multi-user awareness — cursors, presence, typing indicators, voice/video
17
+ - TipTap rich-text editor with 30+ built-in extensions
18
+ - Built-in page renderers: Kanban, Table, Calendar, Gallery, Outline
19
+ - Full-text search with trigram indexing
20
+ - File uploads with offline blob caching
21
+ - Passkey (WebAuthn) authentication
22
+ - Server-side rendering with Nitro plugin system and doc cache
23
+ - Extensible plugin architecture
24
+
25
+ ## Requirements
29
26
 
30
- ## Quick Setup
27
+ - Nuxt >= 4
28
+ - `@abraca/dabra` >= 1.0.0
29
+ - `@tiptap/core`, `@tiptap/vue-3`, `@tiptap/extension-collaboration`, `@tiptap/extension-collaboration-caret`
30
+ - `yjs` >= 13
31
31
 
32
- Install the module to your Nuxt application with one command:
32
+ ## Setup
33
33
 
34
34
  ```bash
35
- npx nuxt module add my-module
35
+ pnpm add @abraca/nuxt @abraca/dabra yjs @tiptap/core @tiptap/vue-3 @tiptap/extension-collaboration @tiptap/extension-collaboration-caret
36
+ ```
37
+
38
+ ```ts
39
+ // nuxt.config.ts
40
+ export default defineNuxtConfig({
41
+ modules: ['@abraca/nuxt'],
42
+ abracadabra: {
43
+ url: 'https://your-abracadabra-server.example.com',
44
+ }
45
+ })
46
+ ```
47
+
48
+ Wrap your app with `<AProvider>` and you're live:
49
+
50
+ ```vue
51
+ <template>
52
+ <AProvider>
53
+ <NuxtPage />
54
+ </AProvider>
55
+ </template>
56
+ ```
57
+
58
+ ## Configuration
59
+
60
+ ```ts
61
+ abracadabra: {
62
+ // Connection
63
+ url?: string // Server URL (default: 'https://abra.cou.sh')
64
+ entryDocId?: string // Root doc ID (skips space discovery)
65
+
66
+ // Auth
67
+ persistAuth?: boolean // Persist JWT in localStorage (default: true)
68
+ authStorageKey?: string // localStorage key (default: 'abracadabra:auth')
69
+ auth?: {
70
+ middleware?: boolean // Register abracadabra-auth middleware
71
+ globalMiddleware?: boolean // Apply to all routes
72
+ loginPath?: string // Redirect target (default: '/login')
73
+ }
74
+
75
+ // Features (control what code is included)
76
+ features?: {
77
+ editor?: boolean // TipTap editor (default: true)
78
+ search?: boolean // Full-text search (default: true)
79
+ backgroundSync?: boolean // Offline sync queue (default: true)
80
+ renderers?: boolean // Built-in page renderers (default: true)
81
+ serverCache?: boolean // Server doc-tree cache runner (default: true)
82
+ }
83
+
84
+ // UI
85
+ prefix?: string // Component name prefix (default: '')
86
+ locale?: Partial<AbracadabraLocale>
87
+ docBasePath?: string // Doc route base (default: '/doc')
88
+
89
+ // Server-side service account (for Nitro runners)
90
+ service?: {
91
+ publicKey?: string // Ed25519 public key (base64url)
92
+ privateKey?: string // Ed25519 private key (base64url)
93
+ }
94
+
95
+ debug?: boolean
96
+ }
36
97
  ```
37
98
 
38
- That's it! You can now use My Module in your Nuxt app ✨
99
+ ## Auto-imported Composables
100
+
101
+ | Composable | Description |
102
+ |---|---|
103
+ | `useAbracadabra()` | Full collaboration state (client, provider, identity, docs) |
104
+ | `useAbracadabraAuth()` | Auth — login, passkey, identity management |
105
+ | `useAwareness()` | All connected users' raw awareness states |
106
+ | `useAwarenessPeers()` | Typed peer list with idle detection |
107
+ | `useAAField(key)` | Per-field interaction awareness (hover, press, focus) |
108
+ | `useYDoc(ydoc)` | Reactive Yjs primitives — `useSyncedMap`, `useSyncedArray`, `useAwarenessOf`, `useSmoothedCursors` |
109
+ | `useEditor(ydoc, opts)` | TipTap setup with collaboration + cursor extensions |
110
+ | `useChildTree(docId)` | Document tree scoped to a parent |
111
+ | `useDocumentPermissions(role)` | RBAC flags (canWrite, canDelete, etc.) |
112
+ | `useChat(channel)` | Real-time group & DM chat |
113
+ | `useNotifications()` | Server-pushed notifications |
114
+ | `useSearchIndex()` | Full-text search over synced docs |
115
+ | `useBackgroundSync()` | Offline sync queue status |
116
+ | `useDocExport()` | Export docs as markdown, HTML, or ZIP |
117
+ | `useDocImport()` | Import .md, .txt, .html files |
118
+ | `useFileBlobStore()` | Offline file blob cache (IndexedDB) |
119
+ | `useVoice()` | WebRTC voice/video state |
120
+ | `useWindowManager()` | Floating window (PiP/panel) management |
121
+ | `useCommandPalette()` | ⌘K command palette state & commands |
122
+ | `useConnectionStatus()` | Connection status as UI-ready label + color |
123
+ | `useRendererBase(docId)` | Shared setup for custom page renderers |
124
+ | `useTrash()` | Document trash (move, restore, permanent delete) |
125
+ | `usePasskeyAccounts()` | WebAuthn passkey account management |
126
+ | `useFollowUser(userId)` | Cursor following for pair programming |
127
+
128
+ ## Auto-imported Components
129
+
130
+ ### Core
131
+ | Component | Description |
132
+ |---|---|
133
+ | `<AProvider>` | Root wrapper — initializes SDK and syncs root doc |
134
+ | `<AEditor>` | Full TipTap collaborative editor |
135
+ | `<ADocumentTree>` | Hierarchical doc tree with drag-drop |
136
+ | `<ANodePanel>` | Slide-over panel with doc metadata and children |
137
+ | `<ACommandPalette>` | ⌘K search and command palette |
138
+ | `<AConnectionStatus>` | Connection state badge |
139
+ | `<APresence>` | Connected users presence indicator |
140
+ | `<ANotifications>` | Notification center |
141
+ | `<AVoiceBar>` | Voice/video call controls |
142
+ | `<ADocTypeSelect>` | Page type selector |
143
+ | `<APermissionGuard>` | Conditional render based on role |
144
+ | `<ARoleBadge>` | Role badge (Owner, Editor, Viewer, etc.) |
145
+ | `<AFloatingWindow>` | Floating/PiP window container |
146
+ | `<AWindowLayer>` | Portal for floating windows |
147
+
148
+ ### Aware Interaction Components
149
+ Interaction components that broadcast awareness state to other users:
150
+
151
+ `<AArea>` `<AAvatar>` `<AButton>` `<AInput>` `<ATextarea>` `<ASelect>` `<ACursorLabel>` `<AFacepile>` `<AUserList>` `<ADocBadge>`
152
+
153
+ ### Page Renderers (requires `features.renderers`)
154
+ `<AKanbanRenderer>` `<ATableRenderer>` `<ACalendarRenderer>` `<AGalleryRenderer>` `<AOutlineRenderer>`
155
+
156
+ ## Server-Side Usage
157
+
158
+ Configure a service account for server-side doc access:
159
+
160
+ ```ts
161
+ // nuxt.config.ts
162
+ export default defineNuxtConfig({
163
+ modules: ['@abraca/nuxt'],
164
+ runtimeConfig: {
165
+ abracadabra: {
166
+ servicePublicKey: process.env.ABRA_SERVICE_PUBLIC_KEY,
167
+ servicePrivateKey: process.env.ABRA_SERVICE_PRIVATE_KEY,
168
+ }
169
+ }
170
+ })
171
+ ```
39
172
 
173
+ Register custom server runners via the Nitro hook:
174
+
175
+ ```ts
176
+ // server/plugins/my-runner.ts
177
+ export default defineNitroPlugin((nitro) => {
178
+ nitro.hooks.hook('abracadabra:before-runners', (ctx) => {
179
+ registerServerPlugin({
180
+ name: 'my-runner',
181
+ runners: [{
182
+ name: 'my-background-task',
183
+ run: async ({ provider, client }) => {
184
+ // background work
185
+ return () => { /* cleanup */ }
186
+ }
187
+ }]
188
+ })
189
+ })
190
+ })
191
+ ```
192
+
193
+ ## Plugin System
194
+
195
+ Extend the editor, add toolbar items, slash commands, and page types:
196
+
197
+ ```ts
198
+ import type { AbracadabraPlugin } from '@abraca/nuxt'
199
+
200
+ const myPlugin: AbracadabraPlugin = {
201
+ name: 'my-plugin',
202
+ extensions: () => [/* TipTap extensions */],
203
+ toolbarItems: () => [/* toolbar groups */],
204
+ suggestionItems: () => [/* slash commands */],
205
+ pageTypes: [{ type: 'my-type', label: 'My Page', component: MyRenderer }],
206
+ clientSetup: async (state) => { /* init */ }
207
+ }
208
+ ```
40
209
 
41
210
  ## Contribution
42
211
 
43
- <details>
44
- <summary>Local development</summary>
45
-
46
- ```bash
47
- # Install dependencies
48
- npm install
49
-
50
- # Generate type stubs
51
- npm run dev:prepare
52
-
53
- # Develop with the playground
54
- npm run dev
55
-
56
- # Build the playground
57
- npm run dev:build
58
-
59
- # Run ESLint
60
- npm run lint
61
-
62
- # Run Vitest
63
- npm run test
64
- npm run test:watch
65
-
66
- # Release new version
67
- npm run release
68
- ```
69
-
70
- </details>
212
+ ```bash
213
+ # Install dependencies
214
+ pnpm install
71
215
 
216
+ # Generate type stubs
217
+ pnpm dev:prepare
218
+
219
+ # Develop with the playground
220
+ pnpm dev
221
+
222
+ # Build
223
+ pnpm prepack
224
+
225
+ # Lint
226
+ pnpm lint
227
+
228
+ # Test
229
+ pnpm test
230
+ pnpm test:watch
231
+ ```
72
232
 
73
233
  <!-- Badges -->
74
- [npm-version-src]: https://img.shields.io/npm/v/my-module/latest.svg?style=flat&colorA=020420&colorB=00DC82
75
- [npm-version-href]: https://npmjs.com/package/my-module
234
+ [npm-version-src]: https://img.shields.io/npm/v/@abraca/nuxt/latest.svg?style=flat&colorA=020420&colorB=00DC82
235
+ [npm-version-href]: https://npmjs.com/package/@abraca/nuxt
76
236
 
77
- [npm-downloads-src]: https://img.shields.io/npm/dm/my-module.svg?style=flat&colorA=020420&colorB=00DC82
78
- [npm-downloads-href]: https://npm.chart.dev/my-module
237
+ [npm-downloads-src]: https://img.shields.io/npm/dm/@abraca/nuxt.svg?style=flat&colorA=020420&colorB=00DC82
238
+ [npm-downloads-href]: https://npm.chart.dev/@abraca/nuxt
79
239
 
80
- [license-src]: https://img.shields.io/npm/l/my-module.svg?style=flat&colorA=020420&colorB=00DC82
81
- [license-href]: https://npmjs.com/package/my-module
240
+ [license-src]: https://img.shields.io/npm/l/@abraca/nuxt.svg?style=flat&colorA=020420&colorB=00DC82
241
+ [license-href]: https://npmjs.com/package/@abraca/nuxt
82
242
 
83
243
  [nuxt-src]: https://img.shields.io/badge/Nuxt-020420?logo=nuxt
84
244
  [nuxt-href]: https://nuxt.com
package/dist/module.json CHANGED
@@ -4,7 +4,7 @@
4
4
  "compatibility": {
5
5
  "nuxt": ">=4.0.0"
6
6
  },
7
- "version": "0.1.0",
7
+ "version": "0.2.0",
8
8
  "builder": {
9
9
  "@nuxt/module-builder": "1.0.2",
10
10
  "unbuild": "3.6.1"
@@ -1,53 +1,18 @@
1
- import type { AbracadabraLocale } from '../locale.js';
2
1
  type __VLS_Props = {
3
- showTrash?: boolean;
4
- allowFileDrop?: boolean;
5
- draggable?: boolean;
2
+ collapsed?: boolean;
3
+ editable?: boolean;
6
4
  selectedId?: string | null;
7
- labels?: Partial<AbracadabraLocale['documentTree']>;
8
5
  };
9
- interface FlatItem {
10
- id: string;
11
- label: string;
12
- type?: string;
13
- meta?: Record<string, any>;
14
- depth: number;
15
- parentId: string | null;
16
- order: number;
17
- isExpanded: boolean;
18
- hasChildren: boolean;
19
- }
20
- declare var __VLS_1: {}, __VLS_20: {
21
- entry: FlatItem;
22
- depth: number;
23
- isExpanded: boolean;
24
- }, __VLS_42: {}, __VLS_85: {};
25
- type __VLS_Slots = {} & {
26
- header?: (props: typeof __VLS_1) => any;
27
- } & {
28
- item?: (props: typeof __VLS_20) => any;
29
- } & {
30
- empty?: (props: typeof __VLS_42) => any;
31
- } & {
32
- footer?: (props: typeof __VLS_85) => any;
33
- };
34
- declare const __VLS_base: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
35
- select: (docId: string) => any;
6
+ declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {
7
+ handleExternalDrop: (e: DragEvent, parentId?: string | null) => any;
8
+ }, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
9
+ navigate: (id: string) => any;
36
10
  create: (parentId: string | null) => any;
37
11
  }, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{
38
- onSelect?: ((docId: string) => any) | undefined;
12
+ onNavigate?: ((id: string) => any) | undefined;
39
13
  onCreate?: ((parentId: string | null) => any) | undefined;
40
14
  }>, {
41
- draggable: boolean;
42
- showTrash: boolean;
43
- allowFileDrop: boolean;
44
- selectedId: string | null;
15
+ editable: boolean;
45
16
  }, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
46
- declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
47
17
  declare const _default: typeof __VLS_export;
48
18
  export default _default;
49
- type __VLS_WithSlots<T, S> = T & {
50
- new (): {
51
- $slots: S;
52
- };
53
- };