@abraca/nuxt 0.2.0 → 0.3.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.
Files changed (152) hide show
  1. package/dist/module.d.mts +46 -0
  2. package/dist/module.json +1 -1
  3. package/dist/module.mjs +95 -2
  4. package/dist/runtime/assets/editor.css +1 -0
  5. package/dist/runtime/components/ACommandPalette.vue +4 -1
  6. package/dist/runtime/components/ADocRenderer.d.vue.ts +29 -0
  7. package/dist/runtime/components/ADocRenderer.vue +99 -0
  8. package/dist/runtime/components/ADocRenderer.vue.d.ts +29 -0
  9. package/dist/runtime/components/ADocTypeSelect.vue +4 -1
  10. package/dist/runtime/components/ADocumentTree.vue +78 -19
  11. package/dist/runtime/components/AEditor.d.vue.ts +9 -4
  12. package/dist/runtime/components/AEditor.vue +102 -7
  13. package/dist/runtime/components/AEditor.vue.d.ts +9 -4
  14. package/dist/runtime/components/AIconPicker.vue +8 -2
  15. package/dist/runtime/components/ANodePanel.vue +100 -61
  16. package/dist/runtime/components/ANotifications.vue +35 -8
  17. package/dist/runtime/components/APermissionGuard.vue +3 -1
  18. package/dist/runtime/components/APresence.vue +14 -3
  19. package/dist/runtime/components/AProvider.vue +7 -1
  20. package/dist/runtime/components/AVoiceBar.vue +57 -15
  21. package/dist/runtime/components/AVoiceTile.vue +4 -1
  22. package/dist/runtime/components/aware/AArea.vue +1 -1
  23. package/dist/runtime/components/aware/AAvatar.vue +85 -16
  24. package/dist/runtime/components/aware/AButton.vue +5 -1
  25. package/dist/runtime/components/aware/ACursorLabel.vue +5 -1
  26. package/dist/runtime/components/aware/ADocBadge.vue +4 -1
  27. package/dist/runtime/components/aware/AFacepile.vue +13 -3
  28. package/dist/runtime/components/aware/AInput.vue +5 -1
  29. package/dist/runtime/components/aware/ATextarea.vue +5 -1
  30. package/dist/runtime/components/aware/AUserList.vue +8 -2
  31. package/dist/runtime/components/renderers/ACalendarRenderer.d.vue.ts +12 -1
  32. package/dist/runtime/components/renderers/ACalendarRenderer.vue +388 -114
  33. package/dist/runtime/components/renderers/ACalendarRenderer.vue.d.ts +12 -1
  34. package/dist/runtime/components/renderers/ACallRenderer.d.vue.ts +13 -0
  35. package/dist/runtime/components/renderers/ACallRenderer.vue +169 -0
  36. package/dist/runtime/components/renderers/ACallRenderer.vue.d.ts +13 -0
  37. package/dist/runtime/components/renderers/AChecklistRenderer.d.vue.ts +19 -0
  38. package/dist/runtime/components/renderers/AChecklistRenderer.vue +581 -0
  39. package/dist/runtime/components/renderers/AChecklistRenderer.vue.d.ts +19 -0
  40. package/dist/runtime/components/renderers/ADashboardRenderer.d.vue.ts +19 -0
  41. package/dist/runtime/components/renderers/ADashboardRenderer.vue +1372 -0
  42. package/dist/runtime/components/renderers/ADashboardRenderer.vue.d.ts +19 -0
  43. package/dist/runtime/components/renderers/AGalleryCoverImage.d.vue.ts +8 -0
  44. package/dist/runtime/components/renderers/AGalleryCoverImage.vue +60 -0
  45. package/dist/runtime/components/renderers/AGalleryCoverImage.vue.d.ts +8 -0
  46. package/dist/runtime/components/renderers/AGalleryRenderer.d.vue.ts +12 -1
  47. package/dist/runtime/components/renderers/AGalleryRenderer.vue +221 -55
  48. package/dist/runtime/components/renderers/AGalleryRenderer.vue.d.ts +12 -1
  49. package/dist/runtime/components/renderers/AGraphRenderer.d.vue.ts +19 -0
  50. package/dist/runtime/components/renderers/AGraphRenderer.vue +1027 -0
  51. package/dist/runtime/components/renderers/AGraphRenderer.vue.d.ts +19 -0
  52. package/dist/runtime/components/renderers/AKanbanRenderer.d.vue.ts +13 -1
  53. package/dist/runtime/components/renderers/AKanbanRenderer.vue +474 -140
  54. package/dist/runtime/components/renderers/AKanbanRenderer.vue.d.ts +13 -1
  55. package/dist/runtime/components/renderers/AMapRenderer.d.vue.ts +19 -0
  56. package/dist/runtime/components/renderers/AMapRenderer.vue +1622 -0
  57. package/dist/runtime/components/renderers/AMapRenderer.vue.d.ts +19 -0
  58. package/dist/runtime/components/renderers/AOutlineRenderer.d.vue.ts +12 -1
  59. package/dist/runtime/components/renderers/AOutlineRenderer.vue +294 -134
  60. package/dist/runtime/components/renderers/AOutlineRenderer.vue.d.ts +12 -1
  61. package/dist/runtime/components/renderers/ATableRenderer.d.vue.ts +12 -1
  62. package/dist/runtime/components/renderers/ATableRenderer.vue +437 -145
  63. package/dist/runtime/components/renderers/ATableRenderer.vue.d.ts +12 -1
  64. package/dist/runtime/components/renderers/ATimelineRenderer.d.vue.ts +19 -0
  65. package/dist/runtime/components/renderers/ATimelineRenderer.vue +446 -0
  66. package/dist/runtime/components/renderers/ATimelineRenderer.vue.d.ts +19 -0
  67. package/dist/runtime/composables/useAwareness.js +5 -0
  68. package/dist/runtime/composables/useBroadcastSync.d.ts +18 -0
  69. package/dist/runtime/composables/useBroadcastSync.js +26 -0
  70. package/dist/runtime/composables/useChat.js +4 -2
  71. package/dist/runtime/composables/useChatUsers.js +2 -1
  72. package/dist/runtime/composables/useCommandPalette.js +62 -3
  73. package/dist/runtime/composables/useConnectionStatus.js +7 -0
  74. package/dist/runtime/composables/useDevicePairing.d.ts +58 -0
  75. package/dist/runtime/composables/useDevicePairing.js +108 -0
  76. package/dist/runtime/composables/useDocExport.d.ts +5 -0
  77. package/dist/runtime/composables/useDocExport.js +2 -2
  78. package/dist/runtime/composables/useDocImport.js +4 -3
  79. package/dist/runtime/composables/useDocSeo.d.ts +20 -0
  80. package/dist/runtime/composables/useDocSeo.js +44 -0
  81. package/dist/runtime/composables/useDocSlugs.d.ts +7 -0
  82. package/dist/runtime/composables/useDocSlugs.js +20 -0
  83. package/dist/runtime/composables/useDocTree.d.ts +34 -0
  84. package/dist/runtime/composables/useDocTree.js +35 -0
  85. package/dist/runtime/composables/useEditorDragHandle.js +2 -1
  86. package/dist/runtime/composables/useEditorMentions.js +4 -2
  87. package/dist/runtime/composables/useEditorSuggestions.d.ts +1 -0
  88. package/dist/runtime/composables/useEditorSuggestions.js +9 -2
  89. package/dist/runtime/composables/useEditorToolbar.js +2 -1
  90. package/dist/runtime/composables/useFileIndex.js +2 -1
  91. package/dist/runtime/composables/useFileTransfer.d.ts +112 -0
  92. package/dist/runtime/composables/useFileTransfer.js +171 -0
  93. package/dist/runtime/composables/useFollowUser.js +2 -1
  94. package/dist/runtime/composables/useInvites.d.ts +56 -0
  95. package/dist/runtime/composables/useInvites.js +77 -0
  96. package/dist/runtime/composables/useNodePanel.d.ts +14 -0
  97. package/dist/runtime/composables/useNodePanel.js +52 -0
  98. package/dist/runtime/composables/useNotifications.js +4 -2
  99. package/dist/runtime/composables/usePasskeyAccounts.js +4 -2
  100. package/dist/runtime/composables/useSearchIndex.d.ts +1 -0
  101. package/dist/runtime/composables/useSearchIndex.js +13 -5
  102. package/dist/runtime/composables/useServerInfo.d.ts +31 -0
  103. package/dist/runtime/composables/useServerInfo.js +80 -0
  104. package/dist/runtime/composables/useSlugRoute.d.ts +6 -0
  105. package/dist/runtime/composables/useSlugRoute.js +19 -0
  106. package/dist/runtime/composables/useSpaces.d.ts +37 -0
  107. package/dist/runtime/composables/useSpaces.js +83 -0
  108. package/dist/runtime/composables/useTouchDrag.d.ts +34 -0
  109. package/dist/runtime/composables/useTouchDrag.js +191 -0
  110. package/dist/runtime/composables/useTrash.d.ts +1 -1
  111. package/dist/runtime/composables/useTrash.js +6 -3
  112. package/dist/runtime/composables/useWebRTC.d.ts +50 -0
  113. package/dist/runtime/composables/useWebRTC.js +177 -0
  114. package/dist/runtime/extensions/meta-field.d.ts +4 -1
  115. package/dist/runtime/extensions/steps.js +1 -1
  116. package/dist/runtime/extensions/views/AccordionItemView.vue +13 -3
  117. package/dist/runtime/extensions/views/AccordionView.vue +4 -1
  118. package/dist/runtime/extensions/views/BadgeView.vue +11 -2
  119. package/dist/runtime/extensions/views/CalloutView.vue +4 -1
  120. package/dist/runtime/extensions/views/CardGroupView.vue +4 -1
  121. package/dist/runtime/extensions/views/CardView.vue +17 -3
  122. package/dist/runtime/extensions/views/CodeGroupView.vue +4 -1
  123. package/dist/runtime/extensions/views/CollapsibleView.vue +8 -2
  124. package/dist/runtime/extensions/views/FileNodeView.vue +32 -8
  125. package/dist/runtime/extensions/views/KbdView.vue +8 -2
  126. package/dist/runtime/extensions/views/MetaFieldView.vue +208 -46
  127. package/dist/runtime/extensions/views/ProseIconView.vue +8 -2
  128. package/dist/runtime/extensions/views/TabsView.vue +17 -4
  129. package/dist/runtime/locale.d.ts +71 -0
  130. package/dist/runtime/locale.js +71 -0
  131. package/dist/runtime/plugin-abracadabra.client.js +29 -3
  132. package/dist/runtime/plugin-abracadabra.server.js +2 -0
  133. package/dist/runtime/server/api/_abracadabra/render/[docId].get.d.ts +1 -1
  134. package/dist/runtime/server/api/_abracadabra/render/[docId].get.js +29 -4
  135. package/dist/runtime/server/api/_abracadabra/resolve/[...slug].get.d.ts +2 -0
  136. package/dist/runtime/server/api/_abracadabra/resolve/[...slug].get.js +43 -0
  137. package/dist/runtime/server/api/_abracadabra/slugs.get.d.ts +2 -0
  138. package/dist/runtime/server/api/_abracadabra/slugs.get.js +7 -0
  139. package/dist/runtime/server/plugins/abracadabra-service.js +10 -5
  140. package/dist/runtime/server/runners/doc-tree-cache.js +4 -0
  141. package/dist/runtime/server/utils/slugMap.d.ts +32 -0
  142. package/dist/runtime/server/utils/slugMap.js +58 -0
  143. package/dist/runtime/types.d.ts +1 -0
  144. package/dist/runtime/utils/docTypes.d.ts +29 -1
  145. package/dist/runtime/utils/docTypes.js +129 -1
  146. package/dist/runtime/utils/markdownToYjs.js +2 -2
  147. package/dist/runtime/utils/sdkRef.d.ts +2 -0
  148. package/dist/runtime/utils/sdkRef.js +7 -0
  149. package/dist/runtime/utils/slugify.d.ts +40 -0
  150. package/dist/runtime/utils/slugify.js +36 -0
  151. package/dist/types.d.mts +6 -0
  152. package/package.json +32 -19
