mirror of
https://github.com/mosip/inji-wallet.git
synced 2026-01-08 21:18:14 -05:00
* [INJIMOB-1192] : use wellknown response instead of mimoto issuer config. -- Remove hardcoding for sunbird issuer in vc activation and verification flow. -- Render idType from wellknown response -- Remove UIN/VID from default add-on fields Signed-off-by: Swati Goel <meet2swati@gmail.com> * [INJIMOB-1192] : fix propType and some refactoring Signed-off-by: Swati Goel <meet2swati@gmail.com> * [INJIMOB-1192] : add credentialType in VcMetadata Signed-off-by: Swati Goel <meet2swati@gmail.com> * [INJIMOB-1192] fix vc download via issuer flow due to credentialType mismatch Co-authored-by: PuBHARGAVI <46226958+PuBHARGAVI@users.noreply.github.com> Signed-off-by: KiruthikaJeyashankar <81218987+KiruthikaJeyashankar@users.noreply.github.com> * [INJIMOB-1192] rename supported list of credential type in issuers model Co-authored-by: PuBHARGAVI <46226958+PuBHARGAVI@users.noreply.github.com> Signed-off-by: KiruthikaJeyashankar <81218987+KiruthikaJeyashankar@users.noreply.github.com> * [INJIMOB-1192] display id type in history based on wellknown for issuers VC Signed-off-by: KiruthikaJeyashankar <81218987+KiruthikaJeyashankar@users.noreply.github.com> * [INJIMOB-1192] fix id type not shown for VC activation Signed-off-by: KiruthikaJeyashankar <81218987+KiruthikaJeyashankar@users.noreply.github.com> * [INJIMOB-1192] remove unused credentialType field from VCMetaData Signed-off-by: KiruthikaJeyashankar <81218987+KiruthikaJeyashankar@users.noreply.github.com> * [INJIMOB-1192] set default idType for logging activity Signed-off-by: KiruthikaJeyashankar <81218987+KiruthikaJeyashankar@users.noreply.github.com> * [INJIMOB-1192] move vc item machine events into model Events should not be exported to other packages for direct use so that Xstate's createModel() can decorate the function appropriately Signed-off-by: KiruthikaJeyashankar <81218987+KiruthikaJeyashankar@users.noreply.github.com> * [INJIMOB-1192] show verify banner id type from wellknown Signed-off-by: KiruthikaJeyashankar <81218987+KiruthikaJeyashankar@users.noreply.github.com> * [INJIMOB-1192] refactor duplication and unused code Co-authored-by: PuBHARGAVI <46226958+PuBHARGAVI@users.noreply.github.com> Signed-off-by: KiruthikaJeyashankar <81218987+KiruthikaJeyashankar@users.noreply.github.com> * [INJIMOB-1192] remove unused displayId in metadata Signed-off-by: KiruthikaJeyashankar <81218987+KiruthikaJeyashankar@users.noreply.github.com> * [INJIMOB-1192] revert the dimensions of camera scanner to old values to support face liveness verification Co-authored-by: KiruthikaJeyashankar <81218987+KiruthikaJeyashankar@users.noreply.github.com> Signed-off-by: PuBHARGAVI <46226958+PuBHARGAVI@users.noreply.github.com> * [INJIMOB-1192] remove unused code & debug logs Signed-off-by: KiruthikaJeyashankar <81218987+KiruthikaJeyashankar@users.noreply.github.com> * [INJIMOB-1192] fix failing test cases Co-authored-by: KiruthikaJeyashankar <81218987+KiruthikaJeyashankar@users.noreply.github.com> Signed-off-by: PuBHARGAVI <46226958+PuBHARGAVI@users.noreply.github.com> * [INJIMOB-1192] remove unused translations Signed-off-by: KiruthikaJeyashankar <81218987+KiruthikaJeyashankar@users.noreply.github.com> --------- Signed-off-by: Swati Goel <meet2swati@gmail.com> Signed-off-by: KiruthikaJeyashankar <81218987+KiruthikaJeyashankar@users.noreply.github.com> Signed-off-by: PuBHARGAVI <46226958+PuBHARGAVI@users.noreply.github.com> Co-authored-by: Swati Goel <meet2swati@gmail.com> Co-authored-by: PuBHARGAVI <46226958+PuBHARGAVI@users.noreply.github.com>
646 lines
22 KiB
TypeScript
646 lines
22 KiB
TypeScript
import {AppServices} from '../../../shared/GlobalContext';
|
|
import {VCMetadata} from '../../../shared/VCMetadata';
|
|
import {assign, EventFrom, send} from 'xstate';
|
|
import {log} from 'xstate/lib/actions';
|
|
import {VCItemActions} from './VCItemActions';
|
|
import {VCItemGaurds} from './VCItemGaurds';
|
|
import {VCItemServices} from './VCItemServices';
|
|
import {VCItemModel} from './VCItemModel';
|
|
import {BannerStatusType} from '../../../components/BannerNotification';
|
|
|
|
const machineName = 'vc-item-machine';
|
|
const model = VCItemModel;
|
|
export const VCItemEvents = model.events;
|
|
export const VCItemMachine = model.createMachine(
|
|
{
|
|
predictableActionArguments: true,
|
|
preserveActionOrder: true,
|
|
tsTypes: {} as import('./VCItemMachine.typegen').Typegen0,
|
|
schema: {
|
|
context: model.initialContext,
|
|
events: {} as EventFrom<typeof model>,
|
|
},
|
|
description:
|
|
'This machine is spawned for every VC downloaded, and tracks its lifecycle.',
|
|
id: machineName,
|
|
type: 'parallel',
|
|
states: {
|
|
vcUtilitiesState: {
|
|
on: {
|
|
REFRESH: {
|
|
target: '.loadVc',
|
|
},
|
|
UPDATE_VC_METADATA: {
|
|
actions: 'setVcMetadata',
|
|
},
|
|
},
|
|
initial: 'loadVc',
|
|
states: {
|
|
loadVc: {
|
|
initial: 'loadVcFromContext',
|
|
states: {
|
|
loadVcFromContext: {
|
|
entry: ['requestVcContext'],
|
|
description: 'Fetch the VC data from the Memory.',
|
|
on: {
|
|
GET_VC_RESPONSE: [
|
|
{
|
|
actions: ['setContext'],
|
|
cond: 'hasCredentialAndWellknown',
|
|
target: '.fetchWellknown',
|
|
},
|
|
{
|
|
actions: ['setContext'],
|
|
cond: 'hasCredential',
|
|
target: `#vc-item-machine.vcUtilitiesState.idle`,
|
|
},
|
|
{
|
|
actions: 'addVcToInProgressDownloads',
|
|
target: 'loadVcFromServer',
|
|
},
|
|
],
|
|
TAMPERED_VC: {
|
|
target: '#vc-item-machine.vcUtilitiesState.idle',
|
|
},
|
|
},
|
|
initial: 'idle',
|
|
states: {
|
|
idle: {},
|
|
fetchWellknown: {
|
|
invoke: {
|
|
src: 'fetchIssuerWellknown',
|
|
onDone: {
|
|
actions: 'updateWellknownResponse',
|
|
|
|
target: `#vc-item-machine.vcUtilitiesState.idle`,
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
loadVcFromServer: {
|
|
description:
|
|
"Download VC data from the server. Uses polling method to check when it's available.",
|
|
initial: 'loadDownloadLimitConfig',
|
|
states: {
|
|
loadDownloadLimitConfig: {
|
|
invoke: {
|
|
src: 'loadDownloadLimitConfig',
|
|
onDone: {
|
|
actions: ['setMaxDownloadCount', 'setDownloadInterval'],
|
|
target: 'verifyingDownloadLimitExpiry',
|
|
},
|
|
},
|
|
},
|
|
verifyingDownloadLimitExpiry: {
|
|
entry: ['incrementDownloadCounter'],
|
|
invoke: {
|
|
src: 'checkDownloadExpiryLimit',
|
|
onDone: {
|
|
target: 'checkingStatus',
|
|
},
|
|
onError: {
|
|
actions: [
|
|
log((_, event) => (event.data as Error).message),
|
|
'sendDownloadLimitExpire',
|
|
],
|
|
},
|
|
},
|
|
},
|
|
checkingStatus: {
|
|
invoke: {
|
|
src: 'checkStatus',
|
|
id: 'checkStatus',
|
|
},
|
|
on: {
|
|
POLL: {
|
|
actions: send('POLL_STATUS', {to: 'checkStatus'}),
|
|
},
|
|
DOWNLOAD_READY: {
|
|
target: 'downloadingCredential',
|
|
},
|
|
FAILED: {
|
|
actions: 'sendDownloadLimitExpire',
|
|
},
|
|
},
|
|
},
|
|
downloadingCredential: {
|
|
invoke: {
|
|
src: 'downloadCredential',
|
|
id: 'downloadCredential',
|
|
onError: {
|
|
actions: [
|
|
'sendDownloadingFailedToVcMeta',
|
|
'removeVcFromInProgressDownloads',
|
|
],
|
|
},
|
|
},
|
|
on: {
|
|
POLL: [
|
|
{
|
|
cond: 'isDownloadAllowed',
|
|
actions: [
|
|
send('POLL_DOWNLOAD', {to: 'downloadCredential'}),
|
|
'incrementDownloadCounter',
|
|
],
|
|
},
|
|
{
|
|
target: 'verifyingDownloadLimitExpiry',
|
|
},
|
|
],
|
|
CREDENTIAL_DOWNLOADED: {
|
|
actions: 'setContext',
|
|
target:
|
|
'#vc-item-machine.vcUtilitiesState.verifyingCredential',
|
|
},
|
|
},
|
|
},
|
|
savingFailed: {
|
|
entry: ['removeVcMetaDataFromStorage'],
|
|
initial: 'idle',
|
|
states: {
|
|
idle: {},
|
|
viewingVc: {},
|
|
},
|
|
on: {
|
|
DISMISS: {
|
|
actions: ['removeVcMetaDataFromVcMachineContext'],
|
|
target: '.viewingVc',
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
walletBinding: {
|
|
initial: 'showBindingWarning',
|
|
states: {
|
|
showBindingWarning: {
|
|
on: {
|
|
CONFIRM: {
|
|
actions: 'sendActivationStartEvent',
|
|
target: 'requestingBindingOTP',
|
|
},
|
|
CANCEL: [
|
|
{
|
|
cond: context => context.isMachineInKebabPopupState,
|
|
target: '#vc-item-machine.vcUtilitiesState.kebabPopUp',
|
|
},
|
|
{
|
|
target: '#vc-item-machine.vcUtilitiesState.idle',
|
|
},
|
|
],
|
|
},
|
|
},
|
|
requestingBindingOTP: {
|
|
invoke: {
|
|
src: 'requestBindingOTP',
|
|
onDone: [
|
|
{
|
|
target: 'acceptingBindingOTP',
|
|
actions: ['setCommunicationDetails'],
|
|
},
|
|
],
|
|
onError: [
|
|
{
|
|
actions: [
|
|
'setErrorAsWalletBindingError',
|
|
'sendWalletBindingErrorEvent',
|
|
'logWalletBindingFailure',
|
|
],
|
|
target: 'showingWalletBindingError',
|
|
},
|
|
],
|
|
},
|
|
},
|
|
showingWalletBindingError: {
|
|
on: {
|
|
CANCEL: [
|
|
{
|
|
cond: context => context.isMachineInKebabPopupState,
|
|
actions: ['unSetError'],
|
|
target: '#vc-item-machine.vcUtilitiesState.kebabPopUp',
|
|
},
|
|
{
|
|
actions: ['unSetError'],
|
|
target: '#vc-item-machine.vcUtilitiesState.idle',
|
|
},
|
|
],
|
|
},
|
|
},
|
|
acceptingBindingOTP: {
|
|
entry: ['unSetOTP'],
|
|
on: {
|
|
INPUT_OTP: {
|
|
target: 'addKeyPair',
|
|
actions: ['setOTP'],
|
|
},
|
|
DISMISS: [
|
|
{
|
|
cond: context => context.isMachineInKebabPopupState,
|
|
target: '#vc-item-machine.vcUtilitiesState.kebabPopUp',
|
|
actions: [
|
|
'sendUserCancelledActivationFailedEndEvent',
|
|
'unSetOTP',
|
|
'unSetBindingTransactionId',
|
|
],
|
|
},
|
|
{
|
|
target: '#vc-item-machine.vcUtilitiesState.idle',
|
|
actions: [
|
|
'sendUserCancelledActivationFailedEndEvent',
|
|
'unSetOTP',
|
|
'unSetBindingTransactionId',
|
|
],
|
|
},
|
|
],
|
|
RESEND_OTP: {
|
|
target: '.resendOTP',
|
|
},
|
|
},
|
|
initial: 'idle',
|
|
states: {
|
|
idle: {},
|
|
resendOTP: {
|
|
invoke: {
|
|
src: 'requestBindingOTP',
|
|
onDone: {
|
|
target:
|
|
'#vc-item-machine.vcUtilitiesState.walletBinding.acceptingBindingOTP',
|
|
actions: ['setCommunicationDetails'],
|
|
},
|
|
onError: {
|
|
actions: [
|
|
'setErrorAsWalletBindingError',
|
|
'sendWalletBindingErrorEvent',
|
|
],
|
|
target:
|
|
'#vc-item-machine.vcUtilitiesState.walletBinding.showingWalletBindingError',
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
addKeyPair: {
|
|
invoke: {
|
|
src: 'generateKeyPair',
|
|
onDone: [
|
|
{
|
|
cond: 'isCustomSecureKeystore',
|
|
target: 'addingWalletBindingId',
|
|
actions: ['setPublicKey'],
|
|
},
|
|
{
|
|
target: 'addingWalletBindingId',
|
|
actions: ['setPublicKey', 'setPrivateKey'],
|
|
},
|
|
],
|
|
onError: [
|
|
{
|
|
actions: [
|
|
'setErrorAsWalletBindingError',
|
|
'sendWalletBindingErrorEvent',
|
|
'logWalletBindingFailure',
|
|
],
|
|
target: 'showingWalletBindingError',
|
|
},
|
|
],
|
|
},
|
|
},
|
|
addingWalletBindingId: {
|
|
invoke: {
|
|
src: 'addWalletBindingId',
|
|
onDone: [
|
|
{
|
|
cond: 'isCustomSecureKeystore',
|
|
target: 'updatingContextVariables',
|
|
actions: ['setWalletBindingResponse'],
|
|
},
|
|
{
|
|
target: 'updatingPrivateKey',
|
|
/*The walletBindingResponse is used for conditional rendering in wallet binding. response and use it in updatingPrivateKey state*/
|
|
actions: ['setWalletBindingResponse'],
|
|
},
|
|
],
|
|
onError: [
|
|
{
|
|
actions: [
|
|
'setErrorAsWalletBindingError',
|
|
'sendWalletBindingErrorEvent',
|
|
'logWalletBindingFailure',
|
|
],
|
|
target: 'showingWalletBindingError',
|
|
},
|
|
],
|
|
},
|
|
},
|
|
|
|
updatingPrivateKey: {
|
|
invoke: {
|
|
src: 'updatePrivateKey',
|
|
onDone: {
|
|
target: 'updatingContextVariables',
|
|
},
|
|
onError: {
|
|
actions: [
|
|
'setErrorAsWalletBindingError',
|
|
'sendWalletBindingErrorEvent',
|
|
'logWalletBindingFailure',
|
|
],
|
|
target: 'showingWalletBindingError',
|
|
},
|
|
},
|
|
},
|
|
updatingContextVariables: {
|
|
entry: [
|
|
'setThumbprintForWalletBindingId',
|
|
'storeContext',
|
|
'resetPrivateKey',
|
|
'storeVcInContext',
|
|
'unSetError',
|
|
'sendActivationSuccessEvent',
|
|
'logWalletBindingSuccess',
|
|
send('SHOW_BINDING_STATUS'),
|
|
],
|
|
on: {
|
|
SHOW_BINDING_STATUS: [
|
|
{
|
|
cond: context => context.isMachineInKebabPopupState,
|
|
actions: 'sendWalletBindingSuccess',
|
|
target: '#vc-item-machine.vcUtilitiesState.kebabPopUp',
|
|
},
|
|
{
|
|
actions: 'sendWalletBindingSuccess',
|
|
target: '#vc-item-machine.vcUtilitiesState.idle',
|
|
},
|
|
],
|
|
},
|
|
},
|
|
},
|
|
},
|
|
kebabPopUp: {
|
|
entry: assign({isMachineInKebabPopupState: () => true}),
|
|
exit: 'resetIsMachineInKebabPopupState',
|
|
on: {
|
|
DISMISS: {
|
|
target: '#vc-item-machine.vcUtilitiesState.idle',
|
|
},
|
|
ADD_WALLET_BINDING_ID: {
|
|
target: '#vc-item-machine.vcUtilitiesState.walletBinding',
|
|
},
|
|
PIN_CARD: {
|
|
target: '.pinCard',
|
|
actions: 'setPinCard',
|
|
},
|
|
SHOW_ACTIVITY: {
|
|
target:
|
|
'#vc-item-machine.vcUtilitiesState.kebabPopUp.showActivities',
|
|
},
|
|
REMOVE: {
|
|
actions: 'setVcKey',
|
|
target:
|
|
'#vc-item-machine.vcUtilitiesState.kebabPopUp.removeWallet',
|
|
},
|
|
CLOSE_VC_MODAL: {
|
|
actions: ['closeViewVcModal'],
|
|
target: '#vc-item-machine.vcUtilitiesState.idle',
|
|
},
|
|
},
|
|
initial: 'idle',
|
|
states: {
|
|
idle: {},
|
|
pinCard: {
|
|
entry: 'updateVcMetadata',
|
|
always: {
|
|
target: '#vc-item-machine.vcUtilitiesState.idle',
|
|
},
|
|
},
|
|
showActivities: {
|
|
entry: 'resetIsMachineInKebabPopupState',
|
|
on: {
|
|
DISMISS: '#vc-item-machine.vcUtilitiesState.idle',
|
|
},
|
|
},
|
|
removeWallet: {
|
|
entry: 'resetIsMachineInKebabPopupState',
|
|
on: {
|
|
CONFIRM: {
|
|
target: 'removingVc',
|
|
},
|
|
CANCEL: {
|
|
target: '#vc-item-machine.vcUtilitiesState.idle',
|
|
},
|
|
},
|
|
},
|
|
removingVc: {
|
|
entry: 'removeVcItem',
|
|
on: {
|
|
STORE_RESPONSE: {
|
|
actions: [
|
|
'closeViewVcModal',
|
|
'refreshAllVcs',
|
|
'logRemovedVc',
|
|
],
|
|
target: 'triggerAutoBackup',
|
|
},
|
|
},
|
|
},
|
|
triggerAutoBackup: {
|
|
invoke: {
|
|
src: 'isUserSignedAlready',
|
|
onDone: [
|
|
{
|
|
cond: 'isSignedIn',
|
|
actions: [
|
|
'sendBackupEvent',
|
|
'refreshAllVcs',
|
|
'logRemovedVc',
|
|
],
|
|
target: '#vc-item-machine.vcUtilitiesState.idle',
|
|
},
|
|
{
|
|
actions: ['refreshAllVcs', 'logRemovedVc'],
|
|
target: '#vc-item-machine.vcUtilitiesState.idle',
|
|
},
|
|
],
|
|
},
|
|
},
|
|
},
|
|
},
|
|
verifyingCredential: {
|
|
invoke: {
|
|
src: 'verifyCredential',
|
|
onDone: {
|
|
actions: ['setIsVerified', 'storeContext'],
|
|
},
|
|
onError: [
|
|
{
|
|
cond: 'isVerificationPendingBecauseOfNetworkIssue',
|
|
actions: ['resetIsVerified', 'storeContext'],
|
|
},
|
|
{
|
|
actions: ['setErrorAsVerificationError'],
|
|
target: '.handleVCVerificationFailure',
|
|
},
|
|
],
|
|
},
|
|
on: {
|
|
STORE_RESPONSE: {
|
|
actions: [
|
|
'storeVcInContext',
|
|
'updateVcMetadata',
|
|
'logDownloaded',
|
|
'sendTelemetryEvents',
|
|
'removeVcFromInProgressDownloads',
|
|
],
|
|
target: '.triggerAutoBackupForVcDownload',
|
|
},
|
|
STORE_ERROR: {
|
|
target:
|
|
'#vc-item-machine.vcUtilitiesState.loadVc.loadVcFromServer.savingFailed',
|
|
},
|
|
},
|
|
initial: 'idle',
|
|
states: {
|
|
idle: {},
|
|
triggerAutoBackupForVcDownload: {
|
|
invoke: {
|
|
src: 'isUserSignedAlready',
|
|
onDone: [
|
|
{
|
|
cond: 'isSignedIn',
|
|
actions: ['sendBackupEvent'],
|
|
target: `#vc-item-machine.vcUtilitiesState.idle`,
|
|
},
|
|
{
|
|
target: `#vc-item-machine.vcUtilitiesState.idle`,
|
|
},
|
|
],
|
|
},
|
|
},
|
|
handleVCVerificationFailure: {
|
|
entry: [
|
|
'removeVcMetaDataFromStorage',
|
|
'removeVcFromInProgressDownloads',
|
|
],
|
|
on: {
|
|
STORE_RESPONSE: {
|
|
actions: ['sendVerificationError'],
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
idle: {
|
|
on: {
|
|
DISMISS: {
|
|
target:
|
|
'#vc-item-machine.vcUtilitiesState.loadVc.loadVcFromContext',
|
|
},
|
|
KEBAB_POPUP: {
|
|
target: 'kebabPopUp',
|
|
},
|
|
ADD_WALLET_BINDING_ID: {
|
|
target: '#vc-item-machine.vcUtilitiesState.walletBinding',
|
|
},
|
|
PIN_CARD: {
|
|
target: '#vc-item-machine.vcUtilitiesState.kebabPopUp.pinCard',
|
|
actions: 'setPinCard',
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
verifyState: {
|
|
on: {
|
|
VERIFY: {
|
|
target: '#vc-item-machine.verifyState.verifyingCredential',
|
|
},
|
|
RESET_VERIFICATION_STATUS: {
|
|
actions: [
|
|
'resetVerificationStatus',
|
|
'removeVerificationStatusFromVcMeta',
|
|
],
|
|
},
|
|
},
|
|
initial: 'idle',
|
|
states: {
|
|
idle: {},
|
|
verifyingCredential: {
|
|
entry: send({
|
|
type: 'SET_VERIFICATION_STATUS',
|
|
response: {statusType: BannerStatusType.IN_PROGRESS},
|
|
}),
|
|
|
|
invoke: {
|
|
src: 'verifyCredential',
|
|
onDone: {
|
|
actions: ['setIsVerified', 'storeContext'],
|
|
},
|
|
onError: [
|
|
{
|
|
cond: 'isVerificationPendingBecauseOfNetworkIssue',
|
|
actions: ['resetIsVerified', 'storeContext'],
|
|
},
|
|
],
|
|
},
|
|
after: {
|
|
500: [
|
|
{
|
|
actions: 'showVerificationBannerStatus',
|
|
},
|
|
],
|
|
},
|
|
on: {
|
|
STORE_RESPONSE: {
|
|
actions: [
|
|
'setVerificationStatus',
|
|
'sendVerificationStatusToVcMeta',
|
|
'updateVcMetadata',
|
|
],
|
|
target: 'verificationCompleted',
|
|
},
|
|
SET_VERIFICATION_STATUS: {
|
|
actions: 'setVerificationStatus',
|
|
},
|
|
SHOW_VERIFICATION_STATUS_BANNER: {
|
|
actions: [
|
|
'setVerificationStatus',
|
|
'showVerificationBannerStatus',
|
|
],
|
|
},
|
|
//TO-DO: Handle if some error is thrown when storing verified status into storage
|
|
STORE_ERROR: {},
|
|
},
|
|
},
|
|
verificationCompleted: {
|
|
entry: 'showVerificationBannerStatus',
|
|
on: {
|
|
REMOVE_VERIFICATION_STATUS_BANNER: {
|
|
actions: 'resetVerificationStatus',
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
{
|
|
actions: VCItemActions(model),
|
|
services: VCItemServices(model),
|
|
guards: VCItemGaurds(),
|
|
},
|
|
);
|
|
|
|
export const createVCItemMachine = (
|
|
serviceRefs: AppServices,
|
|
vcMetadata: VCMetadata,
|
|
) => {
|
|
return VCItemMachine.withContext({
|
|
...VCItemMachine.context,
|
|
serviceRefs,
|
|
vcMetadata,
|
|
});
|
|
};
|