collabmd 0.1.31 → 0.1.33

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 (99) hide show
  1. package/dist/client/assets/{drawio-editor-B4sHHwWJ.js → drawio-editor-BMTwP5mD.js} +1 -1
  2. package/dist/client/assets/drawioEditor-D6clB5OH.js +2 -0
  3. package/dist/client/assets/{editor-session-BKHEYkbY.js → editor-session-Dzy_85Wp.js} +2 -2
  4. package/dist/client/assets/embedded-editor-base-CgEkjNYn.css +1 -0
  5. package/dist/client/assets/{excalidraw-editor-CHbeNZu6.js → excalidraw-editor-CAP9F8CB.js} +3 -3
  6. package/dist/client/assets/{excalidrawEditor-BhaTX2Ko.js → excalidrawEditor-DD4AvzYP.js} +2 -2
  7. package/dist/client/assets/exportDocument-BbkN85c4.css +1 -0
  8. package/dist/client/assets/index-BIt5EZXz.css +1 -0
  9. package/dist/client/assets/{index-kPgEYvEX.js → index-Czg_KL-i.js} +2 -2
  10. package/dist/client/assets/inter-cyrillic-ext-wght-normal-BOeWTOD4.woff2 +0 -0
  11. package/dist/client/assets/inter-cyrillic-wght-normal-DqGufNeO.woff2 +0 -0
  12. package/dist/client/assets/inter-greek-ext-wght-normal-DlzME5K_.woff2 +0 -0
  13. package/dist/client/assets/inter-greek-wght-normal-CkhJZR-_.woff2 +0 -0
  14. package/dist/client/assets/inter-latin-ext-wght-normal-DO1Apj_S.woff2 +0 -0
  15. package/dist/client/assets/inter-latin-wght-normal-Dx4kXJAl.woff2 +0 -0
  16. package/dist/client/assets/inter-vietnamese-wght-normal-CBcvBZtf.woff2 +0 -0
  17. package/dist/client/assets/jetbrains-mono-cyrillic-400-normal-BEIGL1Tu.woff2 +0 -0
  18. package/dist/client/assets/jetbrains-mono-cyrillic-400-normal-ugxPyKxw.woff +0 -0
  19. package/dist/client/assets/jetbrains-mono-greek-400-normal-B9oWc5Lo.woff +0 -0
  20. package/dist/client/assets/jetbrains-mono-greek-400-normal-C190GLew.woff2 +0 -0
  21. package/dist/client/assets/jetbrains-mono-latin-400-normal-6-qcROiO.woff +0 -0
  22. package/dist/client/assets/jetbrains-mono-latin-400-normal-V6pRDFza.woff2 +0 -0
  23. package/dist/client/assets/jetbrains-mono-latin-ext-400-normal-Bc8Ftmh3.woff2 +0 -0
  24. package/dist/client/assets/jetbrains-mono-latin-ext-400-normal-fXTG6kC5.woff +0 -0
  25. package/dist/client/assets/jetbrains-mono-vietnamese-400-normal-CqNFfHCs.woff +0 -0
  26. package/dist/client/assets/main-DeowJOSp.js +1368 -0
  27. package/dist/client/assets/vault-api-client-D7Ck0CvR.css +1 -0
  28. package/dist/client/assets/vault-api-client-p7h7cXKM.js +1 -0
  29. package/dist/client/drawio-editor.html +1 -1
  30. package/dist/client/excalidraw-editor.html +1 -1
  31. package/dist/client/export-document.html +2 -2
  32. package/dist/client/index.html +2 -2
  33. package/package.json +8 -5
  34. package/src/client/app/main-entry.js +2 -0
  35. package/src/client/application/app-shell/git-feature.js +28 -36
  36. package/src/client/application/app-shell/presence-feature.js +3 -1
  37. package/src/client/application/diagram-preview-hydrator.js +24 -15
  38. package/src/client/application/mermaid-preview-hydrator.js +121 -4
  39. package/src/client/application/plantuml-preview-hydrator.js +6 -16
  40. package/src/client/application/preview-renderer.js +11 -2
  41. package/src/client/bootstrap/collabmd-app-shell.js +182 -50
  42. package/src/client/domain/excalidraw-document-switch.js +3 -0
  43. package/src/client/excalidraw-editor.js +187 -84
  44. package/src/client/infrastructure/auth-client.js +4 -4
  45. package/src/client/infrastructure/backlinks-api-client.js +18 -0
  46. package/src/client/infrastructure/comment-thread-store.js +4 -0
  47. package/src/client/infrastructure/editor-session.js +6 -0
  48. package/src/client/infrastructure/editor-view-adapter.js +23 -0
  49. package/src/client/infrastructure/git-api-client.js +134 -0
  50. package/src/client/infrastructure/plantuml-api-client.js +21 -0
  51. package/src/client/infrastructure/vault-api-client.js +115 -0
  52. package/src/client/presentation/backlinks-panel.js +6 -9
  53. package/src/client/presentation/bases-preview-controller.js +1413 -34
  54. package/src/client/presentation/comments-panel.js +50 -5
  55. package/src/client/presentation/excalidraw-embed-controller.js +251 -15
  56. package/src/client/presentation/excalidraw-embed-reconciler.js +0 -1
  57. package/src/client/presentation/file-action-controller.js +97 -0
  58. package/src/client/presentation/file-explorer-controller.js +2 -0
  59. package/src/client/presentation/file-explorer-view.js +368 -0
  60. package/src/client/presentation/file-history-view-controller.js +41 -40
  61. package/src/client/presentation/git-diff-view-controller.js +70 -53
  62. package/src/client/presentation/git-panel-controller.js +12 -30
  63. package/src/client/styles/components/scrollbars.css +5 -0
  64. package/src/client/styles/export-document.css +45 -2
  65. package/src/client/styles/features/auth-gate.css +13 -24
  66. package/src/client/styles/features/comment-card.css +6 -0
  67. package/src/client/styles/features/comments-drawer.css +38 -18
  68. package/src/client/styles/features/diagram-preview.css +33 -0
  69. package/src/client/styles/features/embedded-preview.css +37 -11
  70. package/src/client/styles/features/preview-markdown.css +559 -39
  71. package/src/client/styles/foundation/themes.css +4 -0
  72. package/src/client/styles/foundation/tokens.css +4 -3
  73. package/src/client/styles/layout/sidebar.css +72 -0
  74. package/src/server/auth/auth-common.js +224 -0
  75. package/src/server/auth/auth-constants.js +30 -0
  76. package/src/server/auth/auth-strategies.js +320 -0
  77. package/src/server/auth/create-auth-service.js +24 -545
  78. package/src/server/domain/backlink-index.js +177 -5
  79. package/src/server/domain/bases/base-definition.js +382 -0
  80. package/src/server/domain/bases/base-expression-runtime.js +1196 -0
  81. package/src/server/domain/bases/base-index-snapshot-store.js +565 -0
  82. package/src/server/domain/bases/base-query-metadata.js +242 -0
  83. package/src/server/domain/bases/base-query-results.js +215 -0
  84. package/src/server/domain/bases/base-query-service.js +406 -1992
  85. package/src/server/domain/bases/base-transform.js +116 -0
  86. package/src/server/domain/collaboration/collaboration-room.js +36 -1
  87. package/src/server/domain/collaboration/room-client-state-store.js +1 -0
  88. package/src/server/domain/collaboration/room-persistence-controller.js +1 -1
  89. package/src/server/infrastructure/http/create-vault-api-query-handler.js +161 -1
  90. package/src/server/infrastructure/http/http-response.js +56 -0
  91. package/src/server/infrastructure/persistence/vault-file-store.js +110 -0
  92. package/dist/client/assets/drawioEditor-DGpo2hcx.js +0 -2
  93. package/dist/client/assets/embedded-editor-base-DgmRcsR8.css +0 -1
  94. package/dist/client/assets/exportDocument-DmV7Gngb.css +0 -1
  95. package/dist/client/assets/index-D69HOZHr.css +0 -1
  96. package/dist/client/assets/main-DSxNTtD-.js +0 -1243
  97. package/dist/client/assets/vault-api-client-BzHQseMN.js +0 -1
  98. package/dist/client/assets/vault-api-client-De7kMvrE.css +0 -1
  99. /package/dist/client/assets/{exportDocument-CtZKWE2c.js → exportDocument-Zfwq1XVx.js} +0 -0
