react-embed-docs 0.1.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/LICENSE +21 -0
- package/README.md +422 -0
- package/dist/client/components/Breadcrumbs.d.ts +21 -0
- package/dist/client/components/Breadcrumbs.d.ts.map +1 -0
- package/dist/client/components/Breadcrumbs.js +123 -0
- package/dist/client/components/DocsLayout.d.ts +20 -0
- package/dist/client/components/DocsLayout.d.ts.map +1 -0
- package/dist/client/components/DocsLayout.js +387 -0
- package/dist/client/components/DocumentContent.d.ts +5 -0
- package/dist/client/components/DocumentContent.d.ts.map +1 -0
- package/dist/client/components/DocumentContent.js +15 -0
- package/dist/client/components/DocumentEdit.d.ts +6 -0
- package/dist/client/components/DocumentEdit.d.ts.map +1 -0
- package/dist/client/components/DocumentEdit.js +153 -0
- package/dist/client/components/DocumentList.d.ts +5 -0
- package/dist/client/components/DocumentList.d.ts.map +1 -0
- package/dist/client/components/DocumentList.js +39 -0
- package/dist/client/components/DocumentProvider.d.ts +42 -0
- package/dist/client/components/DocumentProvider.d.ts.map +1 -0
- package/dist/client/components/DocumentProvider.js +47 -0
- package/dist/client/components/DocumentView.d.ts +6 -0
- package/dist/client/components/DocumentView.d.ts.map +1 -0
- package/dist/client/components/DocumentView.js +58 -0
- package/dist/client/components/DragOverlayItem.d.ts +5 -0
- package/dist/client/components/DragOverlayItem.d.ts.map +1 -0
- package/dist/client/components/DragOverlayItem.js +9 -0
- package/dist/client/components/EmojiPicker.d.ts +8 -0
- package/dist/client/components/EmojiPicker.d.ts.map +1 -0
- package/dist/client/components/EmojiPicker.js +48 -0
- package/dist/client/components/ExportButton.d.ts +22 -0
- package/dist/client/components/ExportButton.d.ts.map +1 -0
- package/dist/client/components/ExportButton.js +97 -0
- package/dist/client/components/Layout.d.ts +7 -0
- package/dist/client/components/Layout.d.ts.map +1 -0
- package/dist/client/components/Layout.js +172 -0
- package/dist/client/components/ReactEmbedDocs.d.ts +8 -0
- package/dist/client/components/ReactEmbedDocs.d.ts.map +1 -0
- package/dist/client/components/ReactEmbedDocs.js +8 -0
- package/dist/client/components/SearchInput.d.ts +2 -0
- package/dist/client/components/SearchInput.d.ts.map +1 -0
- package/dist/client/components/SearchInput.js +7 -0
- package/dist/client/components/Sidebar.d.ts +10 -0
- package/dist/client/components/Sidebar.d.ts.map +1 -0
- package/dist/client/components/Sidebar.js +176 -0
- package/dist/client/components/SortableTreeItem.d.ts +13 -0
- package/dist/client/components/SortableTreeItem.d.ts.map +1 -0
- package/dist/client/components/SortableTreeItem.js +24 -0
- package/dist/client/components/VersionHistory.d.ts +14 -0
- package/dist/client/components/VersionHistory.d.ts.map +1 -0
- package/dist/client/components/VersionHistory.js +102 -0
- package/dist/client/hooks/useCollaboration.d.ts +99 -0
- package/dist/client/hooks/useCollaboration.d.ts.map +1 -0
- package/dist/client/hooks/useCollaboration.js +180 -0
- package/dist/client/hooks/useDocsQuery.d.ts +84 -0
- package/dist/client/hooks/useDocsQuery.d.ts.map +1 -0
- package/dist/client/hooks/useDocsQuery.js +241 -0
- package/dist/client/hooks/useExport.d.ts +31 -0
- package/dist/client/hooks/useExport.d.ts.map +1 -0
- package/dist/client/hooks/useExport.js +66 -0
- package/dist/client/hooks/useFileUpload.d.ts +44 -0
- package/dist/client/hooks/useFileUpload.d.ts.map +1 -0
- package/dist/client/hooks/useFileUpload.js +193 -0
- package/dist/client/hooks/useSystemTheme.d.ts +2 -0
- package/dist/client/hooks/useSystemTheme.d.ts.map +1 -0
- package/dist/client/hooks/useSystemTheme.js +19 -0
- package/dist/client/hooks/useVersions.d.ts +105 -0
- package/dist/client/hooks/useVersions.d.ts.map +1 -0
- package/dist/client/hooks/useVersions.js +129 -0
- package/dist/client/index.d.ts +23 -0
- package/dist/client/index.d.ts.map +1 -0
- package/dist/client/index.js +18 -0
- package/dist/client/lib/blocknoteTheme.d.ts +13 -0
- package/dist/client/lib/blocknoteTheme.d.ts.map +1 -0
- package/dist/client/lib/blocknoteTheme.js +76 -0
- package/dist/client/lib/path.d.ts +8 -0
- package/dist/client/lib/path.d.ts.map +1 -0
- package/dist/client/lib/path.js +30 -0
- package/dist/client/providers/DocumentProvider.d.ts +1 -0
- package/dist/client/providers/DocumentProvider.d.ts.map +1 -0
- package/dist/client/providers/DocumentProvider.js +1 -0
- package/dist/server/CollaborationService.d.ts +134 -0
- package/dist/server/CollaborationService.d.ts.map +1 -0
- package/dist/server/CollaborationService.js +307 -0
- package/dist/server/DocsService.d.ts +115 -0
- package/dist/server/DocsService.d.ts.map +1 -0
- package/dist/server/DocsService.js +512 -0
- package/dist/server/ExportService.d.ts +106 -0
- package/dist/server/ExportService.d.ts.map +1 -0
- package/dist/server/ExportService.js +501 -0
- package/dist/server/FilesService.d.ts +44 -0
- package/dist/server/FilesService.d.ts.map +1 -0
- package/dist/server/FilesService.js +78 -0
- package/dist/server/VersioningService.d.ts +112 -0
- package/dist/server/VersioningService.d.ts.map +1 -0
- package/dist/server/VersioningService.js +264 -0
- package/dist/server/db.d.ts +7 -0
- package/dist/server/db.d.ts.map +1 -0
- package/dist/server/db.js +22 -0
- package/dist/server/index.d.ts +55 -0
- package/dist/server/index.d.ts.map +1 -0
- package/dist/server/index.js +36 -0
- package/dist/server/routes.d.ts +9 -0
- package/dist/server/routes.d.ts.map +1 -0
- package/dist/server/routes.js +483 -0
- package/dist/server/schema.d.ts +587 -0
- package/dist/server/schema.d.ts.map +1 -0
- package/dist/server/schema.js +126 -0
- package/dist/shared/types.d.ts +314 -0
- package/dist/shared/types.d.ts.map +1 -0
- package/dist/shared/types.js +48 -0
- package/drizzle/migrations/0000_gray_monster_badoon.sql +88 -0
- package/drizzle/migrations/meta/0000_snapshot.json +574 -0
- package/drizzle/migrations/meta/_journal.json +13 -0
- package/package.json +109 -0
- package/styles/docs.css +981 -0
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
import type { DB } from './db.js';
|
|
2
|
+
import { documentsTable } from './schema.js';
|
|
3
|
+
import type { DocumentVersion } from './schema.js';
|
|
4
|
+
/**
|
|
5
|
+
* Diff result for comparing versions
|
|
6
|
+
*/
|
|
7
|
+
export interface VersionDiff {
|
|
8
|
+
title: {
|
|
9
|
+
from: string;
|
|
10
|
+
to: string;
|
|
11
|
+
changed: boolean;
|
|
12
|
+
};
|
|
13
|
+
content: {
|
|
14
|
+
blocksAdded: number;
|
|
15
|
+
blocksRemoved: number;
|
|
16
|
+
blocksChanged: number;
|
|
17
|
+
changed: boolean;
|
|
18
|
+
};
|
|
19
|
+
meta: {
|
|
20
|
+
emoji?: {
|
|
21
|
+
from: string | null;
|
|
22
|
+
to: string | null;
|
|
23
|
+
changed: boolean;
|
|
24
|
+
};
|
|
25
|
+
cover?: {
|
|
26
|
+
from: string | null;
|
|
27
|
+
to: string | null;
|
|
28
|
+
changed: boolean;
|
|
29
|
+
};
|
|
30
|
+
};
|
|
31
|
+
changedAt: Date;
|
|
32
|
+
changedBy: string | null;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Options for creating a version
|
|
36
|
+
*/
|
|
37
|
+
export interface CreateVersionOptions {
|
|
38
|
+
description?: string;
|
|
39
|
+
createdBy?: string;
|
|
40
|
+
createdByName?: string;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Options for restoring a version
|
|
44
|
+
*/
|
|
45
|
+
export interface RestoreVersionOptions {
|
|
46
|
+
restoredBy?: string;
|
|
47
|
+
restoredByName?: string;
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Service for document versioning and history management
|
|
51
|
+
*/
|
|
52
|
+
export declare class VersioningService {
|
|
53
|
+
private readonly db;
|
|
54
|
+
constructor(db: DB);
|
|
55
|
+
/**
|
|
56
|
+
* Create a new version snapshot of a document
|
|
57
|
+
*/
|
|
58
|
+
createVersion(documentId: string, options?: CreateVersionOptions): Promise<DocumentVersion>;
|
|
59
|
+
/**
|
|
60
|
+
* List all versions of a document
|
|
61
|
+
*/
|
|
62
|
+
listVersions(documentId: string): Promise<DocumentVersion[]>;
|
|
63
|
+
/**
|
|
64
|
+
* Get a specific version by ID
|
|
65
|
+
*/
|
|
66
|
+
getVersion(versionId: string): Promise<DocumentVersion | undefined>;
|
|
67
|
+
/**
|
|
68
|
+
* Get a specific version by document ID and version number
|
|
69
|
+
*/
|
|
70
|
+
getVersionByNumber(documentId: string, versionNumber: number): Promise<DocumentVersion | undefined>;
|
|
71
|
+
/**
|
|
72
|
+
* Restore a document to a specific version
|
|
73
|
+
* Automatically creates a backup version of current state first
|
|
74
|
+
*/
|
|
75
|
+
restoreVersion(documentId: string, versionId: string, options?: RestoreVersionOptions): Promise<{
|
|
76
|
+
document: typeof documentsTable.$inferSelect;
|
|
77
|
+
version: DocumentVersion;
|
|
78
|
+
}>;
|
|
79
|
+
/**
|
|
80
|
+
* Compare two versions and return differences
|
|
81
|
+
*/
|
|
82
|
+
compareVersions(versionId1: string, versionId2: string): Promise<VersionDiff>;
|
|
83
|
+
/**
|
|
84
|
+
* Delete a specific version
|
|
85
|
+
*/
|
|
86
|
+
deleteVersion(versionId: string): Promise<void>;
|
|
87
|
+
/**
|
|
88
|
+
* Prune old versions, keeping only the specified count
|
|
89
|
+
*/
|
|
90
|
+
pruneVersions(documentId: string, keepCount?: number): Promise<number>;
|
|
91
|
+
/**
|
|
92
|
+
* Get the latest version number for a document
|
|
93
|
+
*/
|
|
94
|
+
getLatestVersionNumber(documentId: string): Promise<number>;
|
|
95
|
+
/**
|
|
96
|
+
* Calculate diff between two versions
|
|
97
|
+
*/
|
|
98
|
+
private calculateDiff;
|
|
99
|
+
/**
|
|
100
|
+
* Calculate content diff between two BlockNote contents
|
|
101
|
+
*/
|
|
102
|
+
private calculateContentDiff;
|
|
103
|
+
/**
|
|
104
|
+
* Flatten nested block structure
|
|
105
|
+
*/
|
|
106
|
+
private flattenBlocks;
|
|
107
|
+
/**
|
|
108
|
+
* Compare two blocks for equality
|
|
109
|
+
*/
|
|
110
|
+
private blocksEqual;
|
|
111
|
+
}
|
|
112
|
+
//# sourceMappingURL=VersioningService.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"VersioningService.d.ts","sourceRoot":"","sources":["../../src/server/VersioningService.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,264 @@
|
|
|
1
|
+
import { eq, desc, and, sql } from 'drizzle-orm';
|
|
2
|
+
import { documentsTable, documentVersionsTable } from './schema.js';
|
|
3
|
+
/**
|
|
4
|
+
* Service for document versioning and history management
|
|
5
|
+
*/
|
|
6
|
+
export class VersioningService {
|
|
7
|
+
db;
|
|
8
|
+
constructor(db) {
|
|
9
|
+
this.db = db;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Create a new version snapshot of a document
|
|
13
|
+
*/
|
|
14
|
+
async createVersion(documentId, options = {}) {
|
|
15
|
+
// Get current document
|
|
16
|
+
const doc = await this.db.query.documentsTable.findFirst({
|
|
17
|
+
where: eq(documentsTable.id, documentId),
|
|
18
|
+
});
|
|
19
|
+
if (!doc) {
|
|
20
|
+
throw new Error('Document not found');
|
|
21
|
+
}
|
|
22
|
+
// Get next version number
|
|
23
|
+
const lastVersion = await this.db.query.documentVersionsTable.findFirst({
|
|
24
|
+
where: eq(documentVersionsTable.documentId, documentId),
|
|
25
|
+
orderBy: desc(documentVersionsTable.versionNumber),
|
|
26
|
+
});
|
|
27
|
+
const versionNumber = (lastVersion?.versionNumber ?? 0) + 1;
|
|
28
|
+
// Create version snapshot
|
|
29
|
+
const [version] = await this.db
|
|
30
|
+
.insert(documentVersionsTable)
|
|
31
|
+
.values({
|
|
32
|
+
documentId,
|
|
33
|
+
versionNumber,
|
|
34
|
+
title: doc.title,
|
|
35
|
+
content: doc.content,
|
|
36
|
+
emoji: doc.emoji,
|
|
37
|
+
cover: doc.cover,
|
|
38
|
+
ydocState: doc.ydocState,
|
|
39
|
+
changeDescription: options.description || `Version ${versionNumber}`,
|
|
40
|
+
createdBy: options.createdBy,
|
|
41
|
+
createdByName: options.createdByName,
|
|
42
|
+
})
|
|
43
|
+
.returning();
|
|
44
|
+
return version;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* List all versions of a document
|
|
48
|
+
*/
|
|
49
|
+
async listVersions(documentId) {
|
|
50
|
+
return this.db.query.documentVersionsTable.findMany({
|
|
51
|
+
where: eq(documentVersionsTable.documentId, documentId),
|
|
52
|
+
orderBy: desc(documentVersionsTable.createdAt),
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Get a specific version by ID
|
|
57
|
+
*/
|
|
58
|
+
async getVersion(versionId) {
|
|
59
|
+
return this.db.query.documentVersionsTable.findFirst({
|
|
60
|
+
where: eq(documentVersionsTable.id, versionId),
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Get a specific version by document ID and version number
|
|
65
|
+
*/
|
|
66
|
+
async getVersionByNumber(documentId, versionNumber) {
|
|
67
|
+
return this.db.query.documentVersionsTable.findFirst({
|
|
68
|
+
where: and(eq(documentVersionsTable.documentId, documentId), eq(documentVersionsTable.versionNumber, versionNumber)),
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Restore a document to a specific version
|
|
73
|
+
* Automatically creates a backup version of current state first
|
|
74
|
+
*/
|
|
75
|
+
async restoreVersion(documentId, versionId, options = {}) {
|
|
76
|
+
const version = await this.getVersion(versionId);
|
|
77
|
+
if (!version) {
|
|
78
|
+
throw new Error('Version not found');
|
|
79
|
+
}
|
|
80
|
+
// Get current document
|
|
81
|
+
const currentDoc = await this.db.query.documentsTable.findFirst({
|
|
82
|
+
where: eq(documentsTable.id, documentId),
|
|
83
|
+
});
|
|
84
|
+
if (!currentDoc) {
|
|
85
|
+
throw new Error('Document not found');
|
|
86
|
+
}
|
|
87
|
+
// Create backup of current state before restore
|
|
88
|
+
await this.createVersion(documentId, {
|
|
89
|
+
description: `Auto-saved before restoring to version ${version.versionNumber}`,
|
|
90
|
+
createdBy: options.restoredBy,
|
|
91
|
+
createdByName: options.restoredByName,
|
|
92
|
+
});
|
|
93
|
+
// Restore document to version
|
|
94
|
+
const [updated] = await this.db
|
|
95
|
+
.update(documentsTable)
|
|
96
|
+
.set({
|
|
97
|
+
title: version.title,
|
|
98
|
+
content: version.content,
|
|
99
|
+
emoji: version.emoji,
|
|
100
|
+
cover: version.cover,
|
|
101
|
+
ydocState: version.ydocState,
|
|
102
|
+
updatedAt: new Date(),
|
|
103
|
+
})
|
|
104
|
+
.where(eq(documentsTable.id, documentId))
|
|
105
|
+
.returning();
|
|
106
|
+
if (!updated) {
|
|
107
|
+
throw new Error('Failed to restore document');
|
|
108
|
+
}
|
|
109
|
+
return { document: updated, version };
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* Compare two versions and return differences
|
|
113
|
+
*/
|
|
114
|
+
async compareVersions(versionId1, versionId2) {
|
|
115
|
+
const [v1, v2] = await Promise.all([
|
|
116
|
+
this.getVersion(versionId1),
|
|
117
|
+
this.getVersion(versionId2),
|
|
118
|
+
]);
|
|
119
|
+
if (!v1 || !v2) {
|
|
120
|
+
throw new Error('One or both versions not found');
|
|
121
|
+
}
|
|
122
|
+
return this.calculateDiff(v1, v2);
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* Delete a specific version
|
|
126
|
+
*/
|
|
127
|
+
async deleteVersion(versionId) {
|
|
128
|
+
await this.db
|
|
129
|
+
.delete(documentVersionsTable)
|
|
130
|
+
.where(eq(documentVersionsTable.id, versionId));
|
|
131
|
+
}
|
|
132
|
+
/**
|
|
133
|
+
* Prune old versions, keeping only the specified count
|
|
134
|
+
*/
|
|
135
|
+
async pruneVersions(documentId, keepCount = 50) {
|
|
136
|
+
const versionsToDelete = await this.db.query.documentVersionsTable.findMany({
|
|
137
|
+
where: eq(documentVersionsTable.documentId, documentId),
|
|
138
|
+
orderBy: desc(documentVersionsTable.versionNumber),
|
|
139
|
+
offset: keepCount,
|
|
140
|
+
});
|
|
141
|
+
if (versionsToDelete.length === 0) {
|
|
142
|
+
return 0;
|
|
143
|
+
}
|
|
144
|
+
await this.db
|
|
145
|
+
.delete(documentVersionsTable)
|
|
146
|
+
.where(and(eq(documentVersionsTable.documentId, documentId), sql `${documentVersionsTable.id} IN (${versionsToDelete.map((v) => `'${v.id}'`).join(',')})`));
|
|
147
|
+
return versionsToDelete.length;
|
|
148
|
+
}
|
|
149
|
+
/**
|
|
150
|
+
* Get the latest version number for a document
|
|
151
|
+
*/
|
|
152
|
+
async getLatestVersionNumber(documentId) {
|
|
153
|
+
const lastVersion = await this.db.query.documentVersionsTable.findFirst({
|
|
154
|
+
where: eq(documentVersionsTable.documentId, documentId),
|
|
155
|
+
orderBy: desc(documentVersionsTable.versionNumber),
|
|
156
|
+
});
|
|
157
|
+
return lastVersion?.versionNumber ?? 0;
|
|
158
|
+
}
|
|
159
|
+
/**
|
|
160
|
+
* Calculate diff between two versions
|
|
161
|
+
*/
|
|
162
|
+
calculateDiff(v1, v2) {
|
|
163
|
+
// Title diff
|
|
164
|
+
const titleChanged = v1.title !== v2.title;
|
|
165
|
+
// Content diff
|
|
166
|
+
const content1 = v1.content;
|
|
167
|
+
const content2 = v2.content;
|
|
168
|
+
const contentDiff = this.calculateContentDiff(content1, content2);
|
|
169
|
+
// Meta diff
|
|
170
|
+
const emojiChanged = v1.emoji !== v2.emoji;
|
|
171
|
+
const coverChanged = v1.cover !== v2.cover;
|
|
172
|
+
return {
|
|
173
|
+
title: {
|
|
174
|
+
from: v1.title,
|
|
175
|
+
to: v2.title,
|
|
176
|
+
changed: titleChanged,
|
|
177
|
+
},
|
|
178
|
+
content: {
|
|
179
|
+
blocksAdded: contentDiff.added,
|
|
180
|
+
blocksRemoved: contentDiff.removed,
|
|
181
|
+
blocksChanged: contentDiff.changed,
|
|
182
|
+
changed: contentDiff.added > 0 || contentDiff.removed > 0 || contentDiff.changed > 0,
|
|
183
|
+
},
|
|
184
|
+
meta: {
|
|
185
|
+
emoji: emojiChanged
|
|
186
|
+
? { from: v1.emoji ?? null, to: v2.emoji ?? null, changed: true }
|
|
187
|
+
: undefined,
|
|
188
|
+
cover: coverChanged
|
|
189
|
+
? { from: v1.cover ?? null, to: v2.cover ?? null, changed: true }
|
|
190
|
+
: undefined,
|
|
191
|
+
},
|
|
192
|
+
changedAt: v2.createdAt,
|
|
193
|
+
changedBy: v2.createdByName,
|
|
194
|
+
};
|
|
195
|
+
}
|
|
196
|
+
/**
|
|
197
|
+
* Calculate content diff between two BlockNote contents
|
|
198
|
+
*/
|
|
199
|
+
calculateContentDiff(content1, content2) {
|
|
200
|
+
const blocks1 = this.flattenBlocks(content1);
|
|
201
|
+
const blocks2 = this.flattenBlocks(content2);
|
|
202
|
+
const ids1 = new Set(blocks1.map((b) => b.id).filter(Boolean));
|
|
203
|
+
const ids2 = new Set(blocks2.map((b) => b.id).filter(Boolean));
|
|
204
|
+
let added = 0;
|
|
205
|
+
let removed = 0;
|
|
206
|
+
let changed = 0;
|
|
207
|
+
// Count added blocks
|
|
208
|
+
for (const id of ids2) {
|
|
209
|
+
if (!ids1.has(id)) {
|
|
210
|
+
added++;
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
// Count removed blocks
|
|
214
|
+
for (const id of ids1) {
|
|
215
|
+
if (!ids2.has(id)) {
|
|
216
|
+
removed++;
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
// Count changed blocks
|
|
220
|
+
for (const id of ids1) {
|
|
221
|
+
if (ids2.has(id)) {
|
|
222
|
+
const block1 = blocks1.find((b) => b.id === id);
|
|
223
|
+
const block2 = blocks2.find((b) => b.id === id);
|
|
224
|
+
if (block1 && block2 && !this.blocksEqual(block1, block2)) {
|
|
225
|
+
changed++;
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
// Also count as changed if only order changed
|
|
230
|
+
if (added === 0 && removed === 0 && blocks1.length === blocks2.length) {
|
|
231
|
+
for (let i = 0; i < blocks1.length; i++) {
|
|
232
|
+
if (blocks1[i].id !== blocks2[i].id) {
|
|
233
|
+
changed++;
|
|
234
|
+
break;
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
return { added, removed, changed };
|
|
239
|
+
}
|
|
240
|
+
/**
|
|
241
|
+
* Flatten nested block structure
|
|
242
|
+
*/
|
|
243
|
+
flattenBlocks(blocks) {
|
|
244
|
+
const result = [];
|
|
245
|
+
const traverse = (block) => {
|
|
246
|
+
result.push(block);
|
|
247
|
+
if (block.children?.length) {
|
|
248
|
+
block.children.forEach(traverse);
|
|
249
|
+
}
|
|
250
|
+
};
|
|
251
|
+
if (Array.isArray(blocks)) {
|
|
252
|
+
blocks.forEach(traverse);
|
|
253
|
+
}
|
|
254
|
+
return result;
|
|
255
|
+
}
|
|
256
|
+
/**
|
|
257
|
+
* Compare two blocks for equality
|
|
258
|
+
*/
|
|
259
|
+
blocksEqual(block1, block2) {
|
|
260
|
+
return (block1.type === block2.type &&
|
|
261
|
+
JSON.stringify(block1.props) === JSON.stringify(block2.props) &&
|
|
262
|
+
JSON.stringify(block1.content) === JSON.stringify(block2.content));
|
|
263
|
+
}
|
|
264
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { type PostgresJsDatabase } from 'drizzle-orm/postgres-js';
|
|
2
|
+
import * as schema from './schema.js';
|
|
3
|
+
export type DB = PostgresJsDatabase<typeof schema>;
|
|
4
|
+
export declare function configureDb({ url }: {
|
|
5
|
+
readonly url: string;
|
|
6
|
+
}): DB;
|
|
7
|
+
//# sourceMappingURL=db.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"db.d.ts","sourceRoot":"","sources":["../../src/server/db.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,kBAAkB,EAAW,MAAM,yBAAyB,CAAA;AAG1E,OAAO,KAAK,MAAM,MAAM,aAAa,CAAA;AAErC,MAAM,MAAM,EAAE,GAAG,kBAAkB,CAAC,OAAO,MAAM,CAAC,CAAA;AAElD,wBAAgB,WAAW,CAAC,EAAE,GAAG,EAAE,EAAE;IAAE,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAA;CAAE,GAAG,EAAE,CAkBjE"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { drizzle } from 'drizzle-orm/postgres-js';
|
|
2
|
+
import { migrate } from 'drizzle-orm/postgres-js/migrator';
|
|
3
|
+
import postgres from 'postgres';
|
|
4
|
+
import * as schema from './schema.js';
|
|
5
|
+
export function configureDb({ url }) {
|
|
6
|
+
console.log(`Docs: Initializing database ${url}`);
|
|
7
|
+
const connection = postgres(url);
|
|
8
|
+
const db = drizzle(connection, { schema, logger: false });
|
|
9
|
+
console.log(`Docs: Connecting to database`, __dirname);
|
|
10
|
+
migrate(db, {
|
|
11
|
+
migrationsTable: '_drizzle_docs_migrations',
|
|
12
|
+
migrationsFolder: __dirname + '/../../drizzle/migrations',
|
|
13
|
+
})
|
|
14
|
+
.then(() => {
|
|
15
|
+
console.log(`Docs: Database initialized`);
|
|
16
|
+
})
|
|
17
|
+
.catch((error) => {
|
|
18
|
+
console.error(`Docs: Error initializing database`, error);
|
|
19
|
+
process.exit(1);
|
|
20
|
+
});
|
|
21
|
+
return db;
|
|
22
|
+
}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { Hono } from 'hono';
|
|
2
|
+
/**
|
|
3
|
+
* DocsService - Document management service
|
|
4
|
+
*/
|
|
5
|
+
export { DocsService, type DocumentSummary } from './DocsService.js';
|
|
6
|
+
/**
|
|
7
|
+
* FilesService - File upload and management service
|
|
8
|
+
*/
|
|
9
|
+
export { FilesService } from './FilesService.js';
|
|
10
|
+
/**
|
|
11
|
+
* ExportService - Document export service (DOCX, PDF, HTML, Markdown)
|
|
12
|
+
*/
|
|
13
|
+
export { ExportService } from './ExportService.js';
|
|
14
|
+
export type { DocxExportOptions, ExportResult, PdfExportOptions } from './ExportService.js';
|
|
15
|
+
/**
|
|
16
|
+
* CollaborationService - Real-time collaborative editing service
|
|
17
|
+
*/
|
|
18
|
+
export { CollaborationService } from './CollaborationService.js';
|
|
19
|
+
export type { AwarenessState, AwarenessUser } from './CollaborationService.js';
|
|
20
|
+
/**
|
|
21
|
+
* VersioningService - Document version history service
|
|
22
|
+
*/
|
|
23
|
+
export { VersioningService } from './VersioningService.js';
|
|
24
|
+
export type { CreateVersionOptions, RestoreVersionOptions, VersionDiff } from './VersioningService.js';
|
|
25
|
+
/**
|
|
26
|
+
* createDocsRouter - Factory function for creating Hono routes
|
|
27
|
+
* Combines both document and file routes
|
|
28
|
+
*
|
|
29
|
+
* @example
|
|
30
|
+
* ```typescript
|
|
31
|
+
* import { createDocsRouter, DocsService, FilesService } from './server'
|
|
32
|
+
*
|
|
33
|
+
* const docsService = new DocsService(db)
|
|
34
|
+
* const filesService = new FilesService(db)
|
|
35
|
+
* const router = createDocsRouter(docsService, filesService)
|
|
36
|
+
*
|
|
37
|
+
* // Mount in your Hono app
|
|
38
|
+
* app.route('/api', router)
|
|
39
|
+
* ```
|
|
40
|
+
*/
|
|
41
|
+
export type ConfigureServerOptions = {
|
|
42
|
+
dbUrl: string;
|
|
43
|
+
};
|
|
44
|
+
export declare function createDocsRouter(options: ConfigureServerOptions): Hono;
|
|
45
|
+
/**
|
|
46
|
+
* Database schema exports
|
|
47
|
+
* Use these to access table definitions and types
|
|
48
|
+
*/
|
|
49
|
+
export { docsTableSchema, documentPresenceTable, documentRelations, documentsTable, documentVersionsTable, filesTable, type Document, type DocumentPresence, type DocumentVersion, type File, type InsertDocument, type InsertFile, type UpdateDocument } from './schema.js';
|
|
50
|
+
/**
|
|
51
|
+
* Type re-exports from shared module
|
|
52
|
+
* These are commonly used types for consumers of this package
|
|
53
|
+
*/
|
|
54
|
+
export type { BlockNoteBlock, BlockNoteContent, BlockNoteContentItem, Document as DocumentType, FileUpload, CreateDocument as InsertDocumentType, InsertFileUpload as InsertFileType, ListDocumentsFilters, ListDocumentsOptions, ListDocumentsResult, SearchResult, SearchTextResult, UpdateDocument as UpdateDocumentType } from '../shared/types.js';
|
|
55
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/server/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAA;AAM3B;;GAEG;AACH,OAAO,EAAE,WAAW,EAAE,KAAK,eAAe,EAAE,MAAM,kBAAkB,CAAA;AAEpE;;GAEG;AACH,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAA;AAEhD;;GAEG;AACH,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAA;AAClD,YAAY,EAAE,iBAAiB,EAAE,YAAY,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAA;AAE3F;;GAEG;AACH,OAAO,EAAE,oBAAoB,EAAE,MAAM,2BAA2B,CAAA;AAChE,YAAY,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAA;AAE9E;;GAEG;AACH,OAAO,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAA;AAC1D,YAAY,EAAE,oBAAoB,EAAE,qBAAqB,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAA;AAEtG;;;;;;;;;;;;;;;GAeG;AAEH,MAAM,MAAM,sBAAsB,GAAG;IACnC,KAAK,EAAE,MAAM,CAAA;CACd,CAAA;AAED,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,sBAAsB,GAAG,IAAI,CAMtE;AAED;;;GAGG;AACH,OAAO,EACL,eAAe,EAAE,qBAAqB,EAAE,iBAAiB,EAAE,cAAc,EAAE,qBAAqB,EAAE,UAAU,EAAE,KAAK,QAAQ,EAAE,KAAK,gBAAgB,EAAE,KAAK,eAAe,EAAE,KAAK,IAAI,EAAE,KAAK,cAAc,EAAE,KAAK,UAAU,EAAE,KAAK,cAAc,EAC/O,MAAM,aAAa,CAAA;AAGpB;;;GAGG;AACH,YAAY,EACV,cAAc,EAAE,gBAAgB,EAAE,oBAAoB,EACtD,QAAQ,IAAI,YAAY,EAAE,UAAU,EAAE,cAAc,IAAI,kBAAkB,EAAE,gBAAgB,IAAI,cAAc,EAC9G,oBAAoB,EACpB,oBAAoB,EACpB,mBAAmB,EAAE,YAAY,EACjC,gBAAgB,EAAE,cAAc,IAAI,kBAAkB,EACvD,MAAM,oBAAoB,CAAA"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { configureDb } from './db.js';
|
|
2
|
+
import { DocsService } from './DocsService.js';
|
|
3
|
+
import { FilesService } from './FilesService.js';
|
|
4
|
+
import { createRouter } from './routes.js';
|
|
5
|
+
/**
|
|
6
|
+
* DocsService - Document management service
|
|
7
|
+
*/
|
|
8
|
+
export { DocsService } from './DocsService.js';
|
|
9
|
+
/**
|
|
10
|
+
* FilesService - File upload and management service
|
|
11
|
+
*/
|
|
12
|
+
export { FilesService } from './FilesService.js';
|
|
13
|
+
/**
|
|
14
|
+
* ExportService - Document export service (DOCX, PDF, HTML, Markdown)
|
|
15
|
+
*/
|
|
16
|
+
export { ExportService } from './ExportService.js';
|
|
17
|
+
/**
|
|
18
|
+
* CollaborationService - Real-time collaborative editing service
|
|
19
|
+
*/
|
|
20
|
+
export { CollaborationService } from './CollaborationService.js';
|
|
21
|
+
/**
|
|
22
|
+
* VersioningService - Document version history service
|
|
23
|
+
*/
|
|
24
|
+
export { VersioningService } from './VersioningService.js';
|
|
25
|
+
export function createDocsRouter(options) {
|
|
26
|
+
console.log('createDocsRouter options', options);
|
|
27
|
+
const db = configureDb({ url: options.dbUrl });
|
|
28
|
+
const docsService = new DocsService(db);
|
|
29
|
+
const filesService = new FilesService(db);
|
|
30
|
+
return createRouter(docsService, filesService, db);
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Database schema exports
|
|
34
|
+
* Use these to access table definitions and types
|
|
35
|
+
*/
|
|
36
|
+
export { docsTableSchema, documentPresenceTable, documentRelations, documentsTable, documentVersionsTable, filesTable } from './schema.js';
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { Hono } from 'hono';
|
|
2
|
+
import type { DocsService } from './DocsService.js';
|
|
3
|
+
import type { FilesService } from './FilesService.js';
|
|
4
|
+
/**
|
|
5
|
+
* Document routes
|
|
6
|
+
* All routes are prefixed with /docs
|
|
7
|
+
*/
|
|
8
|
+
export declare function createRouter(docsService: DocsService, filesService: FilesService, db: any): Hono;
|
|
9
|
+
//# sourceMappingURL=routes.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"routes.d.ts","sourceRoot":"","sources":["../../src/server/routes.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAA;AAQ3B,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAA;AAEnD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAA;AAGrD;;;GAGG;AACH,wBAAgB,YAAY,CAAC,WAAW,EAAE,WAAW,EAAE,YAAY,EAAE,YAAY,EAAE,EAAE,EAAE,GAAG,GAAG,IAAI,CA2iBhG"}
|