@@ -0,0 +1,171 @@
1
+ import { ref, shallowRef } from "vue";
2
+ const inboundTransfers = shallowRef(/* @__PURE__ */ new Map());
3
+ const outboundTransfers = shallowRef(/* @__PURE__ */ new Map());
4
+ const completedFiles = ref([]);
5
+ const _unbinds = [];
6
+ export function _wireFileTransferEvents(rtc) {
7
+ _cleanupFileTransfer();
8
+ const on = (event, handler) => {
9
+ rtc.on(event, handler);
10
+ _unbinds.push(() => rtc.off(event, handler));
11
+ };
12
+ on("fileReceiveStart", (data) => {
13
+ const next = new Map(inboundTransfers.value);
14
+ next.set(data.transferId, {
15
+ transferId: data.transferId,
16
+ peerId: data.peerId,
17
+ filename: data.filename ?? "unknown",
18
+ mimeType: data.mimeType ?? "application/octet-stream",
19
+ totalSize: data.totalSize ?? 0,
20
+ progress: 0,
21
+ status: "receiving"
22
+ });
23
+ inboundTransfers.value = next;
24
+ });
25
+ on("fileReceiveProgress", (data) => {
26
+ const existing = inboundTransfers.value.get(data.transferId);
27
+ if (existing) {
28
+ const next = new Map(inboundTransfers.value);
29
+ next.set(data.transferId, {
30
+ ...existing,
31
+ progress: data.total > 0 ? data.received / data.total : 0
32
+ });
33
+ inboundTransfers.value = next;
34
+ }
35
+ });
36
+ on("fileReceiveComplete", (data) => {
37
+ const next = new Map(inboundTransfers.value);
38
+ next.delete(data.transferId);
39
+ inboundTransfers.value = next;
40
+ const objectUrl = URL.createObjectURL(data.blob);
41
+ completedFiles.value = [
42
+ ...completedFiles.value,
43
+ {
44
+ transferId: data.transferId,
45
+ peerId: data.peerId ?? "",
46
+ filename: data.filename ?? "unknown",
47
+ mimeType: data.mimeType ?? "application/octet-stream",
48
+ size: data.blob?.size ?? 0,
49
+ blob: data.blob,
50
+ objectUrl,
51
+ receivedAt: Date.now()
52
+ }
53
+ ];
54
+ });
55
+ on("fileReceiveError", (data) => {
56
+ const existing = inboundTransfers.value.get(data.transferId);
57
+ if (existing) {
58
+ const next = new Map(inboundTransfers.value);
59
+ next.set(data.transferId, { ...existing, status: "error" });
60
+ inboundTransfers.value = next;
61
+ }
62
+ });
63
+ on("fileReceiveCancelled", (data) => {
64
+ const next = new Map(inboundTransfers.value);
65
+ next.delete(data.transferId);
66
+ inboundTransfers.value = next;
67
+ });
68
+ }
69
+ function _cleanupFileTransfer() {
70
+ for (const unsub of _unbinds) unsub();
71
+ _unbinds.length = 0;
72
+ }
73
+ export function _destroyFileTransfer() {
74
+ _cleanupFileTransfer();
75
+ inboundTransfers.value = /* @__PURE__ */ new Map();
76
+ outboundTransfers.value = /* @__PURE__ */ new Map();
77
+ for (const file of completedFiles.value) {
78
+ try {
79
+ URL.revokeObjectURL(file.objectUrl);
80
+ } catch {
81
+ }
82
+ }
83
+ completedFiles.value = [];
84
+ }
85
+ async function sendFile(peerId, file, filename) {
86
+ const { sendFile: rtcSendFile } = useWebRTC();
87
+ const transferId = crypto.randomUUID();
88
+ const next = new Map(outboundTransfers.value);
89
+ next.set(transferId, {
90
+ transferId,
91
+ peerId,
92
+ filename,
93
+ mimeType: file.type || "application/octet-stream",
94
+ totalSize: file.size,
95
+ progress: 0,
96
+ status: "sending"
97
+ });
98
+ outboundTransfers.value = next;
99
+ try {
100
+ const handle = await rtcSendFile(peerId, file, filename);
101
+ if (handle) {
102
+ handle.on?.("progress", (p) => {
103
+ const existing = outboundTransfers.value.get(transferId);
104
+ if (existing) {
105
+ const updated = new Map(outboundTransfers.value);
106
+ updated.set(transferId, { ...existing, progress: p });
107
+ outboundTransfers.value = updated;
108
+ }
109
+ });
110
+ handle.on?.("complete", () => {
111
+ const updated = new Map(outboundTransfers.value);
112
+ const existing = updated.get(transferId);
113
+ if (existing) updated.set(transferId, { ...existing, status: "complete", progress: 1 });
114
+ outboundTransfers.value = updated;
115
+ });
116
+ handle.on?.("error", () => {
117
+ const updated = new Map(outboundTransfers.value);
118
+ const existing = updated.get(transferId);
119
+ if (existing) updated.set(transferId, { ...existing, status: "error" });
120
+ outboundTransfers.value = updated;
121
+ });
122
+ }
123
+ } catch {
124
+ const updated = new Map(outboundTransfers.value);
125
+ const existing = updated.get(transferId);
126
+ if (existing) updated.set(transferId, { ...existing, status: "error" });
127
+ outboundTransfers.value = updated;
128
+ }
129
+ }
130
+ function downloadFile(transferId) {
131
+ const file = completedFiles.value.find((f) => f.transferId === transferId);
132
+ if (!file) return;
133
+ const a = document.createElement("a");
134
+ a.href = file.objectUrl;
135
+ a.download = file.filename;
136
+ document.body.appendChild(a);
137
+ a.click();
138
+ document.body.removeChild(a);
139
+ }
140
+ function clearCompleted() {
141
+ for (const file of completedFiles.value) {
142
+ try {
143
+ URL.revokeObjectURL(file.objectUrl);
144
+ } catch {
145
+ }
146
+ }
147
+ completedFiles.value = [];
148
+ const next = /* @__PURE__ */ new Map();
149
+ for (const [id, transfer] of outboundTransfers.value) {
150
+ if (transfer.status !== "complete" && transfer.status !== "error") {
151
+ next.set(id, transfer);
152
+ }
153
+ }
154
+ outboundTransfers.value = next;
155
+ }
156
+ export function useFileTransfer() {
157
+ return {
158
+ /** Active inbound file transfers. */
159
+ inboundTransfers,
160
+ /** Active outbound file transfers. */
161
+ outboundTransfers,
162
+ /** Completed received files (with object URLs for download). */
163
+ completedFiles,
164
+ /** Send a file to a specific peer. */
165
+ sendFile,
166
+ /** Trigger browser download for a completed file. */
167
+ downloadFile,
168
+ /** Clear all completed transfers and revoke object URLs. */
169
+ clearCompleted
170
+ };
171
+ }
@@ -3,6 +3,7 @@ const followingUserKey = ref(null);
3
3
  let cleanup = null;
