@sphereon/ssi-sdk.oid4vci-holder 0.32.1-next.20 → 0.32.1-next.291

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (68) hide show
  1. package/dist/agent/OID4VCIHolder.d.ts +1 -0
  2. package/dist/agent/OID4VCIHolder.d.ts.map +1 -1
  3. package/dist/agent/OID4VCIHolder.js +38 -24
  4. package/dist/agent/OID4VCIHolder.js.map +1 -1
  5. package/dist/index.d.ts +5 -2
  6. package/dist/index.d.ts.map +1 -1
  7. package/dist/index.js +5 -2
  8. package/dist/index.js.map +1 -1
  9. package/dist/link-handler/index.d.ts +3 -2
  10. package/dist/link-handler/index.d.ts.map +1 -1
  11. package/dist/link-handler/index.js +2 -1
  12. package/dist/link-handler/index.js.map +1 -1
  13. package/dist/listeners/headlessStateNavListener.d.ts.map +1 -0
  14. package/dist/listeners/headlessStateNavListener.js.map +1 -0
  15. package/dist/localization/translations/en.json +5 -1
  16. package/dist/localization/translations/nl.json +5 -1
  17. package/dist/machines/firstPartyMachine.d.ts +15 -0
  18. package/dist/machines/firstPartyMachine.d.ts.map +1 -0
  19. package/dist/machines/firstPartyMachine.js +222 -0
  20. package/dist/machines/firstPartyMachine.js.map +1 -0
  21. package/dist/machines/oid4vciMachine.d.ts.map +1 -0
  22. package/dist/{machine → machines}/oid4vciMachine.js +58 -2
  23. package/dist/machines/oid4vciMachine.js.map +1 -0
  24. package/dist/mappers/OIDC4VCIBrandingMapper.d.ts.map +1 -0
  25. package/dist/{agent → mappers}/OIDC4VCIBrandingMapper.js +1 -1
  26. package/dist/mappers/OIDC4VCIBrandingMapper.js.map +1 -0
  27. package/dist/services/FirstPartyMachineServices.d.ts +9 -0
  28. package/dist/services/FirstPartyMachineServices.d.ts.map +1 -0
  29. package/dist/services/FirstPartyMachineServices.js +53 -0
  30. package/dist/services/FirstPartyMachineServices.js.map +1 -0
  31. package/dist/{agent → services}/OID4VCIHolderService.d.ts +3 -2
  32. package/dist/services/OID4VCIHolderService.d.ts.map +1 -0
  33. package/dist/{agent → services}/OID4VCIHolderService.js +49 -4
  34. package/dist/services/OID4VCIHolderService.js.map +1 -0
  35. package/dist/types/FirstPartyMachine.d.ts +112 -0
  36. package/dist/types/FirstPartyMachine.d.ts.map +1 -0
  37. package/dist/types/FirstPartyMachine.js +30 -0
  38. package/dist/types/FirstPartyMachine.js.map +1 -0
  39. package/dist/types/IOID4VCIHolder.d.ts +26 -15
  40. package/dist/types/IOID4VCIHolder.d.ts.map +1 -1
  41. package/dist/types/IOID4VCIHolder.js +3 -1
  42. package/dist/types/IOID4VCIHolder.js.map +1 -1
  43. package/package.json +26 -22
  44. package/src/agent/OID4VCIHolder.ts +48 -23
  45. package/src/index.ts +5 -2
  46. package/src/link-handler/index.ts +10 -5
  47. package/src/localization/translations/en.json +5 -1
  48. package/src/localization/translations/nl.json +5 -1
  49. package/src/machines/firstPartyMachine.ts +278 -0
  50. package/src/{machine → machines}/oid4vciMachine.ts +62 -3
  51. package/src/{agent → mappers}/OIDC4VCIBrandingMapper.ts +26 -25
  52. package/src/services/FirstPartyMachineServices.ts +64 -0
  53. package/src/{agent → services}/OID4VCIHolderService.ts +58 -10
  54. package/src/types/FirstPartyMachine.ts +161 -0
  55. package/src/types/IOID4VCIHolder.ts +52 -39
  56. package/dist/agent/OID4VCIHolderService.d.ts.map +0 -1
  57. package/dist/agent/OID4VCIHolderService.js.map +0 -1
  58. package/dist/agent/OIDC4VCIBrandingMapper.d.ts.map +0 -1
  59. package/dist/agent/OIDC4VCIBrandingMapper.js.map +0 -1
  60. package/dist/machine/headlessStateNavListener.d.ts.map +0 -1
  61. package/dist/machine/headlessStateNavListener.js.map +0 -1
  62. package/dist/machine/oid4vciMachine.d.ts.map +0 -1
  63. package/dist/machine/oid4vciMachine.js.map +0 -1
  64. /package/dist/{machine → listeners}/headlessStateNavListener.d.ts +0 -0
  65. /package/dist/{machine → listeners}/headlessStateNavListener.js +0 -0
  66. /package/dist/{machine → machines}/oid4vciMachine.d.ts +0 -0
  67. /package/dist/{agent → mappers}/OIDC4VCIBrandingMapper.d.ts +0 -0
  68. /package/src/{machine → listeners}/headlessStateNavListener.ts +0 -0
