@eudiplo/cli 8.1.0-main.7e6a44b → 8.1.0-main.8f6abca

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
@@ -14907,7 +14907,7 @@ var CONFIG_FORMATS = {
14907
14907
  PresentationConfig: {
14908
14908
  slug: "presentation-config",
14909
14909
  file: "PresentationConfigFile",
14910
- version: 2
14910
+ version: 3
14911
14911
  },
14912
14912
  AttributeProvider: {
14913
14913
  slug: "attribute-provider",
@@ -14980,7 +14980,18 @@ var CONFIG_MIGRATIONS = [
14980
14980
  // valid v2 spec whose offers keep having no lifetime.
14981
14981
  migrate: (spec) => ({ spec })
14982
14982
  },
14983
- presentationConfigV1ToV2
14983
+ presentationConfigV1ToV2,
14984
+ {
14985
+ id: "presentation-config-v3-typed-claim-values",
14986
+ kind: "PresentationConfig",
14987
+ from: 2,
14988
+ to: 3,
14989
+ // v3 accepts integer and boolean DCQL claim `values` besides strings
14990
+ // and requires them to be non-empty. A v2 spec with non-empty string
14991
+ // values is a valid v3 spec; an empty `values` array fails v3
14992
+ // validation, since it could never match a disclosed claim.
14993
+ migrate: (spec) => ({ spec })
14994
+ }
14984
14995
  ];
14985
14996
  function schemaUrl(kind, version = CONFIG_FORMATS[kind].version) {
14986
14997
  if (!Number.isSafeInteger(version) || version < 1)
@@ -21440,212 +21451,957 @@ var CONFIG_SCHEMAS = [
21440
21451
  "title": "PresentationConfigCreateDto"
21441
21452
  }
21442
21453
  }
21443
- }
21444
- ];
21445
-
21446
- // ../../packages/eudiplo-config-format/dist/config-validator.js
21447
- var ajv = new import__.Ajv2020({
21448
- allErrors: true,
21449
- strict: false,
21450
- validateFormats: false
21451
- });
21452
- for (const schema of CONFIG_SCHEMAS)
21453
- ajv.addSchema(schema);
21454
- function validateConfigDocument(document) {
21455
- const file = serializeDocument(document);
21456
- const validate = ajv.getSchema(file.$schema);
21457
- if (!validate)
21458
- throw new Error(`No bundled validator for ${file.$schema}`);
21459
- const issues = [];
21460
- if (!validate(file)) {
21461
- for (const issue of validate.errors ?? [])
21462
- issues.push({
21463
- severity: "error",
21464
- code: "CONFIG_SCHEMA_VALIDATION_FAILED",
21465
- path: issue.instancePath || "/",
21466
- message: issue.keyword === "additionalProperties" ? `Unknown property: ${String(issue.params.additionalProperty)}` : issue.message ?? "Invalid configuration",
21467
- resource: { kind: document.kind, id: resourceId(document) }
21468
- });
21469
- }
21470
- const id = document.kind === "Client" ? document.spec.clientId : document.spec.id;
21471
- if (id !== void 0 && id !== resourceId(document))
21472
- issues.push({
21473
- severity: "error",
21474
- code: "RESOURCE_ID_MISMATCH",
21475
- path: document.kind === "Client" ? "/spec/clientId" : "/spec/id",
21476
- message: "Resource identifier does not match metadata.id"
21477
- });
21478
- return issues;
21479
- }
21480
-
21481
- // src/commands/config/portability/migrations.ts
21482
- function upgradeDocument(input) {
21483
- const result = migrateDocument(input, validateConfigDocument);
21484
- return { ...result, document: serializeDocument(result.document) };
21485
- }
21486
-
21487
- // src/commands/config/portability/upgrade.ts
21488
- var codec = new ConfigBundleCodec();
21489
- function parse3(text, path2) {
21490
- try {
21491
- return JSON.parse(text);
21492
- } catch {
21493
- throw new Error(`Invalid JSON in ${path2}`);
21494
- }
21495
- }
21496
- function upgradeJson(input, file, context) {
21497
- const bundle = Array.isArray(input?.documents);
21498
- if (bundle) assertConfigBundle(input);
21499
- const results = (bundle ? input.documents : [input]).map(
21500
- (document) => upgradeDocument(document)
21501
- );
21502
- let blocked = false;
21503
- for (const result of results) {
21504
- for (const issue of result.issues) {
21505
- context.stderr.write(
21506
- `${file}${issue.path}: ${issue.severity} ${issue.code}: ${issue.message}
21507
- `
21508
- );
21509
- if (issue.severity !== "warning") blocked = true;
21510
- }
21511
- for (const migration of result.migrations)
21512
- context.stdout.write(`${file}: migration ${migration}
21513
- `);
21514
- }
21515
- if (blocked) throw new Error(`${file}: upgrade blocked; no output written`);
21516
- if (!bundle) return results[0].document;
21517
- const documents = results.map(
21518
- (result) => result.document
21519
- );
21520
- const resources = input.manifest.resources.map(
21521
- (resource) => {
21522
- const index = input.documents.findIndex(
21523
- (candidate) => normalizeDocument(candidate).kind === resource.kind && resourceId(candidate) === resource.id
21524
- );
21525
- const document = documents[index];
21526
- return {
21527
- ...resource,
21528
- id: resourceId(document),
21529
- $schema: document.$schema,
21530
- sha256: createHash2("sha256").update(JSON.stringify(document)).digest("hex")
21531
- };
21532
- }
21533
- );
21534
- const output = {
21535
- ...input,
21536
- manifest: { ...input.manifest, formatVersion: 2, resources },
21537
- documents
21538
- };
21539
- assertConfigBundle(output);
21540
- return output;
21541
- }
21542
- function report(input, output, file, parsed, context) {
21543
- const changed = stableConfigJson(input) !== stableConfigJson(output);
21544
- context.stdout.write(
21545
- `${file}: ${changed ? "upgrade required" : "current"}
21546
- `
21547
- );
21548
- if (parsed.flags.diff === true)
21549
- for (const change of configChanges(input, output)) {
21550
- context.stdout.write(
21551
- ` ${change.path}: ${JSON.stringify(change.before) ?? "(absent)"} -> ${JSON.stringify(change.after) ?? "(absent)"}
21552
- `
21553
- );
21554
- }
21555
- return changed;
21556
- }
21557
- function inferredKind(path2) {
21558
- const normalized = path2.split(sep2).join("/");
21559
- const match = TENANT_RESOURCE_REGISTRY.find(
21560
- (entry) => entry.kind === "file" ? normalized === entry.file || normalized.endsWith(`/${entry.file}`) : normalized.endsWith(`/${entry.subfolder}/${basename2(path2)}`) || normalized === `${entry.subfolder}/${basename2(path2)}`
21561
- );
21562
- return CONFIG_RESOURCE_KINDS.find(
21563
- (kind) => `${CONFIG_FORMATS[kind].file}.schema.json` === match?.schemaFile
21564
- );
21565
- }
21566
- function wrapBare(kind, input, path2) {
21567
- if (!input || typeof input !== "object" || Array.isArray(input))
21568
- throw new Error(`${path2}: configuration must be an object`);
21569
- const singleton = {
21570
- Tenant: "tenant",
21571
- KmsConfig: "kms",
21572
- RegistrarConfig: "registrar",
21573
- IssuanceConfig: "issuance"
21574
- };
21575
- const spec = structuredClone(input);
21576
- if (kind === "KeyChain" && spec.key && !spec.keySource) {
21577
- spec.keySource = { type: "private-jwk", jwk: spec.key };
21578
- delete spec.key;
21579
- }
21580
- const id = String(
21581
- singleton[kind] ?? spec.id ?? spec.clientId ?? basename2(path2, ".json")
21582
- );
21583
- if (!singleton[kind]) spec[kind === "Client" ? "clientId" : "id"] = id;
21584
- return { $schema: schemaUrl(kind, 1), metadata: { generation: 1 }, spec };
21585
- }
21586
- async function folderFiles(path2) {
21587
- const files = [];
21588
- for (const entry of await readdir(path2, { withFileTypes: true })) {
21589
- if (entry.name.startsWith(".")) continue;
21590
- const file = join4(path2, entry.name);
21591
- if (entry.isSymbolicLink())
21592
- throw new Error(`Config folder contains a symbolic link: ${file}`);
21593
- if (entry.isDirectory()) files.push(...await folderFiles(file));
21594
- else if (entry.isFile()) files.push(file);
21595
- }
21596
- return files.sort();
21597
- }
21598
- async function upgradeFolder(source, parsed, context) {
21599
- const outputs = /* @__PURE__ */ new Map();
21600
- let changed = 0;
21601
- for (const file of await folderFiles(source)) {
21602
- if (extname(file) !== ".json" || relative2(source, file).split(sep2).includes("images"))
21603
- continue;
21604
- const input = parse3(await readFile4(file, "utf8"), file);
21605
- const kind = inferredKind(relative2(source, file));
21606
- if (!kind && !isConfigDocument(input)) continue;
21607
- const candidate = isConfigDocument(input) ? input : wrapBare(kind, input, file);
21608
- const output = upgradeJson(candidate, file, context);
21609
- if (kind && normalizeDocument(output).kind !== kind)
21610
- throw new Error(`${file}: expected ${kind} configuration`);
21611
- if (report(input, output, relative2(source, file), parsed, context))
21612
- changed++;
21613
- outputs.set(
21614
- relative2(source, file),
21615
- `${JSON.stringify(output, null, 2)}
21616
- `
21617
- );
21618
- }
21619
- if (!outputs.size)
21620
- throw new Error(`No configuration documents found in ${source}`);
21621
- context.stdout.write(
21622
- `${outputs.size - changed} current, ${changed} require upgrading
21623
- `
21624
- );
21625
- if (parsed.flags.check === true) return changed ? 1 : 0;
21626
- if (parsed.flags["dry-run"] === true) return 0;
21627
- const destination = resolve3(
21628
- context.cwd,
21629
- readStringFlag(parsed.flags, "output") ?? `${source}.upgraded`
21630
- );
21631
- const overlap = (parent, child) => {
21632
- const path2 = relative2(parent, child);
21633
- return path2 === "" || !path2.startsWith(`..${sep2}`) && path2 !== "..";
21634
- };
21635
- if (overlap(source, destination) || overlap(destination, source))
21636
- throw new Error(
21637
- "Folder output must be separate from the source directory"
21638
- );
21639
- await lstat(destination).then(
21640
- () => {
21641
- throw new Error(`Output already exists: ${destination}`);
21454
+ },
21455
+ {
21456
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
21457
+ "$id": "https://eudiplo.dev/schemas/v3/PresentationConfigFile.schema.json",
21458
+ "title": "PresentationConfigFile",
21459
+ "type": "object",
21460
+ "properties": {
21461
+ "$schema": {
21462
+ "type": "string",
21463
+ "const": "https://eudiplo.dev/schemas/v3/PresentationConfigFile.schema.json"
21464
+ },
21465
+ "metadata": {
21466
+ "type": "object",
21467
+ "properties": {
21468
+ "generation": {
21469
+ "type": "integer",
21470
+ "minimum": 1,
21471
+ "description": "Monotonically increasing configuration generation."
21472
+ },
21473
+ "ownership": {
21474
+ "type": "string",
21475
+ "enum": [
21476
+ "unmanaged",
21477
+ "file-managed"
21478
+ ],
21479
+ "description": "Requested ownership recorded when the document is applied."
21480
+ }
21481
+ },
21482
+ "additionalProperties": false
21483
+ },
21484
+ "spec": {
21485
+ "allOf": [
21486
+ {
21487
+ "$ref": "#/$defs/PresentationConfigCreateDto"
21488
+ },
21489
+ {
21490
+ "type": "object",
21491
+ "required": [
21492
+ "id"
21493
+ ],
21494
+ "properties": {
21495
+ "id": {
21496
+ "type": "string",
21497
+ "minLength": 1
21498
+ }
21499
+ }
21500
+ }
21501
+ ]
21502
+ }
21642
21503
  },
21643
- (error) => {
21644
- if (error.code !== "ENOENT") throw error;
21645
- }
21646
- );
21647
- await mkdir3(dirname3(destination), { recursive: true });
21648
- const staging = await mkdtemp(
21504
+ "required": [
21505
+ "$schema",
21506
+ "spec"
21507
+ ],
21508
+ "additionalProperties": false,
21509
+ "$defs": {
21510
+ "PresentationConfigCreateDto": {
21511
+ "type": "object",
21512
+ "properties": {
21513
+ "id": {
21514
+ "type": "string",
21515
+ "minLength": 1,
21516
+ "description": "Presentation configuration identifier."
21517
+ },
21518
+ "description": {
21519
+ "description": "Optional presentation configuration description.",
21520
+ "type": [
21521
+ "string",
21522
+ "null"
21523
+ ]
21524
+ },
21525
+ "lifeTime": {
21526
+ "description": "Presentation request lifetime in seconds.",
21527
+ "type": "integer",
21528
+ "minimum": 1,
21529
+ "maximum": 9007199254740991
21530
+ },
21531
+ "skewSeconds": {
21532
+ "description": "Clock skew tolerance in seconds.",
21533
+ "type": "integer",
21534
+ "minimum": 0,
21535
+ "maximum": 9007199254740991
21536
+ },
21537
+ "statusCheckMode": {
21538
+ "description": "Revocation/status check mode.",
21539
+ "type": "string",
21540
+ "enum": [
21541
+ "strict",
21542
+ "best_effort",
21543
+ "disabled"
21544
+ ]
21545
+ },
21546
+ "dcql_query": {
21547
+ "type": "object",
21548
+ "properties": {
21549
+ "credentials": {
21550
+ "minItems": 1,
21551
+ "type": "array",
21552
+ "items": {
21553
+ "oneOf": [
21554
+ {
21555
+ "type": "object",
21556
+ "properties": {
21557
+ "id": {
21558
+ "type": "string",
21559
+ "minLength": 1,
21560
+ "pattern": "^[A-Za-z0-9_-]+$",
21561
+ "description": "Credential query identifier."
21562
+ },
21563
+ "multiple": {
21564
+ "description": "Allow multiple matching credentials.",
21565
+ "type": "boolean"
21566
+ },
21567
+ "claim_sets": {
21568
+ "description": "Optional claim set constraints.",
21569
+ "type": "array",
21570
+ "items": {
21571
+ "type": "array",
21572
+ "items": {
21573
+ "type": "string"
21574
+ }
21575
+ }
21576
+ },
21577
+ "trusted_authorities": {
21578
+ "description": "Optional trusted authority constraints.",
21579
+ "type": "array",
21580
+ "items": {
21581
+ "oneOf": [
21582
+ {
21583
+ "type": "object",
21584
+ "properties": {
21585
+ "type": {
21586
+ "type": "string",
21587
+ "const": "etsi_tl",
21588
+ "description": "Trusted authority type discriminator for ETSI trust lists."
21589
+ },
21590
+ "values": {
21591
+ "type": "array",
21592
+ "items": {
21593
+ "type": "object",
21594
+ "properties": {
21595
+ "trustListId": {
21596
+ "description": "Optional trust list id reference.",
21597
+ "type": "string"
21598
+ },
21599
+ "url": {
21600
+ "description": "Optional trust list URL reference.",
21601
+ "anyOf": [
21602
+ {
21603
+ "type": "string",
21604
+ "format": "uri"
21605
+ },
21606
+ {
21607
+ "type": "string",
21608
+ "pattern": "^<TENANT_URL>(?:\\/.*)?$"
21609
+ }
21610
+ ]
21611
+ },
21612
+ "verifierKey": {
21613
+ "description": "Optional verifier key material.",
21614
+ "type": "object",
21615
+ "propertyNames": {
21616
+ "type": "string"
21617
+ },
21618
+ "additionalProperties": {}
21619
+ },
21620
+ "verifierX509Der": {
21621
+ "description": "Optional verifier certificate in DER/base64 form.",
21622
+ "type": "string"
21623
+ }
21624
+ },
21625
+ "additionalProperties": false
21626
+ },
21627
+ "description": "Trust list references for ETSI TL verification."
21628
+ }
21629
+ },
21630
+ "required": [
21631
+ "type",
21632
+ "values"
21633
+ ],
21634
+ "additionalProperties": false
21635
+ },
21636
+ {
21637
+ "type": "object",
21638
+ "properties": {
21639
+ "type": {
21640
+ "type": "string",
21641
+ "const": "openid_federation",
21642
+ "description": "Trusted authority type discriminator for OpenID Federation."
21643
+ },
21644
+ "values": {
21645
+ "type": "array",
21646
+ "items": {
21647
+ "type": "string"
21648
+ },
21649
+ "description": "OpenID Federation authority identifiers."
21650
+ }
21651
+ },
21652
+ "required": [
21653
+ "type",
21654
+ "values"
21655
+ ],
21656
+ "additionalProperties": false
21657
+ }
21658
+ ]
21659
+ }
21660
+ },
21661
+ "format": {
21662
+ "type": "string",
21663
+ "const": "dc+sd-jwt",
21664
+ "description": "Credential format discriminator."
21665
+ },
21666
+ "meta": {
21667
+ "type": "object",
21668
+ "properties": {
21669
+ "vct_values": {
21670
+ "minItems": 1,
21671
+ "type": "array",
21672
+ "items": {
21673
+ "type": "string"
21674
+ },
21675
+ "description": "Accepted VCT values."
21676
+ }
21677
+ },
21678
+ "required": [
21679
+ "vct_values"
21680
+ ],
21681
+ "additionalProperties": false
21682
+ },
21683
+ "claims": {
21684
+ "description": "Optional claim-level constraints.",
21685
+ "type": "array",
21686
+ "items": {
21687
+ "type": "object",
21688
+ "properties": {
21689
+ "id": {
21690
+ "description": "Optional claim query id.",
21691
+ "type": "string"
21692
+ },
21693
+ "path": {
21694
+ "type": "array",
21695
+ "items": {
21696
+ "type": [
21697
+ "string",
21698
+ "number"
21699
+ ]
21700
+ },
21701
+ "description": "Path to the claim value in presented credentials."
21702
+ },
21703
+ "values": {
21704
+ "description": "Optional allowed values for the claim. A disclosed value must equal one of them in type and value.",
21705
+ "minItems": 1,
21706
+ "type": "array",
21707
+ "items": {
21708
+ "anyOf": [
21709
+ {
21710
+ "type": "string"
21711
+ },
21712
+ {
21713
+ "type": "integer",
21714
+ "minimum": -9007199254740991,
21715
+ "maximum": 9007199254740991
21716
+ },
21717
+ {
21718
+ "type": "boolean"
21719
+ }
21720
+ ]
21721
+ }
21722
+ }
21723
+ },
21724
+ "required": [
21725
+ "path"
21726
+ ],
21727
+ "additionalProperties": false
21728
+ }
21729
+ }
21730
+ },
21731
+ "required": [
21732
+ "id",
21733
+ "format",
21734
+ "meta"
21735
+ ],
21736
+ "additionalProperties": false
21737
+ },
21738
+ {
21739
+ "type": "object",
21740
+ "properties": {
21741
+ "id": {
21742
+ "type": "string",
21743
+ "minLength": 1,
21744
+ "pattern": "^[A-Za-z0-9_-]+$",
21745
+ "description": "Credential query identifier."
21746
+ },
21747
+ "multiple": {
21748
+ "description": "Allow multiple matching credentials.",
21749
+ "type": "boolean"
21750
+ },
21751
+ "claim_sets": {
21752
+ "description": "Optional claim set constraints.",
21753
+ "type": "array",
21754
+ "items": {
21755
+ "type": "array",
21756
+ "items": {
21757
+ "type": "string"
21758
+ }
21759
+ }
21760
+ },
21761
+ "trusted_authorities": {
21762
+ "description": "Optional trusted authority constraints.",
21763
+ "type": "array",
21764
+ "items": {
21765
+ "oneOf": [
21766
+ {
21767
+ "type": "object",
21768
+ "properties": {
21769
+ "type": {
21770
+ "type": "string",
21771
+ "const": "etsi_tl",
21772
+ "description": "Trusted authority type discriminator for ETSI trust lists."
21773
+ },
21774
+ "values": {
21775
+ "type": "array",
21776
+ "items": {
21777
+ "type": "object",
21778
+ "properties": {
21779
+ "trustListId": {
21780
+ "description": "Optional trust list id reference.",
21781
+ "type": "string"
21782
+ },
21783
+ "url": {
21784
+ "description": "Optional trust list URL reference.",
21785
+ "anyOf": [
21786
+ {
21787
+ "type": "string",
21788
+ "format": "uri"
21789
+ },
21790
+ {
21791
+ "type": "string",
21792
+ "pattern": "^<TENANT_URL>(?:\\/.*)?$"
21793
+ }
21794
+ ]
21795
+ },
21796
+ "verifierKey": {
21797
+ "description": "Optional verifier key material.",
21798
+ "type": "object",
21799
+ "propertyNames": {
21800
+ "type": "string"
21801
+ },
21802
+ "additionalProperties": {}
21803
+ },
21804
+ "verifierX509Der": {
21805
+ "description": "Optional verifier certificate in DER/base64 form.",
21806
+ "type": "string"
21807
+ }
21808
+ },
21809
+ "additionalProperties": false
21810
+ },
21811
+ "description": "Trust list references for ETSI TL verification."
21812
+ }
21813
+ },
21814
+ "required": [
21815
+ "type",
21816
+ "values"
21817
+ ],
21818
+ "additionalProperties": false
21819
+ },
21820
+ {
21821
+ "type": "object",
21822
+ "properties": {
21823
+ "type": {
21824
+ "type": "string",
21825
+ "const": "openid_federation",
21826
+ "description": "Trusted authority type discriminator for OpenID Federation."
21827
+ },
21828
+ "values": {
21829
+ "type": "array",
21830
+ "items": {
21831
+ "type": "string"
21832
+ },
21833
+ "description": "OpenID Federation authority identifiers."
21834
+ }
21835
+ },
21836
+ "required": [
21837
+ "type",
21838
+ "values"
21839
+ ],
21840
+ "additionalProperties": false
21841
+ }
21842
+ ]
21843
+ }
21844
+ },
21845
+ "format": {
21846
+ "type": "string",
21847
+ "const": "mso_mdoc",
21848
+ "description": "Credential format discriminator."
21849
+ },
21850
+ "meta": {
21851
+ "type": "object",
21852
+ "properties": {
21853
+ "doctype_value": {
21854
+ "type": "string",
21855
+ "minLength": 1,
21856
+ "description": "Expected mDoc doctype value."
21857
+ }
21858
+ },
21859
+ "required": [
21860
+ "doctype_value"
21861
+ ],
21862
+ "additionalProperties": false
21863
+ },
21864
+ "claims": {
21865
+ "description": "Optional mDoc claim-level constraints.",
21866
+ "type": "array",
21867
+ "items": {
21868
+ "type": "object",
21869
+ "properties": {
21870
+ "id": {
21871
+ "description": "Optional claim query id.",
21872
+ "type": "string"
21873
+ },
21874
+ "path": {
21875
+ "type": "array",
21876
+ "items": {
21877
+ "type": [
21878
+ "string",
21879
+ "number"
21880
+ ]
21881
+ },
21882
+ "description": "Path to the claim value in presented credentials."
21883
+ },
21884
+ "values": {
21885
+ "description": "Optional allowed values for the claim. A disclosed value must equal one of them in type and value.",
21886
+ "minItems": 1,
21887
+ "type": "array",
21888
+ "items": {
21889
+ "anyOf": [
21890
+ {
21891
+ "type": "string"
21892
+ },
21893
+ {
21894
+ "type": "integer",
21895
+ "minimum": -9007199254740991,
21896
+ "maximum": 9007199254740991
21897
+ },
21898
+ {
21899
+ "type": "boolean"
21900
+ }
21901
+ ]
21902
+ }
21903
+ },
21904
+ "intent_to_retain": {
21905
+ "description": "Whether relying party intends to retain the claim.",
21906
+ "type": "boolean"
21907
+ }
21908
+ },
21909
+ "required": [
21910
+ "path"
21911
+ ],
21912
+ "additionalProperties": false
21913
+ }
21914
+ }
21915
+ },
21916
+ "required": [
21917
+ "id",
21918
+ "format",
21919
+ "meta"
21920
+ ],
21921
+ "additionalProperties": false
21922
+ }
21923
+ ]
21924
+ },
21925
+ "description": "Credential queries requested by the verifier."
21926
+ },
21927
+ "credential_sets": {
21928
+ "description": "Optional higher-level credential set requirements.",
21929
+ "type": "array",
21930
+ "items": {
21931
+ "type": "object",
21932
+ "properties": {
21933
+ "options": {
21934
+ "minItems": 1,
21935
+ "type": "array",
21936
+ "items": {
21937
+ "minItems": 1,
21938
+ "type": "array",
21939
+ "items": {
21940
+ "type": "string"
21941
+ }
21942
+ },
21943
+ "description": "Alternative credential query id combinations."
21944
+ },
21945
+ "required": {
21946
+ "description": "Whether this credential set is mandatory.",
21947
+ "type": "boolean"
21948
+ }
21949
+ },
21950
+ "required": [
21951
+ "options"
21952
+ ],
21953
+ "additionalProperties": false
21954
+ }
21955
+ }
21956
+ },
21957
+ "required": [
21958
+ "credentials"
21959
+ ],
21960
+ "additionalProperties": false,
21961
+ "description": "DCQL query defining requested credentials and claims."
21962
+ },
21963
+ "transaction_data": {
21964
+ "description": "Optional transaction data descriptors.",
21965
+ "anyOf": [
21966
+ {
21967
+ "type": "array",
21968
+ "items": {
21969
+ "type": "object",
21970
+ "properties": {
21971
+ "type": {
21972
+ "type": "string",
21973
+ "description": "Transaction data type identifier."
21974
+ },
21975
+ "credential_ids": {
21976
+ "type": "array",
21977
+ "items": {
21978
+ "type": "string"
21979
+ },
21980
+ "description": "Credential query ids this transaction data applies to."
21981
+ },
21982
+ "payload": {
21983
+ "description": "Transaction details. Required for TS12 SCA transaction data."
21984
+ }
21985
+ },
21986
+ "required": [
21987
+ "type",
21988
+ "credential_ids"
21989
+ ],
21990
+ "additionalProperties": {}
21991
+ }
21992
+ },
21993
+ {
21994
+ "type": "null"
21995
+ }
21996
+ ]
21997
+ },
21998
+ "registration_cert": {
21999
+ "description": "Optional registration certificate request settings.",
22000
+ "anyOf": [
22001
+ {
22002
+ "type": "object",
22003
+ "properties": {
22004
+ "id": {
22005
+ "type": "string"
22006
+ },
22007
+ "body": {
22008
+ "type": "object",
22009
+ "properties": {
22010
+ "privacy_policy": {
22011
+ "type": "string"
22012
+ },
22013
+ "support_uri": {
22014
+ "type": "string"
22015
+ },
22016
+ "intermediary": {
22017
+ "type": "string"
22018
+ },
22019
+ "purpose": {
22020
+ "type": "array",
22021
+ "items": {
22022
+ "type": "object",
22023
+ "properties": {
22024
+ "lang": {
22025
+ "type": "string"
22026
+ },
22027
+ "content": {
22028
+ "type": "string"
22029
+ }
22030
+ },
22031
+ "required": [
22032
+ "lang",
22033
+ "content"
22034
+ ],
22035
+ "additionalProperties": false
22036
+ }
22037
+ },
22038
+ "credentials": {
22039
+ "type": "array",
22040
+ "items": {
22041
+ "type": "object",
22042
+ "propertyNames": {
22043
+ "type": "string"
22044
+ },
22045
+ "additionalProperties": {}
22046
+ }
22047
+ },
22048
+ "provides_attestations": {
22049
+ "type": "array",
22050
+ "items": {
22051
+ "type": "string",
22052
+ "minLength": 1
22053
+ }
22054
+ }
22055
+ },
22056
+ "additionalProperties": false
22057
+ },
22058
+ "jwt": {
22059
+ "type": "string"
22060
+ }
22061
+ },
22062
+ "additionalProperties": false
22063
+ },
22064
+ {
22065
+ "type": "null"
22066
+ }
22067
+ ]
22068
+ },
22069
+ "registrationCertImportJwt": {
22070
+ "description": "Optional imported registration certificate JWT.",
22071
+ "type": [
22072
+ "string",
22073
+ "null"
22074
+ ]
22075
+ },
22076
+ "registrationCertImportId": {
22077
+ "description": "Optional registrar-side registration certificate id.",
22078
+ "type": [
22079
+ "string",
22080
+ "null"
22081
+ ]
22082
+ },
22083
+ "registrationCertBodyPrivacyPolicy": {
22084
+ "description": "Optional registration certificate privacy policy URI.",
22085
+ "type": [
22086
+ "string",
22087
+ "null"
22088
+ ]
22089
+ },
22090
+ "registrationCertBodySupportUri": {
22091
+ "description": "Optional registration certificate support URI.",
22092
+ "type": [
22093
+ "string",
22094
+ "null"
22095
+ ]
22096
+ },
22097
+ "registrationCertBodyIntermediary": {
22098
+ "description": "Optional registration certificate intermediary.",
22099
+ "type": [
22100
+ "string",
22101
+ "null"
22102
+ ]
22103
+ },
22104
+ "registrationCertBodyPurpose": {
22105
+ "description": "Optional registration certificate purpose entries.",
22106
+ "anyOf": [
22107
+ {
22108
+ "type": "array",
22109
+ "items": {
22110
+ "type": "object",
22111
+ "properties": {
22112
+ "lang": {
22113
+ "type": "string"
22114
+ },
22115
+ "content": {
22116
+ "type": "string"
22117
+ }
22118
+ },
22119
+ "additionalProperties": false
22120
+ }
22121
+ },
22122
+ {
22123
+ "type": "null"
22124
+ }
22125
+ ]
22126
+ },
22127
+ "webhookEndpointId": {
22128
+ "description": "Optional webhook endpoint id for presentation callbacks.",
22129
+ "type": [
22130
+ "string",
22131
+ "null"
22132
+ ]
22133
+ },
22134
+ "attached": {
22135
+ "description": "Optional attachments included with presentation requests.",
22136
+ "anyOf": [
22137
+ {
22138
+ "type": "array",
22139
+ "items": {
22140
+ "type": "object",
22141
+ "properties": {
22142
+ "format": {
22143
+ "type": "string",
22144
+ "description": "Attachment format identifier."
22145
+ },
22146
+ "data": {
22147
+ "description": "Attachment payload."
22148
+ },
22149
+ "credential_ids": {
22150
+ "description": "Optional credential query ids bound to this attachment.",
22151
+ "type": "array",
22152
+ "items": {
22153
+ "type": "string"
22154
+ }
22155
+ }
22156
+ },
22157
+ "required": [
22158
+ "format",
22159
+ "data"
22160
+ ],
22161
+ "additionalProperties": false
22162
+ }
22163
+ },
22164
+ {
22165
+ "type": "null"
22166
+ }
22167
+ ]
22168
+ },
22169
+ "redirectUri": {
22170
+ "description": "Optional redirect URI after presentation completion.",
22171
+ "type": [
22172
+ "string",
22173
+ "null"
22174
+ ]
22175
+ },
22176
+ "accessKeyChainId": {
22177
+ "description": "Optional key chain id for access token/auth operations.",
22178
+ "type": [
22179
+ "string",
22180
+ "null"
22181
+ ]
22182
+ },
22183
+ "readerAuth": {
22184
+ "description": "Whether reader authentication is required for mDoc requests.",
22185
+ "type": [
22186
+ "boolean",
22187
+ "null"
22188
+ ]
22189
+ }
22190
+ },
22191
+ "required": [
22192
+ "id",
22193
+ "dcql_query"
22194
+ ],
22195
+ "additionalProperties": false,
22196
+ "title": "PresentationConfigCreateDto"
22197
+ }
22198
+ }
22199
+ }
22200
+ ];
22201
+
22202
+ // ../../packages/eudiplo-config-format/dist/config-validator.js
22203
+ var ajv = new import__.Ajv2020({
22204
+ allErrors: true,
22205
+ strict: false,
22206
+ validateFormats: false
22207
+ });
22208
+ for (const schema of CONFIG_SCHEMAS)
22209
+ ajv.addSchema(schema);
22210
+ function validateConfigDocument(document) {
22211
+ const file = serializeDocument(document);
22212
+ const validate = ajv.getSchema(file.$schema);
22213
+ if (!validate)
22214
+ throw new Error(`No bundled validator for ${file.$schema}`);
22215
+ const issues = [];
22216
+ if (!validate(file)) {
22217
+ for (const issue of validate.errors ?? [])
22218
+ issues.push({
22219
+ severity: "error",
22220
+ code: "CONFIG_SCHEMA_VALIDATION_FAILED",
22221
+ path: issue.instancePath || "/",
22222
+ message: issue.keyword === "additionalProperties" ? `Unknown property: ${String(issue.params.additionalProperty)}` : issue.message ?? "Invalid configuration",
22223
+ resource: { kind: document.kind, id: resourceId(document) }
22224
+ });
22225
+ }
22226
+ const id = document.kind === "Client" ? document.spec.clientId : document.spec.id;
22227
+ if (id !== void 0 && id !== resourceId(document))
22228
+ issues.push({
22229
+ severity: "error",
22230
+ code: "RESOURCE_ID_MISMATCH",
22231
+ path: document.kind === "Client" ? "/spec/clientId" : "/spec/id",
22232
+ message: "Resource identifier does not match metadata.id"
22233
+ });
22234
+ return issues;
22235
+ }
22236
+
22237
+ // src/commands/config/portability/migrations.ts
22238
+ function upgradeDocument(input) {
22239
+ const result = migrateDocument(input, validateConfigDocument);
22240
+ return { ...result, document: serializeDocument(result.document) };
22241
+ }
22242
+
22243
+ // src/commands/config/portability/upgrade.ts
22244
+ var codec = new ConfigBundleCodec();
22245
+ function parse3(text, path2) {
22246
+ try {
22247
+ return JSON.parse(text);
22248
+ } catch {
22249
+ throw new Error(`Invalid JSON in ${path2}`);
22250
+ }
22251
+ }
22252
+ function upgradeJson(input, file, context) {
22253
+ const bundle = Array.isArray(input?.documents);
22254
+ if (bundle) assertConfigBundle(input);
22255
+ const results = (bundle ? input.documents : [input]).map(
22256
+ (document) => upgradeDocument(document)
22257
+ );
22258
+ let blocked = false;
22259
+ for (const result of results) {
22260
+ for (const issue of result.issues) {
22261
+ context.stderr.write(
22262
+ `${file}${issue.path}: ${issue.severity} ${issue.code}: ${issue.message}
22263
+ `
22264
+ );
22265
+ if (issue.severity !== "warning") blocked = true;
22266
+ }
22267
+ for (const migration of result.migrations)
22268
+ context.stdout.write(`${file}: migration ${migration}
22269
+ `);
22270
+ }
22271
+ if (blocked) throw new Error(`${file}: upgrade blocked; no output written`);
22272
+ if (!bundle) return results[0].document;
22273
+ const documents = results.map(
22274
+ (result) => result.document
22275
+ );
22276
+ const resources = input.manifest.resources.map(
22277
+ (resource) => {
22278
+ const index = input.documents.findIndex(
22279
+ (candidate) => normalizeDocument(candidate).kind === resource.kind && resourceId(candidate) === resource.id
22280
+ );
22281
+ const document = documents[index];
22282
+ return {
22283
+ ...resource,
22284
+ id: resourceId(document),
22285
+ $schema: document.$schema,
22286
+ sha256: createHash2("sha256").update(JSON.stringify(document)).digest("hex")
22287
+ };
22288
+ }
22289
+ );
22290
+ const output = {
22291
+ ...input,
22292
+ manifest: { ...input.manifest, formatVersion: 2, resources },
22293
+ documents
22294
+ };
22295
+ assertConfigBundle(output);
22296
+ return output;
22297
+ }
22298
+ function report(input, output, file, parsed, context) {
22299
+ const changed = stableConfigJson(input) !== stableConfigJson(output);
22300
+ context.stdout.write(
22301
+ `${file}: ${changed ? "upgrade required" : "current"}
22302
+ `
22303
+ );
22304
+ if (parsed.flags.diff === true)
22305
+ for (const change of configChanges(input, output)) {
22306
+ context.stdout.write(
22307
+ ` ${change.path}: ${JSON.stringify(change.before) ?? "(absent)"} -> ${JSON.stringify(change.after) ?? "(absent)"}
22308
+ `
22309
+ );
22310
+ }
22311
+ return changed;
22312
+ }
22313
+ function inferredKind(path2) {
22314
+ const normalized = path2.split(sep2).join("/");
22315
+ const match = TENANT_RESOURCE_REGISTRY.find(
22316
+ (entry) => entry.kind === "file" ? normalized === entry.file || normalized.endsWith(`/${entry.file}`) : normalized.endsWith(`/${entry.subfolder}/${basename2(path2)}`) || normalized === `${entry.subfolder}/${basename2(path2)}`
22317
+ );
22318
+ return CONFIG_RESOURCE_KINDS.find(
22319
+ (kind) => `${CONFIG_FORMATS[kind].file}.schema.json` === match?.schemaFile
22320
+ );
22321
+ }
22322
+ function wrapBare(kind, input, path2) {
22323
+ if (!input || typeof input !== "object" || Array.isArray(input))
22324
+ throw new Error(`${path2}: configuration must be an object`);
22325
+ const singleton = {
22326
+ Tenant: "tenant",
22327
+ KmsConfig: "kms",
22328
+ RegistrarConfig: "registrar",
22329
+ IssuanceConfig: "issuance"
22330
+ };
22331
+ const spec = structuredClone(input);
22332
+ if (kind === "KeyChain" && spec.key && !spec.keySource) {
22333
+ spec.keySource = { type: "private-jwk", jwk: spec.key };
22334
+ delete spec.key;
22335
+ }
22336
+ const id = String(
22337
+ singleton[kind] ?? spec.id ?? spec.clientId ?? basename2(path2, ".json")
22338
+ );
22339
+ if (!singleton[kind]) spec[kind === "Client" ? "clientId" : "id"] = id;
22340
+ return { $schema: schemaUrl(kind, 1), metadata: { generation: 1 }, spec };
22341
+ }
22342
+ async function folderFiles(path2) {
22343
+ const files = [];
22344
+ for (const entry of await readdir(path2, { withFileTypes: true })) {
22345
+ if (entry.name.startsWith(".")) continue;
22346
+ const file = join4(path2, entry.name);
22347
+ if (entry.isSymbolicLink())
22348
+ throw new Error(`Config folder contains a symbolic link: ${file}`);
22349
+ if (entry.isDirectory()) files.push(...await folderFiles(file));
22350
+ else if (entry.isFile()) files.push(file);
22351
+ }
22352
+ return files.sort();
22353
+ }
22354
+ async function upgradeFolder(source, parsed, context) {
22355
+ const outputs = /* @__PURE__ */ new Map();
22356
+ let changed = 0;
22357
+ for (const file of await folderFiles(source)) {
22358
+ if (extname(file) !== ".json" || relative2(source, file).split(sep2).includes("images"))
22359
+ continue;
22360
+ const input = parse3(await readFile4(file, "utf8"), file);
22361
+ const kind = inferredKind(relative2(source, file));
22362
+ if (!kind && !isConfigDocument(input)) continue;
22363
+ const candidate = isConfigDocument(input) ? input : wrapBare(kind, input, file);
22364
+ const output = upgradeJson(candidate, file, context);
22365
+ if (kind && normalizeDocument(output).kind !== kind)
22366
+ throw new Error(`${file}: expected ${kind} configuration`);
22367
+ if (report(input, output, relative2(source, file), parsed, context))
22368
+ changed++;
22369
+ outputs.set(
22370
+ relative2(source, file),
22371
+ `${JSON.stringify(output, null, 2)}
22372
+ `
22373
+ );
22374
+ }
22375
+ if (!outputs.size)
22376
+ throw new Error(`No configuration documents found in ${source}`);
22377
+ context.stdout.write(
22378
+ `${outputs.size - changed} current, ${changed} require upgrading
22379
+ `
22380
+ );
22381
+ if (parsed.flags.check === true) return changed ? 1 : 0;
22382
+ if (parsed.flags["dry-run"] === true) return 0;
22383
+ const destination = resolve3(
22384
+ context.cwd,
22385
+ readStringFlag(parsed.flags, "output") ?? `${source}.upgraded`
22386
+ );
22387
+ const overlap = (parent, child) => {
22388
+ const path2 = relative2(parent, child);
22389
+ return path2 === "" || !path2.startsWith(`..${sep2}`) && path2 !== "..";
22390
+ };
22391
+ if (overlap(source, destination) || overlap(destination, source))
22392
+ throw new Error(
22393
+ "Folder output must be separate from the source directory"
22394
+ );
22395
+ await lstat(destination).then(
22396
+ () => {
22397
+ throw new Error(`Output already exists: ${destination}`);
22398
+ },
22399
+ (error) => {
22400
+ if (error.code !== "ENOENT") throw error;
22401
+ }
22402
+ );
22403
+ await mkdir3(dirname3(destination), { recursive: true });
22404
+ const staging = await mkdtemp(
21649
22405
  join4(dirname3(destination), ".eudiplo-upgrade-")
21650
22406
  );
21651
22407
  try {
@@ -21996,8 +22752,8 @@ function createComposeEnv(options) {
21996
22752
  const authClientSecret = options.authClientSecret ?? "root";
21997
22753
  const lines = [
21998
22754
  `EUDIPLO_ENV_FILE=${envFileName}`,
21999
- `EUDIPLO_IMAGE=ghcr.io/openwallet-foundation/eudiplo:${imageTag}`,
22000
- `EUDIPLO_CLIENT_IMAGE=ghcr.io/openwallet-foundation/eudiplo-client:${imageTag}`,
22755
+ `EUDIPLO_IMAGE=ghcr.io/eudiplo/eudiplo:${imageTag}`,
22756
+ `EUDIPLO_CLIENT_IMAGE=ghcr.io/eudiplo/eudiplo-client:${imageTag}`,
22001
22757
  ...options.mode === "demo" ? ["EUDIPLO_BIND_ADDRESS=127.0.0.1"] : [],
22002
22758
  `EUDIPLO_CONFIG_MOUNT=./${configDirectoryName}:/app/config`,
22003
22759
  "CONFIG_FOLDER=/app/config",
@@ -24161,7 +24917,7 @@ function createDeploymentCommands(context, setExitCode) {
24161
24917
  // package.json
24162
24918
  var package_default = {
24163
24919
  name: "@eudiplo/cli",
24164
- version: "8.1.0-main.7e6a44b",
24920
+ version: "8.1.0-main.8f6abca",
24165
24921
  description: "Deployment-aware command line tools for EUDIPLO",
24166
24922
  private: false,
24167
24923
  type: "module",
@@ -24197,14 +24953,14 @@ var package_default = {
24197
24953
  ],
24198
24954
  repository: {
24199
24955
  type: "git",
24200
- url: "git+https://github.com/openwallet-foundation/eudiplo.git",
24956
+ url: "git+https://github.com/EUDIPLO/eudiplo.git",
24201
24957
  directory: "apps/cli"
24202
24958
  },
24203
- homepage: "https://github.com/openwallet-foundation/eudiplo/tree/main/apps/cli#readme",
24959
+ homepage: "https://github.com/EUDIPLO/eudiplo/tree/main/apps/cli#readme",
24204
24960
  bugs: {
24205
- url: "https://github.com/openwallet-foundation/eudiplo/issues"
24961
+ url: "https://github.com/EUDIPLO/eudiplo/issues"
24206
24962
  },
24207
- author: "OpenWallet Foundation",
24963
+ author: "LF Decentralized Trust",
24208
24964
  license: "Apache-2.0",
24209
24965
  engines: {
24210
24966
  node: ">=22.12.0"
@@ -25511,6 +26267,10 @@ import { resolve as resolve8 } from "node:path";
25511
26267
 
25512
26268
  // src/services/compose-upgrade.ts
25513
26269
  var managedImages = {
26270
+ EUDIPLO_IMAGE: "ghcr.io/eudiplo/eudiplo",
26271
+ EUDIPLO_CLIENT_IMAGE: "ghcr.io/eudiplo/eudiplo-client"
26272
+ };
26273
+ var legacyImages = {
25514
26274
  EUDIPLO_IMAGE: "ghcr.io/openwallet-foundation/eudiplo",
25515
26275
  EUDIPLO_CLIENT_IMAGE: "ghcr.io/openwallet-foundation/eudiplo-client"
25516
26276
  };
@@ -25522,6 +26282,14 @@ function assertImageTag(tag) {
25522
26282
  );
25523
26283
  }
25524
26284
  }
26285
+ function tagOf(value, repository) {
26286
+ const prefix = `${repository}:`;
26287
+ if (!value.startsWith(prefix)) {
26288
+ return void 0;
26289
+ }
26290
+ const tag = value.slice(prefix.length);
26291
+ return TAG.test(tag) ? tag : void 0;
26292
+ }
25525
26293
  function planImageUpgrade(content, tag) {
25526
26294
  assertImageTag(tag);
25527
26295
  const found = /* @__PURE__ */ new Set();
@@ -25543,17 +26311,26 @@ function planImageUpgrade(content, tag) {
25543
26311
  );
25544
26312
  }
25545
26313
  found.add(key);
25546
- const prefix = `${repository}:`;
25547
- const current = value.startsWith(prefix) ? value.slice(prefix.length) : void 0;
25548
- if (current === void 0 || !TAG.test(current)) {
26314
+ const currentTag = tagOf(value, repository);
26315
+ const legacyTag = tagOf(value, legacyImages[key]);
26316
+ const current = currentTag ?? legacyTag;
26317
+ if (current === void 0) {
25549
26318
  throw new Error(
25550
- `${key} is set to ${value}, which is not a CLI-managed image. Update it yourself, or restore ${prefix}<tag> to let the CLI manage it.`
26319
+ `${key} is set to ${value}, which is not a CLI-managed image. Update it yourself, or restore ${repository}:<tag> to let the CLI manage it.`
25551
26320
  );
25552
26321
  }
25553
- if (current !== tag) {
26322
+ if (currentTag === void 0) {
26323
+ changes.push({
26324
+ key,
26325
+ repository,
26326
+ movedFrom: legacyImages[key],
26327
+ from: current,
26328
+ to: tag
26329
+ });
26330
+ } else if (current !== tag) {
25554
26331
  changes.push({ key, repository, from: current, to: tag });
25555
26332
  }
25556
- return `${key}=${prefix}${tag}${lineEnding}`;
26333
+ return `${key}=${repository}:${tag}${lineEnding}`;
25557
26334
  });
25558
26335
  if (!found.has("EUDIPLO_IMAGE")) {
25559
26336
  throw new Error(
@@ -25640,7 +26417,8 @@ async function runUpgradeCommand(config, parsed, context) {
25640
26417
  `);
25641
26418
  for (const change of plan.changes) {
25642
26419
  context.stdout.write(
25643
- ` ${change.repository}: ${change.from} -> ${change.to}
26420
+ change.movedFrom ? ` ${change.movedFrom}:${change.from} -> ${change.repository}:${change.to}
26421
+ ` : ` ${change.repository}: ${change.from} -> ${change.to}
25644
26422
  `
25645
26423
  );
25646
26424
  }