4
4
  let navLock = false;
5
5
  export function useFollowUser() {
6
+ const { getDocUrl } = useDocSlugs();
6
7
  function setFollowing(key, provider, getCurrentDocId) {
7
8
  cleanup?.();
8
9
  cleanup = null;
@@ -18,7 +19,7 @@ export function useFollowUser() {
18
19
  const targetDocId = state.docId;
19
20
  if (targetDocId && targetDocId !== getCurrentDocId()) {
20
21
  navLock = true;
21
- navigateTo(`${useRuntimeConfig().public.abracadabra?.docBasePath ?? "/doc"}/${targetDocId}`);
22
+ navigateTo(getDocUrl(targetDocId));
22
23
  setTimeout(() => {
23
24
  navLock = false;
24
25
  }, 1e3);
@@ -0,0 +1,56 @@
1
+ /**
2
+ * useInvites
3
+ *
4
+ * Focused composable for invite management. Wraps the invite methods
5
+ * from useAbracadabra() with reactive state for the invite list.
6
+ *
7
+ * Usage:
8
+ * const { invites, create, revoke, redeem, refresh } = useInvites()
9
+ */
10
+ export interface Invite {
11
+ code: string;
12
+ role: string;
13
+ uses: number;
14
+ max_uses: number | null;
15
+ expires_at: number | null;
16
+ created_at: number;
17
+ }
18
+ declare function refresh(): Promise<void>;
19
+ declare function create(opts?: {
20
+ role?: string;
21
+ maxUses?: number;
22
+ expiresIn?: number;
23
+ }): Promise<Invite>;
24
+ declare function revoke(code: string): Promise<void>;
25
+ declare function redeem(code: string): Promise<void>;
26
+ export declare function useInvites(): {
27
+ /** Reactive list of invites. */
28
+ invites: import("vue").Ref<{
29
+ code: string;
30
+ role: string;
31
+ uses: number;
32
+ max_uses: number | null;
33
+ expires_at: number | null;
34
+ created_at: number;
35
+ }[], Invite[] | {
36
+ code: string;
37
+ role: string;
38
+ uses: number;
39
+ max_uses: number | null;
40
+ expires_at: number | null;
41
+ created_at: number;
42
+ }[]>;
43
+ /** Whether invite list is loading. */
44
+ loading: import("vue").Ref<boolean, boolean>;
45
+ /** Last error message. */
46
+ error: import("vue").Ref<string | null, string | null>;
47
+ /** Refresh the invite list from server. */
48
+ refresh: typeof refresh;
49
+ /** Create a new invite. */
50
+ create: typeof create;
51
+ /** Revoke an existing invite by code. */
52
+ revoke: typeof revoke;
53
+ /** Redeem an invite code. */
54
+ redeem: typeof redeem;
55
+ };
56
+ export {};
@@ -0,0 +1,77 @@
1
+ import { ref } from "vue";
2
+ const invites = ref([]);
3
+ const loading = ref(false);
4
+ const error = ref(null);
5
+ let _fetched = false;
6
+ async function refresh() {
7
+ const abra = useAbracadabra();
8
+ if (!abra.client.value) return;
9
+ loading.value = true;
10
+ error.value = null;
11
+ try {
12
+ const result = await abra.listInvites();
13
+ invites.value = result ?? [];
14
+ _fetched = true;
15
+ } catch (e) {
16
+ error.value = e.message ?? "Failed to fetch invites";
17
+ } finally {
18
+ loading.value = false;
19
+ }
20
+ }
21
+ async function create(opts) {
22
+ const abra = useAbracadabra();
23
+ error.value = null;
24
+ try {
25
+ const result = await abra.createInvite(opts);
26
+ await refresh();
27
+ return result;
28
+ } catch (e) {
29
+ error.value = e.message ?? "Failed to create invite";
30
+ throw e;
31
+ }
32
+ }
33
+ async function revoke(code) {
34
+ const abra = useAbracadabra();
35
+ error.value = null;
36
+ try {
37
+ await abra.revokeInvite(code);
38
+ invites.value = invites.value.filter((i) => i.code !== code);
39
+ } catch (e) {
40
+ error.value = e.message ?? "Failed to revoke invite";
41
+ throw e;
42
+ }
43
+ }
44
+ async function redeem(code) {
45
+ const abra = useAbracadabra();
46
+ error.value = null;
47
+ try {
48
+ await abra.redeemInvite(code);
49
+ } catch (e) {
50
+ error.value = e.message ?? "Failed to redeem invite";
51
+ throw e;
52
+ }
53
+ }
54
+ export function useInvites() {
55
+ if (!_fetched && !loading.value) {
56
+ const abra = useAbracadabra();
57
+ if (abra.client.value) {
58
+ refresh();
59
+ }
60
+ }
61
+ return {
62
+ /** Reactive list of invites. */
63
+ invites,
64
+ /** Whether invite list is loading. */
65
+ loading,
66
+ /** Last error message. */
67
+ error,
68
+ /** Refresh the invite list from server. */
69
+ refresh,
70
+ /** Create a new invite. */
71
+ create,
72
+ /** Revoke an existing invite by code. */
73
+ revoke,
74
+ /** Redeem an invite code. */
75
+ redeem
76
+ };
77
+ }
@@ -0,0 +1,14 @@
1
+ import type { ShallowRef } from 'vue';
2
+ /**
3
+ * Manages the state for opening a child document in a slide-over panel.
4
+ * Loads the child provider, waits for sync, and primes the Y.XmlFragment
5
+ * so TipTap can initialise without errors.
6
+ */
7
+ export declare function useNodePanel(parentProvider: ShallowRef<any>): {
8
+ openNodeId: import("vue").Ref<string | null, string | null>;
9
+ openNodeLabel: import("vue").Ref<string, string>;
10
+ openNodeProvider: import("vue").Ref<any, any>;
11
+ isLoading: import("vue").Ref<boolean, boolean>;
12
+ openNode: (nodeId: string, label: string) => Promise<void>;
13
+ closePanel: () => void;
14
+ };
@@ -0,0 +1,52 @@
1
+ import { ref } from "vue";
2
+ export function useNodePanel(parentProvider) {
3
+ const openNodeId = ref(null);
4
+ const openNodeLabel = ref("");
5
+ const openNodeProvider = ref(null);
6
+ const isLoading = ref(false);
7
+ async function openNode(nodeId, label) {
8
+ if (!parentProvider.value) return;
9
+ isLoading.value = true;
10
+ try {
11
+ const childProv = await parentProvider.value.loadChild(nodeId);
12
+ if (!childProv.isSynced) {
13
+ await new Promise((resolve) => {
14
+ const done = () => {
15
+ childProv.off("synced", done);
16
+ resolve();
17
+ };
18
+ childProv.on("synced", done);
19
+ setTimeout(resolve, 6e3);
20
+ });
21
+ }
22
+ const doc = childProv.document;
23
+ const frag = doc.getXmlFragment("default");
24
+ if (!frag._item) {
25
+ doc.transact(() => {
26
+ void frag.length;
27
+ });
28
+ }
29
+ openNodeProvider.value = childProv;
30
+ openNodeLabel.value = label;
31
+ openNodeId.value = nodeId;
32
+ } catch (e) {
33
+ console.error("Failed to load node:", e);
34
+ } finally {
35
+ isLoading.value = false;
36
+ }
37
+ }
38
+ function closePanel() {
39
+ openNodeId.value = null;
40
+ openNodeLabel.value = "";
41
+ openNodeProvider.value = null;
42
+ isLoading.value = false;
43
+ }
44
+ return {
45
+ openNodeId,
46
+ openNodeLabel,
47
+ openNodeProvider,
48
+ isLoading,
49
+ openNode,
50
+ closePanel
51
+ };
52
+ }
@@ -71,7 +71,8 @@ export function _handleStatelessNotification(payload) {
71
71
  break;
72
72
  }
73
73
  }
74
- } catch {
74
+ } catch (e) {
75
+ if (import.meta.dev) console.warn("[abracadabra] notifications: failed to handle stateless message:", e);
75
76
  }
76
77
  }
77
78
  function _scheduleToast(notif) {
@@ -117,7 +118,8 @@ function _flushToasts() {
117
118
  duration: 5e3
118
119
  });
119
120
  }
