import{ok,err}from"./_deps/shared/index.js";export var InvitationErrorCode;!function(e){e.INVALID_TOKEN="INVITATION_INVALID_TOKEN",e.EXPIRED_TOKEN="INVITATION_EXPIRED_TOKEN",e.ALREADY_REDEEMED="INVITATION_ALREADY_REDEEMED",e.RATE_LIMIT_EXCEEDED="INVITATION_RATE_LIMIT_EXCEEDED",e.SERVER_ERROR="INVITATION_SERVER_ERROR"}(InvitationErrorCode||(InvitationErrorCode={}));export class InvitationClient{invitationApiUrl;constructor(e={}){this.invitationApiUrl=e.invitationApiUrl||"https://api.private.me"}async create(e,t,r=7){try{const n=await fetch(`${this.invitationApiUrl}/invitations/create`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({senderDid:e,recipientContact:t,expiryDays:r})});if(429===n.status)return err({code:InvitationErrorCode.RATE_LIMIT_EXCEEDED,message:"Too many invitations created. Limit: 10 per day",hint:"Wait before creating more invitations"});if(!n.ok)return err({code:InvitationErrorCode.SERVER_ERROR,message:`Server error: ${n.status}`});const i=await n.json();return ok({token:i.token,expiresAt:new Date(i.expiresAt),senderDid:i.senderDid,recipientContact:i.recipientContact,inviteUrl:i.inviteUrl})}catch(e){return err({code:InvitationErrorCode.SERVER_ERROR,message:e instanceof Error?e.message:"Network error"})}}async redeem(e){try{if(!e||"string"!=typeof e)return err({code:InvitationErrorCode.INVALID_TOKEN,message:"Invitation token is required"});const t=await fetch(`${this.invitationApiUrl}/invitations/redeem`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({token:e})});if(400===t.status)return err({code:InvitationErrorCode.INVALID_TOKEN,message:"Invitation token is invalid",hint:"Check the token in your URL"});if(410===t.status){return"expired"===(await t.json()).reason?err({code:InvitationErrorCode.EXPIRED_TOKEN,message:"Invitation has expired",hint:"Ask the sender for a new invitation"}):err({code:InvitationErrorCode.ALREADY_REDEEMED,message:"Invitation has already been used",hint:"Each invitation can only be used once"})}if(!t.ok)return err({code:InvitationErrorCode.SERVER_ERROR,message:`Server error: ${t.status}`});const r=await t.json();return ok(r.did)}catch(e){return err({code:InvitationErrorCode.SERVER_ERROR,message:e instanceof Error?e.message:"Network error"})}}async get(e){try{const t=await fetch(`${this.invitationApiUrl}/invitations/${encodeURIComponent(e)}`,{headers:{Accept:"application/json"}});if(404===t.status)return err({code:InvitationErrorCode.INVALID_TOKEN,message:"Invitation not found"});if(!t.ok)return err({code:InvitationErrorCode.SERVER_ERROR,message:`Server error: ${t.status}`});const r=await t.json();return ok({senderDid:r.senderDid,recipientContact:r.recipientContact,expiresAt:new Date(r.expiresAt)})}catch(e){return err({code:InvitationErrorCode.SERVER_ERROR,message:e instanceof Error?e.message:"Network error"})}}}export class InvitationStore{invitations=new Map;redeemedTokens=new Set;creationCounts=new Map;create(e,t,r=7){const n=Date.now(),i=this.creationCounts.get(e);if(i&&i.count>=10&&n<i.resetTime)return err({code:InvitationErrorCode.RATE_LIMIT_EXCEEDED,message:"Rate limit exceeded. Maximum 10 invitations per day."});i&&n>=i.resetTime&&this.creationCounts.delete(e);const o=generateInvitationToken(),a={token:o,senderDid:e,recipientContact:t,createdAt:n,expiresAt:n+24*r*60*60*1e3,redeemed:!1};return this.invitations.set(o,a),i?i.count+=1:this.creationCounts.set(e,{count:1,resetTime:n+864e5}),ok(a)}get(e){const t=this.invitations.get(e);if(!t)return err({code:InvitationErrorCode.INVALID_TOKEN,message:"Invitation not found"});return Date.now()>t.expiresAt?(this.invitations.delete(e),err({code:InvitationErrorCode.EXPIRED_TOKEN,message:"Invitation has expired"})):t.redeemed?err({code:InvitationErrorCode.ALREADY_REDEEMED,message:"Invitation has already been redeemed"}):ok(t)}redeem(e){const t=this.get(e);if(!t.ok)return t;const r=t.value;r.redeemed=!0,this.redeemedTokens.add(e);const n=generateRecipientDid(r.senderDid,r.recipientContact);return ok(n)}cleanup(){const e=Date.now();let t=0;for(const[r,n]of this.invitations.entries())(e>n.expiresAt||n.redeemed)&&(this.invitations.delete(r),t+=1);return t}get count(){return this.invitations.size}}export function generateInvitationToken(){const e=new Uint8Array(24);return crypto.getRandomValues(e),Array.from(e).map(e=>e.toString(16).padStart(2,"0")).join("")}function generateRecipientDid(e,t){return`did:key:z6Mk${hashString(`${e}:${t}`)}`}function hashString(e){let t=0;for(let r=0;r<e.length;r+=1)t=(t<<5)-t+e.charCodeAt(r),t&=t;return Math.abs(t).toString(16).padStart(8,"0")}