1const TYPE = "prompt-vault-yucang-publish"; 2const PROTOCOL_VERSION = 1; 3const EXTENSION_IDS = Object.freeze([ 4 "fapladhajicfoiadhcpmbmfkodekkckg", 5 "idiemjhonlahnlnalpanhplbgjcfbpnl", 6]); 7 8function requestId() { 9 return crypto.randomUUID(); 10} 11 12function uuid(value) { 13 return typeof value === "string" && /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i.test(value); 14} 15 16export function stableHandoffStringify(value) { 17 if (Array.isArray(value)) return `[${value.map(stableHandoffStringify).join(",")}]`; 18 if (value && typeof value === "object") { 19 return `{${Object.keys(value).sort().map((key) => `${JSON.stringify(key)}:${stableHandoffStringify(value[key])}`).join(",")}}`; 20 } 21 return JSON.stringify(value); 22} 23 24export async function hashHandoffContent(content) { 25 const bytes = new TextEncoder().encode(stableHandoffStringify(content)); 26 const digest = await crypto.subtle.digest("SHA-256", bytes); 27 return [...new Uint8Array(digest)].map((byte) => byte.toString(16).padStart(2, "0")).join(""); 28} 29 30function send(extensionId, message) { 31 return new Promise((resolve, reject) => { 32 if (!globalThis.chrome?.runtime?.sendMessage) return reject(new Error("prompt_vault_not_installed")); 33 chrome.runtime.sendMessage(extensionId, message, (response) => { 34 const lastError = chrome.runtime.lastError; 35 if (lastError) reject(new Error(lastError.message || "prompt_vault_unreachable")); 36 else resolve(response); 37 }); 38 }); 39} 40 41export function createPromptVaultPublishBridge() { 42 return { 43 async claim(handoffId) { 44 if (!uuid(handoffId)) throw new Error("invalid_handoff_id"); 45 const claimRequestId = requestId(); 46 let lastError = new Error("prompt_vault_not_installed"); 47 for (const extensionId of EXTENSION_IDS) { 48 try { 49 const response = await send(extensionId, { 50 type: TYPE, 51 protocolVersion: PROTOCOL_VERSION, 52 action: "claim", 53 requestId: claimRequestId, 54 handoffId, 55 }); 56 if (!response?.ok) throw new Error(response?.error || "claim_failed"); 57 if (response.requestId !== claimRequestId || response.handoffId !== handoffId 58 || !response.content || typeof response.payloadHash !== "string") { 59 throw new Error("invalid_claim_response"); 60 } 61 return { extensionId, requestId: claimRequestId, handoffId, ...response }; 62 } catch (error) { 63 lastError = error; 64 } 65 } 66 throw lastError; 67 }, 68 69 async complete(claim, result) { 70 const response = await send(claim.extensionId, { 71 type: TYPE, 72 protocolVersion: PROTOCOL_VERSION, 73 action: "complete", 74 requestId: claim.requestId, 75 handoffId: claim.handoffId, 76 workId: result.workId, 77 versionId: result.versionId, 78 status: result.status, 79 }); 80 if (!response?.ok || response.requestId !== claim.requestId || response.handoffId !== claim.handoffId) { 81 throw new Error(response?.error || "complete_failed"); 82 } 83 return response; 84 }, 85 86 async discard(claim) { 87 const response = await send(claim.extensionId, { 88 type: TYPE, 89 protocolVersion: PROTOCOL_VERSION, 90 action: "discard", 91 requestId: claim.requestId, 92 handoffId: claim.handoffId, 93 }); 94 if (!response?.ok || response.requestId !== claim.requestId || response.handoffId !== claim.handoffId) { 95 throw new Error(response?.error || "discard_failed"); 96 } 97 return response; 98 }, 99 }; 100} 101 102export const PUBLISH_HANDOFF_PROTOCOL = Object.freeze({ 103 type: TYPE, 104 protocolVersion: PROTOCOL_VERSION, 105 extensionIds: EXTENSION_IDS, 106});
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.