@eudiplo/cli 9.0.0 → 9.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (39) hide show
  1. package/dist/commands/config/portability/migrations.spec.js +3 -2
  2. package/dist/commands/config/portability/migrations.spec.js.map +1 -1
  3. package/dist/commands/config/validate/index.d.ts.map +1 -1
  4. package/dist/commands/config/validate/index.js +2 -2
  5. package/dist/commands/config/validate/index.js.map +1 -1
  6. package/dist/commands/deployment/index.d.ts.map +1 -1
  7. package/dist/commands/deployment/index.js +8 -3
  8. package/dist/commands/deployment/index.js.map +1 -1
  9. package/dist/commands/deployment/pass-through.d.ts +15 -0
  10. package/dist/commands/deployment/pass-through.d.ts.map +1 -0
  11. package/dist/commands/deployment/pass-through.js +52 -0
  12. package/dist/commands/deployment/pass-through.js.map +1 -0
  13. package/dist/commands/upgrade/action.d.ts.map +1 -1
  14. package/dist/commands/upgrade/action.js +5 -2
  15. package/dist/commands/upgrade/action.js.map +1 -1
  16. package/dist/index.js +930 -140
  17. package/dist/services/compose-args.d.ts +1 -1
  18. package/dist/services/compose-args.d.ts.map +1 -1
  19. package/dist/services/compose-args.js +4 -2
  20. package/dist/services/compose-args.js.map +1 -1
  21. package/dist/services/compose-upgrade.d.ts +2 -0
  22. package/dist/services/compose-upgrade.d.ts.map +1 -1
  23. package/dist/services/compose-upgrade.js +5 -0
  24. package/dist/services/compose-upgrade.js.map +1 -1
  25. package/dist/services/container-state.d.ts +4 -1
  26. package/dist/services/container-state.d.ts.map +1 -1
  27. package/dist/services/container-state.js +21 -8
  28. package/dist/services/container-state.js.map +1 -1
  29. package/dist/services/diagnostics.d.ts.map +1 -1
  30. package/dist/services/diagnostics.js +10 -0
  31. package/dist/services/diagnostics.js.map +1 -1
  32. package/package.json +5 -5
  33. package/templates/demo-config/presentation/pid.json +1 -2
  34. package/templates/demo-config.manifest.json +1 -3
  35. package/templates/docker-compose.yml +11 -6
  36. package/templates/schemas/IssuanceConfig.schema.json +20 -0
  37. package/templates/schemas/IssuanceConfigFile.schema.json +676 -1
  38. package/templates/demo-config/attribute-providers/claims-provider.json +0 -15
  39. package/templates/demo-config/webhook-endpoints/notification.json +0 -15
package/dist/index.js CHANGED
@@ -3099,12 +3099,13 @@ var require_data = __commonJS({
3099
3099
  }
3100
3100
  });
3101
3101
 
