211 lines
7.5 KiB
JavaScript
211 lines
7.5 KiB
JavaScript
// @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<any>} - 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<void>}
|
|
*/
|
|
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();
|
|
});
|
|
}
|