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.
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}`);}
}