3102
- // ../../node_modules/.pnpm/fast-uri@3.1.6/node_modules/fast-uri/lib/utils.js
3102
+ // ../../node_modules/.pnpm/fast-uri@3.1.8/node_modules/fast-uri/lib/utils.js
3103
3103
  var require_utils = __commonJS({
3104
- "../../node_modules/.pnpm/fast-uri@3.1.6/node_modules/fast-uri/lib/utils.js"(exports, module) {
3104
+ "../../node_modules/.pnpm/fast-uri@3.1.8/node_modules/fast-uri/lib/utils.js"(exports, module) {
3105
3105
  "use strict";
3106
3106
  var isUUID = RegExp.prototype.test.bind(/^[\da-f]{8}-[\da-f]{4}-[\da-f]{4}-[\da-f]{4}-[\da-f]{12}$/iu);
3107
3107
  var isIPv4 = RegExp.prototype.test.bind(/^(?:(?:25[0-5]|2[0-4]\d|1\d{2}|[1-9]\d|\d)\.){3}(?:25[0-5]|2[0-4]\d|1\d{2}|[1-9]\d|\d)$/u);
3108
+ var isPort = RegExp.prototype.test.bind(/^\d*$/u);
3108
3109
  var isHexPair = RegExp.prototype.test.bind(/^[\da-f]{2}$/iu);
3109
3110
  var isUnreserved = RegExp.prototype.test.bind(/^[\da-z\-._~]$/iu);
3110
3111
  var isPathCharacter = RegExp.prototype.test.bind(/^[A-Za-z0-9\-._~!$&'()*+,;=:@/]$/u);
@@ -3570,8 +3571,12 @@ var require_utils = __commonJS({
3570
3571
  uriTokens.push(host);
3571
3572
  }
3572
3573
  if (typeof component.port === "number" || typeof component.port === "string") {
3574
+ const port = String(component.port);
3575
+ if (!isPort(port)) {
3576
+ throw new TypeError("URI port is malformed.");
3577
+ }
3573
3578
  uriTokens.push(":");
3574
- uriTokens.push(String(component.port));
3579
+ uriTokens.push(port);
3575
3580
  }
3576
3581
  return uriTokens.length ? uriTokens.join("") : void 0;
3577
3582
  }
@@ -3596,9 +3601,9 @@ var require_utils = __commonJS({
3596
3601
  }
3597
3602
  });
3598
3603
 
3599
- // ../../node_modules/.pnpm/fast-uri@3.1.6/node_modules/fast-uri/lib/schemes.js
3604
+ // ../../node_modules/.pnpm/fast-uri@3.1.8/node_modules/fast-uri/lib/schemes.js
3600
3605
  var require_schemes = __commonJS({
3601
- "../../node_modules/.pnpm/fast-uri@3.1.6/node_modules/fast-uri/lib/schemes.js"(exports, module) {
3606
+ "../../node_modules/.pnpm/fast-uri@3.1.8/node_modules/fast-uri/lib/schemes.js"(exports, module) {
3602
3607
  "use strict";
3603
3608
  var { isUUID } = require_utils();
3604
3609
  var URN_REG = /^([\da-z][\d\-a-z]{0,31}):((?:[\w!$'()*+,\-./:;=@]|%[\da-f]{2})+)$/iu;
@@ -3807,9 +3812,9 @@ var require_schemes = __commonJS({
3807
3812
  }
3808
3813
  });
3809
3814
 
3810
- // ../../node_modules/.pnpm/fast-uri@3.1.6/node_modules/fast-uri/index.js
3815
+ // ../../node_modules/.pnpm/fast-uri@3.1.8/node_modules/fast-uri/index.js
3811
3816
  var require_fast_uri = __commonJS({
3812
- "../../node_modules/.pnpm/fast-uri@3.1.6/node_modules/fast-uri/index.js"(exports, module) {
3817
+ "../../node_modules/.pnpm/fast-uri@3.1.8/node_modules/fast-uri/index.js"(exports, module) {
3813
3818
  "use strict";
3814
3819
  var { normalizeIPv6, removeDotSegments, recomposeAuthority, normalizePercentEncoding, normalizePathEncoding, serializePathEncoding, normalizeQueryFragmentEncoding, encodeQuery, encodeFragment, reescapeHostDelimiters, isIPv4, nonSimpleDomain } = require_utils();
3815
3820
  var { SCHEMES, getSchemeHandler } = require_schemes();
@@ -4014,12 +4019,15 @@ var require_fast_uri = __commonJS({
4014
4019
  }
4015
4020
  return false;
4016
4021
  }
4022
+ function isIPLiteral(host) {
4023
+ return host[0] === "[" && host[host.length - 1] === "]";
4024
+ }
4017
4025
  function hasMalformedComponentPercentEncoding(matches) {
4018
4026
  const host = matches[4];
4019
- return hasMalformedPercentEncoding(matches[3]) || host !== void 0 && !(host[0] === "[" && host[host.length - 1] === "]") && hasMalformedPercentEncoding(host) || hasMalformedPercentEncoding(matches[6]) || hasMalformedPercentEncoding(matches[7]) || hasMalformedPercentEncoding(matches[8]);
4027
+ return hasMalformedPercentEncoding(matches[3]) || host !== void 0 && !isIPLiteral(host) && hasMalformedPercentEncoding(host) || hasMalformedPercentEncoding(matches[6]) || hasMalformedPercentEncoding(matches[7]) || hasMalformedPercentEncoding(matches[8]);
4020
4028
  }
4021
4029
  function canonicalizeHost(parsed, options, schemeHandler, isIP) {
4022
- if (!options.unicodeSupport && (!schemeHandler || !schemeHandler.unicodeSupport) && parsed.host && parsed.host[0] !== "[" && (options.domainHost || schemeHandler && schemeHandler.domainHost) && isIP === false && nonSimpleDomain(parsed.host)) {
4030
+ if (!options.unicodeSupport && (!schemeHandler || !schemeHandler.unicodeSupport) && parsed.host && !isIPLiteral(parsed.host) && (options.domainHost || schemeHandler && schemeHandler.domainHost) && isIP === false && nonSimpleDomain(parsed.host)) {
4023
4031
  try {
4024
4032
  parsed.host = new URL("http://" + parsed.host).hostname;
4025
4033
  } catch (e) {
@@ -4106,10 +4114,11 @@ var require_fast_uri = __commonJS({
4106
4114
  if (parsed.host) {
4107
4115
  const ipv4result = isIPv4(parsed.host);
4108
4116
  if (ipv4result === false) {
4109
- const bracketedIPLiteral = parsed.host[0] === "[" && parsed.host[parsed.host.length - 1] === "]";
4117
+ const bracketedIPLiteral = isIPLiteral(parsed.host);
4118
+ const hasIPLiteralBracket = parsed.host.indexOf("[") !== -1 || parsed.host.indexOf("]") !== -1;
4110
4119
  const ipv6result = normalizeIPv6(parsed.host);
4111
4120
  isIP = ipv6result.isIPV6 || ipv6result.isIPVFuture === true;
4112
- malformedIPLiteral = bracketedIPLiteral && ipv6result.error === true;
4121
+ malformedIPLiteral = hasIPLiteralBracket && (!bracketedIPLiteral || ipv6result.error === true);
4113
4122
  parsed.host = isIP ? ipv6result.host : ipv6result.host.toLowerCase();
4114
4123
  if (malformedIPLiteral) {
4115
4124
  parsed.error = parsed.error || "URI host is malformed.";
@@ -4132,14 +4141,17 @@ var require_fast_uri = __commonJS({
4132
4141
  parsed.error = parsed.error || "URI is not a " + options.reference + " reference.";
4133
4142
  }
4134
4143
  const schemeHandler = getSchemeHandler(options.scheme || parsed.scheme);
4135
- malformedHost = canonicalizeHost(parsed, options, schemeHandler, isIP);
4136
- if (!schemeHandler || schemeHandler && !schemeHandler.skipNormalize) {
4137
- if (uri.indexOf("%") !== -1) {
4138
- if (parsed.host !== void 0 && !malformedIPLiteral) {
4139
- const host = isIP ? parsed.host : normalizePercentEncoding(parsed.host, true);
4140
- parsed.host = reescapeHostDelimiters(host, isIP);
4141
- }
4144
+ if (!malformedIPLiteral) {
4145
+ malformedHost = canonicalizeHost(parsed, options, schemeHandler, isIP);
4146
+ }
4147
+ if (uri.indexOf("%") !== -1 && parsed.host !== void 0 && !malformedIPLiteral) {
4148
+ let host = isIP ? parsed.host : normalizePercentEncoding(parsed.host, true);
4149
+ if (!isIP) {
4150
+ host = normalizePercentEncoding(host.toLowerCase());
4142
4151
  }
4152
+ parsed.host = reescapeHostDelimiters(host, isIP);
4153
+ }
4154
+ if (!schemeHandler || schemeHandler && !schemeHandler.skipNormalize) {
4143
4155
  if (parsed.path) {
4144
4156
  parsed.path = normalizePathEncoding(parsed.path);
4145
4157
  }
@@ -14897,7 +14909,7 @@ var CONFIG_FORMATS = {
14897
14909
  IssuanceConfig: {
14898
14910
  slug: "issuance-config",
14899
14911
  file: "IssuanceConfigFile",
14900
- version: 2
14912
+ version: 3
14901
14913
  },
14902
14914
  CredentialConfig: {
14903
14915
  slug: "credential-config",
@@ -14980,6 +14992,15 @@ var CONFIG_MIGRATIONS = [
14980
14992
  // valid v2 spec whose offers keep having no lifetime.
14981
14993
  migrate: (spec) => ({ spec })
14982
14994
  },
14995
+ {
14996
+ id: "issuance-config-v3-trust-list-verifier-pem",
14997
+ kind: "IssuanceConfig",
14998
+ from: 2,
14999
+ to: 3,
15000
+ // v3 only adds the optional verifierKeyPem to wallet provider trust
15001
+ // list references: a v2 spec is a valid v3 spec.
15002
+ migrate: (spec) => ({ spec })
15003
+ },
14983
15004
  presentationConfigV1ToV2,
14984
15005
  {
14985
15006
  id: "presentation-config-v3-typed-claim-values",
@@ -21454,13 +21475,13 @@ var CONFIG_SCHEMAS = [
21454
21475
  },
21455
21476
  {
21456
21477
  "$schema": "https://json-schema.org/draft/2020-12/schema",
21457
- "$id": "https://eudiplo.dev/schemas/v3/PresentationConfigFile.schema.json",
21458
- "title": "PresentationConfigFile",
21478
+ "$id": "https://eudiplo.dev/schemas/v3/IssuanceConfigFile.schema.json",
21479
+ "title": "IssuanceConfigFile",
21459
21480
  "type": "object",
21460
21481
  "properties": {
21461
21482
  "$schema": {
21462
21483
  "type": "string",
21463
- "const": "https://eudiplo.dev/schemas/v3/PresentationConfigFile.schema.json"
21484
+ "const": "https://eudiplo.dev/schemas/v3/IssuanceConfigFile.schema.json"
21464
21485
  },
21465
21486
  "metadata": {
21466
21487
  "type": "object",
@@ -21482,23 +21503,7 @@ var CONFIG_SCHEMAS = [
21482
21503
  "additionalProperties": false
21483
21504
  },
21484
21505
  "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
- ]
21506
+ "$ref": "#/$defs/IssuanceConfig"
21502
21507
  }
21503
21508
  },
21504
21509
  "required": [
@@ -21507,103 +21512,814 @@ var CONFIG_SCHEMAS = [
21507
21512
  ],
21508
21513
  "additionalProperties": false,
21509
21514
  "$defs": {
21510
- "PresentationConfigCreateDto": {
21515
+ "IssuanceConfig": {
21511
21516
  "type": "object",
21512
21517
  "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.",
21518
+ "batchSize": {
21519
+ "description": "Optional issuance batch size.",
21527
21520
  "type": "integer",
21528
21521
  "minimum": 1,
21529
21522
  "maximum": 9007199254740991
21530
21523
  },
21531
- "skewSeconds": {
21532
- "description": "Clock skew tolerance in seconds.",
21533
- "type": "integer",
21534
- "minimum": 0,
21535
- "maximum": 9007199254740991
21524
+ "dPopRequired": {
21525
+ "description": "Require DPoP proofs for issuance endpoints.",
21526
+ "type": "boolean"
21536
21527
  },
21537
- "statusCheckMode": {
21538
- "description": "Revocation/status check mode.",
21528
+ "walletAttestationRequired": {
21529
+ "description": "Default wallet attestation requirement for managed authorization servers.",
21530
+ "type": "boolean"
21531
+ },
21532
+ "walletProviderTrustLists": {
21533
+ "description": "Shared wallet provider trust lists for key attestations and default authorization server wallet authentication.",
21534
+ "type": "array",
21535
+ "items": {
21536
+ "type": "object",
21537
+ "properties": {
21538
+ "trustListId": {
21539
+ "type": "string",
21540
+ "minLength": 1
21541
+ },
21542
+ "url": {
21543
+ "description": "URL of the wallet provider trust list.",
21544
+ "type": "string",
21545
+ "format": "uri"
21546
+ },
21547
+ "verifierKey": {
21548
+ "description": "Optional verifier key material used for trust list verification.",
21549
+ "type": "object",
21550
+ "propertyNames": {
21551
+ "type": "string"
21552
+ },
21553
+ "additionalProperties": {}
21554
+ },
21555
+ "verifierKeyPem": {
21556
+ "description": "Optional verifier public key in SPKI PEM form (-----BEGIN PUBLIC KEY-----).",
21557
+ "type": "string",
21558
+ "pattern": "^\\s*-----BEGIN PUBLIC KEY-----[A-Za-z0-9+/=\\s]+-----END PUBLIC KEY-----\\s*$"
21559
+ },
21560
+ "verifierX509Der": {
21561
+ "description": "Optional verifier certificate in DER/base64 form.",
21562
+ "type": "string"
21563
+ }
21564
+ },
21565
+ "additionalProperties": false
21566
+ }
21567
+ },
21568
+ "signingKeyId": {
21569
+ "description": "Default signing key chain id for credential issuance.",
21539
21570
  "type": "string",
21540
- "enum": [
21541
- "strict",
21542
- "best_effort",
21543
- "disabled"
21544
- ]
21571
+ "minLength": 1
21545
21572
  },
21546
- "dcql_query": {
21547
- "type": "object",
21548
- "properties": {
21549
- "credentials": {
21550
- "minItems": 1,
21551
- "type": "array",
21552
- "items": {
21553
- "oneOf": [
21554
- {
21573
+ "authorizationServers": {
21574
+ "minItems": 1,
21575
+ "type": "array",
21576
+ "items": {
21577
+ "oneOf": [
21578
+ {
21579
+ "type": "object",
21580
+ "properties": {
21581
+ "type": {
21582
+ "type": "string",
21583
+ "const": "external",
21584
+ "description": "Use an externally managed authorization server."
21585
+ },
21586
+ "id": {
21587
+ "type": "string",
21588
+ "minLength": 1,
21589
+ "description": "Authorization server identifier."
21590
+ },
21591
+ "issuer": {
21592
+ "type": "string",
21593
+ "format": "uri",
21594
+ "description": "Issuer URL for the external authorization server."
21595
+ },
21596
+ "sessionBinding": {
21597
+ "description": "Explicit mapping from an external access-token claim to an existing issuance session.",
21555
21598
  "type": "object",
21556
21599
  "properties": {
21557
- "id": {
21600
+ "method": {
21601
+ "type": "string",
21602
+ "const": "access_token_claim",
21603
+ "description": "Read the correlation value from a configured access-token claim."
21604
+ },
21605
+ "claim": {
21558
21606
  "type": "string",
21559
21607
  "minLength": 1,
21560
- "pattern": "^[A-Za-z0-9_-]+$",
21561
- "description": "Credential query identifier."
21608
+ "description": "Claim name that contains the issuance-session correlation value."
21609
+ }
21610
+ },
21611
+ "required": [
21612
+ "method",
21613
+ "claim"
21614
+ ],
21615
+ "additionalProperties": false
21616
+ },
21617
+ "label": {
21618
+ "description": "Optional display label for UI selection.",
21619
+ "type": "string"
21620
+ },
21621
+ "enabled": {
21622
+ "description": "Whether this authorization server entry is enabled.",
21623
+ "type": "boolean"
21624
+ }
21625
+ },
21626
+ "required": [
21627
+ "type",
21628
+ "id",
21629
+ "issuer"
21630
+ ],
21631
+ "additionalProperties": false
21632
+ },
21633
+ {
21634
+ "type": "object",
21635
+ "properties": {
21636
+ "type": {
21637
+ "type": "string",
21638
+ "const": "oid4vp",
21639
+ "description": "Use OID4VP-based authorization server chaining."
21640
+ },
21641
+ "id": {
21642
+ "type": "string",
21643
+ "minLength": 1,
21644
+ "description": "Authorization server identifier."
21645
+ },
21646
+ "presentationConfigId": {
21647
+ "type": "string",
21648
+ "minLength": 1,
21649
+ "description": "Presentation configuration id used during authorization."
21650
+ },
21651
+ "immediateWalletRedirect": {
21652
+ "description": "Redirect wallets immediately after authorization response creation.",
21653
+ "type": "boolean"
21654
+ },
21655
+ "token": {
21656
+ "description": "Optional token issuance settings.",
21657
+ "type": "object",
21658
+ "properties": {
21659
+ "lifetimeSeconds": {
21660
+ "description": "Access token lifetime in seconds.",
21661
+ "type": "number",
21662
+ "minimum": 60
21562
21663
  },
21563
- "multiple": {
21564
- "description": "Allow multiple matching credentials.",
21565
- "type": "boolean"
21664
+ "signingKeyId": {
21665
+ "description": "Optional key chain id used to sign issued tokens.",
21666
+ "type": "string",
21667
+ "minLength": 1
21566
21668
  },
21567
- "claim_sets": {
21568
- "description": "Optional claim set constraints.",
21569
- "type": "array",
21570
- "items": {
21571
- "type": "array",
21572
- "items": {
21573
- "type": "string"
21574
- }
21575
- }
21669
+ "refreshTokenEnabled": {
21670
+ "description": "Enable issuing refresh tokens.",
21671
+ "type": "boolean"
21576
21672
  },
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
- {
21673
+ "refreshTokenExpiresInSeconds": {
21674
+ "description": "Refresh token lifetime in seconds.",
21675
+ "type": "number",
21676
+ "minimum": 60
21677
+ }
21678
+ },
21679
+ "additionalProperties": false
21680
+ },
21681
+ "requireDPoP": {
21682
+ "description": "Require DPoP proofs for token/credential requests.",
21683
+ "type": "boolean"
21684
+ },
21685
+ "walletAttestationRequired": {
21686
+ "description": "Require wallet attestation for this authorization server.",
21687
+ "type": "boolean"
21688
+ },
21689
+ "walletProviderTrustLists": {
21690
+ "description": "Optional wallet provider trust list references for this authorization server.",
21691
+ "type": "array",
21692
+ "items": {
21693
+ "type": "object",
21694
+ "properties": {
21695
+ "trustListId": {
21696
+ "type": "string",
21697
+ "minLength": 1
21698
+ },
21699
+ "url": {
21700
+ "description": "URL of the wallet provider trust list.",
21701
+ "type": "string",
21702
+ "format": "uri"
21703
+ },
21704
+ "verifierKey": {
21705
+ "description": "Optional verifier key material used for trust list verification.",
21706
+ "type": "object",
21707
+ "propertyNames": {
21708
+ "type": "string"
21709
+ },
21710
+ "additionalProperties": {}
21711
+ },
21712
+ "verifierKeyPem": {
21713
+ "description": "Optional verifier public key in SPKI PEM form (-----BEGIN PUBLIC KEY-----).",
21714
+ "type": "string",
21715
+ "pattern": "^\\s*-----BEGIN PUBLIC KEY-----[A-Za-z0-9+/=\\s]+-----END PUBLIC KEY-----\\s*$"
21716
+ },
21717
+ "verifierX509Der": {
21718
+ "description": "Optional verifier certificate in DER/base64 form.",
21719
+ "type": "string"
21720
+ }
21721
+ },
21722
+ "additionalProperties": false
21723
+ }
21724
+ },
21725
+ "label": {
21726
+ "description": "Optional display label for UI selection.",
21727
+ "type": "string"
21728
+ },
21729
+ "enabled": {
21730
+ "description": "Whether this authorization server entry is enabled.",
21731
+ "type": "boolean"
21732
+ }
21733
+ },
21734
+ "required": [
21735
+ "type",
21736
+ "id",
21737
+ "presentationConfigId"
21738
+ ],
21739
+ "additionalProperties": false
21740
+ },
21741
+ {
21742
+ "type": "object",
21743
+ "properties": {
21744
+ "type": {
21745
+ "type": "string",
21746
+ "const": "chained",
21747
+ "description": "Use upstream OIDC as authorization source."
21748
+ },
21749
+ "id": {
21750
+ "type": "string",
21751
+ "minLength": 1,
21752
+ "description": "Authorization server identifier."
21753
+ },
21754
+ "upstream": {
21755
+ "type": "object",
21756
+ "properties": {
21757
+ "issuer": {
21758
+ "type": "string",
21759
+ "format": "uri",
21760
+ "description": "Upstream OIDC issuer URL."
21761
+ },
21762
+ "clientId": {
21763
+ "type": "string",
21764
+ "minLength": 1,
21765
+ "description": "Client id for upstream OIDC authentication."
21766
+ },
21767
+ "clientSecret": {
21768
+ "description": "Optional client secret for upstream OIDC authentication.",
21769
+ "type": "string",
21770
+ "minLength": 1
21771
+ },
21772
+ "scopes": {
21773
+ "description": "Optional scopes requested from the upstream issuer.",
21774
+ "type": "array",
21775
+ "items": {
21776
+ "type": "string",
21777
+ "minLength": 1
21778
+ }
21779
+ }
21780
+ },
21781
+ "required": [
21782
+ "issuer",
21783
+ "clientId"
21784
+ ],
21785
+ "additionalProperties": false,
21786
+ "description": "Upstream OIDC connection settings."
21787
+ },
21788
+ "token": {
21789
+ "description": "Optional token issuance settings.",
21790
+ "type": "object",
21791
+ "properties": {
21792
+ "lifetimeSeconds": {
21793
+ "description": "Access token lifetime in seconds.",
21794
+ "type": "number",
21795
+ "minimum": 60
21796
+ },
21797
+ "signingKeyId": {
21798
+ "description": "Optional key chain id used to sign issued tokens.",
21799
+ "type": "string",
21800
+ "minLength": 1
21801
+ },
21802
+ "refreshTokenEnabled": {
21803
+ "description": "Enable issuing refresh tokens.",
21804
+ "type": "boolean"
21805
+ },
21806
+ "refreshTokenExpiresInSeconds": {
21807
+ "description": "Refresh token lifetime in seconds.",
21808
+ "type": "number",
21809
+ "minimum": 60
21810
+ }
21811
+ },
21812
+ "additionalProperties": false
21813
+ },
21814
+ "requireDPoP": {
21815
+ "description": "Require DPoP proofs for token/credential requests.",
21816
+ "type": "boolean"
21817
+ },
21818
+ "walletAttestationRequired": {
21819
+ "description": "Require wallet attestation for this authorization server.",
21820
+ "type": "boolean"
21821
+ },
21822
+ "walletProviderTrustLists": {
21823
+ "description": "Optional wallet provider trust list references for this authorization server.",
21824
+ "type": "array",
21825
+ "items": {
21826
+ "type": "object",
21827
+ "properties": {
21828
+ "trustListId": {
21829
+ "type": "string",
21830
+ "minLength": 1
21831
+ },
21832
+ "url": {
21833
+ "description": "URL of the wallet provider trust list.",
21834
+ "type": "string",
21835
+ "format": "uri"
21836
+ },
21837
+ "verifierKey": {
21838
+ "description": "Optional verifier key material used for trust list verification.",
21839
+ "type": "object",
21840
+ "propertyNames": {
21841
+ "type": "string"
21842
+ },
21843
+ "additionalProperties": {}
21844
+ },
21845
+ "verifierKeyPem": {
21846
+ "description": "Optional verifier public key in SPKI PEM form (-----BEGIN PUBLIC KEY-----).",
21847
+ "type": "string",
21848
+ "pattern": "^\\s*-----BEGIN PUBLIC KEY-----[A-Za-z0-9+/=\\s]+-----END PUBLIC KEY-----\\s*$"
21849
+ },
21850
+ "verifierX509Der": {
21851
+ "description": "Optional verifier certificate in DER/base64 form.",
21852
+ "type": "string"
21853
+ }
21854
+ },
21855
+ "additionalProperties": false
21856
+ }
21857
+ },
21858
+ "label": {
21859
+ "description": "Optional display label for UI selection.",
21860
+ "type": "string"
21861
+ },
21862
+ "enabled": {
21863
+ "description": "Whether this authorization server entry is enabled.",
21864
+ "type": "boolean"
21865
+ }
21866
+ },
21867
+ "required": [
21868
+ "type",
21869
+ "id",
21870
+ "upstream"
21871
+ ],
21872
+ "additionalProperties": false
21873
+ },
21874
+ {
21875
+ "type": "object",
21876
+ "properties": {
21877
+ "type": {
21878
+ "type": "string",
21879
+ "const": "built-in",
21880
+ "description": "Use EUDIPLO built-in authorization server."
21881
+ },
21882
+ "id": {
21883
+ "type": "string",
21884
+ "minLength": 1,
21885
+ "description": "Authorization server identifier."
21886
+ },
21887
+ "token": {
21888
+ "description": "Optional token issuance settings.",
21889
+ "type": "object",
21890
+ "properties": {
21891
+ "lifetimeSeconds": {
21892
+ "description": "Access token lifetime in seconds.",
21893
+ "type": "number",
21894
+ "minimum": 60
21895
+ },
21896
+ "signingKeyId": {
21897
+ "description": "Optional key chain id used to sign issued tokens.",
21898
+ "type": "string",
21899
+ "minLength": 1
21900
+ },
21901
+ "refreshTokenEnabled": {
21902
+ "description": "Enable issuing refresh tokens.",
21903
+ "type": "boolean"
21904
+ },
21905
+ "refreshTokenExpiresInSeconds": {
21906
+ "description": "Refresh token lifetime in seconds.",
21907
+ "type": "number",
21908
+ "minimum": 60
21909
+ }
21910
+ },
21911
+ "additionalProperties": false
21912
+ },
21913
+ "requireDPoP": {
21914
+ "description": "Require DPoP proofs for token/credential requests.",
21915
+ "type": "boolean"
21916
+ },
21917
+ "walletAttestationRequired": {
21918
+ "description": "Require wallet attestation for this authorization server.",
21919
+ "type": "boolean"
21920
+ },
21921
+ "walletProviderTrustLists": {
21922
+ "description": "Optional wallet provider trust list references for this authorization server.",
21923
+ "type": "array",
21924
+ "items": {
21925
+ "type": "object",
21926
+ "properties": {
21927
+ "trustListId": {
21928
+ "type": "string",
21929
+ "minLength": 1
21930
+ },
21931
+ "url": {
21932
+ "description": "URL of the wallet provider trust list.",
21933
+ "type": "string",
21934
+ "format": "uri"
21935
+ },
21936
+ "verifierKey": {
21937
+ "description": "Optional verifier key material used for trust list verification.",
21938
+ "type": "object",
21939
+ "propertyNames": {
21940
+ "type": "string"
21941
+ },
21942
+ "additionalProperties": {}
21943
+ },
21944
+ "verifierKeyPem": {
21945
+ "description": "Optional verifier public key in SPKI PEM form (-----BEGIN PUBLIC KEY-----).",
21946
+ "type": "string",
21947
+ "pattern": "^\\s*-----BEGIN PUBLIC KEY-----[A-Za-z0-9+/=\\s]+-----END PUBLIC KEY-----\\s*$"
21948
+ },
21949
+ "verifierX509Der": {
21950
+ "description": "Optional verifier certificate in DER/base64 form.",
21951
+ "type": "string"
21952
+ }
21953
+ },
21954
+ "additionalProperties": false
21955
+ }
21956
+ },
21957
+ "label": {
21958
+ "description": "Optional display label for UI selection.",
21959
+ "type": "string"
21960
+ },
21961
+ "enabled": {
21962
+ "description": "Whether this authorization server entry is enabled.",
21963
+ "type": "boolean"
21964
+ }
21965
+ },
21966
+ "required": [
21967
+ "type",
21968
+ "id"
21969
+ ],
21970
+ "additionalProperties": false
21971
+ }
21972
+ ],
21973
+ "description": "Supported authorization server configurations."
21974
+ },
21975
+ "description": "Configured authorization server entries."
21976
+ },
21977
+ "federation": {
21978
+ "description": "Optional OpenID Federation settings.",
21979
+ "anyOf": [
21980
+ {
21981
+ "type": "object",
21982
+ "properties": {
21983
+ "role": {
21984
+ "description": "Federation role for this issuer.",
21985
+ "type": "string",
21986
+ "enum": [
21987
+ "trust_anchor",
21988
+ "intermediate",
21989
+ "leaf"
21990
+ ]
21991
+ },
21992
+ "mode": {
21993
+ "description": "Federation operation mode.",
21994
+ "type": "string",
21995
+ "enum": [
21996
+ "federation-only",
21997
+ "hybrid"
21998
+ ]
21999
+ },
22000
+ "entityId": {
22001
+ "description": "Optional local federation entity id.",
22002
+ "type": "string"
22003
+ },
22004
+ "enforceSigningPolicy": {
22005
+ "description": "Enforce strict signing policy checks.",
22006
+ "type": "boolean"
22007
+ },
22008
+ "cacheTtlSeconds": {
22009
+ "description": "Cache time-to-live for federation metadata in seconds.",
22010
+ "type": "integer",
22011
+ "minimum": 1,
22012
+ "maximum": 9007199254740991
22013
+ },
22014
+ "trustAnchors": {
22015
+ "type": "array",
22016
+ "items": {
22017
+ "type": "object",
22018
+ "properties": {
22019
+ "entityId": {
22020
+ "type": "string",
22021
+ "minLength": 1,
22022
+ "description": "Federation trust anchor entity id."
22023
+ },
22024
+ "entityConfigurationUri": {
22025
+ "type": "string",
22026
+ "format": "uri",
22027
+ "description": "Entity configuration URI for the trust anchor."
22028
+ }
22029
+ },
22030
+ "required": [
22031
+ "entityId",
22032
+ "entityConfigurationUri"
22033
+ ],
22034
+ "additionalProperties": false
22035
+ },
22036
+ "description": "Federation trust anchors."
22037
+ }
22038
+ },
22039
+ "required": [
22040
+ "trustAnchors"
22041
+ ],
22042
+ "additionalProperties": false
22043
+ },
22044
+ {
22045
+ "type": "null"
22046
+ }
22047
+ ]
22048
+ },
22049
+ "registrationCertificate": {
22050
+ "description": "Optional registration certificate settings.",
22051
+ "anyOf": [
22052
+ {
22053
+ "type": "object",
22054
+ "properties": {
22055
+ "enabled": {
22056
+ "description": "Enable issuer registration certificate support.",
22057
+ "type": "boolean"
22058
+ },
22059
+ "mode": {
22060
+ "description": "How registration certificate data is provided.",
22061
+ "type": "string",
22062
+ "enum": [
22063
+ "import",
22064
+ "generate"
22065
+ ]
22066
+ },
22067
+ "jwt": {
22068
+ "description": "Optional registration certificate JWT when using import mode.",
22069
+ "type": "string"
22070
+ },
22071
+ "privacyPolicy": {
22072
+ "description": "Optional privacy policy URI.",
22073
+ "type": "string"
22074
+ },
22075
+ "supportUri": {
22076
+ "description": "Optional support URI.",
22077
+ "type": "string"
22078
+ }
22079
+ },
22080
+ "additionalProperties": false
22081
+ },
22082
+ {
22083
+ "type": "null"
22084
+ }
22085
+ ]
22086
+ },
22087
+ "display": {
22088
+ "description": "Localized issuer metadata shown to wallets.",
22089
+ "type": "array",
22090
+ "items": {
22091
+ "type": "object",
22092
+ "properties": {
22093
+ "name": {
22094
+ "description": "Issuer display name.",
22095
+ "type": "string"
22096
+ },
22097
+ "locale": {
22098
+ "description": "Locale tag for this display entry.",
22099
+ "type": "string"
22100
+ },
22101
+ "logo": {
22102
+ "description": "Optional issuer logo metadata.",
22103
+ "type": "object",
22104
+ "properties": {
22105
+ "uri": {
22106
+ "type": "string",
22107
+ "minLength": 1,
22108
+ "description": "Logo URI."
22109
+ },
22110
+ "alt_text": {
22111
+ "description": "Optional localized alternative text.",
22112
+ "type": "string"
22113
+ }
22114
+ },
22115
+ "required": [
22116
+ "uri"
22117
+ ],
22118
+ "additionalProperties": {}
22119
+ }
22120
+ },
22121
+ "additionalProperties": {}
22122
+ }
22123
+ },
22124
+ "notificationEndpointEnabled": {
22125
+ "description": "Whether the OID4VCI notification endpoint is exposed for this issuance configuration.",
22126
+ "type": "boolean"
22127
+ },
22128
+ "credentialResponseEncryption": {
22129
+ "description": "Enable encrypted credential responses.",
22130
+ "type": "boolean"
22131
+ },
22132
+ "credentialRequestEncryption": {
22133
+ "description": "Require encrypted credential requests.",
22134
+ "type": "boolean"
22135
+ },
22136
+ "txCodeMaxAttempts": {
22137
+ "description": "Maximum verification attempts for transaction codes. Null resets to defaults.",
22138
+ "anyOf": [
22139
+ {
22140
+ "type": "integer",
22141
+ "minimum": 1,
22142
+ "maximum": 9007199254740991
22143
+ },
22144
+ {
22145
+ "type": "null"
22146
+ }
22147
+ ]
22148
+ },
22149
+ "offerLifetimeSeconds": {
22150
+ "description": "Default lifetime of credential offers in seconds. Can be overridden per offer request. Null or unset: offers do not expire.",
22151
+ "anyOf": [
22152
+ {
22153
+ "type": "integer",
22154
+ "minimum": 1,
22155
+ "maximum": 9007199254740991
22156
+ },
22157
+ {
22158
+ "type": "null"
22159
+ }
22160
+ ]
22161
+ }
22162
+ },
22163
+ "required": [
22164
+ "authorizationServers"
22165
+ ],
22166
+ "additionalProperties": false,
22167
+ "title": "IssuanceConfig"
22168
+ }
22169
+ }
22170
+ },
22171
+ {
22172
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
22173
+ "$id": "https://eudiplo.dev/schemas/v3/PresentationConfigFile.schema.json",
22174
+ "title": "PresentationConfigFile",
22175
+ "type": "object",
22176
+ "properties": {
22177
+ "$schema": {
22178
+ "type": "string",
22179
+ "const": "https://eudiplo.dev/schemas/v3/PresentationConfigFile.schema.json"
22180
+ },
22181
+ "metadata": {
22182
+ "type": "object",
22183
+ "properties": {
22184
+ "generation": {
22185
+ "type": "integer",
22186
+ "minimum": 1,
22187
+ "description": "Monotonically increasing configuration generation."
22188
+ },
22189
+ "ownership": {
22190
+ "type": "string",
22191
+ "enum": [
22192
+ "unmanaged",
22193
+ "file-managed"
22194
+ ],
22195
+ "description": "Requested ownership recorded when the document is applied."
22196
+ }
22197
+ },
22198
+ "additionalProperties": false
22199
+ },
22200
+ "spec": {
22201
+ "allOf": [
22202
+ {
22203
+ "$ref": "#/$defs/PresentationConfigCreateDto"
22204
+ },
22205
+ {
22206
+ "type": "object",
22207
+ "required": [
22208
+ "id"
22209
+ ],
22210
+ "properties": {
22211
+ "id": {
22212
+ "type": "string",
22213
+ "minLength": 1
22214
+ }
22215
+ }
22216
+ }
22217
+ ]
22218
+ }
22219
+ },
22220
+ "required": [
22221
+ "$schema",
22222
+ "spec"
22223
+ ],
22224
+ "additionalProperties": false,
22225
+ "$defs": {
22226
+ "PresentationConfigCreateDto": {
22227
+ "type": "object",
22228
+ "properties": {
22229
+ "id": {
22230
+ "type": "string",
22231
+ "minLength": 1,
22232
+ "description": "Presentation configuration identifier."
22233
+ },
22234
+ "description": {
22235
+ "description": "Optional presentation configuration description.",
22236
+ "type": [
22237
+ "string",
22238
+ "null"
22239
+ ]
22240
+ },
22241
+ "lifeTime": {
22242
+ "description": "Presentation request lifetime in seconds.",
22243
+ "type": "integer",
22244
+ "minimum": 1,
22245
+ "maximum": 9007199254740991
22246
+ },
22247
+ "skewSeconds": {
22248
+ "description": "Clock skew tolerance in seconds.",
22249
+ "type": "integer",
22250
+ "minimum": 0,
22251
+ "maximum": 9007199254740991
22252
+ },
22253
+ "statusCheckMode": {
22254
+ "description": "Revocation/status check mode.",
22255
+ "type": "string",
22256
+ "enum": [
22257
+ "strict",
22258
+ "best_effort",
22259
+ "disabled"
22260
+ ]
22261
+ },
22262
+ "dcql_query": {
22263
+ "type": "object",
22264
+ "properties": {
22265
+ "credentials": {
22266
+ "minItems": 1,
22267
+ "type": "array",
22268
+ "items": {
22269
+ "oneOf": [
22270
+ {
22271
+ "type": "object",
22272
+ "properties": {
22273
+ "id": {
22274
+ "type": "string",
22275
+ "minLength": 1,
22276
+ "pattern": "^[A-Za-z0-9_-]+$",
22277
+ "description": "Credential query identifier."
22278
+ },
22279
+ "multiple": {
22280
+ "description": "Allow multiple matching credentials.",
22281
+ "type": "boolean"
22282
+ },
22283
+ "claim_sets": {
22284
+ "description": "Optional claim set constraints.",
22285
+ "type": "array",
22286
+ "items": {
22287
+ "type": "array",
22288
+ "items": {
22289
+ "type": "string"
22290
+ }
22291
+ }
22292
+ },
22293
+ "trusted_authorities": {
22294
+ "description": "Optional trusted authority constraints.",
22295
+ "type": "array",
22296
+ "items": {
22297
+ "oneOf": [
22298
+ {
22299
+ "type": "object",
22300
+ "properties": {
22301
+ "type": {
22302
+ "type": "string",
22303
+ "const": "etsi_tl",
22304
+ "description": "Trusted authority type discriminator for ETSI trust lists."
22305
+ },
22306
+ "values": {
22307
+ "type": "array",
22308
+ "items": {
22309
+ "type": "object",
22310
+ "properties": {
22311
+ "trustListId": {
22312
+ "description": "Optional trust list id reference.",
22313
+ "type": "string"
22314
+ },
22315
+ "url": {
22316
+ "description": "Optional trust list URL reference.",
22317
+ "anyOf": [
22318
+ {
22319
+ "type": "string",
22320
+ "format": "uri"
22321
+ },
22322
+ {
21607
22323
  "type": "string",
21608
22324
  "pattern": "^<TENANT_URL>(?:\\/.*)?$"
21609
22325
  }
@@ -23723,7 +24439,10 @@ function createTenantCommand(context, setExitCode) {
23723
24439
 
23724
24440
  // src/commands/config/validate/index.ts
23725
24441
  function createValidateCommand(context, setExitCode) {
23726
- return new Command("validate").description("Validate CLI or tenant config-import files").argument("[scope]").argument("[path]").addOption(
24442
+ return new Command("validate").description("Validate CLI or tenant config-import files").argument(
24443
+ "[scope]",
24444
+ '"tenant" for one tenant folder or "tenants" for a folder of tenant folders; omit it to validate the CLI config file'
24445
+ ).argument("[path]", "the folder to validate (required with a scope)").addOption(
23727
24446
  new Option("--format <text|json>", "tenant report format").choices(["text", "json"]).default("text")
23728
24447
  ).action(async (scope, path2, options) => {
23729
24448
  const state = await loadCliState(context);
@@ -23842,9 +24561,9 @@ function buildComposeLogsArgs(service, options = {}) {
23842
24561
  }
23843
24562
  return args;
23844
24563
  }
23845
- function buildComposePullArgs(service) {
24564
+ function buildComposePullArgs(services) {
23846
24565
  const args = ["pull"];
23847
- if (service !== void 0) {
24566
+ for (const service of typeof services === "string" ? [services] : services ?? []) {
23848
24567
  assertServiceName(service);
23849
24568
  args.push(service);
23850
24569
  }
@@ -23882,23 +24601,28 @@ function parseContainerStates(stdout) {
23882
24601
  return entries.map((entry) => {
23883
24602
  const record = entry;
23884
24603
  const names = record.Names;
24604
+ const status = String(record.Status ?? "");
24605
+ const exitCode2 = typeof record.ExitCode === "number" ? record.ExitCode : /^Exited \((\d+)\)/.exec(status)?.[1];
23885
24606
  return {
23886
24607
  name: Array.isArray(names) ? String(names[0] ?? "") : String(names ?? record.Name ?? ""),
23887
24608
  state: String(record.State ?? ""),
23888
- status: String(record.Status ?? "")
24609
+ status,
24610
+ exitCode: exitCode2 === void 0 ? void 0 : Number(exitCode2)
23889
24611
  };
23890
24612
  });
23891
24613
  }
23892
24614
  function summarizeContainerStates(containers, projectName) {
23893
24615
  const name = "service containers";
23894
- if (containers.length === 0) {
24616
+ const services = containers.filter((container) => !hasCompleted(container));
24617
+ const completed = containers.length - services.length;
24618
+ if (services.length === 0) {
23895
24619
  return {
23896
24620
  name,
23897
24621
  status: "warn",
23898
24622
  message: `No containers found for project ${projectName}. Start it with eudiplo up.`
23899
24623
  };
23900
24624
  }
23901
- const unhealthy = containers.filter(
24625
+ const unhealthy = services.filter(
23902
24626
  (container) => container.status.toLowerCase().includes("unhealthy")
23903
24627
  );
23904
24628
  if (unhealthy.length > 0) {
@@ -23908,25 +24632,28 @@ function summarizeContainerStates(containers, projectName) {
23908
24632
  message: `Unhealthy: ${describe(unhealthy)}`
23909
24633
  };
23910
24634
  }
23911
- const notRunning = containers.filter(
24635
+ const notRunning = services.filter(
23912
24636
  (container) => container.state.toLowerCase() !== "running"
23913
24637
  );
23914
24638
  if (notRunning.length > 0) {
23915
24639
  return {
23916
24640
  name,
23917
24641
  status: "warn",
23918
- message: `${containers.length - notRunning.length}/${containers.length} running. Not running: ${describe(notRunning)}`
24642
+ message: `${services.length - notRunning.length}/${services.length} running. Not running: ${describe(notRunning)}`
23919
24643
  };
23920
24644
  }
23921
- const starting = containers.filter(
24645
+ const starting = services.filter(
23922
24646
  (container) => container.status.toLowerCase().includes("starting")
23923
24647
  ).length;
23924
24648
  return {
23925
24649
  name,
23926
24650
  status: "pass",
23927
- message: `${containers.length} container(s) running${starting > 0 ? `, ${starting} still starting` : ""}.`
24651
+ message: `${services.length} container(s) running${starting > 0 ? `, ${starting} still starting` : ""}${completed > 0 ? `, ${completed} completed` : ""}.`
23928
24652
  };
23929
24653
  }
24654
+ function hasCompleted(container) {
24655
+ return container.state.toLowerCase() === "exited" && container.exitCode === 0;
24656
+ }
23930
24657
  function asArray(value) {
23931
24658
  return Array.isArray(value) ? value : [];
23932
24659
  }
@@ -24860,11 +25587,57 @@ async function runDriverCommand(config, command, parsed, context) {
24860
25587
  });
24861
25588
  }
24862
25589
 
25590
+ // src/commands/deployment/pass-through.ts
25591
+ function runtimeArguments(command, args) {
25592
+ const options = command.options.flatMap((option) => option.long ?? []);
25593
+ for (const arg of args) {
25594
+ if (!arg.startsWith("--") || arg === "--") {
25595
+ continue;
25596
+ }
25597
+ const flag = arg.split("=", 1)[0];
25598
+ const similar = options.filter(
25599
+ (option) => option !== flag && editDistance2(flag, option) <= 2
25600
+ );
25601
+ if (similar.length > 0) {
25602
+ const suggestion = similar.length === 1 ? similar[0] : `one of ${similar.join(", ")}`;
25603
+ command.error(
25604
+ `error: unknown option '${arg}'
25605
+ (Did you mean ${suggestion}?)`,
25606
+ { code: "commander.unknownOption" }
25607
+ );
25608
+ }
25609
+ }
25610
+ const separator = args.indexOf("--");
25611
+ return separator === -1 ? args : [...args.slice(0, separator), ...args.slice(separator + 1)];
25612
+ }
25613
+ function editDistance2(a, b) {
25614
+ const distances = Array.from(
25615
+ { length: a.length + 1 },
25616
+ (_, i2) => Array.from({ length: b.length + 1 }, (_2, j) => Math.max(i2, j))
25617
+ );
25618
+ for (let i2 = 1; i2 <= a.length; i2++) {
25619
+ for (let j = 1; j <= b.length; j++) {
25620
+ distances[i2][j] = Math.min(
25621
+ distances[i2 - 1][j] + 1,
25622
+ distances[i2][j - 1] + 1,
25623
+ distances[i2 - 1][j - 1] + (a[i2 - 1] === b[j - 1] ? 0 : 1)
25624
+ );
25625
+ if (i2 > 1 && j > 1 && a[i2 - 1] === b[j - 2] && a[i2 - 2] === b[j - 1]) {
25626
+ distances[i2][j] = Math.min(
25627
+ distances[i2][j],
25628
+ distances[i2 - 2][j - 2] + 1
25629
+ );
25630
+ }
25631
+ }
25632
+ }
25633
+ return distances[a.length][b.length];
25634
+ }
25635
+
24863
25636
  // src/commands/deployment/index.ts
24864
25637
  var descriptions = {
24865
25638
  up: "Start the selected Compose deployment",
24866
25639
  down: "Stop the selected Compose deployment",
24867
- logs: "Stream logs for the selected deployment",
25640
+ logs: "Print the logs of the selected deployment, or stream them with --follow",
24868
25641
  ps: "List the running containers or pods for the selected deployment",
24869
25642
  restart: "Restart the workloads of the selected deployment",
24870
25643
  pull: "Download the configured images without changing configuration"
@@ -24879,8 +25652,8 @@ function createDeploymentCommands(context, setExitCode) {
24879
25652
  (name) => {
24880
25653
  const command = new Command(name).description(descriptions[name]).argument(
24881
25654
  "[args...]",
24882
- "additional arguments passed to the deployment runtime"
24883
- ).option("--instance <name>", "select a configured instance");
25655
+ "additional arguments and options passed to the deployment runtime"
25656
+ ).allowUnknownOption().option("--instance <name>", "select a configured instance");
24884
25657
  if (serviceScoped.has(name)) {
24885
25658
  command.option(
24886
25659
  "--service <name>",
@@ -24900,12 +25673,13 @@ function createDeploymentCommands(context, setExitCode) {
24900
25673
  );
24901
25674
  }
24902
25675
  return command.action(async (args, options) => {
25676
+ const runtimeArgs = runtimeArguments(command, args);
24903
25677
  const { config } = await loadCliState(context);
24904
25678
  setExitCode(
24905
25679
  await runDriverCommand(
24906
25680
  config,
24907
25681
  name,
24908
- parsedArgs(name, void 0, args, options),
25682
+ parsedArgs(name, void 0, runtimeArgs, options),
24909
25683
  context
24910
25684
  )
24911
25685
  );
@@ -24917,7 +25691,7 @@ function createDeploymentCommands(context, setExitCode) {
24917
25691
  // package.json
24918
25692
  var package_default = {
24919
25693
  name: "@eudiplo/cli",
24920
- version: "9.0.0",
25694
+ version: "9.1.0",
24921
25695
  description: "Deployment-aware command line tools for EUDIPLO",
24922
25696
  private: false,
24923
25697
  type: "module",
@@ -24977,12 +25751,12 @@ var package_default = {
24977
25751
  "jsonc-parser": "^3.3.1"
24978
25752
  },
24979
25753
  devDependencies: {
24980
- "@biomejs/biome": "2.5.14",
24981
- "@types/node": "^26.4.0",
25754
+ "@biomejs/biome": "2.5.15",
25755
+ "@types/node": "^26.6.4",
24982
25756
  esbuild: "^0.28.2",
24983
- tsx: "^4.23.13",
25757
+ tsx: "^4.23.15",
24984
25758
  typescript: "^7.0.2",
24985
- vitest: "5.0.2"
25759
+ vitest: "5.0.3"
24986
25760
  }
24987
25761
  };
24988
25762
 
@@ -25360,6 +26134,13 @@ var kmsHealthCheck = {
25360
26134
  message: "This backend does not expose the KMS provider health endpoint."
25361
26135
  };
25362
26136
  }
26137
+ if (response.status === 401 || response.status === 403) {
26138
+ return {
26139
+ name: "KMS providers",
26140
+ status: "skip",
26141
+ message: `Needs a tenant client with issuance:manage or presentation:manage (${response.reason}).`
26142
+ };
26143
+ }
25363
26144
  return {
25364
26145
  name: "KMS providers",
25365
26146
  status: "fail",
@@ -26270,6 +27051,10 @@ var managedImages = {
26270
27051
  EUDIPLO_IMAGE: "ghcr.io/eudiplo/eudiplo",
26271
27052
  EUDIPLO_CLIENT_IMAGE: "ghcr.io/eudiplo/eudiplo-client"
26272
27053
  };
27054
+ var managedServices = {
27055
+ EUDIPLO_IMAGE: "eudiplo",
27056
+ EUDIPLO_CLIENT_IMAGE: "eudiplo-client"
27057
+ };
26273
27058
  var legacyImages = {
26274
27059
  EUDIPLO_IMAGE: "ghcr.io/openwallet-foundation/eudiplo",
26275
27060
  EUDIPLO_CLIENT_IMAGE: "ghcr.io/openwallet-foundation/eudiplo-client"
@@ -26436,7 +27221,12 @@ async function runUpgradeCommand(config, parsed, context) {
26436
27221
  return 0;
26437
27222
  }
26438
27223
  await writeFile6(envPath, plan.content, "utf8");
26439
- const pulled = await runCompose(buildComposePullArgs(void 0), options);
27224
+ const pulled = await runCompose(
27225
+ buildComposePullArgs(
27226
+ plan.changes.map((change) => managedServices[change.key])
27227
+ ),
27228
+ options
27229
+ );
26440
27230
  if (pulled !== 0) {
26441
27231
  await writeFile6(envPath, original, "utf8");
26442
27232
  context.stderr.write(