Back to Body Journal
SOURCE / PINNED RELEASE

Made of little things.

Body Journal

Release
e8049f8da4e2…
Author-recorded commit
61c04bf0e8aa…
License
LICENSE
Author’s source reference
nostr://npub182jczunncwe0jn6frpqwq3e0qjws7yqqnc3auccqv9nte2dnd63scjm4rf/wss%3A%2F%2Fgit.napplet.soy%2F/n-6c4554844c7

Archive hash verified: 4369d778da046a8b…. The source-to-build association is the author’s claim; it has not been independently rebuilt.

bridge/image-store.mjs
import { createHash } from 'node:crypto';
import { IMAGE_CHUNK_CHARS, MAX_IMAGE_CHARS, MAX_IMAGE_TOTAL, MAX_IMAGES, validImage } from '../src/vision-contract.ts';

/** Short-lived, owner-bound staging for encrypted MCP calls. Never public URLs. */
export class ImageStore {
  items=new Map();
  constructor(now=()=>Date.now()){this.now=now;}
  sweep(){for(const [k,v] of this.items)if(this.now()-v.at>300_000)this.items.delete(k);}
  put(actor,{id,index,total,chunk,sha256}){
    this.sweep();
    if(!/^[a-f0-9]{64}$/.test(actor||'') || !/^[a-z0-9-]{8,80}$/.test(id||'') || !Number.isInteger(index) || !Number.isInteger(total) || total<1 || total>Math.ceil(MAX_IMAGE_CHARS/IMAGE_CHUNK_CHARS) || index<0 || index>=total || typeof chunk!=='string' || !chunk.length || chunk.length>IMAGE_CHUNK_CHARS || !/^[a-f0-9]{64}$/.test(sha256||''))throw new Error('Invalid image chunk.');
    const key=`${actor}:${id}`;
    let entry=this.items.get(key);
    if(!entry){
      const owned=[...this.items.values()].filter(v=>v.actor===actor);
      if(owned.length>=MAX_IMAGES || this.items.size>=MAX_IMAGES*4)throw new Error('Image capacity reached.');
      entry={actor,total,sha256,chunks:[],size:0,at:this.now()};this.items.set(key,entry);
    }
    if(entry.total!==total || entry.sha256!==sha256 || (entry.chunks[index]!==undefined && entry.chunks[index]!==chunk))throw new Error('Image ID conflict.');
    if(entry.chunks[index]===undefined){
      const owned=[...this.items.values()].filter(v=>v.actor===actor).reduce((n,v)=>n+v.size,0);
      const all=[...this.items.values()].reduce((n,v)=>n+v.size,0);
      if(entry.size+chunk.length>MAX_IMAGE_CHARS || owned+chunk.length>MAX_IMAGE_TOTAL || all+chunk.length>MAX_IMAGE_TOTAL*4)throw new Error('Image size limit.');
      entry.chunks[index]=chunk;entry.size+=chunk.length;
    }
    // Fixed TTL from first chunk: repeated writes cannot keep abandoned data alive.
    if(entry.chunks.filter(v=>v!==undefined).length===total){
      const data=entry.chunks.join('');
      if(!validImage(data) || createHash('sha256').update(data).digest('hex')!==sha256){this.items.delete(key);throw new Error('Image integrity failure.');}
      entry.data=data;
    }
    return {ok:true,complete:!!entry.data};
  }
  take(actor,refs){
    this.sweep();
    if(!Array.isArray(refs)||refs.length>MAX_IMAGES||new Set(refs.map(r=>r.id)).size!==refs.length)throw new Error('Invalid image references.');
    const images=refs.map(ref=>{
      const e=this.items.get(`${actor}:${ref.id}`);
      if(!e?.data || e.sha256!==ref.sha256 || !(Number.isInteger(ref.concernId) && ref.concernId>0 || ref.kind==='patient-photo' && ref.concernId===null) || typeof ref.caption!=='string' || ref.caption.length>1200)throw new Error('Image missing or expired.');
      const kind=ref.kind || 'body-map';
      if(!['body-map','patient-photo'].includes(kind) || (kind==='patient-photo' && !/^photo-[a-f0-9]{24}$/.test(ref.attachmentId||'')))throw new Error('Invalid image category.');
      return {concernId:ref.concernId,kind,...(ref.attachmentId ? {attachmentId:ref.attachmentId} : {}),caption:ref.caption,dataUrl:e.data};
    });
    for(const ref of refs)this.items.delete(`${actor}:${ref.id}`);
    return images;
  }
  clear(actor,ids){for(const id of ids)this.items.delete(`${actor}:${id}`);}
}