@@ -239,7 +239,10 @@ const manifestFromSigil = async (opts: {
239239 return { manifestHash, ...manifestPayload } ;
240240} ;
241241
242- const ensureZkProofInSvg = async ( svgText : string ) : Promise < string > => {
242+ const ensureZkProofInSvg = async (
243+ svgText : string ,
244+ opts ?: Readonly < { allowMissingZkProof ?: boolean } > ,
245+ ) : Promise < string > => {
243246 const metadataRegex = / < m e t a d a t a (?: \s [ ^ > ] * ) ? > ( [ \s \S ] * ?) < \/ m e t a d a t a > / gi;
244247 let match : RegExpExecArray | null ;
245248
@@ -292,11 +295,15 @@ const ensureZkProofInSvg = async (svgText: string): Promise<string> => {
292295 proofHints,
293296 } ) ;
294297 if ( ! generated ) {
295- throw new Error ( "ZK proof unavailable for export" ) ;
298+ if ( ! opts ?. allowMissingZkProof ) {
299+ throw new Error ( "ZK proof unavailable for export" ) ;
300+ }
301+ payload . proofHints = proofHints ;
302+ } else {
303+ payload . zkProof = generated . proof as unknown ;
304+ payload . zkPublicInputs = generated . zkPublicInputs ;
305+ payload . proofHints = generated . proofHints ;
296306 }
297- payload . zkProof = generated . proof as unknown ;
298- payload . zkPublicInputs = generated . zkPublicInputs ;
299- payload . proofHints = generated . proofHints ;
300307 } else {
301308 payload . proofHints = proofHints ;
302309 }
@@ -371,6 +378,9 @@ export type SigilExportOptions = Readonly<{
371378 /** Export which formats. Default: both */
372379 exportSvg ?: boolean ;
373380 exportPng ?: boolean ;
381+
382+ /** Allow export without an embedded ZK proof. */
383+ allowMissingZkProof ?: boolean ;
374384} > ;
375385
376386export type SigilZipOptions = Readonly < {
@@ -383,6 +393,9 @@ export type SigilZipOptions = Readonly<{
383393
384394 /** PNG size px (square). Default: 1024 */
385395 pngSizePx ?: number ;
396+
397+ /** Allow export without an embedded ZK proof. */
398+ allowMissingZkProof ?: boolean ;
386399} > ;
387400
388401export const exportSigil = async ( opts : SigilExportOptions ) : Promise < ExportResult > => {
@@ -397,7 +410,15 @@ export const exportSigil = async (opts: SigilExportOptions): Promise<ExportResul
397410 const svgText = opts . svgText ?? ( opts . svgUrl ? await fetchText ( opts . svgUrl ) : null ) ;
398411 if ( ! svgText ) return { ok : false , error : "Missing svgText/svgUrl" } ;
399412
400- const svgWithProof = await ensureZkProofInSvg ( svgText ) ;
413+ let svgWithProof = svgText ;
414+ try {
415+ svgWithProof = await ensureZkProofInSvg ( svgText , { allowMissingZkProof : opts . allowMissingZkProof } ) ;
416+ } catch ( err ) {
417+ const message = err instanceof Error ? err . message : "export failed" ;
418+ if ( ! opts . allowMissingZkProof || message !== "Sigil metadata missing; cannot generate ZK proof" ) {
419+ throw err ;
420+ }
421+ }
401422
402423 if ( exportSvg ) {
403424 const blob = new Blob ( [ svgWithProof ] , { type : "image/svg+xml" } ) ;
@@ -423,7 +444,15 @@ export const exportSigilZip = async (opts: SigilZipOptions): Promise<ExportResul
423444 const svgText = opts . svgText ?? ( opts . svgUrl ? await fetchText ( opts . svgUrl ) : null ) ;
424445 if ( ! svgText ) return { ok : false , error : "Missing svgText/svgUrl" } ;
425446
426- const svgWithProof = await ensureZkProofInSvg ( svgText ) ;
447+ let svgWithProof = svgText ;
448+ try {
449+ svgWithProof = await ensureZkProofInSvg ( svgText , { allowMissingZkProof : opts . allowMissingZkProof } ) ;
450+ } catch ( err ) {
451+ const message = err instanceof Error ? err . message : "export failed" ;
452+ if ( ! opts . allowMissingZkProof || message !== "Sigil metadata missing; cannot generate ZK proof" ) {
453+ throw err ;
454+ }
455+ }
427456 const size = Math . max ( 256 , Math . min ( 4096 , Math . floor ( opts . pngSizePx ?? 1024 ) ) ) ;
428457 const png = await svgToPngBlob ( svgWithProof , size ) ;
429458 const exportMoment = momentFromUTC ( new Date ( ) ) ;
@@ -459,6 +488,7 @@ export type SigilExportButtonProps = Readonly<{
459488 mode ?: "pair" | "zip" ;
460489 className ?: string ;
461490 label ?: string ;
491+ allowMissingZkProof ?: boolean ;
462492} > ;
463493
464494export const SigilExportButton = ( props : SigilExportButtonProps ) => {
@@ -478,6 +508,7 @@ export const SigilExportButton = (props: SigilExportButtonProps) => {
478508 svgText : props . svgText ,
479509 svgUrl : props . svgUrl ,
480510 pngSizePx : props . pngSizePx ?? 1400 ,
511+ allowMissingZkProof : props . allowMissingZkProof ,
481512 } )
482513 : await exportSigil ( {
483514 filenameBase : props . filenameBase ,
@@ -486,6 +517,7 @@ export const SigilExportButton = (props: SigilExportButtonProps) => {
486517 pngSizePx : props . pngSizePx ?? 1024 ,
487518 exportSvg : true ,
488519 exportPng : true ,
520+ allowMissingZkProof : props . allowMissingZkProof ,
489521 } ) ;
490522 if ( ! res . ok ) ui . toast ( "error" , "Export failed" , res . error ) ;
491523 else {
0 commit comments