@@ -132,10 +132,10 @@ class SuperConverter {
132132 this . fileSource = params ?. fileSource || null ;
133133 this . documentId = params ?. documentId || null ;
134134
135- // Two-tier identification system
135+ // Document identification
136136 this . documentGuid = null ; // Permanent GUID for modified documents
137137 this . documentHash = null ; // Temporary hash for unmodified documents
138- this . documentModified = false ; // Track if document has been modified
138+ this . documentModified = false ; // Track if document has been edited
139139
140140 // Parse the initial XML, if provided
141141 if ( this . docx . length || this . xml ) this . parseFromXml ( ) ;
@@ -166,8 +166,8 @@ class SuperConverter {
166166 if ( ! this . initialJSON ) this . initialJSON = this . parseXmlToJson ( this . xml ) ;
167167 this . declaration = this . initialJSON ?. declaration ;
168168
169- // Resolve document identifier (GUID or hash)
170- this . resolveDocumentIdentifier ( ) ;
169+ // Only resolve existing GUIDs synchronously (no hash generation yet )
170+ this . resolveDocumentGuid ( ) ;
171171 }
172172
173173 parseXmlToJson ( xml ) {
@@ -322,90 +322,96 @@ class SuperConverter {
322322 }
323323
324324 /**
325- * Resolve document identifier - check for existing GUID or generate hash
325+ * Resolve existing document GUID (synchronous)
326326 */
327- resolveDocumentIdentifier ( ) {
328- // Only run this once during initialization
329- if ( this . documentGuid || this . documentHash ) return ;
330-
331- // 1. Check for Microsoft's docId (READ ONLY - never modify settings.xml)
332- try {
333- this . getDocumentInternalId ( ) ; // This sets this.documentInternalId
334- if ( this . documentInternalId ) {
335- this . documentGuid = this . documentInternalId . replace ( / [ { } ] / g, '' ) ;
336- return ;
337- }
338- } catch {
339- // Continue to next check
327+ resolveDocumentGuid ( ) {
328+ // 1. Check Microsoft's docId (READ ONLY)
329+ const microsoftGuid = this . getMicrosoftDocId ( ) ;
330+ if ( microsoftGuid ) {
331+ this . documentGuid = microsoftGuid ;
332+ return ;
340333 }
341334
342335 // 2. Check our custom property
343336 const customGuid = SuperConverter . getStoredCustomProperty ( this . docx , 'DocumentGuid' ) ;
344337 if ( customGuid ) {
345338 this . documentGuid = customGuid ;
346- return ;
347339 }
340+ // Don't generate hash here - do it lazily when needed
341+ }
348342
349- // 3. Generate hash for unmodified document (telemetry only)
350- this . documentHash = this . generateDocumentHash ( ) ;
343+ /**
344+ * Get Microsoft's docId from settings.xml (READ ONLY)
345+ */
346+ getMicrosoftDocId ( ) {
347+ this . getDocumentInternalId ( ) ; // Existing method
348+ if ( this . documentInternalId ) {
349+ return this . documentInternalId . replace ( / [ { } ] / g, '' ) ;
350+ }
351+ return null ;
351352 }
352353
353354 /**
354- * Generate hash for unmodified documents
355- * @returns {string|null } Hash-based temporary identifier
355+ * Generate document hash for telemetry (async, lazy)
356356 */
357- generateDocumentHash ( ) {
358- if ( ! this . fileSource ) return null ;
357+ async generateDocumentHash ( ) {
358+ if ( ! this . fileSource ) return `HASH- ${ Date . now ( ) } ` ;
359359
360360 try {
361361 let buffer ;
362+
362363 if ( Buffer . isBuffer ( this . fileSource ) ) {
363364 buffer = this . fileSource ;
364365 } else if ( this . fileSource instanceof ArrayBuffer ) {
365366 buffer = Buffer . from ( this . fileSource ) ;
367+ } else if ( this . fileSource instanceof Blob || this . fileSource instanceof File ) {
368+ const arrayBuffer = await this . fileSource . arrayBuffer ( ) ;
369+ buffer = Buffer . from ( arrayBuffer ) ;
366370 } else {
367- // For File or Blob objects
368- buffer = Buffer . from ( this . fileSource ) ;
371+ return `HASH-${ Date . now ( ) } ` ;
369372 }
370373
371374 const hash = crc32 ( buffer ) ;
372375 return `HASH-${ hash . toString ( 'hex' ) . toUpperCase ( ) } ` ;
373376 } catch ( e ) {
374377 console . warn ( 'Could not generate document hash:' , e ) ;
375- return `HASH-${ Date . now ( ) } ` ; // Fallback
378+ return `HASH-${ Date . now ( ) } ` ;
376379 }
377380 }
378381
379382 /**
380- * Get document identifier (GUID or hash)
381- * @returns {string|null } Either permanent GUID or temporary hash
383+ * Get document identifier (GUID or hash) - async for lazy hash generation
382384 */
383- getDocumentIdentifier ( ) {
384- return this . documentGuid || this . documentHash || null ;
385+ async getDocumentIdentifier ( ) {
386+ if ( this . documentGuid ) {
387+ return this . documentGuid ;
388+ }
389+
390+ if ( ! this . documentHash && this . fileSource ) {
391+ this . documentHash = await this . generateDocumentHash ( ) ;
392+ }
393+
394+ return this . documentHash ;
385395 }
386396
387397 /**
388- * Check if this is a temporary identifier
389- * @returns {boolean }
398+ * Check if using temporary ID
390399 */
391400 hasTemporaryId ( ) {
392- const id = this . getDocumentIdentifier ( ) ;
393- return id && id . startsWith ( 'HASH-' ) ;
401+ // Has temporary ID if no GUID but has hash (or could generate one)
402+ return ! this . documentGuid && ! ! ( this . documentHash || this . fileSource ) ;
394403 }
395404
396405 /**
397- * Convert temporary hash to permanent GUID
398- * @returns {string } The new or existing GUID
406+ * Promote from hash to GUID on first edit
399407 */
400408 promoteToGuid ( ) {
401409 if ( this . documentGuid ) return this . documentGuid ;
402410
403- // Generate new GUID
404- this . documentGuid = uuidv4 ( ) ;
411+ this . documentGuid = this . getMicrosoftDocId ( ) || uuidv4 ( ) ;
405412 this . documentModified = true ;
406413 this . documentHash = null ; // Clear temporary hash
407414
408- console . debug ( 'Document promoted from hash to GUID:' , this . documentGuid ) ;
409415 return this . documentGuid ;
410416 }
411417
@@ -650,18 +656,17 @@ class SuperConverter {
650656 // Update the rels table
651657 this . #exportProcessNewRelationships( [ ...params . relationships , ...commentsRels , ...headFootRels ] ) ;
652658
653- // Only store GUID in custom.xml if document was modified
654- if ( this . documentModified && this . documentGuid ) {
655- // Store SuperDoc version (indicates document was edited)
656- SuperConverter . setStoredSuperdocVersion ( this . convertedXml ) ;
657-
658- // Store document GUID in custom.xml (never modify settings.xml)
659- this . documentGuid = SuperConverter . setStoredCustomProperty (
660- this . convertedXml ,
661- 'DocumentGuid' ,
662- this . documentGuid ,
663- true , // preserve existing
664- ) ;
659+ // Store SuperDoc version
660+ SuperConverter . setStoredSuperdocVersion ( this . convertedXml ) ;
661+
662+ // Store document GUID if document was modified
663+ if ( this . documentModified || this . documentGuid ) {
664+ if ( ! this . documentGuid ) {
665+ this . documentGuid = this . getMicrosoftDocId ( ) || uuidv4 ( ) ;
666+ }
667+
668+ // Always store in custom.xml (never modify settings.xml)
669+ SuperConverter . setStoredCustomProperty ( this . convertedXml , 'DocumentGuid' , this . documentGuid , true ) ;
665670 }
666671
667672 // Update the numbering.xml
@@ -921,6 +926,12 @@ class SuperConverter {
921926 this . addedMedia = processedData ;
922927 }
923928
929+ // Deprecated methods for backward compatibility
930+ static getStoredSuperdocId ( docx ) {
931+ console . warn ( 'getStoredSuperdocId is deprecated, use getDocumentGuid instead' ) ;
932+ return SuperConverter . getDocumentGuid ( docx ) ;
933+ }
934+
924935 static updateDocumentVersion ( docx , version ) {
925936 console . warn ( 'updateDocumentVersion is deprecated, use setStoredSuperdocVersion instead' ) ;
926937 return SuperConverter . setStoredSuperdocVersion ( docx , version ) ;
0 commit comments