120
- }).catch(() => {
121
+ }).catch((e) => {
122
+ if (import.meta.dev) console.debug("[abracadabra] notifications: toast display failed:", e);
121
123
  });
122
124
  }
123
125
  function fetchNotifications(opts) {
@@ -4,7 +4,8 @@ function loadAccounts() {
4
4
  try {
5
5
  const raw = localStorage.getItem(ACCOUNTS_KEY);
6
6
  return raw ? JSON.parse(raw) : [];
7
- } catch {
7
+ } catch (e) {
8
+ if (import.meta.dev) console.debug("[abracadabra] passkey: failed to load accounts from localStorage:", e);
8
9
  return [];
9
10
  }
10
11
  }
@@ -18,7 +19,8 @@ export function usePasskeyAccounts() {
18
19
  function persist() {
19
20
  try {
20
21
  localStorage.setItem(ACCOUNTS_KEY, JSON.stringify(accounts.value));
21
- } catch {
22
+ } catch (e) {
23
+ if (import.meta.dev) console.debug("[abracadabra] passkey: failed to persist accounts:", e);
22
24
  }
23
25
  }
24
26
  function registerAccount(account) {
@@ -16,5 +16,6 @@ export declare function useSearchIndex(): {
16
16
  search: (query: string, limit?: number) => Promise<SearchResult[]>;
17
17
  isReady: import("vue").ComputedRef<boolean>;
18
18
  indexedCount: import("vue").ComputedRef<number>;
19
+ error: import("vue").ComputedRef<string | null>;
19
20
  };
20
21
  export {};
@@ -4,6 +4,7 @@ let _searchIndex = null;
4
4
  const _indexedVersions = /* @__PURE__ */ new Map();
5
5
  const _isReady = ref(false);
6
6
  const _indexedCount = ref(0);
7
+ const _error = ref(null);
7
8
  let _stopWatcher = null;
8
9
  function walkXmlForText(node, texts) {
9
10
  for (const child of node.toArray()) {
@@ -38,7 +39,8 @@ function extractDocTexts(ydoc, label, meta) {
38
39
  try {
39
40
  const fragment = ydoc.getXmlFragment("default");
40
41
  walkXmlForText(fragment, texts);
41
- } catch {
42
+ } catch (e) {
43
+ if (import.meta.dev) console.warn("[abracadabra] search: failed to extract doc texts:", e);
42
44
  }
43
45
  return texts;
44
46
  }
@@ -49,7 +51,9 @@ export function _initSearchIndex(serverOrigin) {
49
51
  _indexedVersions.clear();
50
52
  _indexedCount.value = 0;
51
53
  _startWatcher();
52
- }).catch(() => {
54
+ }).catch((e) => {
55
+ _error.value = e?.message ?? "Failed to load SearchIndex";
56
+ if (import.meta.dev) console.warn("[abracadabra] search: failed to load SearchIndex:", e);
53
57
  });
54
58
  }
55
59
  export function _destroySearchIndex() {
@@ -60,6 +64,7 @@ export function _destroySearchIndex() {
60
64
  _isReady.value = false;
61
65
  _indexedVersions.clear();
62
66
  _indexedCount.value = 0;
67
+ _error.value = null;
63
68
  }
64
69
  function _startWatcher() {
65
70
  const { syncStates } = useBackgroundSync();
@@ -82,7 +87,8 @@ function _startWatcher() {
82
87
  await _searchIndex.index(docId, texts);
83
88
  _indexedVersions.set(docId, lastSynced);
84
89
  _indexedCount.value = _indexedVersions.size;
85
- } catch {
90
+ } catch (e) {
91
+ if (import.meta.dev) console.warn(`[abracadabra] search: failed to index doc ${docId}:`, e);
86
92
  }
87
93
  }
88
94
  }, { deep: false });
@@ -94,11 +100,13 @@ export function useSearchIndex() {
94
100
  if (!_searchIndex) return [];
95
101
  try {
96
102
  return await _searchIndex.search(query, limit);
97
- } catch {
103
+ } catch (e) {
104
+ if (import.meta.dev) console.warn("[abracadabra] search: query failed:", e);
98
105
  return [];
99
106
  }
100
107
  },
101
108
  isReady: computed(() => _isReady.value),
102
- indexedCount: computed(() => _indexedCount.value)
109
+ indexedCount: computed(() => _indexedCount.value),
110
+ error: computed(() => _error.value)
103
111
  };
104
112
  }
