dcql 0.3.1-alpha-20250624142312 → 0.4.0-alpha-20250704223101

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.
package/dist/index.js CHANGED
@@ -177,8 +177,11 @@ var v2 = __toESM(require("valibot"));
177
177
  // src/u-dcql.ts
178
178
  var v = __toESM(require("valibot"));
179
179
  var idRegex = /^[a-zA-Z0-9_-]+$/;
180
- var vNonEmptyArray = () => {
181
- return v.custom((input) => input.length > 0);
180
+ var vNonEmptyArray = (item) => {
181
+ return v.pipe(
182
+ v.array(item),
183
+ v.custom((input) => input.length > 0)
184
+ );
182
185
  };
183
186
  var vIncludesAll = (subset) => {
184
187
  return v.custom(
@@ -252,6 +255,24 @@ var vStringToJson = v.rawTransform(({ dataset, addIssue, NEVER }) => {
252
255
  });
253
256
 
254
257
  // src/dcql-query/m-dcql-trusted-authorities.ts
258
+ var getTrustedAuthorityParser = (trustedAuthority) => v2.object(
259
+ {
260
+ type: v2.literal(
261
+ trustedAuthority.type,
262
+ (i) => `Expected trusted authority type to be '${trustedAuthority.type}' but received ${typeof i.input === "string" ? `'${i.input}'` : i.input}`
263
+ ),
264
+ value: v2.union(
265
+ trustedAuthority.values.map(
266
+ (value) => v2.literal(
267
+ value,
268
+ (i) => `Expected trusted authority value to be '${value}' but received ${typeof i.input === "string" ? `'${i.input}'` : i.input}`
269
+ )
270
+ ),
271
+ (i) => `Expected trusted authority value to be '${trustedAuthority.values.join("' | '")}' but received ${typeof i.input === "string" ? `'${i.input}'` : i.input}`
272
+ )
273
+ },
274
+ `Expected trusted authority object with type '${trustedAuthority.type}' to be defined, but received undefined`
275
+ );
255
276
  var vAuthorityKeyIdentifier = v2.object({
256
277
  type: v2.literal("aki"),
257
278
  value: v2.pipe(
@@ -303,8 +324,7 @@ var DcqlTrustedAuthoritiesQuery;
303
324
  )
304
325
  ),
305
326
  values: v2.pipe(
306
- v2.array(authority.entries.value),
307
- vNonEmptyArray(),
327
+ vNonEmptyArray(authority.entries.value),
308
328
  v2.description(
309
329
  "REQUIRED. An array of strings, where each string (value) contains information specific to the used Trusted Authorities Query type that allows to identify an issuer, trust framework, or a federation that an issuer belongs to."
310
330
  )
@@ -397,22 +417,6 @@ var DcqlCredential;
397
417
  DcqlSdJwtVcCredential.vModel,
398
418
  DcqlW3cVcCredential.vModel
399
419
  ]);
400
- DcqlCredential2.vParseSuccess = v4.object({
401
- success: v4.literal(true),
402
- typed: v4.literal(true),
403
- issues: v4.optional(v4.undefined()),
404
- input_credential_index: v4.number(),
405
- claim_set_index: v4.union([v4.number(), v4.undefined()]),
406
- output: DcqlCredential2.vModel
407
- });
408
- DcqlCredential2.vParseFailure = v4.object({
409
- success: v4.literal(false),
410
- typed: v4.boolean(),
411
- output: v4.unknown(),
412
- issues: v4.pipe(v4.array(v4.unknown()), vNonEmptyArray()),
413
- input_credential_index: v4.number(),
414
- claim_set_index: v4.union([v4.number(), v4.undefined()])
415
- });
416
420
  DcqlCredential2.model = new Model({ vModel: DcqlCredential2.vModel });
417
421
  })(DcqlCredential || (DcqlCredential = {}));
418
422
 
@@ -444,10 +448,7 @@ var DcqlCredentialPresentation;
444
448
  })(DcqlCredentialPresentation || (DcqlCredentialPresentation = {}));
445
449
 
446
450
  // src/dcql-presentation/m-dcql-presentation-result.ts
447
- var v12 = __toESM(require("valibot"));
448
-
449
- // src/dcql-parser/dcql-credential-query-result.ts
450
- var v8 = __toESM(require("valibot"));
451
+ var v16 = __toESM(require("valibot"));
451
452
 
452
453
  // src/dcql-parser/dcql-claims-query-result.ts
453
454
  var v7 = __toESM(require("valibot"));
@@ -466,8 +467,7 @@ var DcqlClaimsQuery;
466
467
  )
467
468
  ),
468
469
  path: v6.pipe(
469
- v6.array(DcqlClaimsQuery2.vPath),
470
- vNonEmptyArray(),
470
+ vNonEmptyArray(DcqlClaimsQuery2.vPath),
471
471
  v6.description(
472
472
  "A non-empty array representing a claims path pointer that specifies the path to a claim within the Verifiable Credential."
473
473
  )
@@ -540,304 +540,521 @@ var DcqlClaimsQuery;
540
540
  DcqlClaimsQuery2.vModel = v6.union([DcqlClaimsQuery2.vMdoc, DcqlClaimsQuery2.vW3cSdJwtVc]);
541
541
  })(DcqlClaimsQuery || (DcqlClaimsQuery = {}));
542
542
 