@@ -4,6 +4,8 @@ import {
4
4
  AuthorizationRequestOpts,
5
5
  AuthorizationServerClientOpts,
6
6
  AuthorizationServerOpts,
7
+ CredentialConfigurationSupportedJwtVcJsonLdAndLdpVcV1_0_13,
8
+ CredentialDefinitionJwtVcJsonLdAndLdpVcV1_0_13,
7
9
  CredentialOfferRequestWithBaseUrl,
8
10
  DefaultURISchemes,
9
11
  EndpointMetadataResult,
@@ -45,7 +47,7 @@ import {
45
47
  } from '@sphereon/ssi-sdk.data-store'
46
48
  import {
47
49
  CredentialMapper,
48
- Hasher,
50
+ HasherSync,
49
51
  IVerifiableCredential,
50
52
  JoseSignatureAlgorithm,
51
53
  JoseSignatureAlgorithmString,
@@ -70,12 +72,12 @@ import {
70
72
  import { asArray, computeEntryHash } from '@veramo/utils'
71
73
  import { decodeJWT } from 'did-jwt'
72
74
  import { v4 as uuidv4 } from 'uuid'
73
- import { OID4VCIMachine } from '../machine/oid4vciMachine'
75
+ import { OID4VCIMachine } from '../machines/oid4vciMachine'
74
76
  import {
75
77
  AddContactIdentityArgs,
76
78
  AssertValidCredentialsArgs,
77
79
  Attribute,
78
- createCredentialsToSelectFromArgs,
80
+ CreateCredentialsToSelectFromArgs,
79
81
  CredentialToAccept,
80
82
  CredentialToSelectFromResult,
81
83
  GetContactArgs,
@@ -91,6 +93,8 @@ import {
91
93
  OID4VCIHolderOptions,
92
94
  OID4VCIMachine as OID4VCIMachineId,
93
95
  OID4VCIMachineInstanceOpts,
96
+ OID4VCIMachineServiceDefinitions,
97
+ OID4VCIMachineServices,
94
98
  OnContactIdentityCreatedArgs,
95
99
  OnCredentialStoredArgs,
96
100
  OnIdentifierCreatedArgs,
@@ -98,6 +102,7 @@ import {
98
102
  RequestType,
99
103
  RequiredContext,
100
104
  SendNotificationArgs,
105
+ StartFirstPartApplicationMachine,
101
106
  StartResult,
102
107
  StoreCredentialBrandingArgs,
103
108
  StoreCredentialsArgs,
@@ -114,10 +119,11 @@ import {
114
119
  getIssuanceOpts,
115
120
  mapCredentialToAccept,
116
121
  selectCredentialLocaleBranding,
122
+ startFirstPartApplicationMachine,
117
123
  verifyCredentialToAccept,
118
- } from './OID4VCIHolderService'
119
-
124
+ } from '../services/OID4VCIHolderService'
120
125
  import 'cross-fetch/polyfill'
126
+ import { defaultHasher } from '@sphereon/ssi-sdk.core'
121
127
 
122
128
  /**
123
129
  * {@inheritDoc IOID4VCIHolder}
@@ -199,7 +205,7 @@ export async function verifyEBSICredentialIssuer(args: VerifyEBSICredentialIssue
199
205
  }
200
206
 
201
207
  export class OID4VCIHolder implements IAgentPlugin {
202
- private readonly hasher?: Hasher
208
+ private readonly hasher?: HasherSync
203
209
  readonly eventTypes: Array<OID4VCIHolderEvent> = [
204
210
  OID4VCIHolderEvent.CONTACT_IDENTITY_CREATED,
205
211
  OID4VCIHolderEvent.CREDENTIAL_STORED,
@@ -261,7 +267,7 @@ export class OID4VCIHolder implements IAgentPlugin {
261
267
  didMethodPreferences,
262
268
  jwtCryptographicSuitePreferences,
263
269
  defaultAuthorizationRequestOptions,
264
- hasher,
270
+ hasher = defaultHasher,
265
271
  } = { ...options }
266
272
 
267
273
  this.hasher = hasher
@@ -307,8 +313,8 @@ export class OID4VCIHolder implements IAgentPlugin {
307
313
  */
308
314
  private async oid4vciHolderGetMachineInterpreter(opts: OID4VCIMachineInstanceOpts, context: RequiredContext): Promise<OID4VCIMachineId> {
309
315
  const authorizationRequestOpts = { ...this.defaultAuthorizationRequestOpts, ...opts.authorizationRequestOpts }
310
- const services = {
311
- start: (args: PrepareStartArgs) =>
316
+ const services: OID4VCIMachineServiceDefinitions = {
317
+ [OID4VCIMachineServices.start]: (args: PrepareStartArgs) =>
312
318
  this.oid4vciHolderStart(
313
319
  {
314
320
  ...args,
@@ -316,18 +322,22 @@ export class OID4VCIHolder implements IAgentPlugin {
316
322
  },
317
323
  context,
318
324
  ),
319
- createCredentialsToSelectFrom: (args: createCredentialsToSelectFromArgs) => this.oid4vciHolderCreateCredentialsToSelectFrom(args, context),
320
- getContact: (args: GetContactArgs) => this.oid4vciHolderGetContact(args, context),
321
- getCredentials: (args: GetCredentialsArgs) =>
325
+ [OID4VCIMachineServices.startFirstPartApplicationFlow]: (args: StartFirstPartApplicationMachine) =>
326
+ startFirstPartApplicationMachine({ ...args, stateNavigationListener: opts.firstPartyStateNavigationListener }, context),
327
+ [OID4VCIMachineServices.createCredentialsToSelectFrom]: (args: CreateCredentialsToSelectFromArgs) =>
328
+ this.oid4vciHolderCreateCredentialsToSelectFrom(args, context),
329
+ [OID4VCIMachineServices.getContact]: (args: GetContactArgs) => this.oid4vciHolderGetContact(args, context),
330
+ [OID4VCIMachineServices.getCredentials]: (args: GetCredentialsArgs) =>
322
331
  this.oid4vciHolderGetCredentials({ accessTokenOpts: args.accessTokenOpts ?? opts.accessTokenOpts, ...args }, context),
323
- addContactIdentity: (args: AddContactIdentityArgs) => this.oid4vciHolderAddContactIdentity(args, context),
324
- getIssuerBranding: (args: GetIssuerBrandingArgs) => this.oid4vciHolderGetIssuerBranding(args, context),
325
- storeIssuerBranding: (args: StoreIssuerBrandingArgs) => this.oid4vciHolderStoreIssuerBranding(args, context),
326
- assertValidCredentials: (args: AssertValidCredentialsArgs) => this.oid4vciHolderAssertValidCredentials(args, context),
327
- storeCredentialBranding: (args: StoreCredentialBrandingArgs) => this.oid4vciHolderStoreCredentialBranding(args, context),
328
- storeCredentials: (args: StoreCredentialsArgs) => this.oid4vciHolderStoreCredentials(args, context),
329
- sendNotification: (args: SendNotificationArgs) => this.oid4vciHolderSendNotification(args, context),
330
- getFederationTrust: (args: GetFederationTrustArgs) => this.getFederationTrust(args, context),
332
+ [OID4VCIMachineServices.addContactIdentity]: (args: AddContactIdentityArgs) => this.oid4vciHolderAddContactIdentity(args, context),
333
+ [OID4VCIMachineServices.getIssuerBranding]: (args: GetIssuerBrandingArgs) => this.oid4vciHolderGetIssuerBranding(args, context),
334
+ [OID4VCIMachineServices.storeIssuerBranding]: (args: StoreIssuerBrandingArgs) => this.oid4vciHolderStoreIssuerBranding(args, context),
335
+ [OID4VCIMachineServices.assertValidCredentials]: (args: AssertValidCredentialsArgs) => this.oid4vciHolderAssertValidCredentials(args, context),
336
+ [OID4VCIMachineServices.storeCredentialBranding]: (args: StoreCredentialBrandingArgs) =>
337
+ this.oid4vciHolderStoreCredentialBranding(args, context),
338
+ [OID4VCIMachineServices.storeCredentials]: (args: StoreCredentialsArgs) => this.oid4vciHolderStoreCredentials(args, context),
339
+ [OID4VCIMachineServices.sendNotification]: (args: SendNotificationArgs) => this.oid4vciHolderSendNotification(args, context),
340
+ [OID4VCIMachineServices.getFederationTrust]: (args: GetFederationTrustArgs) => this.getFederationTrust(args, context),
331
341
  }
332
342
 
333
343
  const oid4vciMachineInstanceArgs: OID4VCIMachineInstanceOpts = {
@@ -463,7 +473,7 @@ export class OID4VCIHolder implements IAgentPlugin {
463
473
  }
464
474
 
465
475
  private async oid4vciHolderCreateCredentialsToSelectFrom(
466
- args: createCredentialsToSelectFromArgs,
476
+ args: CreateCredentialsToSelectFromArgs,
467
477
  context: RequiredContext,
468
478
  ): Promise<Array<CredentialToSelectFromResult>> {
469
479
  const { credentialBranding, locale, selectedCredentials /*, openID4VCIClientState*/, credentialsSupported } = args
@@ -629,7 +639,7 @@ export class OID4VCIHolder implements IAgentPlugin {
629
639
  // The VCI lib either expects a jwk or a kid
630
640
  const jwk = isManagedIdentifierJwkResult(identifier) ? identifier.jwk : undefined
631
641
 
632
- const callbacks: ProofOfPossessionCallbacks<never> = {
642
+ const callbacks: ProofOfPossessionCallbacks = {
633
643
  signCallback: signCallback(identifier, context),
634
644
  }
635
645
 
@@ -675,7 +685,10 @@ export class OID4VCIHolder implements IAgentPlugin {
675
685
  if (!credentialTypes || credentialTypes.length === 0) {
676
686
  return Promise.reject(Error('cannot determine credential id to request'))
677
687
  }
688
+
689
+ const credentialDefinition = this.getCredentialDefinition(issuanceOpt)
678
690
  const credentialResponse = await client.acquireCredentials({
691
+ ...(credentialDefinition && { context: credentialDefinition['@context'] }),
679
692
  credentialTypes,
680
693
  proofCallbacks: callbacks,
681
694
  format: issuanceOpt.format,
@@ -908,7 +921,7 @@ export class OID4VCIHolder implements IAgentPlugin {
908
921
  : 'credential_deleted_holder_signed'
909
922
  logger.log(`Subject issuance/signing will be used, with event`, event)
910
923
  const issuerVC = mappedCredentialToAccept.credentialToAccept.credentialResponse.credential as OriginalVerifiableCredential
911
- const wrappedIssuerVC = CredentialMapper.toWrappedVerifiableCredential(issuerVC, { hasher: this.hasher })
924
+ const wrappedIssuerVC = CredentialMapper.toWrappedVerifiableCredential(issuerVC, { hasher: this.hasher ?? defaultHasher })
912
925
  console.log(`Wrapped VC: ${wrappedIssuerVC.type}, ${wrappedIssuerVC.format}`)
913
926
  // We will use the subject of the VCI Issuer (the holder, as the issuer of the new credential, so the below is not a mistake!)
914
927
 
@@ -1075,6 +1088,11 @@ export class OID4VCIHolder implements IAgentPlugin {
1075
1088
  const params = new URLSearchParams(url.search)
1076
1089
  const openidFederation = params.get('openid_federation')
1077
1090
  const entityIdentifier = openidFederation ?? serverMetadata.issuer
1091
+ if (entityIdentifier.startsWith('http://')) {
1092
+ console.warn(`OpenID federation does not support http://, only https:// allowed; got: (${url.toString()})`)
1093
+ // OIDF always needs to be https
1094
+ return []
1095
+ }
1078
1096
 
1079
1097
  const result = await context.agent.identifierExternalResolveByOIDFEntityId({
1080
1098
  method: 'entity_id',
@@ -1127,4 +1145,11 @@ export class OID4VCIHolder implements IAgentPlugin {
1127
1145
  }
1128
1146
  return undefined
1129
1147
  }
1148
+
1149
+ private getCredentialDefinition(issuanceOpt: IssuanceOpts): CredentialDefinitionJwtVcJsonLdAndLdpVcV1_0_13 | undefined {
1150
+ if (issuanceOpt.format == 'ldp_vc' || issuanceOpt.format == 'jwt_vc_json-ld') {
1151
+ return (issuanceOpt as CredentialConfigurationSupportedJwtVcJsonLdAndLdpVcV1_0_13).credential_definition
1152
+ }
1153
+ return undefined
1154
+ }
1130
1155
  }
package/src/index.ts CHANGED
@@ -3,7 +3,10 @@
3
3
  */
4
4
 
5
5
  export { OID4VCIHolder, oid4vciHolderContextMethods, signCallback } from './agent/OID4VCIHolder'
6
- export * from './agent/OID4VCIHolderService'
6
+ export * from './mappers/OIDC4VCIBrandingMapper'
7
+ export * from './services/OID4VCIHolderService'
8
+ export * from './services/FirstPartyMachineServices'
7
9
  export * from './types/IOID4VCIHolder'
8
- export * from './machine/headlessStateNavListener'
10
+ export * from './types/FirstPartyMachine'
11
+ export * from './listeners/headlessStateNavListener'
9
12
  export * from './link-handler'
@@ -3,23 +3,26 @@ import { AuthorizationRequestOpts, AuthorizationServerClientOpts, AuthzFlowType,
3
3
  import { DefaultLinkPriorities, LinkHandlerAdapter } from '@sphereon/ssi-sdk.core'
4
4
  import { IMachineStatePersistence, interpreterStartOrResume, SerializableState } from '@sphereon/ssi-sdk.xstate-machine-persistence'
5
5
  import { IAgentContext } from '@veramo/core'
6
- import { GetMachineArgs, IOID4VCIHolder, OID4VCIMachineEvents, OID4VCIMachineInterpreter, OID4VCIMachineState } from '../types/IOID4VCIHolder'
6
+ import { GetMachineArgs, IOID4VCIHolder, OID4VCIMachineEvents, OID4VCIMachineStateNavigationListener } from '../types/IOID4VCIHolder'
7
+ import { FirstPartyMachineStateNavigationListener } from '../types/FirstPartyMachine'
7
8
 
8
9
  /**
9
10
  * This handler only handles credential offer links (either by value or by reference)
10
11
  */
11
12
  export class OID4VCIHolderLinkHandler extends LinkHandlerAdapter {
12
13
  private readonly context: IAgentContext<IOID4VCIHolder & IMachineStatePersistence>
13
- private readonly stateNavigationListener:
14
- | ((oid4vciMachine: OID4VCIMachineInterpreter, state: OID4VCIMachineState, navigation?: any) => Promise<void>)
15
- | undefined
14
+ private readonly stateNavigationListener?: OID4VCIMachineStateNavigationListener
15
+ private readonly firstPartyStateNavigationListener?: FirstPartyMachineStateNavigationListener
16
16
  private readonly noStateMachinePersistence: boolean
17
17
  private readonly authorizationRequestOpts?: AuthorizationRequestOpts
18
18
  private readonly clientOpts?: AuthorizationServerClientOpts
19
19
  private readonly trustAnchors?: Array<string>
20
20
 
21
21
  constructor(
22
- args: Pick<GetMachineArgs, 'stateNavigationListener' | 'authorizationRequestOpts' | 'clientOpts' | 'trustAnchors'> & {
22
+ args: Pick<
23
+ GetMachineArgs,
24
+ 'stateNavigationListener' | 'authorizationRequestOpts' | 'clientOpts' | 'trustAnchors' | 'firstPartyStateNavigationListener'
25
+ > & {
23
26
  priority?: number | DefaultLinkPriorities
24
27
  protocols?: Array<string | RegExp>
25
28
  noStateMachinePersistence?: boolean
@@ -32,6 +35,7 @@ export class OID4VCIHolderLinkHandler extends LinkHandlerAdapter {
32
35
  this.context = args.context
33
36
  this.noStateMachinePersistence = args.noStateMachinePersistence === true
34
37
  this.stateNavigationListener = args.stateNavigationListener
38
+ this.firstPartyStateNavigationListener = args.firstPartyStateNavigationListener
35
39
  this.trustAnchors = args.trustAnchors
36
40
  }
37
41
 
@@ -63,6 +67,7 @@ export class OID4VCIHolderLinkHandler extends LinkHandlerAdapter {
63
67
  authorizationRequestOpts: { ...this.authorizationRequestOpts, ...opts?.authorizationRequestOpts },
64
68
  ...((clientOpts.clientId || clientOpts.clientAssertionType) && { clientOpts: clientOpts as AuthorizationServerClientOpts }),
65
69
  stateNavigationListener: this.stateNavigationListener,
70
+ firstPartyStateNavigationListener: this.firstPartyStateNavigationListener,
66
71
  })
67
72
 
68
73
  const interpreter = oid4vciMachine.interpreter
@@ -11,5 +11,9 @@
11
11
  "oid4vci_machine_initiation_error_title": "Initiate OID4VCI provider",
12
12
  "oid4vci_machine_credential_verification_failed_message": "The credential verification resulted in an error.",
13
13
  "oid4vci_machine_credential_verification_schema_failed_message": "The credential schema verification resulted in an error.",
14
- "oid4vci_machine_retrieve_federation_trust_error_title": "Retrieve federation trust"
14
+ "oid4vci_machine_retrieve_federation_trust_error_title": "Retrieve federation trust",
15
+ "oid4vci_machine_first_party_error_title": "First party flow",
16
+ "oid4vci_machine_send_authorization_challenge_request_error_title": "Sending authorization challenge request",
17
+ "oid4vci_machine_create_config_error_title": "Creating siopV2 config",
18
+ "oid4vci_machine_get_request_error_title": "Getting siopV2 request"
15
19
  }
@@ -10,5 +10,9 @@
10
10
  "oid4vci_machine_credential_selection_error_title": "Credential selectie",
11
11
  "oid4vci_machine_initiation_error_title": "Initiëren OID4VCI provider",
12
12
  "oid4vci_machine_credential_verification_failed_message": "Verificatie van de credential leidde tot een fout.",
13
- "oid4vci_machine_retrieve_federation_trust_error_title": "Ophalen federatievertrouwen"
13
+ "oid4vci_machine_retrieve_federation_trust_error_title": "Ophalen federatievertrouwen",
14
+ "oid4vci_machine_first_party_error_title": "Eerste partijstroom",
15
+ "oid4vci_machine_send_authorization_challenge_request_error_title": "Versturen autorisatie-uitdaging aanvraag",
16
+ "oid4vci_machine_create_config_error_title": "SiopV2-configuratie aanmaken",
17
+ "oid4vci_machine_get_request_error_title": "SiopV2-verzoek ophalen"
14
18
  }
@@ -0,0 +1,278 @@
1
+ import { assign, createMachine, DoneInvokeEvent, interpret } from 'xstate'
2
+ import { AuthorizationChallengeCodeResponse, AuthorizationChallengeError, AuthorizationChallengeErrorResponse } from '@sphereon/oid4vci-common'
3
+ import { DidAuthConfig } from '@sphereon/ssi-sdk.data-store'
4
+ import { CreateConfigResult } from '@sphereon/ssi-sdk.siopv2-oid4vp-op-auth'
5
+ import { createConfig, getSiopRequest, sendAuthorizationChallengeRequest, sendAuthorizationResponse } from '../services/FirstPartyMachineServices'
6
+ import { translate } from '../localization/Localization'
7
+ import { ErrorDetails } from '../types/IOID4VCIHolder'
8
+ import {
9
+ CreateConfigArgs,
10
+ CreateFirstPartyMachineOpts,
11
+ FirstPartyMachineContext,
12
+ FirstPartyMachineEvents,
13
+ FirstPartyMachineEventTypes,
14
+ FirstPartyMachineInterpreter,
15
+ FirstPartyMachineServices,
16
+ FirstPartyMachineState,
17
+ FirstPartyMachineStatesConfig,
18
+ FirstPartyMachineStateTypes,
19
+ FirstPartyMachineServiceDefinitions,
20
+ FirstPartyStateMachine,
21
+ GetSiopRequestArgs,
22
+ InstanceFirstPartyMachineOpts,
23
+ SiopV2AuthorizationRequestData,
24
+ SendAuthorizationResponseArgs,
25
+ FirstPartySelectCredentialsEvent,
26
+ } from '../types/FirstPartyMachine'
27
+
28
+ const firstPartyMachineStates: FirstPartyMachineStatesConfig = {
29
+ [FirstPartyMachineStateTypes.sendAuthorizationChallengeRequest]: {
30
+ id: FirstPartyMachineStateTypes.sendAuthorizationChallengeRequest,
31
+ invoke: {
32
+ src: FirstPartyMachineServices.sendAuthorizationChallengeRequest,
33
+ onDone: {
34
+ target: FirstPartyMachineStateTypes.done,
35
+ actions: assign({
36
+ authorizationCodeResponse: (_ctx: FirstPartyMachineContext, _event: DoneInvokeEvent<AuthorizationChallengeCodeResponse>) => _event.data,
37
+ }),
38
+ },
39
+ onError: [
40
+ {
41
+ target: FirstPartyMachineStateTypes.createConfig,
42
+ cond: (_ctx: FirstPartyMachineContext, _event: DoneInvokeEvent<AuthorizationChallengeErrorResponse>): boolean =>
43
+ _event.data.error === AuthorizationChallengeError.insufficient_authorization,
44
+ actions: assign({
45
+ authSession: (_ctx: FirstPartyMachineContext, _event: DoneInvokeEvent<AuthorizationChallengeErrorResponse>) => _event.data.auth_session,
46
+ presentationUri: (_ctx: FirstPartyMachineContext, _event: DoneInvokeEvent<AuthorizationChallengeErrorResponse>) =>
47
+ _event.data.presentation,
48
+ }),
49
+ },
50
+ {
51
+ target: FirstPartyMachineStateTypes.error,
52
+ actions: assign({
53
+ error: (_ctx: FirstPartyMachineContext, _event: DoneInvokeEvent<Error>): ErrorDetails => ({
54
+ title: translate('oid4vci_machine_send_authorization_challenge_request_error_title'),
55
+ message: _event.data.message,
56
+ stack: _event.data.stack,
57
+ }),
58
+ }),
59
+ },
60
+ ],
61
+ },
62
+ },
63
+ [FirstPartyMachineStateTypes.createConfig]: {
64
+ id: FirstPartyMachineStateTypes.createConfig,
65
+ invoke: {
66
+ src: FirstPartyMachineServices.createConfig,
67
+ onDone: {
68
+ target: FirstPartyMachineStateTypes.getSiopRequest,
69
+ actions: assign({
70
+ didAuthConfig: (_ctx: FirstPartyMachineContext, _event: DoneInvokeEvent<DidAuthConfig>) => _event.data,
71
+ }),
72
+ },
73
+ onError: {
74
+ target: FirstPartyMachineStateTypes.error,
75
+ actions: assign({
76
+ error: (_ctx: FirstPartyMachineContext, _event: DoneInvokeEvent<Error>): ErrorDetails => ({
77
+ title: translate('oid4vci_machine_create_config_error_title'),
78
+ message: _event.data.message,
79
+ stack: _event.data.stack,
80
+ }),
81
+ }),
82
+ },
83
+ },
84
+ },
85
+ [FirstPartyMachineStateTypes.getSiopRequest]: {
86
+ id: FirstPartyMachineStateTypes.getSiopRequest,
87
+ invoke: {
88
+ src: FirstPartyMachineServices.getSiopRequest,
89
+ onDone: {
90
+ target: FirstPartyMachineStateTypes.selectCredentials,
91
+ actions: assign({
92
+ authorizationRequestData: (_ctx: FirstPartyMachineContext, _event: DoneInvokeEvent<SiopV2AuthorizationRequestData>) => _event.data,
93
+ }),
94
+ },
95
+ onError: {
96
+ target: FirstPartyMachineStateTypes.error,
97
+ actions: assign({
98
+ error: (_ctx: FirstPartyMachineContext, _event: DoneInvokeEvent<Error>): ErrorDetails => ({
99
+ title: translate('siopV2_machine_get_request_error_title'),
100
+ message: _event.data.message,
101
+ stack: _event.data.stack,
102
+ }),
103
+ }),
104
+ },
105
+ },
106
+ },
107
+ [FirstPartyMachineStateTypes.selectCredentials]: {
108
+ id: FirstPartyMachineStateTypes.selectCredentials,
109
+ on: {
110
+ [FirstPartyMachineEvents.SET_SELECTED_CREDENTIALS]: {
111
+ actions: assign({ selectedCredentials: (_ctx: FirstPartyMachineContext, _event: FirstPartySelectCredentialsEvent) => _event.data }),
112
+ },
113
+ [FirstPartyMachineEvents.NEXT]: {
114
+ target: FirstPartyMachineStateTypes.sendAuthorizationResponse,
115
+ },
116
+ [FirstPartyMachineEvents.DECLINE]: {
117
+ target: FirstPartyMachineStateTypes.declined,
118
+ },
119
+ [FirstPartyMachineEvents.PREVIOUS]: {
120
+ target: FirstPartyMachineStateTypes.aborted,
121
+ },
122
+ },
123
+ },
124
+ [FirstPartyMachineStateTypes.sendAuthorizationResponse]: {
125
+ id: FirstPartyMachineStateTypes.sendAuthorizationResponse,
126
+ invoke: {
127
+ src: FirstPartyMachineServices.sendAuthorizationResponse,
128
+ onDone: {
129
+ target: FirstPartyMachineStateTypes.sendAuthorizationChallengeRequest,
130
+ actions: assign({
131
+ presentationDuringIssuanceSession: (_ctx: FirstPartyMachineContext, _event: DoneInvokeEvent<string>) => _event.data,
132
+ }),
133
+ },
134
+ onError: {
135
+ target: FirstPartyMachineStateTypes.error,
136
+ actions: assign({
137
+ error: (_ctx: FirstPartyMachineContext, _event: DoneInvokeEvent<Error>): ErrorDetails => ({
138
+ title: translate('oid4vci_machine_get_request_error_title'),
139
+ message: _event.data.message,
140
+ stack: _event.data.stack,
141
+ }),
142
+ }),
143
+ },
144
+ },
145
+ },
146
+ [FirstPartyMachineStateTypes.aborted]: {
147
+ id: FirstPartyMachineStateTypes.aborted,
148
+ type: 'final',
149
+ },
150
+ [FirstPartyMachineStateTypes.declined]: {
151
+ id: FirstPartyMachineStateTypes.declined,
152
+ type: 'final',
153
+ },
154
+ [FirstPartyMachineStateTypes.error]: {
155
+ id: FirstPartyMachineStateTypes.error,
156
+ type: 'final',
157
+ },
158
+ [FirstPartyMachineStateTypes.done]: {
159
+ id: FirstPartyMachineStateTypes.done,
160
+ type: 'final',
161
+ },
162
+ }
163
+
164
+ const createFirstPartyActivationMachine = (opts: CreateFirstPartyMachineOpts): FirstPartyStateMachine => {
165
+ const initialContext: FirstPartyMachineContext = {
166
+ openID4VCIClientState: opts.openID4VCIClientState,
167
+ contact: opts.contact,
168
+ selectedCredentials: [],
169
+ }
170
+
171
+ return createMachine<FirstPartyMachineContext, FirstPartyMachineEventTypes>({
172
+ id: opts?.machineId ?? 'FirstParty',
173
+ predictableActionArguments: true,
174
+ initial: FirstPartyMachineStateTypes.sendAuthorizationChallengeRequest,
175
+ context: initialContext,
176
+ states: firstPartyMachineStates,
177
+ schema: {
178
+ events: {} as FirstPartyMachineEventTypes,
179
+ services: {} as {
180
+ [FirstPartyMachineServices.sendAuthorizationChallengeRequest]: {
181
+ data: void
182
+ }
183
+ [FirstPartyMachineServices.createConfig]: {
184
+ data: CreateConfigResult
185
+ }
186
+ [FirstPartyMachineServices.getSiopRequest]: {
187
+ data: SiopV2AuthorizationRequestData
188
+ }
189
+ [FirstPartyMachineServices.sendAuthorizationResponse]: {
190
+ data: string
191
+ }
192
+ },
193
+ },
194
+ })
195
+ }
196
+
197
+ export class FirstPartyMachine {
198
+ private static _instance: FirstPartyMachineInterpreter | undefined
199
+
200
+ static hasInstance(): boolean {
201
+ return FirstPartyMachine._instance !== undefined
202
+ }
203
+
204
+ static get instance(): FirstPartyMachineInterpreter {
205
+ if (!FirstPartyMachine._instance) {
206
+ throw Error('Please initialize ESIMActivation machine first')
207
+ }
208
+ return FirstPartyMachine._instance
209
+ }
210
+
211
+ static clearInstance(opts: { stop: boolean }) {
212
+ const { stop } = opts
213
+ if (FirstPartyMachine.hasInstance()) {
214
+ if (stop) {
215
+ FirstPartyMachine.stopInstance()
216
+ }
217
+ }
218
+ FirstPartyMachine._instance = undefined
219
+ }
220
+
221
+ static stopInstance(): void {
222
+ if (!FirstPartyMachine.hasInstance()) {
223
+ return
224
+ }
225
+ FirstPartyMachine.instance.stop()
226
+ FirstPartyMachine._instance = undefined
227
+ }
228
+
229
+ public static newInstance(opts: InstanceFirstPartyMachineOpts): FirstPartyMachineInterpreter {
230
+ const { agentContext } = opts
231
+ const services: FirstPartyMachineServiceDefinitions = {
232
+ [FirstPartyMachineServices.sendAuthorizationChallengeRequest]: sendAuthorizationChallengeRequest,
233
+ [FirstPartyMachineServices.createConfig]: (args: CreateConfigArgs) => createConfig(args, agentContext),
234
+ [FirstPartyMachineServices.getSiopRequest]: (args: GetSiopRequestArgs) => getSiopRequest(args, agentContext),
235
+ [FirstPartyMachineServices.sendAuthorizationResponse]: (args: SendAuthorizationResponseArgs) => sendAuthorizationResponse(args, agentContext),
236
+ }
237
+
238
+ const newInst: FirstPartyMachineInterpreter = interpret(
239
+ createFirstPartyActivationMachine(opts).withConfig({
240
+ services: {
241
+ ...services,
242
+ ...opts?.services,
243
+ },
244
+ guards: {
245
+ ...opts?.guards,
246
+ },
247
+ }),
248
+ )
249
+
250
+ if (typeof opts?.subscription === 'function') {
251
+ newInst.onTransition(opts.subscription)
252
+ }
253
+
254
+ if (opts?.requireCustomNavigationHook !== true) {
255
+ newInst.onTransition((snapshot: FirstPartyMachineState): void => {
256
+ if (opts?.stateNavigationListener) {
257
+ void opts.stateNavigationListener(newInst, snapshot)
258
+ }
259
+ })
260
+ }
261
+
262
+ return newInst
263
+ }
264
+
265
+ static getInstance(
266
+ opts: InstanceFirstPartyMachineOpts & {
267
+ requireExisting?: boolean
268
+ },
269
+ ): FirstPartyMachineInterpreter {
270
+ if (!FirstPartyMachine._instance) {
271
+ if (opts?.requireExisting === true) {
272
+ throw Error(`Existing FirstPartyMachine instance requested, but none was created at this point!`)
273
+ }
274
+ FirstPartyMachine._instance = FirstPartyMachine.newInstance(opts)
275
+ }
276
+ return FirstPartyMachine._instance
277
+ }
278
+ }