@@ -0,0 +1,31 @@
1
+ /**
2
+ * useServerInfo
3
+ *
4
+ * Fetches and exposes server health, metadata, and ICE server configuration.
5
+ * Automatically fetches on first use when client is available.
6
+ *
7
+ * Usage:
8
+ * const { serverName, serverVersion, healthy, iceServers, refresh } = useServerInfo()
9
+ */
10
+ export declare function _initServerInfo(client: any): void;
11
+ export declare function _destroyServerInfo(): void;
12
+ declare function refresh(): Promise<void>;
13
+ export declare function useServerInfo(): {
14
+ /** Server display name. */
15
+ serverName: import("vue").Ref<string | null, string | null>;
16
+ /** Server version string. */
17
+ serverVersion: import("vue").Ref<string | null, string | null>;
18
+ /** Root/index document ID from server. */
19
+ indexDocId: import("vue").Ref<string | null, string | null>;
20
+ /** Whether the server is healthy. */
21
+ healthy: import("vue").Ref<boolean, boolean>;
22
+ /** ICE servers from server (STUN/TURN). */
23
+ iceServers: import("vue").ShallowRef<RTCIceServer[], RTCIceServer[]>;
24
+ /** Whether a fetch is in progress. */
25
+ loading: import("vue").Ref<boolean, boolean>;
26
+ /** Last error message. */
27
+ error: import("vue").Ref<string | null, string | null>;
28
+ /** Re-fetch server info. */
29
+ refresh: typeof refresh;
30
+ };
31
+ export {};
@@ -0,0 +1,80 @@
1
+ import { ref, shallowRef } from "vue";
2
+ const serverName = ref(null);
3
+ const serverVersion = ref(null);
4
+ const indexDocId = ref(null);
5
+ const healthy = ref(false);
6
+ const iceServers = shallowRef([]);
7
+ const loading = ref(false);
8
+ const error = ref(null);
9
+ let _fetched = false;
10
+ let _client = null;
11
+ export function _initServerInfo(client) {
12
+ _client = client;
13
+ _fetched = false;
14
+ _fetchAll();
15
+ }
16
+ export function _destroyServerInfo() {
17
+ _client = null;
18
+ _fetched = false;
19
+ serverName.value = null;
20
+ serverVersion.value = null;
21
+ indexDocId.value = null;
22
+ healthy.value = false;
23
+ iceServers.value = [];
24
+ error.value = null;
25
+ }
26
+ async function _fetchAll() {
27
+ if (!_client || loading.value) return;
28
+ loading.value = true;
29
+ error.value = null;
30
+ try {
31
+ const [healthResult, infoResult, iceResult] = await Promise.allSettled([
32
+ _client.health(),
33
+ _client.serverInfo(),
34
+ _client.getIceServers()
35
+ ]);
36
+ if (healthResult.status === "fulfilled") {
37
+ healthy.value = healthResult.value?.status === "ok" || !!healthResult.value;
38
+ }
39
+ if (infoResult.status === "fulfilled") {
40
+ const info = infoResult.value;
41
+ serverName.value = info?.name ?? null;
42
+ serverVersion.value = info?.version ?? null;
43
+ indexDocId.value = info?.index_doc_id ?? null;
44
+ }
45
+ if (iceResult.status === "fulfilled") {
46
+ iceServers.value = iceResult.value ?? [];
47
+ }
48
+ _fetched = true;
49
+ } catch (e) {
50
+ error.value = e.message ?? "Failed to fetch server info";
51
+ } finally {
52
+ loading.value = false;
53
+ }
54
+ }
55
+ async function refresh() {
56
+ await _fetchAll();
57
+ }
58
+ export function useServerInfo() {
59
+ if (!_fetched && _client && !loading.value) {
60
+ _fetchAll();
61
+ }
62
+ return {
63
+ /** Server display name. */
64
+ serverName,
65
+ /** Server version string. */
66
+ serverVersion,
67
+ /** Root/index document ID from server. */
68
+ indexDocId,
69
+ /** Whether the server is healthy. */
70
+ healthy,
71
+ /** ICE servers from server (STUN/TURN). */
72
+ iceServers,
73
+ /** Whether a fetch is in progress. */
74
+ loading,
75
+ /** Last error message. */
76
+ error,
77
+ /** Re-fetch server info. */
78
+ refresh
79
+ };
80
+ }
@@ -0,0 +1,6 @@
1
+ export declare function useSlugRoute(): {
2
+ slugPath: import("vue").ComputedRef<string>;
3
+ docId: import("vue").ComputedRef<string | null>;
4
+ isLoading: import("vue").ComputedRef<boolean>;
5
+ notFound: import("vue").ComputedRef<boolean>;
6
+ };
@@ -0,0 +1,19 @@
1
+ import { computed } from "vue";
2
+ import { isUUID } from "../utils/slugify.js";
3
+ export function useSlugRoute() {
4
+ const route = useRoute();
5
+ const { getDocId, slugMap } = useDocSlugs();
6
+ const slugPath = computed(() => {
7
+ const params = route.params.slug;
8
+ return Array.isArray(params) ? params.join("/") : params ?? "";
9
+ });
10
+ const docId = computed(() => {
11
+ const s = slugPath.value;
12
+ if (isUUID(s)) return s;
13
+ return getDocId(s);
14
+ });
15
+ const slugMapReady = computed(() => Object.keys(slugMap.value.slugToId).length > 0);
16
+ const isLoading = computed(() => !isUUID(slugPath.value) && !slugMapReady.value);
17
+ const notFound = computed(() => !docId.value && slugMapReady.value);
18
+ return { slugPath, docId, isLoading, notFound };
19
+ }
@@ -0,0 +1,37 @@
1
+ /**
2
+ * useSpaces
3
+ *
4
+ * Focused composable for space management. Wraps the space methods
5
+ * from useAbracadabra() with a cleaner API surface.
6
+ *
7
+ * Usage:
8
+ * const { spaces, currentSpace, create, switchTo, refresh } = useSpaces()
9
+ */
10
+ import type { SpaceMeta } from '../types.js';
11
+ export declare function useSpaces(): {
12
+ /** All spaces on the current server. */
13
+ spaces: import("vue").ComputedRef<SpaceMeta[]>;
14
+ /** Whether the current server supports spaces. */
15
+ spacesEnabled: import("vue").ComputedRef<boolean>;
16
+ /** The currently active space. */
17
+ currentSpace: import("vue").ComputedRef<SpaceMeta | null>;
18
+ /** Whether space operations are in progress. */
19
+ loading: import("vue").Ref<boolean, boolean>;
20
+ /** Last error message. */
21
+ error: import("vue").Ref<string | null, string | null>;
22
+ /** Refresh spaces list from server. */
23
+ refresh: () => Promise<void>;
24
+ /** Create a new space. */
25
+ create: (opts: {
26
+ name: string;
27
+ description?: string;
28
+ visibility?: SpaceMeta["visibility"];
29
+ id?: string;
30
+ }) => Promise<SpaceMeta>;
31
+ /** Update an existing space. */
32
+ update: (id: string, opts: Partial<Pick<SpaceMeta, "name" | "description" | "visibility" | "is_hub">>) => Promise<SpaceMeta>;
33
+ /** Delete a space. */
34
+ remove: (id: string) => Promise<void>;
35
+ /** Switch to a different space. */
36
+ switchTo: (spaceDocId: string) => Promise<void>;
37
+ };