543
- // src/dcql-parser/dcql-claims-query-result.ts
544
- var getTrustedAuthorityValue = (credentialQuery) => v7.object({
545
- authority: credentialQuery.trusted_authorities ? v7.variant(
546
- "type",
547
- credentialQuery.trusted_authorities.map(
548
- (t) => v7.object({ type: v7.literal(t.type), value: v7.union(t.values.map((value) => v7.literal(value))) })
549
- ),
550
- `Credential query '${credentialQuery.id}' requires the credential to be issued by a trusted authority of type ${credentialQuery.trusted_authorities.map((t) => t.type).join(" | ")}, but none of the type or values match.`
551
- ) : v7.optional(DcqlCredentialTrustedAuthority.vModel)
552
- });
553
- var getClaimParser = (input) => {
554
- const { value, values } = input;
555
- if (value) {
556
- return vWithJT(v7.literal(value));
543
+ // src/util/deep-merge.ts
544
+ function deepMerge(source, target) {
545
+ let newTarget = target;
546
+ if (Object.getPrototypeOf(source) !== Object.prototype && !Array.isArray(source)) {
547
+ throw new DcqlError({
548
+ message: "source value provided to deepMerge is neither an array or object.",
549
+ code: "PARSE_ERROR"
550
+ });
557
551
  }
558
- if (values) {
559
- return vWithJT(v7.union(values.map((val) => v7.literal(val))));
552
+ if (Object.getPrototypeOf(target) !== Object.prototype && !Array.isArray(target)) {
553
+ throw new DcqlError({
554
+ message: "target value provided to deepMerge is neither an array or object.",
555
+ code: "PARSE_ERROR"
556
+ });
560
557
  }
561
- return v7.nonNullish(v7.any());
562
- };
563
- var getNamespacesParser = (claimsQueries) => {
564
- const claimsForNamespace = {};
565
- for (const claimQuery of claimsQueries) {
566
- const mdocPathQuery = v7.is(DcqlClaimsQuery.vMdocNamespace, claimQuery) ? {
567
- id: claimQuery.id,
568
- path: [claimQuery.namespace, claimQuery.claim_name],
569
- values: claimQuery.values
570
- } : claimQuery;
571
- const namespace = mdocPathQuery.path[0];
572
- if (claimsForNamespace[namespace]) {
573
- claimsForNamespace[namespace]?.push({ ...mdocPathQuery });
574
- } else {
575
- claimsForNamespace[namespace] = [{ ...mdocPathQuery }];
558
+ for (const [key, val] of Object.entries(source)) {
559
+ if (val !== null && typeof val === "object" && (Object.getPrototypeOf(val) === Object.prototype || Array.isArray(val))) {
560
+ const newValue = deepMerge(
561
+ val,
562
+ newTarget[key] ?? new (Object.getPrototypeOf(val)).constructor()
563
+ );
564
+ newTarget = setValue(newTarget, key, newValue);
565
+ } else if (val != null) {
566
+ newTarget = setValue(newTarget, key, val);
576
567
  }
577
568
  }
578
- const parsersForNamespaces = Object.entries(claimsForNamespace).map(([namespace, claims]) => {
579
- const claimParsers = Object.fromEntries(claims.map((claim) => [claim.path[1], getClaimParser(claim)]));
580
- return [namespace, v7.object(claimParsers)];
581
- });
582
- return v7.object(Object.fromEntries(parsersForNamespaces));
569
+ return newTarget;
570
+ }
571
+ function setValue(target, key, value) {
572
+ let newTarget = target;
573
+ if (Array.isArray(newTarget)) {
574
+ newTarget = [...newTarget];
575
+ newTarget[key] = value;
576
+ } else if (Object.getPrototypeOf(newTarget) === Object.prototype) {
577
+ newTarget = { ...newTarget, [key]: value };
578
+ } else {
579
+ throw new DcqlError({
580
+ message: "Unsupported type for deep merge. Only primitive types or Array and Object are supported",
581
+ code: "INTERNAL_SERVER_ERROR"
582
+ });
583
+ }
584
+ return newTarget;
585
+ }
586
+
587
+ // src/dcql-parser/dcql-claims-query-result.ts
588
+ var pathToString = (path) => path.map((item) => typeof item === "string" ? `'${item}'` : `${item}`).join(".");
589
+ var getClaimParser = (path, values) => {
590
+ if (values) {
591
+ return v7.union(
592
+ values.map(
593
+ (val) => v7.literal(
594
+ val,
595
+ (i) => `Expected claim ${pathToString(path)} to be ${typeof val === "string" ? `'${val}'` : val} but received ${typeof i.input === "string" ? `'${i.input}'` : i.input}`
596
+ )
597
+ ),
598
+ (i) => `Expected claim ${pathToString(path)} to be ${values.map((v19) => typeof v19 === "string" ? `'${v19}'` : v19).join(" | ")} but received ${typeof i.input === "string" ? `'${i.input}'` : i.input}`
599
+ );
600
+ }
601
+ return v7.pipe(
602
+ v7.unknown(),
603
+ v7.check((value) => value !== null && value !== void 0, `Expected claim '${path.join("'.'")}' to be defined`)
604
+ );
605
+ };
606
+ var getMdocClaimParser = (claimQuery) => {
607
+ const mdocPathQuery = v7.is(DcqlClaimsQuery.vMdocNamespace, claimQuery) ? {
608
+ id: claimQuery.id,
609
+ path: [claimQuery.namespace, claimQuery.claim_name],
610
+ values: claimQuery.values
611
+ } : claimQuery;
612
+ const namespace = mdocPathQuery.path[0];
613
+ const field = mdocPathQuery.path[1];
614
+ return v7.object(
615
+ {
616
+ [namespace]: v7.object(
617
+ {
618
+ [field]: getClaimParser(mdocPathQuery.path, claimQuery.values)
619
+ },
620
+ `Expected claim ${pathToString(mdocPathQuery.path)} to be defined`
621
+ )
622
+ },
623
+ `Expected claim ${pathToString(mdocPathQuery.path)} to be defined`
624
+ );
583
625
  };
584
- var getClaimQueryParser = (claimQuery, ctx) => {
626
+ var getJsonClaimParser = (claimQuery, ctx) => {
585
627
  const { index, presentation } = ctx;
586
628
  const pathElement = claimQuery.path[index];
587
629
  const isLast = index === claimQuery.path.length - 1;
588
- const vClaimParser = getClaimParser(claimQuery);
630
+ const vClaimParser = getClaimParser(claimQuery.path, claimQuery.values);
589
631
  if (typeof pathElement === "number") {
590
- const elementParser = isLast ? vClaimParser : getClaimQueryParser(claimQuery, { ...ctx, index: index + 1 });
632
+ const elementParser = isLast ? vClaimParser : getJsonClaimParser(claimQuery, { ...ctx, index: index + 1 });
591
633
  if (presentation) {
592
- return v7.union([
593
- v7.pipe(
594
- v7.array(vJson),
595
- v7.length(1),
596
- v7.transform((input) => input[0]),
597
- elementParser
598
- ),
599
- elementParser
600
- ]);
634
+ return v7.pipe(
635
+ v7.array(v7.any(), `Expected path ${pathToString(claimQuery.path.slice(0, index + 1))} to be an array`),
636
+ v7.rawTransform(({ dataset, addIssue }) => {
637
+ const issues = [];
638
+ for (const item of dataset.value) {
639
+ const itemResult = v7.safeParse(elementParser, item);
640
+ if (itemResult.success) {
641
+ return dataset.value;
642
+ }
643
+ issues.push(itemResult.issues[0]);
644
+ }
645
+ addIssue({
646
+ ...issues[0],
647
+ message: isLast ? issues[0].message : `Expected any element in array ${pathToString(claimQuery.path.slice(0, index + 1))} to match sub requirement but none matched: ${issues[0].message}`
648
+ });
649
+ return dataset.value;
650
+ })
651
+ );
601
652
  }
602
653
  return v7.pipe(
603
- v7.array(vJson),
604
- v7.transform((input) => input[pathElement]),
605
- elementParser
654
+ v7.array(v7.any(), `Expected path ${pathToString(claimQuery.path.slice(0, index + 1))} to be an array`),
655
+ v7.rawTransform(({ addIssue, dataset, NEVER }) => {
656
+ const result = v7.safeParse(elementParser, dataset.value[pathElement]);
657
+ if (!result.success) {
658
+ addIssue(result.issues[0]);
659
+ return NEVER;
660
+ }
661
+ return [...dataset.value.slice(0, pathElement).map(() => null), result.output];
662
+ })
606
663
  );
607
664
  }
608
665
  if (typeof pathElement === "string") {
609
- return v7.object({
610
- [pathElement]: isLast ? vClaimParser : getClaimQueryParser(claimQuery, { ...ctx, index: index + 1 })
611
- });
666
+ return v7.object(
667
+ {
668
+ [pathElement]: isLast ? vClaimParser : getJsonClaimParser(claimQuery, { ...ctx, index: index + 1 })
669
+ },
670
+ `Expected claim ${pathToString(claimQuery.path)} to be defined`
671
+ );
612
672
  }
613
- return isLast ? v7.array(vClaimParser) : v7.array(getClaimQueryParser(claimQuery, { ...ctx, index: index + 1 }));
614
- };
615
- var getJsonClaimsParser = (claimsQueries, ctx) => {
616
- const claimParser = v7.intersect(
617
- claimsQueries.map(
618
- (claimQuery) => getClaimQueryParser(claimQuery, {
619
- ...ctx,
620
- index: 0
621
- })
622
- )
673
+ return v7.pipe(
674
+ v7.array(v7.any(), `Expected path ${pathToString(claimQuery.path.slice(0, index + 1))} to be an array`),
675
+ v7.rawTransform(({ addIssue, dataset, NEVER }) => {
676
+ const mapped = dataset.value.map((item) => {
677
+ const parsed = v7.safeParse(
678
+ isLast ? vClaimParser : getJsonClaimParser(claimQuery, { ...ctx, index: index + 1 }),
679
+ item
680
+ );
681
+ return parsed;
682
+ });
683
+ if (mapped.every((parsed) => !parsed.success)) {
684
+ for (const parsed of mapped) {
685
+ for (const issue of parsed.issues) {
686
+ addIssue(issue);
687
+ }
688
+ }
689
+ return NEVER;
690
+ }
691
+ return mapped.map((parsed) => parsed.success ? parsed.output : null);
692
+ })
623
693
  );
624
- return claimParser;
625
694
  };
626
- var getMdocClaimsQueriesForClaimSet = (claimsQueries, claimSet) => {
627
- return claimSet.map((credential_id) => {
628
- const query = claimsQueries.find((query2) => query2.id === credential_id);
629
- if (!query) {
630
- throw new DcqlInvalidClaimsQueryIdError({
631
- message: `Claims-query with id '${credential_id}' not found.`
695
+ var runClaimsQuery = (credentialQuery, ctx) => {
696
+ if (!credentialQuery.claims) {
697
+ return {
698
+ success: true,
699
+ valid_claims: [],
700
+ failed_claims: [],
701
+ valid_claim_sets: [
702
+ {
703
+ claim_set_index: void 0,
704
+ output: {},
705
+ success: true,
706
+ valid_claim_indexes: []
707
+ }
708
+ ],
709
+ failed_claim_sets: []
710
+ };
711
+ }
712
+ const failedClaims = [];
713
+ const validClaims = [];
714
+ for (const [claimIndex, claimQuery] of credentialQuery.claims.entries()) {
715
+ const parser = credentialQuery.format === "mso_mdoc" ? getMdocClaimParser(claimQuery) : getJsonClaimParser(claimQuery, {
716
+ index: 0,
717
+ presentation: ctx.presentation
718
+ });
719
+ const parseResult = v7.safeParse(
720
+ parser,
721
+ ctx.credential.credential_format === "mso_mdoc" ? ctx.credential.namespaces : ctx.credential.claims
722
+ );
723
+ if (parseResult.success) {
724
+ validClaims.push({
725
+ success: true,
726
+ claim_index: claimIndex,
727
+ claim_id: claimQuery.id,
728
+ output: parseResult.output,
729
+ parser
730
+ });
731
+ } else {
732
+ const flattened = v7.flatten(parseResult.issues);
733
+ failedClaims.push({
734
+ success: false,
735
+ issues: flattened.nested ?? flattened,
736
+ claim_index: claimIndex,
737
+ claim_id: claimQuery.id,
738
+ output: parseResult.output,
739
+ parser
632
740
  });
633
741
  }
634
- return query;
635
- });
636
- };
637
- var getJsonClaimsQueriesForClaimSet = (claimsQueries, claimSet) => {
638
- return claimSet.map((credential_id) => {
639
- const query = claimsQueries.find((query2) => query2.id === credential_id);
640
- if (!query) {
641
- throw new DcqlInvalidClaimsQueryIdError({
642
- message: `Claims-query with id '${credential_id}' not found.`
742
+ }
743
+ const failedClaimSets = [];
744
+ const validClaimSets = [];
745
+ for (const [claimSetIndex, claimSet] of credentialQuery.claim_sets?.entries() ?? [[void 0, void 0]]) {
746
+ const claims = claimSet?.map((id) => {
747
+ const claim = validClaims.find((claim2) => claim2.claim_id === id) ?? failedClaims.find((claim2) => claim2.claim_id === id);
748
+ if (!claim) {
749
+ throw new DcqlParseError({
750
+ message: `Claim with id '${id}' in query '${credentialQuery.id}' from claim set with index '${claimSetIndex}' not found in claims of claim`
751
+ });
752
+ }
753
+ return claim;
754
+ }) ?? [...validClaims, ...failedClaims];
755
+ if (claims.every((claim) => claim.success)) {
756
+ const output = claims.reduce((merged, claim) => deepMerge(claim.output, merged), {});
757
+ validClaimSets.push({
758
+ success: true,
759
+ claim_set_index: claimSetIndex,
760
+ output,
761
+ valid_claim_indexes: validClaims.map((claim) => claim.claim_index)
762
+ });
763
+ } else {
764
+ const issues = failedClaims.reduce((merged, claim) => deepMerge(claim.issues, merged), {});
765
+ failedClaimSets.push({
766
+ success: false,
767
+ issues,
768
+ claim_set_index: claimSetIndex,
769
+ failed_claim_indexes: failedClaims.map((claim) => claim.claim_index),
770
+ valid_claim_indexes: validClaims.map((claim) => claim.claim_index)
643
771
  });
644
772
  }
645
- return query;
646
- });
773
+ }
774
+ if (validClaimSets.length === 0) {
775
+ return {
776
+ success: false,
777
+ failed_claim_sets: failedClaimSets,
778
+ failed_claims: failedClaims.map(({ parser, ...rest }) => rest),
779
+ valid_claims: validClaims.map(({ parser, ...rest }) => rest)
780
+ };
781
+ }
782
+ return {
783
+ success: true,
784
+ failed_claim_sets: failedClaimSets,
785
+ valid_claim_sets: validClaimSets,
786
+ valid_claims: validClaims.map(({ parser, ...rest }) => rest),
787
+ failed_claims: failedClaims.map(({ parser, ...rest }) => rest)
788
+ };
647
789
  };
648
- var getMdocParser = (credentialQuery, ctx) => {
649
- const { claimSet } = ctx;
650
- const vDoctype = credentialQuery.meta?.doctype_value ? v7.literal(credentialQuery.meta.doctype_value) : v7.string();
651
- const claimSetQueries = credentialQuery.claims && claimSet ? getMdocClaimsQueriesForClaimSet(credentialQuery.claims, claimSet) : credentialQuery.claims;
652
- const credentialParser = v7.object({
653
- credential_format: v7.literal("mso_mdoc"),
654
- doctype: vDoctype,
655
- namespaces: claimSetQueries ? getNamespacesParser(claimSetQueries) : v7.record(v7.string(), v7.record(v7.string(), v7.unknown())),
656
- ...getTrustedAuthorityValue(credentialQuery).entries
790
+
791
+ // src/dcql-parser/dcql-meta-query-result.ts
792
+ var v8 = __toESM(require("valibot"));
793
+ var getMdocMetaParser = (credentialQuery) => {
794
+ const vDoctype = credentialQuery.meta?.doctype_value ? v8.literal(
795
+ credentialQuery.meta.doctype_value,
796
+ (i) => `Expected doctype to be '${credentialQuery.meta?.doctype_value}' but received '${i.input}'`
797
+ ) : v8.string("Expected doctype to be defined");
798
+ const credentialParser = v8.object({
799
+ credential_format: v8.literal(
800
+ "mso_mdoc",
801
+ (i) => `Expected credential format to be 'mso_mdoc' but received '${i.input}'`
802
+ ),
803
+ doctype: vDoctype
657
804
  });
658
805
  return credentialParser;
659
806
  };
660
- var getW3cVcSdJwtVcParser = (credentialQuery, ctx) => {
661
- const { claimSet } = ctx;
662
- const claimSetQueries = credentialQuery.claims && claimSet ? getJsonClaimsQueriesForClaimSet(credentialQuery.claims, claimSet) : credentialQuery.claims;
663
- if (credentialQuery.format === "vc+sd-jwt" || credentialQuery.format === "dc+sd-jwt") {
664
- return v7.object({
665
- credential_format: v7.literal(credentialQuery.format),
666
- vct: credentialQuery.meta?.vct_values ? v7.picklist(credentialQuery.meta.vct_values) : v7.string(),
667
- claims: claimSetQueries ? getJsonClaimsParser(claimSetQueries, ctx) : vJsonRecord,
668
- // TODO: we should split up the:
669
- // - vct
670
- // - claim value
671
- // - trusted authorities
672
- // into separate validations so we can make the match result richer with specifically
673
- // which steps failed, also we should look at showing exactly which claim paths failed.
674
- ...getTrustedAuthorityValue(credentialQuery).entries
675
- });
807
+ var getSdJwtVcMetaParser = (credentialQuery) => {
808
+ return v8.object({
809
+ credential_format: v8.literal(
810
+ credentialQuery.format,
811
+ (i) => `Expected credential format to be '${credentialQuery.format}' but received '${i.input}'`
812
+ ),
813
+ vct: credentialQuery.meta?.vct_values ? v8.picklist(
814
+ credentialQuery.meta.vct_values,
815
+ (i) => `Expected vct to be '${credentialQuery.meta?.vct_values?.join("' | '")}' but received '${i.input}'`
816
+ ) : v8.string("Expected vct to be defined")
817
+ });
818
+ };
819
+ var getW3cVcMetaParser = (credentialQuery) => {
820
+ return v8.object({
821
+ credential_format: v8.literal(
822
+ credentialQuery.format,
823
+ (i) => `Expected credential format to be '${credentialQuery.format}' but received '${i.input}'`
824
+ ),
825
+ type: credentialQuery.meta?.type_values ? v8.union(
826
+ credentialQuery.meta.type_values.map((values) => vIncludesAll(values)),
827
+ `Expected type to include all values from one of the following subsets: ${credentialQuery.meta.type_values.map((values) => `[${values.join(", ")}]`).join(" | ")}`
828
+ ) : vNonEmptyArray(v8.string())
829
+ });
830
+ };
831
+ var getMetaParser = (credentialQuery) => {
832
+ if (credentialQuery.format === "mso_mdoc") {
833
+ return getMdocMetaParser(credentialQuery);
676
834
  }
677
- if (credentialQuery.format === "jwt_vc_json" || credentialQuery.format === "ldp_vc") {
678
- return v7.object({
679
- credential_format: v7.literal(credentialQuery.format),
680
- claims: claimSetQueries ? getJsonClaimsParser(claimSetQueries, ctx) : vJsonRecord,
681
- type: credentialQuery.meta?.type_values ? v7.union(
682
- credentialQuery.meta.type_values.map((values) => vIncludesAll(values)),
683
- `Type must include at least all values from one of the following subsets: ${credentialQuery.meta.type_values.map((values) => `[${values.join(", ")}]`).join(" | ")}`
684
- ) : v7.array(v7.string()),
685
- ...getTrustedAuthorityValue(credentialQuery).entries
686
- });
835
+ if (credentialQuery.format === "dc+sd-jwt" || credentialQuery.format === "vc+sd-jwt") {
836
+ return getSdJwtVcMetaParser(credentialQuery);
837
+ }
838
+ if (credentialQuery.format === "ldp_vc" || credentialQuery.format === "jwt_vc_json") {
839
+ return getW3cVcMetaParser(credentialQuery);
687
840
  }
688
841
  throw new DcqlError({
689
842
  code: "NOT_IMPLEMENTED",
690
843
  message: `Usupported format '${credentialQuery.format}'`
691
844
  });
692
845
  };
693
- var getCredentialQueryParser = (credentialQuery, ctx) => {
694
- if (credentialQuery.claim_sets && !ctx.claimSet) {
695
- throw new DcqlMissingClaimSetParseError({
696
- message: "credentialQuery specifies claim_sets but no claim_set for parsing is provided."
697
- });
846
+ var runMetaQuery = (credentialQuery, credential) => {
847
+ const metaParser = getMetaParser(credentialQuery);
848
+ const parseResult = v8.safeParse(metaParser, credential);
849
+ if (!parseResult.success) {
850
+ const issues = v8.flatten(parseResult.issues);
851
+ return {
852
+ success: false,
853
+ issues: issues.nested ?? issues,
854
+ output: parseResult.output
855
+ };
698
856
  }
699
- if (credentialQuery.format === "mso_mdoc") {
700
- return getMdocParser(credentialQuery, ctx);
857
+ return {
858
+ success: true,
859
+ output: parseResult.output
860
+ };
861
+ };
862
+
863
+ // src/dcql-parser/dcql-trusted-authorities-result.ts
864
+ var v9 = __toESM(require("valibot"));
865
+ var runTrustedAuthoritiesQuery = (credentialQuery, credential) => {
866
+ if (!credentialQuery.trusted_authorities) {
867
+ return {
868
+ success: true
869
+ };
701
870
  }
702
- return getW3cVcSdJwtVcParser(credentialQuery, ctx);
871
+ const failedTrustedAuthorities = [];
872
+ for (const [trustedAuthorityIndex, trustedAuthority] of credentialQuery.trusted_authorities.entries()) {
873
+ const trustedAuthorityParser = getTrustedAuthorityParser(trustedAuthority);
874
+ const parseResult = v9.safeParse(trustedAuthorityParser, credential.authority);
875
+ if (parseResult.success) {
876
+ return {
877
+ success: true,
878
+ valid_trusted_authority: {
879
+ success: true,
880
+ trusted_authority_index: trustedAuthorityIndex,
881
+ output: parseResult.output
882
+ },
883
+ failed_trusted_authorities: failedTrustedAuthorities
884
+ };
885
+ }
886
+ const issues = v9.flatten(parseResult.issues);
887
+ failedTrustedAuthorities.push({
888
+ success: false,
889
+ trusted_authority_index: trustedAuthorityIndex,
890
+ issues: issues.nested ?? issues,
891
+ output: parseResult.output
892
+ });
893
+ }
894
+ return {
895
+ success: false,
896
+ failed_trusted_authorities: failedTrustedAuthorities
897
+ };
703
898
  };
704
899
 
705
900
  // src/dcql-parser/dcql-credential-query-result.ts
706
901
  var runCredentialQuery = (credentialQuery, ctx) => {
707
902
  const { credentials, presentation } = ctx;
708
- const claimSets = credentialQuery.claim_sets ?? [void 0];
709
- const credentialQueryResult = [];
710
- for (const [claimSetIndex, claim_set] of claimSets.entries()) {
711
- const credentialParser = getCredentialQueryParser(credentialQuery, {
712
- claimSet: claim_set,
713
- presentation
903
+ if (ctx.credentials.length === 0) {
904
+ throw new DcqlError({
905
+ message: "Credentials array provided to credential query has length of 0, unable to match credentials against credential query.",
906
+ code: "BAD_REQUEST"
714
907
  });
715
- const claimSetResult = [];
716
- for (const [credentialIndex, credential] of credentials.entries()) {
717
- if (claimSetIndex > 0) {
718
- const previous = credentialQueryResult[claimSetIndex - 1][credentialIndex];
719
- if (previous?.success || !previous) {
720
- claimSetResult[credentialIndex] = void 0;
721
- continue;
722
- }
723
- }
724
- const parseResult = v8.safeParse(credentialParser, credential);
725
- claimSetResult.push({
726
- ...parseResult,
727
- ...parseResult.issues && {
728
- flattened: v8.flatten(parseResult.issues)
729
- },
908
+ }
909
+ const validCredentials = [];
910
+ const failedCredentials = [];
911
+ for (const [credentialIndex, credential] of credentials.entries()) {
912
+ const trustedAuthorityResult = runTrustedAuthoritiesQuery(credentialQuery, credential);
913
+ const claimsResult = runClaimsQuery(credentialQuery, { credential, presentation });
914
+ const metaResult = runMetaQuery(credentialQuery, credential);
915
+ if (claimsResult.success && trustedAuthorityResult.success && metaResult.success) {
916
+ validCredentials.push({
917
+ success: true,
918
+ input_credential_index: credentialIndex,
919
+ trusted_authorities: trustedAuthorityResult,
920
+ meta: metaResult,
921
+ claims: claimsResult
922
+ });
923
+ } else {
924
+ failedCredentials.push({
925
+ success: false,
730
926
  input_credential_index: credentialIndex,
731
- claim_set_index: credentialQuery.claim_sets ? claimSetIndex : void 0
927
+ trusted_authorities: trustedAuthorityResult,
928
+ meta: metaResult,
929
+ claims: claimsResult
732
930
  });
733
931
  }
734
- credentialQueryResult.push(claimSetResult);
735
932
  }
736
- return credentialQueryResult;
933
+ if (!validCredentials.length) {
934
+ return {
935
+ success: false,
936
+ credential_query_id: credentialQuery.id,
937
+ // We now for sure that there's at least one invalid credential if there's no valid one.
938
+ failed_credentials: failedCredentials,
939
+ valid_credentials: void 0
940
+ };
941
+ }
942
+ return {
943
+ success: true,
944
+ credential_query_id: credentialQuery.id,
945
+ failed_credentials: failedCredentials,
946
+ // We now for sure that there's at least one valid credential due to the length check
947
+ valid_credentials: validCredentials
948
+ };
737
949
  };
738
950
 
739
951
  // src/dcql-query-result/m-dcql-query-result.ts
740
- var v11 = __toESM(require("valibot"));
952
+ var v15 = __toESM(require("valibot"));
741
953
 
742
954
  // src/dcql-query/m-dcql-credential-query.ts
743
- var v9 = __toESM(require("valibot"));
955
+ var v10 = __toESM(require("valibot"));
744
956
  var DcqlCredentialQuery;
745
957
  ((DcqlCredentialQuery2) => {
746
- const vBase = v9.object({
747
- id: v9.pipe(
748
- v9.string(),
749
- v9.regex(idRegex),
750
- v9.description(
958
+ const vBase = v10.object({
959
+ id: v10.pipe(
960
+ v10.string(),
961
+ v10.regex(idRegex),
962
+ v10.description(
751
963
  `REQUIRED. A string identifying the Credential in the response and, if provided, the constraints in 'credential_sets'.`
752
964
  )
753
965
  ),
754
- claim_sets: v9.pipe(
755
- v9.optional(v9.pipe(v9.array(v9.pipe(v9.array(vIdString), vNonEmptyArray())), vNonEmptyArray())),
756
- v9.description(
966
+ multiple: v10.pipe(
967
+ v10.optional(v10.boolean(), false),
968
+ v10.description(
969
+ "OPTIONAL. A boolean which indicates whether multiple Credentials can be returned for this Credential Query. If omitted, the default value is false."
970
+ )
971
+ ),
972
+ claim_sets: v10.pipe(
973
+ v10.optional(vNonEmptyArray(vNonEmptyArray(vIdString))),
974
+ v10.description(
757
975
  `OPTIONAL. A non-empty array containing arrays of identifiers for elements in 'claims' that specifies which combinations of 'claims' for the Credential are requested.`
758
976
  )
759
977
  ),
760
- trusted_authorities: v9.pipe(
761
- v9.optional(v9.pipe(v9.array(DcqlTrustedAuthoritiesQuery.vModel), vNonEmptyArray())),
762
- v9.description(
978
+ trusted_authorities: v10.pipe(
979
+ v10.optional(vNonEmptyArray(DcqlTrustedAuthoritiesQuery.vModel)),
980
+ v10.description(
763
981
  "OPTIONAL. A non-empty array of objects as defined in Section 6.1.1 that specifies expected authorities or trust frameworks that certify Issuers, that the Verifier will accept. Every Credential returned by the Wallet SHOULD match at least one of the conditions present in the corresponding trusted_authorities array if present."
764
982
  )
765
983
  )
766
984
  });
767
- DcqlCredentialQuery2.vMdoc = v9.object({
985
+ DcqlCredentialQuery2.vMdoc = v10.object({
768
986
  ...vBase.entries,
769
- format: v9.pipe(
770
- v9.literal("mso_mdoc"),
771
- v9.description("REQUIRED. A string that specifies the format of the requested Verifiable Credential.")
987
+ format: v10.pipe(
988
+ v10.literal("mso_mdoc"),
989
+ v10.description("REQUIRED. A string that specifies the format of the requested Verifiable Credential.")
772
990
  ),
773
- claims: v9.pipe(
774
- v9.optional(v9.pipe(v9.array(DcqlClaimsQuery.vMdoc), vNonEmptyArray())),
775
- v9.description("OPTIONAL. A non-empty array of objects as that specifies claims in the requested Credential.")
991
+ claims: v10.pipe(
992
+ v10.optional(vNonEmptyArray(DcqlClaimsQuery.vMdoc)),
993
+ v10.description("OPTIONAL. A non-empty array of objects as that specifies claims in the requested Credential.")
776
994
  ),
777
- meta: v9.pipe(
778
- v9.optional(
779
- v9.object({
780
- doctype_value: v9.pipe(
781
- v9.optional(v9.string()),
782
- v9.description(
995
+ meta: v10.pipe(
996
+ v10.optional(
997
+ v10.object({
998
+ doctype_value: v10.pipe(
999
+ v10.optional(v10.string()),
1000
+ v10.description(
783
1001
  "OPTIONAL. String that specifies an allowed value for the doctype of the requested Verifiable Credential."
784
1002
  )
785
1003
  )
786
1004
  })
787
1005
  ),
788
- v9.description(
1006
+ v10.description(
789
1007
  "OPTIONAL. An object defining additional properties requested by the Verifier that apply to the metadata and validity data of the Credential."
790
1008
  )
791
1009
  )
792
1010
  });
793
- DcqlCredentialQuery2.vSdJwtVc = v9.object({
1011
+ DcqlCredentialQuery2.vSdJwtVc = v10.object({
794
1012
  ...vBase.entries,
795
- format: v9.pipe(
796
- v9.picklist(["vc+sd-jwt", "dc+sd-jwt"]),
797
- v9.description("REQUIRED. A string that specifies the format of the requested Verifiable Credential.")
1013
+ format: v10.pipe(
1014
+ v10.picklist(["vc+sd-jwt", "dc+sd-jwt"]),
1015
+ v10.description("REQUIRED. A string that specifies the format of the requested Verifiable Credential.")
798
1016
  ),
799
- claims: v9.pipe(
800
- v9.optional(v9.pipe(v9.array(DcqlClaimsQuery.vW3cSdJwtVc), vNonEmptyArray())),
801
- v9.description("OPTIONAL. A non-empty array of objects as that specifies claims in the requested Credential.")
1017
+ claims: v10.pipe(
1018
+ v10.optional(vNonEmptyArray(DcqlClaimsQuery.vW3cSdJwtVc)),
1019
+ v10.description("OPTIONAL. A non-empty array of objects as that specifies claims in the requested Credential.")
802
1020
  ),
803
- meta: v9.pipe(
804
- v9.optional(
805
- v9.pipe(
806
- v9.object({
807
- vct_values: v9.optional(v9.array(v9.string()))
1021
+ meta: v10.pipe(
1022
+ v10.optional(
1023
+ v10.pipe(
1024
+ v10.object({
1025
+ vct_values: v10.optional(v10.array(v10.string()))
808
1026
  }),
809
- v9.description(
1027
+ v10.description(
810
1028
  "OPTIONAL. An array of strings that specifies allowed values for the type of the requested Verifiable Credential."
811
1029
  )
812
1030
  )
813
1031
  ),
814
- v9.description(
1032
+ v10.description(
815
1033
  "OPTIONAL. An object defining additional properties requested by the Verifier that apply to the metadata and validity data of the Credential."
816
1034
  )
817
1035
  )
818
1036
  });
819
- DcqlCredentialQuery2.vW3cVc = v9.object({
1037
+ DcqlCredentialQuery2.vW3cVc = v10.object({
820
1038
  ...vBase.entries,
821
- format: v9.picklist(["jwt_vc_json", "ldp_vc"]),
822
- claims: v9.optional(v9.pipe(v9.array(DcqlClaimsQuery.vW3cSdJwtVc), vNonEmptyArray())),
823
- meta: v9.pipe(
824
- v9.pipe(
825
- v9.object({
826
- type_values: v9.pipe(
827
- v9.array(v9.pipe(v9.array(v9.string()), vNonEmptyArray())),
828
- vNonEmptyArray(),
829
- v9.description(
1039
+ format: v10.picklist(["jwt_vc_json", "ldp_vc"]),
1040
+ claims: v10.optional(vNonEmptyArray(DcqlClaimsQuery.vW3cSdJwtVc)),
1041
+ meta: v10.pipe(
1042
+ v10.pipe(
1043
+ v10.object({
1044
+ type_values: v10.pipe(
1045
+ vNonEmptyArray(vNonEmptyArray(v10.string())),
1046
+ v10.description(
830
1047
  "REQUIRED. An array of string arrays that specifies the fully expanded types (IRIs) after the @context was applied that the Verifier accepts to be presented in the Presentation. Each of the top-level arrays specifies one alternative to match the type values of the Verifiable Credential against. Each inner array specifies a set of fully expanded types that MUST be present in the type property of the Verifiable Credential, regardless of order or the presence of additional types."
831
1048
  )
832
1049
  )
833
1050
  })
834
1051
  ),
835
- v9.description(
1052
+ v10.description(
836
1053
  "REQUIRED. An object defining additional properties requested by the Verifier that apply to the metadata and validity data of the Credential."
837
1054
  )
838
1055
  )
839
1056
  });
840
- DcqlCredentialQuery2.vModel = v9.variant("format", [DcqlCredentialQuery2.vMdoc, DcqlCredentialQuery2.vSdJwtVc, DcqlCredentialQuery2.vW3cVc]);
1057
+ DcqlCredentialQuery2.vModel = v10.variant("format", [DcqlCredentialQuery2.vMdoc, DcqlCredentialQuery2.vSdJwtVc, DcqlCredentialQuery2.vW3cVc]);
841
1058
  DcqlCredentialQuery2.validate = (credentialQuery) => {
842
1059
  claimSetIdsAreDefined(credentialQuery);
843
1060
  };
@@ -861,177 +1078,264 @@ var claimSetIdsAreDefined = (credentialQuery) => {
861
1078
  };
862
1079
 
863
1080
  // src/dcql-query/m-dcql-credential-set-query.ts
864
- var v10 = __toESM(require("valibot"));
1081
+ var v11 = __toESM(require("valibot"));
865
1082
  var CredentialSetQuery;
866
1083
  ((CredentialSetQuery2) => {
867
- CredentialSetQuery2.vModel = v10.object({
868
- options: v10.pipe(
869
- v10.array(v10.array(vIdString)),
870
- vNonEmptyArray(),
871
- v10.description(
1084
+ CredentialSetQuery2.vModel = v11.object({
1085
+ options: v11.pipe(
1086
+ vNonEmptyArray(v11.array(vIdString)),
1087
+ v11.description(
872
1088
  "REQUIRED. A non-empty array, where each value in the array is a list of Credential Query identifiers representing one set of Credentials that satisfies the use case."
873
1089
  )
874
1090
  ),
875
- required: v10.pipe(
876
- v10.optional(v10.boolean(), true),
877
- v10.description(
1091
+ required: v11.pipe(
1092
+ v11.optional(v11.boolean(), true),
1093
+ v11.description(
878
1094
  `OPTIONAL. Boolean which indicates whether this set of Credentials is required to satisfy the particular use case at the Verifier. If omitted, the default value is 'true'.`
879
1095
  )
880
1096
  ),
881
- purpose: v10.pipe(
882
- v10.optional(v10.union([v10.string(), v10.number(), v10.record(v10.string(), v10.unknown())])),
883
- v10.description("OPTIONAL. A string, number or object specifying the purpose of the query.")
1097
+ purpose: v11.pipe(
1098
+ v11.optional(v11.union([v11.string(), v11.number(), v11.record(v11.string(), v11.unknown())])),
1099
+ v11.description("OPTIONAL. A string, number or object specifying the purpose of the query.")
884
1100
  )
885
1101
  });
886
1102
  })(CredentialSetQuery || (CredentialSetQuery = {}));
887
1103
 
1104
+ // src/dcql-query-result/m-claims-result.ts
1105
+ var v12 = __toESM(require("valibot"));
1106
+ var DcqlClaimsResult;
1107
+ ((DcqlClaimsResult2) => {
1108
+ const vClaimsOutput = v12.union([
1109
+ DcqlMdocCredential.vModel.entries.namespaces,
1110
+ DcqlSdJwtVcCredential.vModel.entries.claims,
1111
+ DcqlW3cVcCredential.vModel.entries.claims
1112
+ ]);
1113
+ DcqlClaimsResult2.vClaimsEntrySuccessResult = v12.object({
1114
+ success: v12.literal(true),
1115
+ claim_index: v12.number(),
1116
+ claim_id: v12.optional(vIdString),
1117
+ output: vClaimsOutput
1118
+ });
1119
+ DcqlClaimsResult2.vClaimsEntryFailureResult = v12.object({
1120
+ success: v12.literal(false),
1121
+ claim_index: v12.number(),
1122
+ claim_id: v12.optional(vIdString),
1123
+ issues: v12.record(v12.string(), v12.unknown()),
1124
+ output: v12.unknown()
1125
+ });
1126
+ DcqlClaimsResult2.vClaimSetSuccessResult = v12.object({
1127
+ success: v12.literal(true),
1128
+ // Undefined in case of no claim set
1129
+ claim_set_index: v12.union([v12.number(), v12.undefined()]),
1130
+ // We use indexes because if there are no claim sets, the ids can be undefined
1131
+ // Can be empty array in case there are no claims
1132
+ valid_claim_indexes: v12.array(v12.number()),
1133
+ failed_claim_indexes: v12.optional(v12.undefined()),
1134
+ output: vClaimsOutput
1135
+ });
1136
+ DcqlClaimsResult2.vClaimSetFailureResult = v12.object({
1137
+ success: v12.literal(false),
1138
+ // Undefined in case of no claim set
1139
+ claim_set_index: v12.union([v12.number(), v12.undefined()]),
1140
+ // We use indexes because if there are no claim sets, the ids can be undefined
1141
+ valid_claim_indexes: v12.array(v12.number()),
1142
+ failed_claim_indexes: vNonEmptyArray(v12.number()),
1143
+ issues: v12.record(v12.string(), v12.unknown())
1144
+ });
1145
+ DcqlClaimsResult2.vClaimsSuccessResult = v12.object({
1146
+ success: v12.literal(true),
1147
+ valid_claims: v12.array(DcqlClaimsResult2.vClaimsEntrySuccessResult),
1148
+ failed_claims: v12.array(DcqlClaimsResult2.vClaimsEntryFailureResult),
1149
+ valid_claim_sets: vNonEmptyArray(DcqlClaimsResult2.vClaimSetSuccessResult),
1150
+ failed_claim_sets: v12.array(DcqlClaimsResult2.vClaimSetFailureResult)
1151
+ });
1152
+ DcqlClaimsResult2.vClaimsFailureResult = v12.object({
1153
+ success: v12.literal(false),
1154
+ valid_claims: v12.array(DcqlClaimsResult2.vClaimsEntrySuccessResult),
1155
+ failed_claims: vNonEmptyArray(DcqlClaimsResult2.vClaimsEntryFailureResult),
1156
+ valid_claim_sets: v12.optional(v12.undefined()),
1157
+ failed_claim_sets: vNonEmptyArray(DcqlClaimsResult2.vClaimSetFailureResult)
1158
+ });
1159
+ DcqlClaimsResult2.vModel = v12.union([DcqlClaimsResult2.vClaimsSuccessResult, DcqlClaimsResult2.vClaimsFailureResult]);
1160
+ })(DcqlClaimsResult || (DcqlClaimsResult = {}));
1161
+
1162
+ // src/dcql-query-result/m-meta-result.ts
1163
+ var v13 = __toESM(require("valibot"));
1164
+ var DcqlMetaResult;
1165
+ ((DcqlMetaResult2) => {
1166
+ DcqlMetaResult2.vMetaSuccessResult = v13.object({
1167
+ success: v13.literal(true),
1168
+ // TODO: This needs to be format specific
1169
+ output: v13.object({
1170
+ credential_format: v13.string()
1171
+ })
1172
+ });
1173
+ DcqlMetaResult2.vMetaFailureResult = v13.object({
1174
+ success: v13.literal(false),
1175
+ issues: v13.record(v13.string(), v13.unknown()),
1176
+ output: v13.unknown()
1177
+ });
1178
+ DcqlMetaResult2.vModel = v13.union([DcqlMetaResult2.vMetaSuccessResult, DcqlMetaResult2.vMetaFailureResult]);
1179
+ })(DcqlMetaResult || (DcqlMetaResult = {}));
1180
+
1181
+ // src/dcql-query-result/m-trusted-authorities-result.ts
1182
+ var v14 = __toESM(require("valibot"));
1183
+ var DcqlTrustedAuthoritiesResult;
1184
+ ((DcqlTrustedAuthoritiesResult2) => {
1185
+ DcqlTrustedAuthoritiesResult2.vTrustedAuthorityEntrySuccessResult = v14.object({
1186
+ success: v14.literal(true),
1187
+ trusted_authority_index: v14.number(),
1188
+ output: DcqlCredentialTrustedAuthority.vModel
1189
+ });
1190
+ DcqlTrustedAuthoritiesResult2.vTrustedAuthorityEntryFailureResult = v14.object({
1191
+ success: v14.literal(false),
1192
+ trusted_authority_index: v14.number(),
1193
+ issues: v14.record(v14.string(), v14.unknown()),
1194
+ output: v14.unknown()
1195
+ });
1196
+ DcqlTrustedAuthoritiesResult2.vTrustedAuthoritySuccessResult = v14.union([
1197
+ // In this case there is no trusted authority on the query
1198
+ v14.object({
1199
+ success: v14.literal(true),
1200
+ valid_trusted_authority: v14.optional(v14.undefined()),
1201
+ failed_trusted_authorities: v14.optional(v14.undefined())
1202
+ }),
1203
+ v14.object({
1204
+ success: v14.literal(true),
1205
+ valid_trusted_authority: DcqlTrustedAuthoritiesResult2.vTrustedAuthorityEntrySuccessResult,
1206
+ failed_trusted_authorities: v14.array(DcqlTrustedAuthoritiesResult2.vTrustedAuthorityEntryFailureResult)
1207
+ })
1208
+ ]);
1209
+ DcqlTrustedAuthoritiesResult2.vTrustedAuthorityFailureResult = v14.object({
1210
+ success: v14.literal(false),
1211
+ valid_trusted_authority: v14.optional(v14.undefined()),
1212
+ failed_trusted_authorities: vNonEmptyArray(DcqlTrustedAuthoritiesResult2.vTrustedAuthorityEntryFailureResult)
1213
+ });
1214
+ DcqlTrustedAuthoritiesResult2.vModel = v14.union([...DcqlTrustedAuthoritiesResult2.vTrustedAuthoritySuccessResult.options, DcqlTrustedAuthoritiesResult2.vTrustedAuthorityFailureResult]);
1215
+ })(DcqlTrustedAuthoritiesResult || (DcqlTrustedAuthoritiesResult = {}));
1216
+
888
1217
  // src/dcql-query-result/m-dcql-query-result.ts
889
1218
  var DcqlQueryResult;
890
1219
  ((DcqlQueryResult2) => {
891
- DcqlQueryResult2.vCredentialQueryResult = v11.pipe(
892
- v11.array(v11.array(v11.union([v11.undefined(), DcqlCredential.vParseSuccess, DcqlCredential.vParseFailure]))),
893
- vNonEmptyArray()
894
- );
895
- DcqlQueryResult2.vModel = v11.object({
896
- credentials: v11.pipe(
897
- v11.array(DcqlCredentialQuery.vModel),
898
- vNonEmptyArray(),
899
- v11.description(
1220
+ DcqlQueryResult2.vCredentialQueryItemCredentialSuccessResult = v15.object({
1221
+ success: v15.literal(true),
1222
+ input_credential_index: v15.number(),
1223
+ trusted_authorities: DcqlTrustedAuthoritiesResult.vTrustedAuthoritySuccessResult,
1224
+ // TODO: format specific (we should probably add format to this object, to differentiate?)
1225
+ claims: DcqlClaimsResult.vClaimsSuccessResult,
1226
+ meta: DcqlMetaResult.vMetaSuccessResult
1227
+ });
1228
+ DcqlQueryResult2.vCredentialQueryItemCredentialFailureResult = v15.object({
1229
+ success: v15.literal(false),
1230
+ input_credential_index: v15.number(),
1231
+ trusted_authorities: DcqlTrustedAuthoritiesResult.vModel,
1232
+ claims: DcqlClaimsResult.vModel,
1233
+ meta: DcqlMetaResult.vModel
1234
+ });
1235
+ DcqlQueryResult2.vCredentialQueryItemResult = v15.union([
1236
+ v15.object({
1237
+ success: v15.literal(true),
1238
+ credential_query_id: vIdString,
1239
+ valid_credentials: vNonEmptyArray(DcqlQueryResult2.vCredentialQueryItemCredentialSuccessResult),
1240
+ failed_credentials: v15.array(DcqlQueryResult2.vCredentialQueryItemCredentialFailureResult)
1241
+ }),
1242
+ v15.object({
1243
+ success: v15.literal(false),
1244
+ credential_query_id: vIdString,
1245
+ valid_credentials: v15.optional(v15.undefined()),
1246
+ failed_credentials: vNonEmptyArray(DcqlQueryResult2.vCredentialQueryItemCredentialFailureResult)
1247
+ })
1248
+ ]);
1249
+ DcqlQueryResult2.vCredentialQueryResult = v15.record(vIdString, DcqlQueryResult2.vCredentialQueryItemResult);
1250
+ DcqlQueryResult2.vModel = v15.object({
1251
+ credentials: v15.pipe(
1252
+ vNonEmptyArray(DcqlCredentialQuery.vModel),
1253
+ v15.description(
900
1254
  "REQUIRED. A non-empty array of Credential Queries that specify the requested Verifiable Credentials."
901
1255
  )
902
1256
  ),
903
- credential_matches: v11.record(
904
- v11.pipe(vIdString),
905
- v11.union([
906
- v11.object({
907
- ...DcqlCredential.vParseSuccess.entries,
908
- all: v11.pipe(
909
- v11.array(
910
- v11.pipe(
911
- v11.array(v11.union([v11.undefined(), DcqlCredential.vParseSuccess, DcqlCredential.vParseFailure])),
912
- vNonEmptyArray()
913
- )
914
- ),
915
- vNonEmptyArray()
916
- )
917
- }),
918
- v11.object({
919
- success: DcqlCredential.vParseFailure.entries.success,
920
- all: v11.pipe(
921
- v11.array(
922
- v11.pipe(
923
- v11.array(v11.union([v11.undefined(), DcqlCredential.vParseSuccess, DcqlCredential.vParseFailure])),
924
- vNonEmptyArray()
925
- )
926
- ),
927
- vNonEmptyArray()
928
- )
929
- })
930
- ])
931
- ),
932
- credential_sets: v11.optional(
933
- v11.pipe(
934
- v11.array(
935
- v11.object({
1257
+ credential_matches: DcqlQueryResult2.vCredentialQueryResult,
1258
+ credential_sets: v15.optional(
1259
+ v15.pipe(
1260
+ vNonEmptyArray(
1261
+ v15.object({
936
1262
  ...CredentialSetQuery.vModel.entries,
937
- matching_options: v11.union([v11.undefined(), v11.pipe(v11.array(v11.array(v11.string())), vNonEmptyArray())])
1263
+ matching_options: v15.union([v15.undefined(), vNonEmptyArray(v15.array(v15.string()))])
938
1264
  })
939
1265
  ),
940
- vNonEmptyArray(),
941
- v11.description(
1266
+ v15.description(
942
1267
  "OPTIONAL. A non-empty array of credential set queries that specifies additional constraints on which of the requested Verifiable Credentials to return."
943
1268
  )
944
1269
  )
945
1270
  ),
946
- canBeSatisfied: v11.boolean()
1271
+ can_be_satisfied: v15.boolean()
947
1272
  });
948
1273
  })(DcqlQueryResult || (DcqlQueryResult = {}));
949
1274
 
950
1275
  // src/dcql-presentation/m-dcql-presentation-result.ts
951
1276
  var DcqlPresentationResult;
952
1277
  ((DcqlPresentationResult2) => {
953
- DcqlPresentationResult2.vModel = v12.object({
954
- ...v12.omit(DcqlQueryResult.vModel, ["credential_matches"]).entries,
955
- invalid_matches: v12.union([
956
- v12.record(
957
- v12.pipe(vIdString),
958
- v12.object({
959
- ...v12.omit(DcqlCredential.vParseFailure, ["input_credential_index"]).entries,
960
- presentation_id: v12.pipe(vIdString)
961
- })
962
- ),
963
- v12.undefined()
964
- ]),
965
- valid_matches: v12.record(
966
- v12.pipe(vIdString),
967
- v12.object({
968
- ...v12.omit(DcqlCredential.vParseSuccess, ["issues", "input_credential_index"]).entries,
969
- presentation_id: v12.pipe(vIdString)
970
- })
971
- )
972
- });
1278
+ DcqlPresentationResult2.vModel = v16.omit(DcqlQueryResult.vModel, ["credentials"]);
973
1279
  DcqlPresentationResult2.parse = (input) => {
974
- return v12.parse(DcqlPresentationResult2.vModel, input);
1280
+ return v16.parse(DcqlPresentationResult2.vModel, input);
975
1281
  };
976
1282
  DcqlPresentationResult2.fromDcqlPresentation = (dcqlPresentation, ctx) => {
977
1283
  const { dcqlQuery } = ctx;
978
- const presentationQueriesResults = Object.fromEntries(
979
- Object.entries(dcqlPresentation).map(([queryId, presentation]) => {
980
- const credentialQuery = dcqlQuery.credentials.find((c) => c.id === queryId);
981
- if (!credentialQuery) {
1284
+ const queriesResults = Object.entries(dcqlPresentation).map(([credentialQueryId, presentations]) => {
1285
+ const credentialQuery = dcqlQuery.credentials.find((c) => c.id === credentialQueryId);
1286
+ if (!credentialQuery) {
1287
+ throw new DcqlPresentationResultError({
1288
+ message: `Query ${credentialQueryId} not found in the dcql query. Cannot validate presentation.`
1289
+ });
1290
+ }
1291
+ if (Array.isArray(presentations)) {
1292
+ if (presentations.length === 0) {
982
1293
  throw new DcqlPresentationResultError({
983
- message: `Query ${queryId} not found in the dcql query. Cannot validate presentation.`
1294
+ message: `Query credential '${credentialQueryId}' is present in the presentations but the value is an empty array. Each entry must at least provide one presentation.`
984
1295
  });
985
1296
  }
986
- return [
987
- queryId,
988
- runCredentialQuery(credentialQuery, {
989
- presentation: true,
990
- credentials: [presentation]
991
- })
992
- ];
993
- })
994
- );
995
- let invalidMatches = {};
996
- const validMatches = {};
997
- for (const [queryId, presentationQueryResult] of Object.entries(presentationQueriesResults)) {
998
- for (const presentationQueryResultForClaimSet of presentationQueryResult) {
999
- const result = presentationQueryResultForClaimSet[0];
1000
- if (result?.success) {
1001
- const { issues, input_credential_index, ...rest } = result;
1002
- validMatches[queryId] = { ...rest, presentation_id: queryId };
1003
- } else if (result?.success === false) {
1004
- const { input_credential_index, ...rest } = result;
1005
- invalidMatches[queryId] = {
1006
- ...rest,
1007
- presentation_id: queryId
1008
- };
1297
+ if (!credentialQuery.multiple && presentations.length > 1) {
1298
+ throw new DcqlPresentationResultError({
1299
+ message: `Query credential '${credentialQueryId}' has not enabled 'multiple', but multiple presentations were provided. Only a single presentation is allowed for each query credential when 'multiple' is not enabled on the query.`
1300
+ });
1009
1301
  }
1010
1302
  }
1011
- }
1012
- invalidMatches = Object.fromEntries(
1013
- Object.entries(invalidMatches ?? {}).filter(([queryId]) => validMatches[queryId] === void 0)
1014
- );
1303
+ return runCredentialQuery(credentialQuery, {
1304
+ presentation: true,
1305
+ credentials: presentations ? Array.isArray(presentations) ? presentations : [presentations] : []
1306
+ });
1307
+ });
1015
1308
  const credentialSetResults = dcqlQuery.credential_sets?.map((set) => {
1016
1309
  const matchingOptions = set.options.filter(
1017
- (option) => option.every((credentialQueryId) => validMatches[credentialQueryId]?.success)
1310
+ (option) => option.every(
1311
+ (credentialQueryId) => queriesResults.find((result) => result.credential_query_id === credentialQueryId)?.success
1312
+ )
1018
1313
  );
1019
1314
  return {
1020
1315
  ...set,
1021
1316
  matching_options: matchingOptions.length > 0 ? matchingOptions : void 0
1022
1317
  };
1023
1318
  });
1024
- const dqclQueryMatched = credentialSetResults ? credentialSetResults.every((set) => !set.required || set.matching_options) : Object.keys(validMatches).length === ctx.dcqlQuery.credentials.length;
1319
+ const dqclQueryMatched = (
1320
+ // We require that all the submitted presentations match with the queries
1321
+ // So we must have success for all queries, and we don't allow failed_credentials
1322
+ queriesResults.every((result) => result.success && result.failed_credentials.length === 0) && (credentialSetResults ? credentialSetResults.every((set) => !set.required || set.matching_options) : (
1323
+ // If not credential_sets are used, we require that at least every credential has a match
1324
+ dcqlQuery.credentials.every(
1325
+ (credentialQuery) => queriesResults.find((result) => result.credential_query_id === credentialQuery.id)?.success
1326
+ )
1327
+ ))
1328
+ );
1025
1329
  return {
1026
- ...dcqlQuery,
1027
- canBeSatisfied: dqclQueryMatched,
1028
- valid_matches: validMatches,
1029
- invalid_matches: Object.keys(invalidMatches).length === 0 ? void 0 : invalidMatches,
1030
- credential_sets: credentialSetResults
1330
+ // NOTE: can_be_satisfied is maybe not the best term, because we return false if it can be
1331
+ // satisfied, but one of the provided presentations did not match
1332
+ can_be_satisfied: dqclQueryMatched,
1333
+ credential_sets: credentialSetResults,
1334
+ credential_matches: Object.fromEntries(queriesResults.map((result) => [result.credential_query_id, result]))
1031
1335
  };
1032
1336
  };
1033
1337
  DcqlPresentationResult2.validate = (dcqlQueryResult) => {
1034
- if (!dcqlQueryResult.canBeSatisfied) {
1338
+ if (!dcqlQueryResult.can_be_satisfied) {
1035
1339
  throw new DcqlInvalidPresentationRecordError({
1036
1340
  message: "Invalid Presentation record",
1037
1341
  cause: dcqlQueryResult
@@ -1042,15 +1346,28 @@ var DcqlPresentationResult;
1042
1346
  })(DcqlPresentationResult || (DcqlPresentationResult = {}));
1043
1347
 
1044
1348
  // src/dcql-presentation/m-dcql-presentation.ts
1045
- var v13 = __toESM(require("valibot"));
1349
+ var v17 = __toESM(require("valibot"));
1046
1350
  var DcqlPresentation;
1047
1351
  ((DcqlPresentation2) => {
1048
- DcqlPresentation2.vModel = v13.record(vIdString, v13.union([v13.string(), vJsonRecord]));
1352
+ const vPresentationEntry = v17.union([v17.string(), vJsonRecord]);
1353
+ DcqlPresentation2.vModel = v17.pipe(
1354
+ v17.union([
1355
+ v17.record(vIdString, vNonEmptyArray(vPresentationEntry)),
1356
+ v17.record(
1357
+ vIdString,
1358
+ // We support presentation entry directly (not as array) to support older draft of DCQL
1359
+ vPresentationEntry
1360
+ )
1361
+ ]),
1362
+ v17.description(
1363
+ "REQUIRED. This is a JSON-encoded object containing entries where the key is the id value used for a Credential Query in the DCQL query and the value is an array of one or more Presentations that match the respective Credential Query. When multiple is omitted, or set to false, the array MUST contain only one Presentation. There MUST NOT be any entry in the JSON-encoded object for optional Credential Queries when there are no matching Credentials for the respective Credential Query. Each Presentation is represented as a string or object, depending on the format as defined in Appendix B. The same rules as above apply for encoding the Presentations."
1364
+ )
1365
+ );
1049
1366
  DcqlPresentation2.parse = (input) => {
1050
1367
  if (typeof input === "string") {
1051
- return v13.parse(v13.pipe(v13.string(), vStringToJson, DcqlPresentation2.vModel), input);
1368
+ return v17.parse(v17.pipe(v17.string(), vStringToJson, DcqlPresentation2.vModel), input);
1052
1369
  }
1053
- return v13.parse(DcqlPresentation2.vModel, input);
1370
+ return v17.parse(DcqlPresentation2.vModel, input);
1054
1371
  };
1055
1372
  DcqlPresentation2.encode = (input) => {
1056
1373
  return JSON.stringify(input);
@@ -1062,60 +1379,41 @@ var runDcqlQuery = (dcqlQuery, ctx) => {
1062
1379
  const credentialQueriesResults = Object.fromEntries(
1063
1380
  dcqlQuery.credentials.map((credentialQuery) => [credentialQuery.id, runCredentialQuery(credentialQuery, ctx)])
1064
1381
  );
1065
- const credentialMatches = Object.fromEntries(
1066
- Object.entries(credentialQueriesResults).map(([key, credentialQueryResult]) => {
1067
- let bestMatch = void 0;
1068
- for (const credentialParseResult of credentialQueryResult) {
1069
- const bestMatchForCredential = credentialParseResult.find((result) => result?.success === true);
1070
- if (!bestMatch && bestMatchForCredential) {
1071
- const { issues, ...matchWithoutIssues } = bestMatchForCredential;
1072
- bestMatch = matchWithoutIssues;
1073
- continue;
1074
- }
1075
- if (bestMatchForCredential && bestMatchForCredential.claim_set_index < bestMatch?.claim_set_index) {
1076
- const { issues, ...matchWithoutIssues } = bestMatchForCredential;
1077
- bestMatch = matchWithoutIssues;
1078
- }
1079
- }
1080
- return [
1081
- key,
1082
- bestMatch ? { ...bestMatch, all: credentialQueryResult } : { success: false, all: credentialQueryResult }
1083
- ];
1084
- })
1085
- );
1086
1382
  const credentialSetResults = dcqlQuery.credential_sets?.map((set) => {
1087
1383
  const matchingOptions = set.options.filter(
1088
- (option) => option.every((credentialQueryId) => credentialMatches[credentialQueryId]?.success)
1384
+ (option) => option.every((credentialQueryId) => credentialQueriesResults[credentialQueryId].success)
1089
1385
  );
1090
1386
  return {
1091
1387
  ...set,
1092
1388
  matching_options: matchingOptions.length > 0 ? matchingOptions : void 0
1093
1389
  };
1094
1390
  });
1095
- const dqclQueryMatched = credentialSetResults ? credentialSetResults.every((set) => !set.required || set.matching_options) : Object.values(credentialMatches).every((query) => query.success);
1391
+ const dqclQueryMatched = credentialSetResults ? credentialSetResults.every((set) => !set.required || set.matching_options) : (
1392
+ // If not credential_sets are used, we require that at least every credential has a match
1393
+ dcqlQuery.credentials.every(({ id }) => credentialQueriesResults[id].success === true)
1394
+ );
1096
1395
  return {
1097
1396
  ...dcqlQuery,
1098
- canBeSatisfied: dqclQueryMatched,
1099
- credential_matches: credentialMatches,
1397
+ can_be_satisfied: dqclQueryMatched,
1398
+ credential_matches: credentialQueriesResults,
1100
1399
  credential_sets: credentialSetResults
1101
1400
  };
1102
1401
  };
1103
1402
 
1104
1403
  // src/dcql-query/m-dcql-query.ts
1105
- var v14 = __toESM(require("valibot"));
1404
+ var v18 = __toESM(require("valibot"));
1106
1405
  var DcqlQuery;
1107
1406
  ((DcqlQuery2) => {
1108
- DcqlQuery2.vModel = v14.object({
1109
- credentials: v14.pipe(
1110
- v14.array(DcqlCredentialQuery.vModel),
1111
- vNonEmptyArray(),
1112
- v14.description(
1407
+ DcqlQuery2.vModel = v18.object({
1408
+ credentials: v18.pipe(
1409
+ vNonEmptyArray(DcqlCredentialQuery.vModel),
1410
+ v18.description(
1113
1411
  "REQUIRED. A non-empty array of Credential Queries that specify the requested Verifiable Credentials."
1114
1412
  )
1115
1413
  ),
1116
- credential_sets: v14.pipe(
1117
- v14.optional(v14.pipe(v14.array(CredentialSetQuery.vModel), vNonEmptyArray())),
1118
- v14.description(
1414
+ credential_sets: v18.pipe(
1415
+ v18.optional(vNonEmptyArray(CredentialSetQuery.vModel)),
1416
+ v18.description(
1119
1417
  "OPTIONAL. A non-empty array of credential set queries that specifies additional constraints on which of the requested Verifiable Credentials to return."
1120
1418
  )
1121
1419
  )
@@ -1129,7 +1427,7 @@ var DcqlQuery;
1129
1427
  return runDcqlQuery(dcqlQuery, { credentials, presentation: false });
1130
1428
  };
1131
1429
  DcqlQuery2.parse = (input) => {
1132
- return v14.parse(DcqlQuery2.vModel, input);
1430
+ return v18.parse(DcqlQuery2.vModel, input);
1133
1431
  };
1134
1432
  })(DcqlQuery || (DcqlQuery = {}));
1135
1433
  var validateUniqueCredentialQueryIds = (query) => {