@@ -0,0 +1,21 @@
1
+ import { resolveApiUrl } from '../domain/runtime-paths.js';
2
+
3
+ export class PlantUmlApiClient {
4
+ async renderSvg(source) {
5
+ const response = await fetch(resolveApiUrl('/plantuml/render'), {
6
+ body: JSON.stringify({ source }),
7
+ headers: {
8
+ 'Content-Type': 'application/json',
9
+ },
10
+ method: 'POST',
11
+ });
12
+ const data = await response.json().catch(() => null);
13
+ if (!response.ok || !data?.ok || typeof data.svg !== 'string') {
14
+ throw new Error(data?.error || 'Failed to render PlantUML');
15
+ }
16
+
17
+ return data.svg;
18
+ }
19
+ }
20
+
21
+ export const plantUmlApiClient = new PlantUmlApiClient();
@@ -4,6 +4,39 @@ function encodeHeaderMetadata(value) {
4
4
  return encodeURIComponent(String(value ?? ''));
5
5
  }
6
6
 
7
+ function getPathLeaf(pathValue) {
8
+ return String(pathValue ?? '')
9
+ .replace(/\/+$/u, '')
10
+ .split('/')
11
+ .filter(Boolean)
12
+ .pop() || '';
13
+ }
14
+
15
+ function downloadBlob(blob, fileName) {
16
+ const url = URL.createObjectURL(blob);
17
+ const anchor = document.createElement('a');
18
+ anchor.href = url;
19
+ anchor.download = fileName;
20
+ document.body.appendChild(anchor);
21
+ anchor.click();
22
+ anchor.remove();
23
+ window.setTimeout(() => URL.revokeObjectURL(url), 0);
24
+ }
25
+
26
+ function parseDownloadFileName(contentDisposition = '', fallbackName = 'download') {
27
+ const utfMatch = String(contentDisposition).match(/filename\*=UTF-8''([^;]+)/iu);
28
+ if (utfMatch) {
29
+ try {
30
+ return decodeURIComponent(utfMatch[1]);
31
+ } catch {
32
+ return fallbackName;
33
+ }
34
+ }
35
+
36
+ const asciiMatch = String(contentDisposition).match(/filename="([^"]+)"/iu);
37
+ return asciiMatch?.[1] || fallbackName;
38
+ }
39
+
7
40
  function createRequestHeaders(requestId, headers = {}) {
8
41
  const nextHeaders = { ...headers };
9
42
  if (requestId) {
@@ -25,6 +58,24 @@ async function parseApiResponse(response, fallbackError) {
25
58
  return data;
26
59
  }
27
60
 
61
+ async function triggerDownload(url, {
62
+ fallbackError,
63
+ fallbackFileName,
64
+ } = {}) {
65
+ const response = await fetch(url);
66
+ if (!response.ok) {
67
+ const payload = await response.json().catch(() => ({}));
68
+ throw new Error(payload.error || fallbackError);
69
+ }
70
+
71
+ const blob = await response.blob();
72
+ downloadBlob(
73
+ blob,
74
+ parseDownloadFileName(response.headers.get('content-disposition') || '', fallbackFileName),
75
+ );
76
+ return response;
77
+ }
78
+
28
79
  export class VaultApiClient {
29
80
  async readTree() {
30
81
  const response = await fetch(resolveApiUrl('/files'));
@@ -90,6 +141,54 @@ export class VaultApiClient {
90
141
  };
91
142
  }
92
143
 
144
+ async queryBasePropertyValues({
145
+ activeFilePath = '',
146
+ path = '',
147
+ propertyId = '',
148
+ query = '',
149
+ source = null,
150
+ sourcePath = '',
151
+ view = '',
152
+ } = {}) {
153
+ const response = await fetch(resolveApiUrl('/base/property-values'), {
154
+ body: JSON.stringify({
155
+ activeFilePath,
156
+ path,
157
+ propertyId,
158
+ query,
159
+ source,
160
+ sourcePath,
161
+ view,
162
+ }),
163
+ headers: { 'Content-Type': 'application/json' },
164
+ method: 'POST',
165
+ });
166
+ return parseApiResponse(response, 'Failed to load base property values');
167
+ }
168
+
169
+ async transformBase({
170
+ activeFilePath = '',
171
+ mutation = null,
172
+ path = '',
173
+ source = null,
174
+ sourcePath = '',
175
+ view = '',
176
+ } = {}) {
177
+ const response = await fetch(resolveApiUrl('/base/transform'), {
178
+ body: JSON.stringify({
179
+ activeFilePath,
180
+ mutation,
181
+ path,
182
+ source,
183
+ sourcePath,
184
+ view,
185
+ }),
186
+ headers: { 'Content-Type': 'application/json' },
187
+ method: 'POST',
188
+ });
189
+ return parseApiResponse(response, 'Failed to transform base');
190
+ }
191
+
93
192
  async createFile({ content, path, requestId = null }) {
94
193
  const response = await fetch(resolveApiUrl('/file'), {
95
194
  body: JSON.stringify({ content, path }),
@@ -170,6 +269,22 @@ export class VaultApiClient {
170
269
  });
171
270
  return parseApiResponse(response, 'Failed to upload image');
172
271
  }
272
+
273
+ async downloadFile(path) {
274
+ const fallbackFileName = getPathLeaf(path) || 'download';
275
+ return triggerDownload(resolveApiUrl(`/download/file?path=${encodeURIComponent(path)}`), {
276
+ fallbackError: 'Failed to download file',
277
+ fallbackFileName,
278
+ });
279
+ }
280
+
281
+ async downloadDirectory(path) {
282
+ const directoryName = getPathLeaf(path) || 'vault';
283
+ return triggerDownload(resolveApiUrl(`/download/directory?path=${encodeURIComponent(path)}`), {
284
+ fallbackError: 'Failed to download folder',
285
+ fallbackFileName: `${directoryName}.zip`,
286
+ });
287
+ }
173
288
  }
174
289
 
175
290
  export const vaultApiClient = new VaultApiClient();
@@ -1,6 +1,5 @@
1
1
  import { stripVaultFileExtension } from '../../domain/file-kind.js';
2
2
  import { escapeHtml } from '../domain/vault-utils.js';
3
- import { resolveApiUrl } from '../domain/runtime-paths.js';
4
3
 
5
4
  /**
6
5
  * BacklinksPanel — renders "Linked Mentions" for the current file.
@@ -13,6 +12,7 @@ export class BacklinksPanel {
13
12
  documentRef = document,
14
13
  headerPanelElement = null,
15
14
  inlinePanelElement = null,
15
+ loadBacklinks = null,
16
16
  onFileSelect,
17
17
  panelElement,
18
18
  }) {
@@ -20,6 +20,7 @@ export class BacklinksPanel {
20
20
  this.headerPanel = headerPanelElement;
21
21
  this.panelRoot = panelElement;
22
22
  this.inlinePanel = inlinePanelElement;
23
+ this.loadBacklinks = loadBacklinks;
23
24
  this.onFileSelect = onFileSelect;
24
25
 
25
26
  this._expanded = false;
@@ -132,15 +133,11 @@ export class BacklinksPanel {
132
133
  this._fetchController = new AbortController();
133
134
 
134
135
  try {
135
- const response = await fetch(
136
- resolveApiUrl(`/backlinks?file=${encodeURIComponent(filePath)}`),
137
- { signal: this._fetchController.signal },
138
- );
139
- const data = await response.json();
140
-
136
+ const backlinks = await this.loadBacklinks(filePath, {
137
+ signal: this._fetchController.signal,
138
+ });
141
139
  if (this._currentFile !== filePath) return;
142
-
143
- this._backlinks = data.backlinks ?? [];
140
+ this._backlinks = backlinks;
144
141
  } catch (error) {
145
142
  if (error.name === 'AbortError') return;
146
143
  console.warn('[backlinks] Failed to load:', error.message);