@fatagnus/dink-sync 1.0.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 +312 -0
- package/dist/client/attachment.d.ts +225 -0
- package/dist/client/attachment.d.ts.map +1 -0
- package/dist/client/attachment.js +402 -0
- package/dist/client/attachment.js.map +1 -0
- package/dist/client/binary-encoding.d.ts +45 -0
- package/dist/client/binary-encoding.d.ts.map +1 -0
- package/dist/client/binary-encoding.js +90 -0
- package/dist/client/binary-encoding.js.map +1 -0
- package/dist/client/collection.d.ts +10 -0
- package/dist/client/collection.d.ts.map +1 -0
- package/dist/client/collection.js +924 -0
- package/dist/client/collection.js.map +1 -0
- package/dist/client/compression.d.ts +56 -0
- package/dist/client/compression.d.ts.map +1 -0
- package/dist/client/compression.js +173 -0
- package/dist/client/compression.js.map +1 -0
- package/dist/client/crdt/index.d.ts +2 -0
- package/dist/client/crdt/index.d.ts.map +1 -0
- package/dist/client/crdt/index.js +2 -0
- package/dist/client/crdt/index.js.map +1 -0
- package/dist/client/crdt/yjs-doc.d.ts +88 -0
- package/dist/client/crdt/yjs-doc.d.ts.map +1 -0
- package/dist/client/crdt/yjs-doc.js +123 -0
- package/dist/client/crdt/yjs-doc.js.map +1 -0
- package/dist/client/index.d.ts +66 -0
- package/dist/client/index.d.ts.map +1 -0
- package/dist/client/index.js +233 -0
- package/dist/client/index.js.map +1 -0
- package/dist/client/mock-transport.d.ts +155 -0
- package/dist/client/mock-transport.d.ts.map +1 -0
- package/dist/client/mock-transport.js +292 -0
- package/dist/client/mock-transport.js.map +1 -0
- package/dist/client/network-detector.d.ts +65 -0
- package/dist/client/network-detector.d.ts.map +1 -0
- package/dist/client/network-detector.js +147 -0
- package/dist/client/network-detector.js.map +1 -0
- package/dist/client/provisioning.d.ts +126 -0
- package/dist/client/provisioning.d.ts.map +1 -0
- package/dist/client/provisioning.js +125 -0
- package/dist/client/provisioning.js.map +1 -0
- package/dist/client/signal.d.ts +13 -0
- package/dist/client/signal.d.ts.map +1 -0
- package/dist/client/signal.js +27 -0
- package/dist/client/signal.js.map +1 -0
- package/dist/client/sync-engine.d.ts +298 -0
- package/dist/client/sync-engine.d.ts.map +1 -0
- package/dist/client/sync-engine.js +904 -0
- package/dist/client/sync-engine.js.map +1 -0
- package/dist/client/synced-edge.d.ts +109 -0
- package/dist/client/synced-edge.d.ts.map +1 -0
- package/dist/client/synced-edge.js +179 -0
- package/dist/client/synced-edge.js.map +1 -0
- package/dist/client/synced-offline-edge-types.d.ts +540 -0
- package/dist/client/synced-offline-edge-types.d.ts.map +1 -0
- package/dist/client/synced-offline-edge-types.js +10 -0
- package/dist/client/synced-offline-edge-types.js.map +1 -0
- package/dist/client/synced-offline-edge.d.ts +54 -0
- package/dist/client/synced-offline-edge.d.ts.map +1 -0
- package/dist/client/synced-offline-edge.js +731 -0
- package/dist/client/synced-offline-edge.js.map +1 -0
- package/dist/client/transport.d.ts +202 -0
- package/dist/client/transport.d.ts.map +1 -0
- package/dist/client/transport.js +409 -0
- package/dist/client/transport.js.map +1 -0
- package/dist/client/types.d.ts +622 -0
- package/dist/client/types.d.ts.map +1 -0
- package/dist/client/types.js +60 -0
- package/dist/client/types.js.map +1 -0
- package/dist/client/validation.d.ts +61 -0
- package/dist/client/validation.d.ts.map +1 -0
- package/dist/client/validation.js +57 -0
- package/dist/client/validation.js.map +1 -0
- package/dist/client/versioning.d.ts +134 -0
- package/dist/client/versioning.d.ts.map +1 -0
- package/dist/client/versioning.js +304 -0
- package/dist/client/versioning.js.map +1 -0
- package/dist/index.d.ts +40 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +51 -0
- package/dist/index.js.map +1 -0
- package/dist/persistence/encryption.d.ts +114 -0
- package/dist/persistence/encryption.d.ts.map +1 -0
- package/dist/persistence/encryption.js +286 -0
- package/dist/persistence/encryption.js.map +1 -0
- package/dist/persistence/index.d.ts +21 -0
- package/dist/persistence/index.d.ts.map +1 -0
- package/dist/persistence/index.js +20 -0
- package/dist/persistence/index.js.map +1 -0
- package/dist/persistence/memory.d.ts +32 -0
- package/dist/persistence/memory.d.ts.map +1 -0
- package/dist/persistence/memory.js +57 -0
- package/dist/persistence/memory.js.map +1 -0
- package/dist/persistence/migrations.d.ts +106 -0
- package/dist/persistence/migrations.d.ts.map +1 -0
- package/dist/persistence/migrations.js +176 -0
- package/dist/persistence/migrations.js.map +1 -0
- package/dist/persistence/pending-queue.d.ts +109 -0
- package/dist/persistence/pending-queue.d.ts.map +1 -0
- package/dist/persistence/pending-queue.js +249 -0
- package/dist/persistence/pending-queue.js.map +1 -0
- package/dist/persistence/pglite.d.ts +72 -0
- package/dist/persistence/pglite.d.ts.map +1 -0
- package/dist/persistence/pglite.js +126 -0
- package/dist/persistence/pglite.js.map +1 -0
- package/dist/persistence/quota-manager.d.ts +134 -0
- package/dist/persistence/quota-manager.d.ts.map +1 -0
- package/dist/persistence/quota-manager.js +242 -0
- package/dist/persistence/quota-manager.js.map +1 -0
- package/dist/persistence/types.d.ts +54 -0
- package/dist/persistence/types.d.ts.map +1 -0
- package/dist/persistence/types.js +2 -0
- package/dist/persistence/types.js.map +1 -0
- package/dist/react/OfflineEdgeProvider.d.ts +91 -0
- package/dist/react/OfflineEdgeProvider.d.ts.map +1 -0
- package/dist/react/OfflineEdgeProvider.js +127 -0
- package/dist/react/OfflineEdgeProvider.js.map +1 -0
- package/dist/react/SyncedOfflineEdgeProvider.d.ts +105 -0
- package/dist/react/SyncedOfflineEdgeProvider.d.ts.map +1 -0
- package/dist/react/SyncedOfflineEdgeProvider.js +138 -0
- package/dist/react/SyncedOfflineEdgeProvider.js.map +1 -0
- package/dist/react/index.d.ts +50 -0
- package/dist/react/index.d.ts.map +1 -0
- package/dist/react/index.js +51 -0
- package/dist/react/index.js.map +1 -0
- package/dist/react/useCollection.d.ts +77 -0
- package/dist/react/useCollection.d.ts.map +1 -0
- package/dist/react/useCollection.js +113 -0
- package/dist/react/useCollection.js.map +1 -0
- package/dist/react/useCollectionSyncMode.d.ts +61 -0
- package/dist/react/useCollectionSyncMode.d.ts.map +1 -0
- package/dist/react/useCollectionSyncMode.js +93 -0
- package/dist/react/useCollectionSyncMode.js.map +1 -0
- package/dist/react/useConnectionState.d.ts +44 -0
- package/dist/react/useConnectionState.d.ts.map +1 -0
- package/dist/react/useConnectionState.js +46 -0
- package/dist/react/useConnectionState.js.map +1 -0
- package/dist/react/useDocumentSyncStatus.d.ts +72 -0
- package/dist/react/useDocumentSyncStatus.d.ts.map +1 -0
- package/dist/react/useDocumentSyncStatus.js +110 -0
- package/dist/react/useDocumentSyncStatus.js.map +1 -0
- package/dist/react/useOfflineEdge.d.ts +58 -0
- package/dist/react/useOfflineEdge.d.ts.map +1 -0
- package/dist/react/useOfflineEdge.js +54 -0
- package/dist/react/useOfflineEdge.js.map +1 -0
- package/dist/react/usePendingChanges.d.ts +67 -0
- package/dist/react/usePendingChanges.d.ts.map +1 -0
- package/dist/react/usePendingChanges.js +90 -0
- package/dist/react/usePendingChanges.js.map +1 -0
- package/dist/react/useRejectedDocuments.d.ts +112 -0
- package/dist/react/useRejectedDocuments.d.ts.map +1 -0
- package/dist/react/useRejectedDocuments.js +213 -0
- package/dist/react/useRejectedDocuments.js.map +1 -0
- package/dist/react/useSyncControls.d.ts +96 -0
- package/dist/react/useSyncControls.d.ts.map +1 -0
- package/dist/react/useSyncControls.js +112 -0
- package/dist/react/useSyncControls.js.map +1 -0
- package/dist/react/useSyncProgress.d.ts +78 -0
- package/dist/react/useSyncProgress.d.ts.map +1 -0
- package/dist/react/useSyncProgress.js +90 -0
- package/dist/react/useSyncProgress.js.map +1 -0
- package/dist/react/useSyncRejected.d.ts +47 -0
- package/dist/react/useSyncRejected.d.ts.map +1 -0
- package/dist/react/useSyncRejected.js +55 -0
- package/dist/react/useSyncRejected.js.map +1 -0
- package/dist/react/useSyncStatus.d.ts +56 -0
- package/dist/react/useSyncStatus.d.ts.map +1 -0
- package/dist/react/useSyncStatus.js +59 -0
- package/dist/react/useSyncStatus.js.map +1 -0
- package/dist/react/useSyncedOfflineEdge.d.ts +69 -0
- package/dist/react/useSyncedOfflineEdge.d.ts.map +1 -0
- package/dist/react/useSyncedOfflineEdge.js +65 -0
- package/dist/react/useSyncedOfflineEdge.js.map +1 -0
- package/dist/service-worker/index.d.ts +7 -0
- package/dist/service-worker/index.d.ts.map +1 -0
- package/dist/service-worker/index.js +7 -0
- package/dist/service-worker/index.js.map +1 -0
- package/dist/service-worker/sync-worker.d.ts +230 -0
- package/dist/service-worker/sync-worker.d.ts.map +1 -0
- package/dist/service-worker/sync-worker.js +471 -0
- package/dist/service-worker/sync-worker.js.map +1 -0
- package/dist/types.d.ts +6 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +3 -0
- package/dist/types.js.map +1 -0
- package/package.json +95 -0
|
@@ -0,0 +1,402 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Generate a unique attachment ID.
|
|
3
|
+
*/
|
|
4
|
+
function generateAttachmentId() {
|
|
5
|
+
if (typeof crypto !== 'undefined' && crypto.randomUUID) {
|
|
6
|
+
return `att_${crypto.randomUUID()}`;
|
|
7
|
+
}
|
|
8
|
+
return `att_${Date.now().toString(36)}-${Math.random().toString(36).substring(2, 11)}`;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Download policy for attachments.
|
|
12
|
+
*/
|
|
13
|
+
export const DownloadPolicy = {
|
|
14
|
+
/** Download attachment data immediately when fetched */
|
|
15
|
+
Eager: 'eager',
|
|
16
|
+
/** Only download metadata; data loaded on explicit request */
|
|
17
|
+
OnDemand: 'on-demand',
|
|
18
|
+
};
|
|
19
|
+
/** Default chunk size: 256KB */
|
|
20
|
+
const DEFAULT_CHUNK_SIZE = 256 * 1024;
|
|
21
|
+
/** Default max cache size: 50MB */
|
|
22
|
+
const DEFAULT_MAX_CACHE_SIZE = 50 * 1024 * 1024;
|
|
23
|
+
/** Collection name for attachment metadata */
|
|
24
|
+
const ATTACHMENT_METADATA_COLLECTION = '_attachment_metadata';
|
|
25
|
+
/** Collection name for attachment data */
|
|
26
|
+
const ATTACHMENT_DATA_COLLECTION = '_attachment_data';
|
|
27
|
+
/** Collection name for document-to-attachment index */
|
|
28
|
+
const ATTACHMENT_INDEX_COLLECTION = '_attachment_index';
|
|
29
|
+
/**
|
|
30
|
+
* Low-level storage for attachments.
|
|
31
|
+
* Stores metadata and data separately for efficient access.
|
|
32
|
+
*/
|
|
33
|
+
export class AttachmentStorage {
|
|
34
|
+
persistence;
|
|
35
|
+
constructor(persistence) {
|
|
36
|
+
this.persistence = persistence;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Save an attachment.
|
|
40
|
+
*/
|
|
41
|
+
async save(metadata, data) {
|
|
42
|
+
// Save metadata
|
|
43
|
+
const metadataBytes = new TextEncoder().encode(JSON.stringify(metadata));
|
|
44
|
+
await this.persistence.save(ATTACHMENT_METADATA_COLLECTION, metadata.id, metadataBytes);
|
|
45
|
+
// Save data
|
|
46
|
+
await this.persistence.save(ATTACHMENT_DATA_COLLECTION, metadata.id, data);
|
|
47
|
+
// Update document index
|
|
48
|
+
await this.updateIndex(metadata);
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Load an attachment with its data.
|
|
52
|
+
*/
|
|
53
|
+
async load(attachmentId) {
|
|
54
|
+
const metadata = await this.getMetadata(attachmentId);
|
|
55
|
+
if (!metadata) {
|
|
56
|
+
return undefined;
|
|
57
|
+
}
|
|
58
|
+
const data = await this.persistence.load(ATTACHMENT_DATA_COLLECTION, attachmentId);
|
|
59
|
+
if (!data) {
|
|
60
|
+
return undefined;
|
|
61
|
+
}
|
|
62
|
+
return { metadata, data };
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Load just the data for an attachment.
|
|
66
|
+
*/
|
|
67
|
+
async loadData(attachmentId) {
|
|
68
|
+
return this.persistence.load(ATTACHMENT_DATA_COLLECTION, attachmentId);
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Get metadata for an attachment without loading data.
|
|
72
|
+
*/
|
|
73
|
+
async getMetadata(attachmentId) {
|
|
74
|
+
const metadataBytes = await this.persistence.load(ATTACHMENT_METADATA_COLLECTION, attachmentId);
|
|
75
|
+
if (!metadataBytes) {
|
|
76
|
+
return undefined;
|
|
77
|
+
}
|
|
78
|
+
try {
|
|
79
|
+
return JSON.parse(new TextDecoder().decode(metadataBytes));
|
|
80
|
+
}
|
|
81
|
+
catch {
|
|
82
|
+
return undefined;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* List all attachments for a document.
|
|
87
|
+
*/
|
|
88
|
+
async listByDocument(collection, documentId) {
|
|
89
|
+
const indexKey = `${collection}:${documentId}`;
|
|
90
|
+
const indexData = await this.persistence.load(ATTACHMENT_INDEX_COLLECTION, indexKey);
|
|
91
|
+
if (!indexData) {
|
|
92
|
+
return [];
|
|
93
|
+
}
|
|
94
|
+
try {
|
|
95
|
+
const attachmentIds = JSON.parse(new TextDecoder().decode(indexData));
|
|
96
|
+
const results = [];
|
|
97
|
+
for (const id of attachmentIds) {
|
|
98
|
+
const metadata = await this.getMetadata(id);
|
|
99
|
+
if (metadata) {
|
|
100
|
+
results.push(metadata);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
return results;
|
|
104
|
+
}
|
|
105
|
+
catch {
|
|
106
|
+
return [];
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* Delete an attachment.
|
|
111
|
+
*/
|
|
112
|
+
async delete(attachmentId) {
|
|
113
|
+
// Get metadata to update index
|
|
114
|
+
const metadata = await this.getMetadata(attachmentId);
|
|
115
|
+
// Delete metadata and data
|
|
116
|
+
await this.persistence.delete(ATTACHMENT_METADATA_COLLECTION, attachmentId);
|
|
117
|
+
await this.persistence.delete(ATTACHMENT_DATA_COLLECTION, attachmentId);
|
|
118
|
+
// Update index if we had metadata
|
|
119
|
+
if (metadata) {
|
|
120
|
+
await this.removeFromIndex(metadata);
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* Update the document-to-attachment index.
|
|
125
|
+
*/
|
|
126
|
+
async updateIndex(metadata) {
|
|
127
|
+
const indexKey = `${metadata.collection}:${metadata.documentId}`;
|
|
128
|
+
const indexData = await this.persistence.load(ATTACHMENT_INDEX_COLLECTION, indexKey);
|
|
129
|
+
let attachmentIds = [];
|
|
130
|
+
if (indexData) {
|
|
131
|
+
try {
|
|
132
|
+
attachmentIds = JSON.parse(new TextDecoder().decode(indexData));
|
|
133
|
+
}
|
|
134
|
+
catch {
|
|
135
|
+
attachmentIds = [];
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
if (!attachmentIds.includes(metadata.id)) {
|
|
139
|
+
attachmentIds.push(metadata.id);
|
|
140
|
+
const updatedIndex = new TextEncoder().encode(JSON.stringify(attachmentIds));
|
|
141
|
+
await this.persistence.save(ATTACHMENT_INDEX_COLLECTION, indexKey, updatedIndex);
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
/**
|
|
145
|
+
* Remove an attachment from the document index.
|
|
146
|
+
*/
|
|
147
|
+
async removeFromIndex(metadata) {
|
|
148
|
+
const indexKey = `${metadata.collection}:${metadata.documentId}`;
|
|
149
|
+
const indexData = await this.persistence.load(ATTACHMENT_INDEX_COLLECTION, indexKey);
|
|
150
|
+
if (!indexData) {
|
|
151
|
+
return;
|
|
152
|
+
}
|
|
153
|
+
try {
|
|
154
|
+
let attachmentIds = JSON.parse(new TextDecoder().decode(indexData));
|
|
155
|
+
attachmentIds = attachmentIds.filter(id => id !== metadata.id);
|
|
156
|
+
if (attachmentIds.length > 0) {
|
|
157
|
+
const updatedIndex = new TextEncoder().encode(JSON.stringify(attachmentIds));
|
|
158
|
+
await this.persistence.save(ATTACHMENT_INDEX_COLLECTION, indexKey, updatedIndex);
|
|
159
|
+
}
|
|
160
|
+
else {
|
|
161
|
+
await this.persistence.delete(ATTACHMENT_INDEX_COLLECTION, indexKey);
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
catch {
|
|
165
|
+
// Ignore corrupted index
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
/**
|
|
170
|
+
* Manages attachments with caching, chunked upload, and progress tracking.
|
|
171
|
+
*/
|
|
172
|
+
export class AttachmentManager {
|
|
173
|
+
storage;
|
|
174
|
+
chunkSize;
|
|
175
|
+
maxCacheSize;
|
|
176
|
+
downloadPolicy;
|
|
177
|
+
// LRU cache
|
|
178
|
+
cache = new Map();
|
|
179
|
+
currentCacheSize = 0;
|
|
180
|
+
cacheHits = 0;
|
|
181
|
+
cacheMisses = 0;
|
|
182
|
+
cacheEvictions = 0;
|
|
183
|
+
constructor(storage, config = {}) {
|
|
184
|
+
this.storage = storage;
|
|
185
|
+
this.chunkSize = config.chunkSize ?? DEFAULT_CHUNK_SIZE;
|
|
186
|
+
this.maxCacheSize = config.maxCacheSize ?? DEFAULT_MAX_CACHE_SIZE;
|
|
187
|
+
this.downloadPolicy = config.downloadPolicy ?? DownloadPolicy.Eager;
|
|
188
|
+
}
|
|
189
|
+
/**
|
|
190
|
+
* Upload an attachment.
|
|
191
|
+
*/
|
|
192
|
+
async upload(options) {
|
|
193
|
+
const { filename, mimeType, data, documentId, collection, onProgress } = options;
|
|
194
|
+
// Calculate checksum
|
|
195
|
+
const checksum = await this.calculateChecksum(data);
|
|
196
|
+
// Generate ID and create metadata
|
|
197
|
+
const id = generateAttachmentId();
|
|
198
|
+
const metadata = {
|
|
199
|
+
id,
|
|
200
|
+
filename,
|
|
201
|
+
mimeType,
|
|
202
|
+
size: data.length,
|
|
203
|
+
checksum,
|
|
204
|
+
createdAt: Date.now(),
|
|
205
|
+
documentId,
|
|
206
|
+
collection,
|
|
207
|
+
};
|
|
208
|
+
// Split into chunks for progress tracking
|
|
209
|
+
const chunks = this.splitIntoChunks(data);
|
|
210
|
+
const totalChunks = chunks.length;
|
|
211
|
+
let uploadedBytes = 0;
|
|
212
|
+
// Process chunks (simulated chunked upload with progress)
|
|
213
|
+
for (let i = 0; i < chunks.length; i++) {
|
|
214
|
+
uploadedBytes += chunks[i].length;
|
|
215
|
+
if (onProgress) {
|
|
216
|
+
onProgress({
|
|
217
|
+
percent: Math.round((uploadedBytes / data.length) * 100),
|
|
218
|
+
uploadedBytes,
|
|
219
|
+
totalBytes: data.length,
|
|
220
|
+
chunksCompleted: i + 1,
|
|
221
|
+
totalChunks,
|
|
222
|
+
});
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
// Save to storage (full data)
|
|
226
|
+
await this.storage.save(metadata, data);
|
|
227
|
+
// Add to cache
|
|
228
|
+
this.addToCache(id, { metadata, data });
|
|
229
|
+
return { metadata };
|
|
230
|
+
}
|
|
231
|
+
/**
|
|
232
|
+
* Get an attachment by ID.
|
|
233
|
+
*/
|
|
234
|
+
async get(attachmentId) {
|
|
235
|
+
// Check cache first
|
|
236
|
+
const cached = this.cache.get(attachmentId);
|
|
237
|
+
if (cached) {
|
|
238
|
+
this.cacheHits++;
|
|
239
|
+
cached.lastAccessedAt = Date.now();
|
|
240
|
+
return this.createAttachment(cached.attachment, true);
|
|
241
|
+
}
|
|
242
|
+
this.cacheMisses++;
|
|
243
|
+
// Load from storage based on policy
|
|
244
|
+
if (this.downloadPolicy === DownloadPolicy.Eager) {
|
|
245
|
+
const stored = await this.storage.load(attachmentId);
|
|
246
|
+
if (!stored) {
|
|
247
|
+
return undefined;
|
|
248
|
+
}
|
|
249
|
+
// Add to cache
|
|
250
|
+
this.addToCache(attachmentId, stored);
|
|
251
|
+
return this.createAttachment(stored, true);
|
|
252
|
+
}
|
|
253
|
+
else {
|
|
254
|
+
// On-demand: only load metadata
|
|
255
|
+
const metadata = await this.storage.getMetadata(attachmentId);
|
|
256
|
+
if (!metadata) {
|
|
257
|
+
return undefined;
|
|
258
|
+
}
|
|
259
|
+
return this.createAttachment({ metadata, data: new Uint8Array(0) }, false);
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
/**
|
|
263
|
+
* Split data into chunks.
|
|
264
|
+
*/
|
|
265
|
+
splitIntoChunks(data) {
|
|
266
|
+
if (data.length === 0) {
|
|
267
|
+
return [data];
|
|
268
|
+
}
|
|
269
|
+
const chunks = [];
|
|
270
|
+
for (let i = 0; i < data.length; i += this.chunkSize) {
|
|
271
|
+
const end = Math.min(i + this.chunkSize, data.length);
|
|
272
|
+
chunks.push(data.slice(i, end));
|
|
273
|
+
}
|
|
274
|
+
return chunks;
|
|
275
|
+
}
|
|
276
|
+
/**
|
|
277
|
+
* Reassemble chunks into original data.
|
|
278
|
+
*/
|
|
279
|
+
reassembleChunks(chunks) {
|
|
280
|
+
const totalLength = chunks.reduce((sum, chunk) => sum + chunk.length, 0);
|
|
281
|
+
const result = new Uint8Array(totalLength);
|
|
282
|
+
let offset = 0;
|
|
283
|
+
for (const chunk of chunks) {
|
|
284
|
+
result.set(chunk, offset);
|
|
285
|
+
offset += chunk.length;
|
|
286
|
+
}
|
|
287
|
+
return result;
|
|
288
|
+
}
|
|
289
|
+
/**
|
|
290
|
+
* Calculate checksum for data.
|
|
291
|
+
* Uses a simple hash in browser environments.
|
|
292
|
+
*/
|
|
293
|
+
async calculateChecksum(data) {
|
|
294
|
+
// Use Web Crypto API if available
|
|
295
|
+
if (typeof crypto !== 'undefined' && crypto.subtle) {
|
|
296
|
+
try {
|
|
297
|
+
// Create a new ArrayBuffer to ensure compatibility with crypto.subtle.digest
|
|
298
|
+
const buffer = new ArrayBuffer(data.length);
|
|
299
|
+
const view = new Uint8Array(buffer);
|
|
300
|
+
view.set(data);
|
|
301
|
+
const hashBuffer = await crypto.subtle.digest('SHA-256', buffer);
|
|
302
|
+
const hashArray = Array.from(new Uint8Array(hashBuffer));
|
|
303
|
+
const hashHex = hashArray.map(b => b.toString(16).padStart(2, '0')).join('');
|
|
304
|
+
return `sha256-${hashHex}`;
|
|
305
|
+
}
|
|
306
|
+
catch {
|
|
307
|
+
// Fall through to simple hash
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
// Fallback: simple hash
|
|
311
|
+
let hash = 0;
|
|
312
|
+
for (let i = 0; i < data.length; i++) {
|
|
313
|
+
const byte = data[i];
|
|
314
|
+
hash = ((hash << 5) - hash + byte) | 0;
|
|
315
|
+
}
|
|
316
|
+
return `simple-${Math.abs(hash).toString(16)}`;
|
|
317
|
+
}
|
|
318
|
+
/**
|
|
319
|
+
* Get cache statistics.
|
|
320
|
+
*/
|
|
321
|
+
getCacheStats() {
|
|
322
|
+
return {
|
|
323
|
+
hits: this.cacheHits,
|
|
324
|
+
misses: this.cacheMisses,
|
|
325
|
+
evictions: this.cacheEvictions,
|
|
326
|
+
currentSize: this.currentCacheSize,
|
|
327
|
+
cachedIds: Array.from(this.cache.keys()),
|
|
328
|
+
};
|
|
329
|
+
}
|
|
330
|
+
/**
|
|
331
|
+
* Clear the cache.
|
|
332
|
+
*/
|
|
333
|
+
clearCache() {
|
|
334
|
+
this.cache.clear();
|
|
335
|
+
this.currentCacheSize = 0;
|
|
336
|
+
}
|
|
337
|
+
/**
|
|
338
|
+
* Add an attachment to the cache, evicting old entries if needed.
|
|
339
|
+
*/
|
|
340
|
+
addToCache(id, stored) {
|
|
341
|
+
const size = stored.data.length;
|
|
342
|
+
// Evict entries if needed
|
|
343
|
+
while (this.currentCacheSize + size > this.maxCacheSize && this.cache.size > 0) {
|
|
344
|
+
this.evictLRU();
|
|
345
|
+
}
|
|
346
|
+
// Add to cache
|
|
347
|
+
this.cache.set(id, {
|
|
348
|
+
attachment: stored,
|
|
349
|
+
lastAccessedAt: Date.now(),
|
|
350
|
+
});
|
|
351
|
+
this.currentCacheSize += size;
|
|
352
|
+
}
|
|
353
|
+
/**
|
|
354
|
+
* Evict the least recently used cache entry.
|
|
355
|
+
*/
|
|
356
|
+
evictLRU() {
|
|
357
|
+
let oldestId = null;
|
|
358
|
+
let oldestTime = Infinity;
|
|
359
|
+
for (const [id, entry] of this.cache) {
|
|
360
|
+
if (entry.lastAccessedAt < oldestTime) {
|
|
361
|
+
oldestTime = entry.lastAccessedAt;
|
|
362
|
+
oldestId = id;
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
if (oldestId) {
|
|
366
|
+
const entry = this.cache.get(oldestId);
|
|
367
|
+
if (entry) {
|
|
368
|
+
this.currentCacheSize -= entry.attachment.data.length;
|
|
369
|
+
this.cache.delete(oldestId);
|
|
370
|
+
this.cacheEvictions++;
|
|
371
|
+
}
|
|
372
|
+
}
|
|
373
|
+
}
|
|
374
|
+
/**
|
|
375
|
+
* Create an Attachment object with lazy loading support.
|
|
376
|
+
*/
|
|
377
|
+
createAttachment(stored, dataLoaded) {
|
|
378
|
+
let _dataLoaded = dataLoaded;
|
|
379
|
+
let _data = dataLoaded ? stored.data : undefined;
|
|
380
|
+
const attachment = {
|
|
381
|
+
metadata: stored.metadata,
|
|
382
|
+
get data() {
|
|
383
|
+
return _data;
|
|
384
|
+
},
|
|
385
|
+
isDataLoaded: () => _dataLoaded,
|
|
386
|
+
loadData: async () => {
|
|
387
|
+
if (_dataLoaded) {
|
|
388
|
+
return;
|
|
389
|
+
}
|
|
390
|
+
const data = await this.storage.loadData(stored.metadata.id);
|
|
391
|
+
if (data) {
|
|
392
|
+
_data = data;
|
|
393
|
+
_dataLoaded = true;
|
|
394
|
+
// Add to cache
|
|
395
|
+
this.addToCache(stored.metadata.id, { metadata: stored.metadata, data });
|
|
396
|
+
}
|
|
397
|
+
},
|
|
398
|
+
};
|
|
399
|
+
return attachment;
|
|
400
|
+
}
|
|
401
|
+
}
|
|
402
|
+
//# sourceMappingURL=attachment.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"attachment.js","sourceRoot":"","sources":["../../src/client/attachment.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Binary encoding utilities for transport layer.
|
|
3
|
+
*
|
|
4
|
+
* Provides efficient encoding/decoding of Uint8Array for transport metadata
|
|
5
|
+
* while keeping the actual CRDT data in binary format.
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* Encode a Uint8Array to a format suitable for JSON transport metadata.
|
|
9
|
+
* Uses base64 encoding for efficiency.
|
|
10
|
+
* @param data - Binary data to encode
|
|
11
|
+
* @returns Base64 encoded string
|
|
12
|
+
*/
|
|
13
|
+
export declare function encodeBinaryForTransport(data: Uint8Array): string;
|
|
14
|
+
/**
|
|
15
|
+
* Decode a base64 string back to Uint8Array.
|
|
16
|
+
* @param encoded - Base64 encoded string
|
|
17
|
+
* @returns Decoded binary data
|
|
18
|
+
*/
|
|
19
|
+
export declare function decodeBinaryFromTransport(encoded: string): Uint8Array;
|
|
20
|
+
/**
|
|
21
|
+
* Encode Uint8Array to number array for JSON serialization.
|
|
22
|
+
* This is used when we need to include binary data in JSON payloads.
|
|
23
|
+
* @param data - Binary data to encode
|
|
24
|
+
* @returns Array of numbers
|
|
25
|
+
*/
|
|
26
|
+
export declare function binaryToArray(data: Uint8Array): number[];
|
|
27
|
+
/**
|
|
28
|
+
* Decode number array back to Uint8Array.
|
|
29
|
+
* @param array - Array of numbers (0-255)
|
|
30
|
+
* @returns Uint8Array
|
|
31
|
+
*/
|
|
32
|
+
export declare function arrayToBinary(array: number[]): Uint8Array;
|
|
33
|
+
/**
|
|
34
|
+
* Check if a value is a Uint8Array.
|
|
35
|
+
* @param value - Value to check
|
|
36
|
+
* @returns true if value is Uint8Array
|
|
37
|
+
*/
|
|
38
|
+
export declare function isUint8Array(value: unknown): value is Uint8Array;
|
|
39
|
+
/**
|
|
40
|
+
* Concatenate multiple Uint8Arrays into one.
|
|
41
|
+
* @param arrays - Arrays to concatenate
|
|
42
|
+
* @returns Combined Uint8Array
|
|
43
|
+
*/
|
|
44
|
+
export declare function concatBinary(...arrays: Uint8Array[]): Uint8Array;
|
|
45
|
+
//# sourceMappingURL=binary-encoding.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"binary-encoding.d.ts","sourceRoot":"","sources":["../../src/client/binary-encoding.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH;;;;;GAKG;AACH,wBAAgB,wBAAwB,CAAC,IAAI,EAAE,UAAU,GAAG,MAAM,CAkBjE;AAED;;;;GAIG;AACH,wBAAgB,yBAAyB,CAAC,OAAO,EAAE,MAAM,GAAG,UAAU,CAiBrE;AAED;;;;;GAKG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,UAAU,GAAG,MAAM,EAAE,CAExD;AAED;;;;GAIG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,UAAU,CAEzD;AAED;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,UAAU,CAEhE;AAED;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,GAAG,MAAM,EAAE,UAAU,EAAE,GAAG,UAAU,CAShE"}
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Binary encoding utilities for transport layer.
|
|
3
|
+
*
|
|
4
|
+
* Provides efficient encoding/decoding of Uint8Array for transport metadata
|
|
5
|
+
* while keeping the actual CRDT data in binary format.
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* Encode a Uint8Array to a format suitable for JSON transport metadata.
|
|
9
|
+
* Uses base64 encoding for efficiency.
|
|
10
|
+
* @param data - Binary data to encode
|
|
11
|
+
* @returns Base64 encoded string
|
|
12
|
+
*/
|
|
13
|
+
export function encodeBinaryForTransport(data) {
|
|
14
|
+
if (data.length === 0) {
|
|
15
|
+
return '';
|
|
16
|
+
}
|
|
17
|
+
// Use built-in btoa with manual byte-to-char conversion for browser/node compatibility
|
|
18
|
+
let binary = '';
|
|
19
|
+
for (let i = 0; i < data.length; i++) {
|
|
20
|
+
binary += String.fromCharCode(data[i]);
|
|
21
|
+
}
|
|
22
|
+
// Handle both browser and Node.js environments
|
|
23
|
+
if (typeof btoa === 'function') {
|
|
24
|
+
return btoa(binary);
|
|
25
|
+
}
|
|
26
|
+
// Node.js fallback
|
|
27
|
+
return Buffer.from(data).toString('base64');
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Decode a base64 string back to Uint8Array.
|
|
31
|
+
* @param encoded - Base64 encoded string
|
|
32
|
+
* @returns Decoded binary data
|
|
33
|
+
*/
|
|
34
|
+
export function decodeBinaryFromTransport(encoded) {
|
|
35
|
+
if (encoded === '') {
|
|
36
|
+
return new Uint8Array(0);
|
|
37
|
+
}
|
|
38
|
+
// Handle both browser and Node.js environments
|
|
39
|
+
if (typeof atob === 'function') {
|
|
40
|
+
const binary = atob(encoded);
|
|
41
|
+
const bytes = new Uint8Array(binary.length);
|
|
42
|
+
for (let i = 0; i < binary.length; i++) {
|
|
43
|
+
bytes[i] = binary.charCodeAt(i);
|
|
44
|
+
}
|
|
45
|
+
return bytes;
|
|
46
|
+
}
|
|
47
|
+
// Node.js fallback
|
|
48
|
+
return new Uint8Array(Buffer.from(encoded, 'base64'));
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Encode Uint8Array to number array for JSON serialization.
|
|
52
|
+
* This is used when we need to include binary data in JSON payloads.
|
|
53
|
+
* @param data - Binary data to encode
|
|
54
|
+
* @returns Array of numbers
|
|
55
|
+
*/
|
|
56
|
+
export function binaryToArray(data) {
|
|
57
|
+
return Array.from(data);
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Decode number array back to Uint8Array.
|
|
61
|
+
* @param array - Array of numbers (0-255)
|
|
62
|
+
* @returns Uint8Array
|
|
63
|
+
*/
|
|
64
|
+
export function arrayToBinary(array) {
|
|
65
|
+
return new Uint8Array(array);
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Check if a value is a Uint8Array.
|
|
69
|
+
* @param value - Value to check
|
|
70
|
+
* @returns true if value is Uint8Array
|
|
71
|
+
*/
|
|
72
|
+
export function isUint8Array(value) {
|
|
73
|
+
return value instanceof Uint8Array;
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Concatenate multiple Uint8Arrays into one.
|
|
77
|
+
* @param arrays - Arrays to concatenate
|
|
78
|
+
* @returns Combined Uint8Array
|
|
79
|
+
*/
|
|
80
|
+
export function concatBinary(...arrays) {
|
|
81
|
+
const totalLength = arrays.reduce((sum, arr) => sum + arr.length, 0);
|
|
82
|
+
const result = new Uint8Array(totalLength);
|
|
83
|
+
let offset = 0;
|
|
84
|
+
for (const arr of arrays) {
|
|
85
|
+
result.set(arr, offset);
|
|
86
|
+
offset += arr.length;
|
|
87
|
+
}
|
|
88
|
+
return result;
|
|
89
|
+
}
|
|
90
|
+
//# sourceMappingURL=binary-encoding.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"binary-encoding.js","sourceRoot":"","sources":["../../src/client/binary-encoding.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH;;;;;GAKG;AACH,MAAM,UAAU,wBAAwB,CAAC,IAAgB;IACvD,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACtB,OAAO,EAAE,CAAC;IACZ,CAAC;IAED,uFAAuF;IACvF,IAAI,MAAM,GAAG,EAAE,CAAC;IAChB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACrC,MAAM,IAAI,MAAM,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;IACzC,CAAC;IAED,+CAA+C;IAC/C,IAAI,OAAO,IAAI,KAAK,UAAU,EAAE,CAAC;QAC/B,OAAO,IAAI,CAAC,MAAM,CAAC,CAAC;IACtB,CAAC;IAED,mBAAmB;IACnB,OAAO,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;AAC9C,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,yBAAyB,CAAC,OAAe;IACvD,IAAI,OAAO,KAAK,EAAE,EAAE,CAAC;QACnB,OAAO,IAAI,UAAU,CAAC,CAAC,CAAC,CAAC;IAC3B,CAAC;IAED,+CAA+C;IAC/C,IAAI,OAAO,IAAI,KAAK,UAAU,EAAE,CAAC;QAC/B,MAAM,MAAM,GAAG,IAAI,CAAC,OAAO,CAAC,CAAC;QAC7B,MAAM,KAAK,GAAG,IAAI,UAAU,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;QAC5C,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;YACvC,KAAK,CAAC,CAAC,CAAC,GAAG,MAAM,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC;QAClC,CAAC;QACD,OAAO,KAAK,CAAC;IACf,CAAC;IAED,mBAAmB;IACnB,OAAO,IAAI,UAAU,CAAC,MAAM,CAAC,IAAI,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC,CAAC;AACxD,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,aAAa,CAAC,IAAgB;IAC5C,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAC1B,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,aAAa,CAAC,KAAe;IAC3C,OAAO,IAAI,UAAU,CAAC,KAAK,CAAC,CAAC;AAC/B,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,YAAY,CAAC,KAAc;IACzC,OAAO,KAAK,YAAY,UAAU,CAAC;AACrC,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,YAAY,CAAC,GAAG,MAAoB;IAClD,MAAM,WAAW,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE,CAAC,GAAG,GAAG,GAAG,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC;IACrE,MAAM,MAAM,GAAG,IAAI,UAAU,CAAC,WAAW,CAAC,CAAC;IAC3C,IAAI,MAAM,GAAG,CAAC,CAAC;IACf,KAAK,MAAM,GAAG,IAAI,MAAM,EAAE,CAAC;QACzB,MAAM,CAAC,GAAG,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC;QACxB,MAAM,IAAI,GAAG,CAAC,MAAM,CAAC;IACvB,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { Collection } from './types.js';
|
|
2
|
+
import type { PersistenceProvider } from '../persistence/types.js';
|
|
3
|
+
/**
|
|
4
|
+
* Creates a collection implementation backed by a persistence provider.
|
|
5
|
+
* Uses YjsDocument internally for CRDT-based conflict-free merging.
|
|
6
|
+
*/
|
|
7
|
+
export declare function createCollection<T extends {
|
|
8
|
+
id: string;
|
|
9
|
+
}>(name: string, persistence: PersistenceProvider): Collection<T>;
|
|
10
|
+
//# sourceMappingURL=collection.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"collection.d.ts","sourceRoot":"","sources":["../../src/client/collection.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAoP,MAAM,YAAY,CAAC;AAG/R,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,yBAAyB,CAAC;AA0JnE;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,CAAC,SAAS;IAAE,EAAE,EAAE,MAAM,CAAA;CAAE,EACvD,IAAI,EAAE,MAAM,EACZ,WAAW,EAAE,mBAAmB,GAC/B,UAAU,CAAC,CAAC,CAAC,CAg7Bf"}
|