dcql 0.3.1-alpha-20250624142312 → 0.4.0-alpha-20250704223931
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/README.md +4 -40
- package/dist/index.d.mts +7127 -4169
- package/dist/index.d.ts +7127 -4169
- package/dist/index.js +684 -386
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +684 -386
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
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.
|
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
|
-
|
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
|
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
|
-
|
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/
|
544
|
-
|
545
|
-
|
546
|
-
|
547
|
-
|
548
|
-
|
549
|
-
|
550
|
-
|
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 (
|
559
|
-
|
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
|
-
|
562
|
-
|
563
|
-
|
564
|
-
|
565
|
-
|
566
|
-
|
567
|
-
|
568
|
-
|
569
|
-
|
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
|
-
|
579
|
-
|
580
|
-
|
581
|
-
|
582
|
-
|
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
|
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 :
|
632
|
+
const elementParser = isLast ? vClaimParser : getJsonClaimParser(claimQuery, { ...ctx, index: index + 1 });
|
591
633
|
if (presentation) {
|
592
|
-
return v7.
|
593
|
-
v7.
|
594
|
-
|
595
|
-
|
596
|
-
|
597
|
-
|
598
|
-
|
599
|
-
|
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(
|
604
|
-
v7.
|
605
|
-
|
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
|
-
|
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
|
614
|
-
}
|
615
|
-
|
616
|
-
|
617
|
-
|
618
|
-
|
619
|
-
|
620
|
-
|
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
|
627
|
-
|
628
|
-
|
629
|
-
|
630
|
-
|
631
|
-
|
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
|
-
|
635
|
-
|
636
|
-
|
637
|
-
|
638
|
-
|
639
|
-
|
640
|
-
|
641
|
-
|
642
|
-
|
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
|
-
|
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
|
-
|
649
|
-
|
650
|
-
|
651
|
-
|
652
|
-
const
|
653
|
-
|
654
|
-
doctype
|
655
|
-
|
656
|
-
|
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
|
661
|
-
|
662
|
-
|
663
|
-
|
664
|
-
|
665
|
-
|
666
|
-
|
667
|
-
|
668
|
-
|
669
|
-
|
670
|
-
|
671
|
-
|
672
|
-
|
673
|
-
|
674
|
-
|
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 === "
|
678
|
-
return
|
679
|
-
|
680
|
-
|
681
|
-
|
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
|
694
|
-
|
695
|
-
|
696
|
-
|
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
|
-
|
700
|
-
|
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
|
-
|
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
|
-
|
709
|
-
|
710
|
-
|
711
|
-
|
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
|
-
|
716
|
-
|
717
|
-
|
718
|
-
|
719
|
-
|
720
|
-
|
721
|
-
|
722
|
-
|
723
|
-
|
724
|
-
|
725
|
-
|
726
|
-
|
727
|
-
|
728
|
-
|
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
|
-
|
927
|
+
trusted_authorities: trustedAuthorityResult,
|
928
|
+
meta: metaResult,
|
929
|
+
claims: claimsResult
|
732
930
|
});
|
733
931
|
}
|
734
|
-
credentialQueryResult.push(claimSetResult);
|
735
932
|
}
|
736
|
-
|
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
|
952
|
+
var v15 = __toESM(require("valibot"));
|
741
953
|
|
742
954
|
// src/dcql-query/m-dcql-credential-query.ts
|
743
|
-
var
|
955
|
+
var v10 = __toESM(require("valibot"));
|
744
956
|
var DcqlCredentialQuery;
|
745
957
|
((DcqlCredentialQuery2) => {
|
746
|
-
const vBase =
|
747
|
-
id:
|
748
|
-
|
749
|
-
|
750
|
-
|
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
|
-
|
755
|
-
|
756
|
-
|
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:
|
761
|
-
|
762
|
-
|
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 =
|
985
|
+
DcqlCredentialQuery2.vMdoc = v10.object({
|
768
986
|
...vBase.entries,
|
769
|
-
format:
|
770
|
-
|
771
|
-
|
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:
|
774
|
-
|
775
|
-
|
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:
|
778
|
-
|
779
|
-
|
780
|
-
doctype_value:
|
781
|
-
|
782
|
-
|
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
|
-
|
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 =
|
1011
|
+
DcqlCredentialQuery2.vSdJwtVc = v10.object({
|
794
1012
|
...vBase.entries,
|
795
|
-
format:
|
796
|
-
|
797
|
-
|
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:
|
800
|
-
|
801
|
-
|
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:
|
804
|
-
|
805
|
-
|
806
|
-
|
807
|
-
vct_values:
|
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
|
-
|
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
|
-
|
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 =
|
1037
|
+
DcqlCredentialQuery2.vW3cVc = v10.object({
|
820
1038
|
...vBase.entries,
|
821
|
-
format:
|
822
|
-
claims:
|
823
|
-
meta:
|
824
|
-
|
825
|
-
|
826
|
-
type_values:
|
827
|
-
|
828
|
-
|
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
|
-
|
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 =
|
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
|
1081
|
+
var v11 = __toESM(require("valibot"));
|
865
1082
|
var CredentialSetQuery;
|
866
1083
|
((CredentialSetQuery2) => {
|
867
|
-
CredentialSetQuery2.vModel =
|
868
|
-
options:
|
869
|
-
|
870
|
-
|
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:
|
876
|
-
|
877
|
-
|
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:
|
882
|
-
|
883
|
-
|
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.
|
892
|
-
|
893
|
-
|
894
|
-
|
895
|
-
|
896
|
-
|
897
|
-
|
898
|
-
|
899
|
-
|
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:
|
904
|
-
|
905
|
-
|
906
|
-
|
907
|
-
|
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:
|
1263
|
+
matching_options: v15.union([v15.undefined(), vNonEmptyArray(v15.array(v15.string()))])
|
938
1264
|
})
|
939
1265
|
),
|
940
|
-
|
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
|
-
|
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 =
|
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
|
1280
|
+
return v16.parse(DcqlPresentationResult2.vModel, input);
|
975
1281
|
};
|
976
1282
|
DcqlPresentationResult2.fromDcqlPresentation = (dcqlPresentation, ctx) => {
|
977
1283
|
const { dcqlQuery } = ctx;
|
978
|
-
const
|
979
|
-
|
980
|
-
|
981
|
-
|
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 ${
|
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
|
-
|
987
|
-
|
988
|
-
|
989
|
-
|
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
|
-
|
1013
|
-
|
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(
|
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 =
|
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
|
-
|
1027
|
-
|
1028
|
-
|
1029
|
-
|
1030
|
-
|
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.
|
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
|
1349
|
+
var v17 = __toESM(require("valibot"));
|
1046
1350
|
var DcqlPresentation;
|
1047
1351
|
((DcqlPresentation2) => {
|
1048
|
-
|
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
|
1368
|
+
return v17.parse(v17.pipe(v17.string(), vStringToJson, DcqlPresentation2.vModel), input);
|
1052
1369
|
}
|
1053
|
-
return
|
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) =>
|
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) :
|
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
|
-
|
1099
|
-
credential_matches:
|
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
|
1404
|
+
var v18 = __toESM(require("valibot"));
|
1106
1405
|
var DcqlQuery;
|
1107
1406
|
((DcqlQuery2) => {
|
1108
|
-
DcqlQuery2.vModel =
|
1109
|
-
credentials:
|
1110
|
-
|
1111
|
-
|
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:
|
1117
|
-
|
1118
|
-
|
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
|
1430
|
+
return v18.parse(DcqlQuery2.vModel, input);
|
1133
1431
|
};
|
1134
1432
|
})(DcqlQuery || (DcqlQuery = {}));
|
1135
1433
|
var validateUniqueCredentialQueryIds = (query) => {
|