// @ts-check // Import the types from the TypeScript file /** * @typedef {import('../dc-types').GetProtocol} GetProtocol * @typedef {import('../dc-types').DigitalCredentialGetRequest} DigitalCredentialGetRequest * @typedef {import('../dc-types').DigitalCredentialRequestOptions} DigitalCredentialRequestOptions * @typedef {import('../dc-types').CredentialRequestOptions} CredentialRequestOptions * @typedef {import('../dc-types').CreateProtocol} CreateProtocol * @typedef {import('../dc-types').DigitalCredentialCreateRequest} DigitalCredentialCreateRequest * @typedef {import('../dc-types').CredentialCreationOptions} CredentialCreationOptions * @typedef {import('../dc-types').DigitalCredentialCreationOptions} DigitalCredentialCreationOptions * @typedef {import('../dc-types').SendMessageData} SendMessageData */ /** * Internal helper to build the request array from validated input. * Assumes requestsInputArray is a non-empty array of strings. * @private * @param {string[]} requestsInputArray - An array of request type strings. * @param {string} mediation - The mediation requirement. * @param {object} requestMapping - The specific mapping object for the operation type. * @returns {{ digital: { requests: any[] }, mediation: string }} - The final options structure. * @throws {Error} If an unknown request type string is encountered within the array. */ function _makeOptionsInternal(requestsInputArray, mediation, requestMapping) { const requests = []; for (const request of requestsInputArray) { const factoryFunction = requestMapping[request]; if (factoryFunction) { requests.push(factoryFunction()); // Call the mapped function } else { // This error means a string *within the array* was unknown throw new Error(`Unknown request type within array: ${request}`); } } return { digital: { requests }, mediation }; } const allMappings = { get: { "openid4vp": () => makeOID4VPDict(), "default": () => makeDigitalCredentialGetRequest(undefined, undefined), }, create: { "openid4vci": () => makeOID4VCIDict(), "default": () => makeDigitalCredentialCreateRequest(), }, }; /** * Internal unified function to handle option creation logic. * Routes calls from specific public functions. * @private * @param {'get' | 'create'} type - The type of operation. * @param {string | string[]} [requestsToUse] - Raw input for request types from public function. * @param {string} mediation - Mediation requirement (default handled by public function). * @returns {{ digital: { requests: any[] }, mediation: string }} * @throws {Error} If type is invalid internally, or input strings are invalid. */ function _makeOptionsUnified(type, requestsToUse, mediation) { // 1. Get mapping (Type validation primarily happens via caller) const mapping = allMappings[type]; // Added safety check, though public functions should prevent this. if (!mapping) { throw new Error(`Internal error: Invalid options type specified: ${type}`); } // 2. Handle default for requestsToUse const actualRequestsToUse = requestsToUse === undefined ? ["default"] : requestsToUse; // 3. Handle single string input if (typeof actualRequestsToUse === 'string') { if (mapping[actualRequestsToUse]) { // Valid single string: Pass as array to the core array helper return _makeOptionsInternal([actualRequestsToUse], mediation, mapping); } else { // Invalid single string for this type throw new Error(`Unknown request type string '${actualRequestsToUse}' provided for operation type '${type}'`); } } // 4. Handle array input if (Array.isArray(actualRequestsToUse)) { if (actualRequestsToUse.length === 0) { // Handle empty array explicitly return { digital: { requests: [] }, mediation }; } // Pass valid non-empty array to the core array helper return _makeOptionsInternal(actualRequestsToUse, mediation, mapping); } // 5. Handle invalid input types (neither string nor array) return { digital: { requests: [] }, mediation }; } /** * Creates options for getting credentials. * @export * @param {string | string[]} [requestsToUse] - Request types ('default', 'openid4vp', or an array). Defaults to ['default']. * @param {string} [mediation="required"] - Credential mediation requirement ("required", "optional", "silent"). * @returns {{ digital: { requests: any[] }, mediation: string }} */ export function makeGetOptions(requestsToUse, mediation = "required") { // Pass type 'get', the user's input, and the final mediation value return _makeOptionsUnified('get', requestsToUse, mediation); } /** * Creates options for creating credentials. * @export * @param {string | string[]} [requestsToUse] - Request types ('default', 'openid4vci', or an array). Defaults to ['default']. * @param {string} [mediation="required"] - Credential mediation requirement ("required", "optional", "silent"). * @returns {{ digital: { requests: any[] }, mediation: string }} // Adjust inner array type if known */ export function makeCreateOptions(requestsToUse, mediation = "required") { // Pass type 'create', the user's input, and the final mediation value return _makeOptionsUnified('create', requestsToUse, mediation); } /** * * @param {string} protocol * @param {object} data * @returns {DigitalCredentialGetRequest} */ function makeDigitalCredentialGetRequest(protocol = "protocol", data = {}) { return { protocol, data, }; } /** * Representation of an OpenID4VP request. * * @returns {DigitalCredentialGetRequest} **/ function makeOID4VPDict() { return makeDigitalCredentialGetRequest("openid4vp", { // Canonical example of an OpenID4VP request coming soon. }); } /** * * @param {string} protocol * @param {object} data * @returns {DigitalCredentialCreateRequest} */ function makeDigitalCredentialCreateRequest(protocol = "protocol", data = {}) { return { protocol, data, }; } /** * Representation of an OpenID4VCI request. * * @returns {DigitalCredentialCreateRequest} **/ function makeOID4VCIDict() { return makeDigitalCredentialCreateRequest("openid4vci", { // Canonical example of an OpenID4VCI request coming soon. }); } /** * Sends a message to an iframe and return the response. * * @param {HTMLIFrameElement} iframe - The iframe element to send the message to. * @param {SendMessageData} data - The data to be sent to the iframe. * @returns {Promise} - A promise that resolves with the response from the iframe. */ export function sendMessage(iframe, data) { return new Promise((resolve, reject) => { if (!iframe.contentWindow) { reject( new Error( "iframe.contentWindow is undefined, cannot send message (something is wrong with the test that called this)." ) ); return; } window.addEventListener("message", function messageListener(event) { if (event.source === iframe.contentWindow) { window.removeEventListener("message", messageListener); resolve(event.data); } }); iframe.contentWindow.postMessage(data, "*"); }); } /** * Load an iframe with the specified URL and wait for it to load. * * @param {HTMLIFrameElement} iframe * @param {string|URL} url * @returns {Promise} */ export function loadIframe(iframe, url) { return new Promise((resolve, reject) => { iframe.addEventListener("load", resolve, { once: true }); iframe.addEventListener("error", reject, { once: true }); if (!iframe.isConnected) { document.body.appendChild(iframe); } iframe.src = url.toString(); }); }