@pipeline-builder/api-core 4.1.13 → 4.1.14

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 (187) hide show
  1. package/README.md +3 -2
  2. package/lib/constants/index.d.ts +0 -1
  3. package/lib/constants/index.js +1 -2
  4. package/lib/errors/app-errors.d.ts +8 -3
  5. package/lib/errors/app-errors.js +10 -5
  6. package/lib/helpers/access-helpers.d.ts +4 -6
  7. package/lib/helpers/access-helpers.js +6 -8
  8. package/lib/helpers/index.d.ts +3 -3
  9. package/lib/helpers/index.js +4 -4
  10. package/lib/helpers/org-hierarchy-http.d.ts +11 -10
  11. package/lib/helpers/org-hierarchy-http.js +24 -35
  12. package/lib/helpers/org-hierarchy.d.ts +37 -3
  13. package/lib/helpers/org-hierarchy.js +45 -4
  14. package/lib/helpers/restore-helpers.d.ts +44 -24
  15. package/lib/helpers/restore-helpers.js +41 -52
  16. package/lib/helpers/sse-helpers.d.ts +29 -7
  17. package/lib/helpers/sse-helpers.js +36 -9
  18. package/lib/index.d.ts +16 -14
  19. package/lib/index.js +17 -15
  20. package/lib/middleware/assurance.d.ts +116 -0
  21. package/lib/middleware/assurance.js +176 -0
  22. package/lib/middleware/auth.d.ts +5 -427
  23. package/lib/middleware/auth.js +36 -789
  24. package/lib/middleware/ecosystem-guard.d.ts +47 -0
  25. package/lib/middleware/ecosystem-guard.js +60 -0
  26. package/lib/middleware/index.d.ts +11 -4
  27. package/lib/middleware/index.js +12 -5
  28. package/lib/middleware/jwt-verify.d.ts +52 -0
  29. package/lib/middleware/jwt-verify.js +105 -0
  30. package/lib/middleware/permission-gates.d.ts +133 -0
  31. package/lib/middleware/permission-gates.js +260 -0
  32. package/lib/middleware/revocation.d.ts +96 -0
  33. package/lib/middleware/revocation.js +162 -0
  34. package/lib/middleware/route-table.d.ts +11 -0
  35. package/lib/middleware/route-table.js +4 -1
  36. package/lib/middleware/service-tokens.d.ts +83 -0
  37. package/lib/middleware/service-tokens.js +158 -0
  38. package/lib/middleware/step-up.d.ts +2 -2
  39. package/lib/middleware/step-up.js +8 -7
  40. package/lib/middleware/system-org.d.ts +20 -0
  41. package/lib/middleware/system-org.js +25 -0
  42. package/lib/openapi/routes/plugin-routes.js +133 -10
  43. package/lib/openapi/schema-registry.js +2 -5
  44. package/lib/routes/index.d.ts +1 -1
  45. package/lib/routes/index.js +2 -2
  46. package/lib/services/api-key-exchange.js +7 -5
  47. package/lib/services/audit-spool.d.ts +34 -10
  48. package/lib/services/audit-spool.js +75 -34
  49. package/lib/services/cache-service.d.ts +7 -0
  50. package/lib/services/cache-service.js +1 -1
  51. package/lib/services/circuit-breaker.d.ts +14 -1
  52. package/lib/services/circuit-breaker.js +36 -10
  53. package/lib/services/compliance-client.d.ts +10 -2
  54. package/lib/services/compliance-client.js +17 -10
  55. package/lib/services/compliance-event-subscriber.js +6 -6
  56. package/lib/services/durable-event-bus.js +8 -11
  57. package/lib/services/ecosystem-notify-client.d.ts +32 -0
  58. package/lib/services/ecosystem-notify-client.js +71 -0
  59. package/lib/services/env-redis.d.ts +4 -1
  60. package/lib/services/env-redis.js +32 -3
  61. package/lib/services/http-client.d.ts +19 -0
  62. package/lib/services/http-client.js +98 -19
  63. package/lib/services/index.d.ts +25 -24
  64. package/lib/services/index.js +25 -22
  65. package/lib/services/jwks-cache.js +5 -4
  66. package/lib/services/leader-lock.d.ts +22 -5
  67. package/lib/services/leader-lock.js +61 -6
  68. package/lib/services/quota.d.ts +9 -4
  69. package/lib/services/quota.js +34 -40
  70. package/lib/services/remote-audit-client.d.ts +28 -32
  71. package/lib/services/remote-audit-client.js +166 -49
  72. package/lib/services/retry-forever.js +5 -11
  73. package/lib/services/retry-strategy.d.ts +1 -1
  74. package/lib/services/retry-strategy.js +5 -4
  75. package/lib/services/scheduler.d.ts +8 -3
  76. package/lib/services/scheduler.js +17 -5
  77. package/lib/services/service-boot.d.ts +14 -13
  78. package/lib/services/service-boot.js +18 -15
  79. package/lib/services/service-keys.d.ts +1 -1
  80. package/lib/services/service-keys.js +12 -18
  81. package/lib/services/sse-ticket-store.d.ts +9 -1
  82. package/lib/services/sse-ticket-store.js +24 -9
  83. package/lib/services/system-notification.d.ts +27 -0
  84. package/lib/services/system-notification.js +50 -0
  85. package/lib/services/token-revocation.d.ts +50 -1
  86. package/lib/services/token-revocation.js +103 -3
  87. package/lib/types/audit-events.d.ts +6 -6
  88. package/lib/types/audit-events.js +1 -1
  89. package/lib/types/common.d.ts +32 -13
  90. package/lib/types/common.js +2 -1
  91. package/lib/types/ecosystem-notifications.d.ts +142 -0
  92. package/lib/types/ecosystem-notifications.js +210 -0
  93. package/lib/types/ecosystem.d.ts +77 -0
  94. package/lib/types/ecosystem.js +119 -0
  95. package/lib/types/error-codes.d.ts +81 -0
  96. package/lib/types/error-codes.js +108 -1
  97. package/lib/types/feature-flags.d.ts +21 -1
  98. package/lib/types/feature-flags.js +36 -2
  99. package/lib/types/index.d.ts +14 -9
  100. package/lib/types/index.js +15 -10
  101. package/lib/types/permissions.d.ts +46 -8
  102. package/lib/types/permissions.js +75 -12
  103. package/lib/types/plugin-catalog.d.ts +35 -0
  104. package/lib/types/plugin-catalog.js +39 -0
  105. package/lib/types/plugin-health.d.ts +102 -0
  106. package/lib/types/plugin-health.js +184 -0
  107. package/lib/types/quota-tiers.d.ts +15 -0
  108. package/lib/types/quota-tiers.js +23 -3
  109. package/lib/types/wire-vocabulary.d.ts +102 -0
  110. package/lib/types/wire-vocabulary.js +94 -0
  111. package/lib/utils/alias-resolver.js +2 -2
  112. package/lib/utils/audit.d.ts +5 -2
  113. package/lib/utils/audit.js +6 -3
  114. package/lib/utils/compliance-attributes.js +3 -4
  115. package/lib/utils/concurrency.d.ts +7 -0
  116. package/lib/utils/concurrency.js +13 -1
  117. package/lib/utils/env.d.ts +3 -4
  118. package/lib/utils/env.js +4 -5
  119. package/lib/utils/identity.d.ts +13 -4
  120. package/lib/utils/identity.js +18 -10
  121. package/lib/utils/index.d.ts +13 -10
  122. package/lib/utils/index.js +13 -10
  123. package/lib/utils/jwk.d.ts +4 -0
  124. package/lib/utils/jwk.js +13 -1
  125. package/lib/utils/logger.d.ts +1 -1
  126. package/lib/utils/logger.js +1 -1
  127. package/lib/utils/object.d.ts +11 -0
  128. package/lib/utils/object.js +24 -1
  129. package/lib/utils/params.d.ts +8 -22
  130. package/lib/utils/params.js +15 -43
  131. package/lib/utils/plugin-compliance.d.ts +98 -0
  132. package/lib/utils/plugin-compliance.js +78 -0
  133. package/lib/utils/proof-of-work.d.ts +69 -0
  134. package/lib/utils/proof-of-work.js +139 -0
  135. package/lib/utils/response.d.ts +16 -6
  136. package/lib/utils/response.js +18 -15
  137. package/lib/utils/retention.d.ts +17 -0
  138. package/lib/utils/retention.js +30 -0
  139. package/lib/utils/secret-encryption.d.ts +7 -7
  140. package/lib/utils/secret-encryption.js +9 -10
  141. package/lib/utils/secret-rotation.js +2 -2
  142. package/lib/utils/sensitive-patterns.js +4 -5
  143. package/lib/utils/service-registry.d.ts +15 -0
  144. package/lib/utils/service-registry.js +24 -0
  145. package/lib/utils/ssrf.d.ts +11 -2
  146. package/lib/utils/ssrf.js +112 -33
  147. package/lib/validation/ai-schemas.js +3 -2
  148. package/lib/validation/common-schemas.d.ts +0 -9
  149. package/lib/validation/common-schemas.js +1 -7
  150. package/lib/validation/dockerfile-static.d.ts +26 -0
  151. package/lib/validation/dockerfile-static.js +210 -0
  152. package/lib/validation/index.d.ts +13 -4
  153. package/lib/validation/index.js +14 -5
  154. package/lib/validation/message-schemas.js +6 -4
  155. package/lib/validation/pipeline-schemas.d.ts +8 -2
  156. package/lib/validation/pipeline-schemas.js +30 -4
  157. package/lib/validation/plugin-base-images.d.ts +20 -0
  158. package/lib/validation/plugin-base-images.js +17 -0
  159. package/lib/validation/plugin-catalog-detect.d.ts +86 -0
  160. package/lib/validation/plugin-catalog-detect.js +237 -0
  161. package/lib/validation/plugin-catalog-metadata.d.ts +141 -0
  162. package/lib/validation/plugin-catalog-metadata.js +162 -0
  163. package/lib/validation/plugin-heuristics.d.ts +41 -0
  164. package/lib/validation/plugin-heuristics.js +211 -0
  165. package/lib/validation/plugin-lint.d.ts +18 -0
  166. package/lib/validation/plugin-lint.js +136 -0
  167. package/lib/validation/plugin-name-confusable.d.ts +15 -0
  168. package/lib/validation/plugin-name-confusable.js +81 -0
  169. package/lib/validation/plugin-schemas.d.ts +40 -26
  170. package/lib/validation/plugin-schemas.js +26 -23
  171. package/lib/validation/plugin-spec-schema.d.ts +112 -0
  172. package/lib/validation/plugin-spec-schema.js +163 -0
  173. package/lib/validation/plugin-template-contract.d.ts +64 -0
  174. package/lib/validation/plugin-template-contract.js +113 -0
  175. package/package.json +69 -4
  176. package/lib/testing/mock-api-core.d.ts +0 -150
  177. package/lib/testing/mock-api-core.js +0 -246
  178. package/lib/testing/mock-drizzle.d.ts +0 -6
  179. package/lib/testing/mock-drizzle.js +0 -57
  180. package/lib/testing/route-coverage.d.ts +0 -64
  181. package/lib/testing/route-coverage.js +0 -183
  182. package/lib/testing/service-tokens.d.ts +0 -66
  183. package/lib/testing/service-tokens.js +0 -137
  184. package/lib/testing/tier-mock.d.ts +0 -44
  185. package/lib/testing/tier-mock.js +0 -65
  186. package/lib/testing/user-tokens.d.ts +0 -75
  187. package/lib/testing/user-tokens.js +0 -115
@@ -0,0 +1,17 @@
1
+ // Copyright 2026 Pipeline Builder Contributors
2
+ // SPDX-License-Identifier: Apache-2.0
3
+ export const PLUGIN_BASE_IMAGES = [
4
+ { key: 'plugin', image: 'pipeline-plugin-base:24.04', dir: '_plugin-base', provides: 'git, curl, jq, unzip, fetch-verified, run-logged (the root base)', smokeTest: 'bash --version && jq --version' },
5
+ { key: 'aws-cli', image: 'pipeline-aws-cli-base:1.0', dir: '_aws-cli-base', provides: 'AWS CLI v2', smokeTest: 'aws --version' },
6
+ { key: 'cpp', image: 'pipeline-cpp-base:1.0', dir: '_cpp-base', provides: 'C/C++ toolchain, CMake, Conan, Meson', smokeTest: 'cc --version && cmake --version' },
7
+ { key: 'dotnet', image: 'pipeline-dotnet-base:1.0', dir: '_dotnet-base', provides: 'one pinned .NET SDK', smokeTest: 'dotnet --version' },
8
+ { key: 'go', image: 'pipeline-go-base:1.0', dir: '_go-base', provides: 'one pinned Go', smokeTest: 'go version' },
9
+ { key: 'jvm', image: 'pipeline-jvm-base:1.0', dir: '_jvm-base', provides: 'Corretto JDK, Maven, Gradle, Kotlin', smokeTest: 'java -version && mvn --version' },
10
+ { key: 'node', image: 'pipeline-node-base:1.0', dir: '_node-base', provides: 'one pinned Node.js + npm', smokeTest: 'node --version && npm --version' },
11
+ { key: 'php', image: 'pipeline-php-base:1.0', dir: '_php-base', provides: 'one pinned PHP + Composer', smokeTest: 'php --version && composer --version' },
12
+ { key: 'python', image: 'pipeline-python-base:1.0', dir: '_python-base', provides: 'one pinned CPython + pip', smokeTest: 'python3 --version && pip3 --version' },
13
+ { key: 'ruby', image: 'pipeline-ruby-base:1.0', dir: '_ruby-base', provides: 'one pinned Ruby + Bundler', smokeTest: 'ruby --version && bundle --version' },
14
+ { key: 'rust', image: 'pipeline-rust-base:1.0', dir: '_rust-base', provides: 'one pinned Rust toolchain + clippy/rustfmt', smokeTest: 'cargo --version && rustc --version' },
15
+ { key: 'trivy', image: 'pipeline-trivy-base:1.0', dir: '_trivy-base', provides: 'trivy (two pinned versions)', smokeTest: 'trivy --version' },
16
+ ];
17
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicGx1Z2luLWJhc2UtaW1hZ2VzLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL3ZhbGlkYXRpb24vcGx1Z2luLWJhc2UtaW1hZ2VzLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLCtDQUErQztBQUMvQyxzQ0FBc0M7QUF1QnRDLE1BQU0sQ0FBQyxNQUFNLGtCQUFrQixHQUErQjtJQUM1RCxFQUFFLEdBQUcsRUFBRSxRQUFRLEVBQUUsS0FBSyxFQUFFLDRCQUE0QixFQUFFLEdBQUcsRUFBRSxjQUFjLEVBQUUsUUFBUSxFQUFFLGtFQUFrRSxFQUFFLFNBQVMsRUFBRSxnQ0FBZ0MsRUFBRTtJQUN0TSxFQUFFLEdBQUcsRUFBRSxTQUFTLEVBQUUsS0FBSyxFQUFFLDJCQUEyQixFQUFFLEdBQUcsRUFBRSxlQUFlLEVBQUUsUUFBUSxFQUFFLFlBQVksRUFBRSxTQUFTLEVBQUUsZUFBZSxFQUFFO0lBQ2hJLEVBQUUsR0FBRyxFQUFFLEtBQUssRUFBRSxLQUFLLEVBQUUsdUJBQXVCLEVBQUUsR0FBRyxFQUFFLFdBQVcsRUFBRSxRQUFRLEVBQUUsc0NBQXNDLEVBQUUsU0FBUyxFQUFFLGlDQUFpQyxFQUFFO0lBQ2hLLEVBQUUsR0FBRyxFQUFFLFFBQVEsRUFBRSxLQUFLLEVBQUUsMEJBQTBCLEVBQUUsR0FBRyxFQUFFLGNBQWMsRUFBRSxRQUFRLEVBQUUscUJBQXFCLEVBQUUsU0FBUyxFQUFFLGtCQUFrQixFQUFFO0lBQ3pJLEVBQUUsR0FBRyxFQUFFLElBQUksRUFBRSxLQUFLLEVBQUUsc0JBQXNCLEVBQUUsR0FBRyxFQUFFLFVBQVUsRUFBRSxRQUFRLEVBQUUsZUFBZSxFQUFFLFNBQVMsRUFBRSxZQUFZLEVBQUU7SUFDakgsRUFBRSxHQUFHLEVBQUUsS0FBSyxFQUFFLEtBQUssRUFBRSx1QkFBdUIsRUFBRSxHQUFHLEVBQUUsV0FBVyxFQUFFLFFBQVEsRUFBRSxxQ0FBcUMsRUFBRSxTQUFTLEVBQUUsZ0NBQWdDLEVBQUU7SUFDOUosRUFBRSxHQUFHLEVBQUUsTUFBTSxFQUFFLEtBQUssRUFBRSx3QkFBd0IsRUFBRSxHQUFHLEVBQUUsWUFBWSxFQUFFLFFBQVEsRUFBRSwwQkFBMEIsRUFBRSxTQUFTLEVBQUUsaUNBQWlDLEVBQUU7SUFDdkosRUFBRSxHQUFHLEVBQUUsS0FBSyxFQUFFLEtBQUssRUFBRSx1QkFBdUIsRUFBRSxHQUFHLEVBQUUsV0FBVyxFQUFFLFFBQVEsRUFBRSwyQkFBMkIsRUFBRSxTQUFTLEVBQUUscUNBQXFDLEVBQUU7SUFDekosRUFBRSxHQUFHLEVBQUUsUUFBUSxFQUFFLEtBQUssRUFBRSwwQkFBMEIsRUFBRSxHQUFHLEVBQUUsY0FBYyxFQUFFLFFBQVEsRUFBRSwwQkFBMEIsRUFBRSxTQUFTLEVBQUUscUNBQXFDLEVBQUU7SUFDakssRUFBRSxHQUFHLEVBQUUsTUFBTSxFQUFFLEtBQUssRUFBRSx3QkFBd0IsRUFBRSxHQUFHLEVBQUUsWUFBWSxFQUFFLFFBQVEsRUFBRSwyQkFBMkIsRUFBRSxTQUFTLEVBQUUsb0NBQW9DLEVBQUU7SUFDM0osRUFBRSxHQUFHLEVBQUUsTUFBTSxFQUFFLEtBQUssRUFBRSx3QkFBd0IsRUFBRSxHQUFHLEVBQUUsWUFBWSxFQUFFLFFBQVEsRUFBRSw0Q0FBNEMsRUFBRSxTQUFTLEVBQUUsb0NBQW9DLEVBQUU7SUFDNUssRUFBRSxHQUFHLEVBQUUsT0FBTyxFQUFFLEtBQUssRUFBRSx5QkFBeUIsRUFBRSxHQUFHLEVBQUUsYUFBYSxFQUFFLFFBQVEsRUFBRSw2QkFBNkIsRUFBRSxTQUFTLEVBQUUsaUJBQWlCLEVBQUU7Q0FDOUksQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbIi8vIENvcHlyaWdodCAyMDI2IFBpcGVsaW5lIEJ1aWxkZXIgQ29udHJpYnV0b3JzXG4vLyBTUERYLUxpY2Vuc2UtSWRlbnRpZmllcjogQXBhY2hlLTIuMFxuXG4vKipcbiAqIFRoZSBzaGFyZWQgcGx1Z2luIGJhc2UgaW1hZ2VzIChkZXBsb3kvcGx1Z2lucy9fYmFzZSk6IHdoYXQgYHBsdWdpbiBuZXdgXG4gKiBzY2FmZm9sZHMgYEZST01gIGFuZCB3aGF0IEFJIHBsdWdpbiBnZW5lcmF0aW9uIHRlbGxzIHRoZSBtb2RlbCB0byBzdGFydFxuICogZnJvbS4gTGlzdGVkIGhlcmUgYmVjYXVzZSBuZWl0aGVyIHRoZSBDTEkgbm9yIHRoZSBwbHVnaW4gc2VydmljZSBzaGlwcyB0aGVcbiAqIHJlcG87IGEgcGlwZWxpbmUtbWFuYWdlciB0ZXN0IGZhaWxzIHdoZW4gdGhlIGxpc3QgZHJpZnRzIGZyb20gdGhlIHRyZWUuXG4gKi9cblxuLyoqIE9uZSBgcGlwZWxpbmUtPGVjbz4tYmFzZWAgaW1hZ2UgYSBwbHVnaW4gY2FuIHN0YXJ0IGBGUk9NYC4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgUGx1Z2luQmFzZUltYWdlIHtcbiAgLyoqIGAtLWJhc2VgIHZhbHVlLiAqL1xuICBrZXk6IHN0cmluZztcbiAgLyoqIEltYWdlIHRhZyB0aGUgRG9ja2VyZmlsZSdzIGBGUk9NYCBuYW1lcy4gKi9cbiAgaW1hZ2U6IHN0cmluZztcbiAgLyoqIERpcmVjdG9yeSB1bmRlciBkZXBsb3kvcGx1Z2lucy9fYmFzZS4gKi9cbiAgZGlyOiBzdHJpbmc7XG4gIC8qKiBXaGF0IHRoZSBiYXNlIHByb3ZpZGVzIG9uIHRvcCBvZiB0aGUgcm9vdCBiYXNlLiAqL1xuICBwcm92aWRlczogc3RyaW5nO1xuICAvKiogQSBjb21tYW5kIHRoYXQgcHJvdmVzIHRoZSBydW50aW1lIGlzIG9uIFBBVEggKHRoZSBzY2FmZm9sZCdzIHNtb2tlVGVzdCkuICovXG4gIHNtb2tlVGVzdDogc3RyaW5nO1xufVxuXG5leHBvcnQgY29uc3QgUExVR0lOX0JBU0VfSU1BR0VTOiByZWFkb25seSBQbHVnaW5CYXNlSW1hZ2VbXSA9IFtcbiAgeyBrZXk6ICdwbHVnaW4nLCBpbWFnZTogJ3BpcGVsaW5lLXBsdWdpbi1iYXNlOjI0LjA0JywgZGlyOiAnX3BsdWdpbi1iYXNlJywgcHJvdmlkZXM6ICdnaXQsIGN1cmwsIGpxLCB1bnppcCwgZmV0Y2gtdmVyaWZpZWQsIHJ1bi1sb2dnZWQgKHRoZSByb290IGJhc2UpJywgc21va2VUZXN0OiAnYmFzaCAtLXZlcnNpb24gJiYganEgLS12ZXJzaW9uJyB9LFxuICB7IGtleTogJ2F3cy1jbGknLCBpbWFnZTogJ3BpcGVsaW5lLWF3cy1jbGktYmFzZToxLjAnLCBkaXI6ICdfYXdzLWNsaS1iYXNlJywgcHJvdmlkZXM6ICdBV1MgQ0xJIHYyJywgc21va2VUZXN0OiAnYXdzIC0tdmVyc2lvbicgfSxcbiAgeyBrZXk6ICdjcHAnLCBpbWFnZTogJ3BpcGVsaW5lLWNwcC1iYXNlOjEuMCcsIGRpcjogJ19jcHAtYmFzZScsIHByb3ZpZGVzOiAnQy9DKysgdG9vbGNoYWluLCBDTWFrZSwgQ29uYW4sIE1lc29uJywgc21va2VUZXN0OiAnY2MgLS12ZXJzaW9uICYmIGNtYWtlIC0tdmVyc2lvbicgfSxcbiAgeyBrZXk6ICdkb3RuZXQnLCBpbWFnZTogJ3BpcGVsaW5lLWRvdG5ldC1iYXNlOjEuMCcsIGRpcjogJ19kb3RuZXQtYmFzZScsIHByb3ZpZGVzOiAnb25lIHBpbm5lZCAuTkVUIFNESycsIHNtb2tlVGVzdDogJ2RvdG5ldCAtLXZlcnNpb24nIH0sXG4gIHsga2V5OiAnZ28nLCBpbWFnZTogJ3BpcGVsaW5lLWdvLWJhc2U6MS4wJywgZGlyOiAnX2dvLWJhc2UnLCBwcm92aWRlczogJ29uZSBwaW5uZWQgR28nLCBzbW9rZVRlc3Q6ICdnbyB2ZXJzaW9uJyB9LFxuICB7IGtleTogJ2p2bScsIGltYWdlOiAncGlwZWxpbmUtanZtLWJhc2U6MS4wJywgZGlyOiAnX2p2bS1iYXNlJywgcHJvdmlkZXM6ICdDb3JyZXR0byBKREssIE1hdmVuLCBHcmFkbGUsIEtvdGxpbicsIHNtb2tlVGVzdDogJ2phdmEgLXZlcnNpb24gJiYgbXZuIC0tdmVyc2lvbicgfSxcbiAgeyBrZXk6ICdub2RlJywgaW1hZ2U6ICdwaXBlbGluZS1ub2RlLWJhc2U6MS4wJywgZGlyOiAnX25vZGUtYmFzZScsIHByb3ZpZGVzOiAnb25lIHBpbm5lZCBOb2RlLmpzICsgbnBtJywgc21va2VUZXN0OiAnbm9kZSAtLXZlcnNpb24gJiYgbnBtIC0tdmVyc2lvbicgfSxcbiAgeyBrZXk6ICdwaHAnLCBpbWFnZTogJ3BpcGVsaW5lLXBocC1iYXNlOjEuMCcsIGRpcjogJ19waHAtYmFzZScsIHByb3ZpZGVzOiAnb25lIHBpbm5lZCBQSFAgKyBDb21wb3NlcicsIHNtb2tlVGVzdDogJ3BocCAtLXZlcnNpb24gJiYgY29tcG9zZXIgLS12ZXJzaW9uJyB9LFxuICB7IGtleTogJ3B5dGhvbicsIGltYWdlOiAncGlwZWxpbmUtcHl0aG9uLWJhc2U6MS4wJywgZGlyOiAnX3B5dGhvbi1iYXNlJywgcHJvdmlkZXM6ICdvbmUgcGlubmVkIENQeXRob24gKyBwaXAnLCBzbW9rZVRlc3Q6ICdweXRob24zIC0tdmVyc2lvbiAmJiBwaXAzIC0tdmVyc2lvbicgfSxcbiAgeyBrZXk6ICdydWJ5JywgaW1hZ2U6ICdwaXBlbGluZS1ydWJ5LWJhc2U6MS4wJywgZGlyOiAnX3J1YnktYmFzZScsIHByb3ZpZGVzOiAnb25lIHBpbm5lZCBSdWJ5ICsgQnVuZGxlcicsIHNtb2tlVGVzdDogJ3J1YnkgLS12ZXJzaW9uICYmIGJ1bmRsZSAtLXZlcnNpb24nIH0sXG4gIHsga2V5OiAncnVzdCcsIGltYWdlOiAncGlwZWxpbmUtcnVzdC1iYXNlOjEuMCcsIGRpcjogJ19ydXN0LWJhc2UnLCBwcm92aWRlczogJ29uZSBwaW5uZWQgUnVzdCB0b29sY2hhaW4gKyBjbGlwcHkvcnVzdGZtdCcsIHNtb2tlVGVzdDogJ2NhcmdvIC0tdmVyc2lvbiAmJiBydXN0YyAtLXZlcnNpb24nIH0sXG4gIHsga2V5OiAndHJpdnknLCBpbWFnZTogJ3BpcGVsaW5lLXRyaXZ5LWJhc2U6MS4wJywgZGlyOiAnX3RyaXZ5LWJhc2UnLCBwcm92aWRlczogJ3RyaXZ5ICh0d28gcGlubmVkIHZlcnNpb25zKScsIHNtb2tlVGVzdDogJ3RyaXZ5IC0tdmVyc2lvbicgfSxcbl07XG4iXX0=
@@ -0,0 +1,86 @@
1
+ import { type MetadataSource, type MetadataSources, type PluginCatalogField } from '../types/plugin-catalog.js';
2
+ import { type PluginCatalogEdits } from './plugin-catalog-metadata.js';
3
+ /** A source a value can be DETECTED from (`user` is only ever an edit). */
4
+ export type DetectedSource = Exclude<MetadataSource, 'user'>;
5
+ /** One descriptive field as detected from the package. */
6
+ export interface DetectedField {
7
+ field: PluginCatalogField;
8
+ /** The validated (normalized) value, or null when none was found or it failed validation. */
9
+ value: unknown;
10
+ /** Where the winning candidate came from, or null when no source had one. */
11
+ source: DetectedSource | null;
12
+ /** Why the winning candidate was refused, or null. */
13
+ error: string | null;
14
+ }
15
+ /** The spec fields detection reads (a structural subset of the plugin spec). */
16
+ export interface CatalogSpecFields {
17
+ readonly description?: string;
18
+ readonly summary?: string;
19
+ readonly category?: string;
20
+ readonly keywords?: readonly string[];
21
+ readonly license?: string;
22
+ readonly homepageUrl?: string;
23
+ readonly sourceUrl?: string;
24
+ readonly documentationUrl?: string;
25
+ readonly icon?: string | {
26
+ key: string;
27
+ badge?: string;
28
+ };
29
+ readonly changelog?: string;
30
+ }
31
+ /** What detection reads: the spec, the zip-root README and the plugin's own Dockerfile. */
32
+ export interface CatalogInputs {
33
+ spec: CatalogSpecFields;
34
+ readmeMd: string | null;
35
+ dockerfileContent: string | null;
36
+ }
37
+ /** The accepted/edited values of every descriptive field, plus their provenance. */
38
+ export interface ResolvedCatalog {
39
+ values: Record<PluginCatalogField, unknown>;
40
+ sources: MetadataSources;
41
+ }
42
+ /** Strip inline markdown down to readable text (links → text, images/emphasis/code marks removed). */
43
+ export declare function stripInlineMarkdown(text: string): string;
44
+ /** The README's first level-1 ATX heading (`# Title`), as plain text. */
45
+ export declare function readmeTitle(md: string): string | null;
46
+ /**
47
+ * The README's first prose paragraph: the first block of consecutive text
48
+ * lines that is not a heading, badge row, list, table, quote, rule or HTML.
49
+ */
50
+ export declare function readmeFirstParagraph(md: string): string | null;
51
+ /**
52
+ * The first sentence of `text`, capped at {@link PLUGIN_SUMMARY_MAX}: cut at
53
+ * the first `.`/`!`/`?` followed by whitespace (or the end), else the first
54
+ * line; an over-long sentence is shortened on a word boundary with `…`.
55
+ */
56
+ export declare function firstSentence(text: string): string | null;
57
+ /**
58
+ * Detect every descriptive field from the package, in
59
+ * `PLUGIN_CATALOG_FIELDS` order. Pure; never throws.
60
+ */
61
+ export declare function detectCatalogMetadata(inputs: CatalogInputs): DetectedField[];
62
+ /**
63
+ * Apply the user's edits over the detected values. A key present in `edits`
64
+ * is the user's (`null` clears it) and is recorded as `user`; every other field
65
+ * keeps its detected value (none when it failed validation). `edits` must
66
+ * already have passed `PluginCatalogEditsSchema`. A summary that was DERIVED
67
+ * from the description is re-derived when the user edited the description.
68
+ */
69
+ export declare function resolveCatalogMetadata(detected: DetectedField[], edits?: PluginCatalogEdits): ResolvedCatalog;
70
+ /** A detection with every value accepted (no edits) — scripts, the Official loader. */
71
+ export declare function acceptAllCatalogMetadata(detected: DetectedField[]): ResolvedCatalog;
72
+ /**
73
+ * Validate a catalog-edit payload (the upload's `metadata` part, already
74
+ * JSON-decoded). Execution-contract keys are refused by name before the
75
+ * strict schema runs, so the caller learns exactly which keys can't be edited.
76
+ */
77
+ export declare function parseCatalogEdits(raw: unknown): {
78
+ ok: true;
79
+ value: PluginCatalogEdits;
80
+ } | {
81
+ ok: false;
82
+ error: string;
83
+ contractKeys?: string[];
84
+ };
85
+ /** Decode the upload's multipart `metadata` part (JSON text), then {@link parseCatalogEdits}. */
86
+ export declare function parseCatalogEditsPart(text: string | undefined): ReturnType<typeof parseCatalogEdits>;
@@ -0,0 +1,237 @@
1
+ // Copyright 2026 Pipeline Builder Contributors
2
+ // SPDX-License-Identifier: Apache-2.0
3
+ /**
4
+ * Catalog metadata: DETECTED from the package, then ACCEPTED OR EDITED
5
+ * (docs/plugin-publishing.md).
6
+ *
7
+ * Sources, highest priority first — the first non-empty value wins, per field:
8
+ *
9
+ * | Field | 1. spec | 2. README.md | 3. own Dockerfile LABEL |
10
+ * |--------------------|--------------------|--------------------|-----------------------------------------|
11
+ * | summary | `summary` | — | — (then first sentence of description) |
12
+ * | description | `description` | first paragraph | `org.opencontainers.image.description` |
13
+ * | displayName | — | first `# heading` | `org.opencontainers.image.title` |
14
+ * | license | `license` | — | `org.opencontainers.image.licenses` |
15
+ * | homepageUrl | `homepageUrl` | — | `org.opencontainers.image.url` |
16
+ * | sourceUrl | `sourceUrl` | — | `org.opencontainers.image.source` |
17
+ * | documentationUrl | `documentationUrl` | — | `org.opencontainers.image.documentation`|
18
+ * | category, keywords, icon, changelog | spec | — | — |
19
+ * | readme | — | `README.md` | — |
20
+ *
21
+ * Every value — detected or typed — passes the ONE shared validator
22
+ * (api-core `validateCatalogField`). A detected value that fails is returned
23
+ * BLANK WITH THE REASON, never silently dropped, and is not stored unless the
24
+ * user supplies a valid replacement.
25
+ *
26
+ * Pure and shared from api-core: the plugin service's upload and inspect
27
+ * routes and the CLI's `plugin validate` / `plugin publish` run this one
28
+ * detection, so the CLI reports exactly what the server will detect.
29
+ */
30
+ import { OCI_LABELS, parseDockerfile } from './dockerfile-static.js';
31
+ import { PLUGIN_CATALOG_FIELDS, PLUGIN_SUMMARY_MAX, } from '../types/plugin-catalog.js';
32
+ import { PluginCatalogEditsSchema, contractKeysMessage, findContractKeys, validateCatalogField, } from './plugin-catalog-metadata.js';
33
+ // -----------------------------------------------------------------------------
34
+ // README reading
35
+ // -----------------------------------------------------------------------------
36
+ /** Strip inline markdown down to readable text (links → text, images/emphasis/code marks removed). */
37
+ export function stripInlineMarkdown(text) {
38
+ return text
39
+ .replace(/!\[[^\]]*\]\([^)]*\)/g, '') // images / badges
40
+ .replace(/\[([^\]]*)\]\([^)]*\)/g, '$1') // links → text
41
+ .replace(/<[^>]+>/g, '') // inline HTML
42
+ .replace(/(\*\*|__|\*|_|`)/g, '')
43
+ .replace(/\s+/g, ' ')
44
+ .trim();
45
+ }
46
+ /** Markdown lines outside fenced code blocks, in order. */
47
+ function proseLines(md) {
48
+ const out = [];
49
+ let fenced = false;
50
+ for (const line of md.replace(/\r\n?/g, '\n').split('\n')) {
51
+ if (/^\s*(```|~~~)/.test(line)) {
52
+ fenced = !fenced;
53
+ out.push('');
54
+ continue;
55
+ }
56
+ out.push(fenced ? '' : line);
57
+ }
58
+ return out;
59
+ }
60
+ /** The README's first level-1 ATX heading (`# Title`), as plain text. */
61
+ export function readmeTitle(md) {
62
+ for (const line of proseLines(md)) {
63
+ const m = /^#\s+(.+?)\s*#*\s*$/.exec(line);
64
+ if (m) {
65
+ const title = stripInlineMarkdown(m[1]);
66
+ return title || null;
67
+ }
68
+ }
69
+ return null;
70
+ }
71
+ /**
72
+ * The README's first prose paragraph: the first block of consecutive text
73
+ * lines that is not a heading, badge row, list, table, quote, rule or HTML.
74
+ */
75
+ export function readmeFirstParagraph(md) {
76
+ const isStructural = (l) => /^\s*(#|>|[-*+]\s|\d+[.)]\s|\||<|---|\*\*\*|===)/.test(l);
77
+ let para = [];
78
+ for (const line of [...proseLines(md), '']) {
79
+ if (line.trim() === '' || isStructural(line)) {
80
+ if (para.length > 0) {
81
+ const text = stripInlineMarkdown(para.join(' '));
82
+ if (text)
83
+ return text;
84
+ }
85
+ para = [];
86
+ continue;
87
+ }
88
+ para.push(line.trim());
89
+ }
90
+ return null;
91
+ }
92
+ /**
93
+ * The first sentence of `text`, capped at {@link PLUGIN_SUMMARY_MAX}: cut at
94
+ * the first `.`/`!`/`?` followed by whitespace (or the end), else the first
95
+ * line; an over-long sentence is shortened on a word boundary with `…`.
96
+ */
97
+ export function firstSentence(text) {
98
+ const flat = text.replace(/\s+/g, ' ').trim();
99
+ if (!flat)
100
+ return null;
101
+ const m = /^(.+?[.!?])(\s|$)/.exec(flat);
102
+ const sentence = (m ? m[1] : flat).trim();
103
+ if (sentence.length <= PLUGIN_SUMMARY_MAX)
104
+ return sentence;
105
+ const cut = sentence.slice(0, PLUGIN_SUMMARY_MAX - 1);
106
+ const atWord = cut.includes(' ') ? cut.slice(0, cut.lastIndexOf(' ')) : cut;
107
+ return `${atWord.replace(/[\s,;:]+$/, '')}…`;
108
+ }
109
+ const nonEmpty = (v) => v !== undefined && v !== null && !(typeof v === 'string' && v.trim() === '') && !(Array.isArray(v) && v.length === 0);
110
+ /** Pick the first non-empty candidate and validate it (blank + reason on failure). */
111
+ function pick(field, candidates) {
112
+ const winner = candidates.find(([, v]) => nonEmpty(v));
113
+ if (!winner)
114
+ return { field, value: null, source: null, error: null };
115
+ const [source, raw] = winner;
116
+ const checked = validateCatalogField(field, raw);
117
+ return checked.ok
118
+ ? { field, value: checked.value, source, error: null }
119
+ : { field, value: null, source, error: checked.error };
120
+ }
121
+ /** The summary derived from a description, as a detected field. */
122
+ function derivedSummary(description) {
123
+ const sentence = typeof description === 'string' ? firstSentence(description) : null;
124
+ return pick('summary', [['derived', sentence]]);
125
+ }
126
+ /**
127
+ * Detect every descriptive field from the package, in
128
+ * `PLUGIN_CATALOG_FIELDS` order. Pure; never throws.
129
+ */
130
+ export function detectCatalogMetadata(inputs) {
131
+ const { spec } = inputs;
132
+ const readme = inputs.readmeMd;
133
+ const labels = parseDockerfile(inputs.dockerfileContent).labels;
134
+ const label = (key) => labels[key];
135
+ const description = pick('description', [
136
+ ['spec', spec.description],
137
+ ['readme', readme !== null ? readmeFirstParagraph(readme) : null],
138
+ ['dockerfile', label(OCI_LABELS.description)],
139
+ ]);
140
+ const specSummary = pick('summary', [['spec', spec.summary]]);
141
+ const byField = {
142
+ displayName: pick('displayName', [
143
+ ['readme', readme !== null ? readmeTitle(readme) : null],
144
+ ['dockerfile', label(OCI_LABELS.title)],
145
+ ]),
146
+ summary: specSummary.source !== null ? specSummary : derivedSummary(description.value),
147
+ description,
148
+ category: pick('category', [['spec', spec.category]]),
149
+ keywords: pick('keywords', [['spec', spec.keywords]]),
150
+ license: pick('license', [['spec', spec.license], ['dockerfile', label(OCI_LABELS.licenses)]]),
151
+ homepageUrl: pick('homepageUrl', [['spec', spec.homepageUrl], ['dockerfile', label(OCI_LABELS.url)]]),
152
+ sourceUrl: pick('sourceUrl', [['spec', spec.sourceUrl], ['dockerfile', label(OCI_LABELS.source)]]),
153
+ documentationUrl: pick('documentationUrl', [['spec', spec.documentationUrl], ['dockerfile', label(OCI_LABELS.documentation)]]),
154
+ icon: pick('icon', [['spec', spec.icon]]),
155
+ changelog: pick('changelog', [['spec', spec.changelog]]),
156
+ readme: pick('readme', [['readme', readme]]),
157
+ };
158
+ return PLUGIN_CATALOG_FIELDS.map((f) => byField[f]);
159
+ }
160
+ // -----------------------------------------------------------------------------
161
+ // Accept or edit
162
+ // -----------------------------------------------------------------------------
163
+ /**
164
+ * Apply the user's edits over the detected values. A key present in `edits`
165
+ * is the user's (`null` clears it) and is recorded as `user`; every other field
166
+ * keeps its detected value (none when it failed validation). `edits` must
167
+ * already have passed `PluginCatalogEditsSchema`. A summary that was DERIVED
168
+ * from the description is re-derived when the user edited the description.
169
+ */
170
+ export function resolveCatalogMetadata(detected, edits = {}) {
171
+ const values = {};
172
+ const sources = {};
173
+ const set = (field, value, source) => {
174
+ values[field] = value ?? null;
175
+ if (source && (value !== null && value !== undefined || source === 'user'))
176
+ sources[field] = source;
177
+ };
178
+ for (const d of detected) {
179
+ if (Object.prototype.hasOwnProperty.call(edits, d.field)) {
180
+ set(d.field, edits[d.field], 'user');
181
+ }
182
+ else {
183
+ set(d.field, d.error ? null : d.value, d.error ? null : d.source);
184
+ }
185
+ }
186
+ const summaryDetected = detected.find((d) => d.field === 'summary');
187
+ const summaryEdited = Object.prototype.hasOwnProperty.call(edits, 'summary');
188
+ const descriptionEdited = Object.prototype.hasOwnProperty.call(edits, 'description');
189
+ if (!summaryEdited && descriptionEdited && (summaryDetected?.source === 'derived' || summaryDetected?.source === null)) {
190
+ const rederived = derivedSummary(values.description);
191
+ delete sources.summary;
192
+ set('summary', rederived.error ? null : rederived.value, rederived.error ? null : rederived.source);
193
+ }
194
+ return { values, sources };
195
+ }
196
+ /** A detection with every value accepted (no edits) — scripts, the Official loader. */
197
+ export function acceptAllCatalogMetadata(detected) {
198
+ return resolveCatalogMetadata(detected, {});
199
+ }
200
+ // -----------------------------------------------------------------------------
201
+ // Edit payloads
202
+ // -----------------------------------------------------------------------------
203
+ /**
204
+ * Validate a catalog-edit payload (the upload's `metadata` part, already
205
+ * JSON-decoded). Execution-contract keys are refused by name before the
206
+ * strict schema runs, so the caller learns exactly which keys can't be edited.
207
+ */
208
+ export function parseCatalogEdits(raw) {
209
+ if (!raw || typeof raw !== 'object' || Array.isArray(raw)) {
210
+ return { ok: false, error: 'metadata must be a JSON object' };
211
+ }
212
+ const contractKeys = findContractKeys(raw);
213
+ if (contractKeys.length > 0)
214
+ return { ok: false, error: contractKeysMessage(contractKeys), contractKeys };
215
+ const parsed = PluginCatalogEditsSchema.safeParse(raw);
216
+ if (!parsed.success) {
217
+ return {
218
+ ok: false,
219
+ error: `Invalid metadata: ${parsed.error.issues.map((i) => `${i.path.join('.') || '(root)'}: ${i.message}`).join('; ')}`,
220
+ };
221
+ }
222
+ return { ok: true, value: parsed.data };
223
+ }
224
+ /** Decode the upload's multipart `metadata` part (JSON text), then {@link parseCatalogEdits}. */
225
+ export function parseCatalogEditsPart(text) {
226
+ if (text === undefined || text.trim() === '')
227
+ return { ok: true, value: {} };
228
+ let raw;
229
+ try {
230
+ raw = JSON.parse(text);
231
+ }
232
+ catch {
233
+ return { ok: false, error: 'metadata must be valid JSON' };
234
+ }
235
+ return parseCatalogEdits(raw);
236
+ }
237
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicGx1Z2luLWNhdGFsb2ctZGV0ZWN0LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL3ZhbGlkYXRpb24vcGx1Z2luLWNhdGFsb2ctZGV0ZWN0LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLCtDQUErQztBQUMvQyxzQ0FBc0M7QUFFdEM7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O0dBMEJHO0FBRUgsT0FBTyxFQUFFLFVBQVUsRUFBRSxlQUFlLEVBQUUsTUFBTSx3QkFBd0IsQ0FBQztBQUNyRSxPQUFPLEVBQ0wscUJBQXFCLEVBQUUsa0JBQWtCLEdBRTFDLE1BQU0sNEJBQTRCLENBQUM7QUFDcEMsT0FBTyxFQUNMLHdCQUF3QixFQUFFLG1CQUFtQixFQUFFLGdCQUFnQixFQUFFLG9CQUFvQixHQUN0RixNQUFNLDhCQUE4QixDQUFDO0FBMEN0QyxnRkFBZ0Y7QUFDaEYsaUJBQWlCO0FBQ2pCLGdGQUFnRjtBQUVoRixzR0FBc0c7QUFDdEcsTUFBTSxVQUFVLG1CQUFtQixDQUFDLElBQVk7SUFDOUMsT0FBTyxJQUFJO1NBQ1IsT0FBTyxDQUFDLHVCQUF1QixFQUFFLEVBQUUsQ0FBQyxDQUFDLGtCQUFrQjtTQUN2RCxPQUFPLENBQUMsd0JBQXdCLEVBQUUsSUFBSSxDQUFDLENBQUMsZUFBZTtTQUN2RCxPQUFPLENBQUMsVUFBVSxFQUFFLEVBQUUsQ0FBQyxDQUFDLGNBQWM7U0FDdEMsT0FBTyxDQUFDLG1CQUFtQixFQUFFLEVBQUUsQ0FBQztTQUNoQyxPQUFPLENBQUMsTUFBTSxFQUFFLEdBQUcsQ0FBQztTQUNwQixJQUFJLEVBQUUsQ0FBQztBQUNaLENBQUM7QUFFRCwyREFBMkQ7QUFDM0QsU0FBUyxVQUFVLENBQUMsRUFBVTtJQUM1QixNQUFNLEdBQUcsR0FBYSxFQUFFLENBQUM7SUFDekIsSUFBSSxNQUFNLEdBQUcsS0FBSyxDQUFDO0lBQ25CLEtBQUssTUFBTSxJQUFJLElBQUksRUFBRSxDQUFDLE9BQU8sQ0FBQyxRQUFR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QU0sTUFBTSxHQUFHLHdCQUF3QixDQUFDLFNBQVMsQ0FBQyxHQUFHLENBQUMsQ0FBQztJQUN2RCxJQUFJLENBQUMsTUFBTSxDQUFDLE9BQU8sRUFBRSxDQUFDO1FBQ3BCLE9BQU87WUFDTCxFQUFFLEVBQUUsS0FBSztZQUNULEtBQUssRUFBRSxxQkFBcUIsTUFBTSxDQUFDLEtBQUssQ0FBQyxNQUFNLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxFQUFFLEVBQUUsQ0FBQyxHQUFHLENBQUMsQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLEdBQUcsQ0FBQyxJQUFJLFFBQVEsS0FBSyxDQUFDLENBQUMsT0FBTyxFQUFFLENBQUMsQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLEVBQUU7U0FDekgsQ0FBQztJQUNKLENBQUM7SUFDRCxPQUFPLEVBQUUsRUFBRSxFQUFFLElBQUksRUFBRSxLQUFLLEVBQUUsTUFBTSxDQUFDLElBQUksRUFBRSxDQUFDO0FBQzFDLENBQUM7QUFFRCxpR0FBaUc7QUFDakcsTUFBTSxVQUFVLHFCQUFxQixDQUFDLElBQXdCO0lBQzVELElBQUksSUFBSSxLQUFLLFNBQVMsSUFBSSxJQUFJLENBQUMsSUFBSSxFQUFFLEtBQUssRUFBRTtRQUFFLE9BQU8sRUFBRSxFQUFFLEVBQUUsSUFBSSxFQUFFLEtBQUssRUFBRSxFQUFFLEVBQUUsQ0FBQztJQUM3RSxJQUFJLEdBQVksQ0FBQztJQUNqQixJQUFJLENBQUM7UUFDSCxHQUFHLEdBQUcsSUFBSSxDQUFDLEtBQUssQ0FBQyxJQUFJLENBQUMsQ0FBQztJQUN6QixDQUFDO0lBQUMsTUFBTSxDQUFDO1FBQ1AsT0FBTyxFQUFFLEVBQUUsRUFBRSxLQUFLLEVBQUUsS0FBSyxFQUFFLDZCQUE2QixFQUFFLENBQUM7SUFDN0QsQ0FBQztJQUNELE9BQU8saUJBQWlCLENBQUMsR0FBRyxDQUFDLENBQUM7QUFDaEMsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbIi8vIENvcHlyaWdodCAyMDI2IFBpcGVsaW5lIEJ1aWxkZXIgQ29udHJpYnV0b3JzXG4vLyBTUERYLUxpY2Vuc2UtSWRlbnRpZmllcjogQXBhY2hlLTIuMFxuXG4vKipcbiAqIENhdGFsb2cgbWV0YWRhdGE6IERFVEVDVEVEIGZyb20gdGhlIHBhY2thZ2UsIHRoZW4gQUNDRVBURUQgT1IgRURJVEVEXG4gKiAoZG9jcy9wbHVnaW4tcHVibGlzaGluZy5tZCkuXG4gKlxuICogU291cmNlcywgaGlnaGVzdCBwcmlvcml0eSBmaXJzdCDigJQgdGhlIGZpcnN0IG5vbi1lbXB0eSB2YWx1ZSB3aW5zLCBwZXIgZmllbGQ6XG4gKlxuICogfCBGaWVsZCAgICAgICAgICAgICAgfCAxLiBzcGVjICAgICAgICAgICAgfCAyLiBSRUFETUUubWQgICAgICAgfCAzLiBvd24gRG9ja2VyZmlsZSBMQUJFTCAgICAgICAgICAgICAgICAgfFxuICogfC0tLS0tLS0tLS0tLS0tLS0tLS0tfC0tLS0tLS0tLS0tLS0tLS0tLS0tfC0tLS0tLS0tLS0tLS0tLS0tLS0tfC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tfFxuICogfCBzdW1tYXJ5ICAgICAgICAgICAgfCBgc3VtbWFyeWAgICAgICAgICAgfCDigJQgICAgICAgICAgICAgICAgICB8IOKAlCAodGhlbiBmaXJzdCBzZW50ZW5jZSBvZiBkZXNjcmlwdGlvbikgIHxcbiAqIHwgZGVzY3JpcHRpb24gICAgICAgIHwgYGRlc2NyaXB0aW9uYCAgICAgIHwgZmlyc3QgcGFyYWdyYXBoICAgIHwgYG9yZy5vcGVuY29udGFpbmVycy5pbWFnZS5kZXNjcmlwdGlvbmAgIHxcbiAqIHwgZGlzcGxheU5hbWUgICAgICAgIHwg4oCUICAgICAgICAgICAgICAgICAgfCBmaXJzdCBgIyBoZWFkaW5nYCAgfCBgb3JnLm9wZW5jb250YWluZXJzLmltYWdlLnRpdGxlYCAgICAgICAgfFxuICogfCBsaWNlbnNlICAgICAgICAgICAgfCBgbGljZW5zZWAgICAgICAgICAgfCDigJQgICAgICAgICAgICAgICAgICB8IGBvcmcub3BlbmNvbnRhaW5lcnMuaW1hZ2UubGljZW5zZXNgICAgICB8XG4gKiB8IGhvbWVwYWdlVXJsICAgICAgICB8IGBob21lcGFnZVVybGAgICAgICB8IOKAlCAgICAgICAgICAgICAgICAgIHwgYG9yZy5vcGVuY29udGFpbmVycy5pbWFnZS51cmxgICAgICAgICAgIHxcbiAqIHwgc291cmNlVXJsICAgICAgICAgIHwgYHNvdXJjZVVybGAgICAgICAgIHwg4oCUICAgICAgICAgICAgICAgICAgfCBgb3JnLm9wZW5jb250YWluZXJzLmltYWdlLnNvdXJjZWAgICAgICAgfFxuICogfCBkb2N1bWVudGF0aW9uVXJsICAgfCBgZG9jdW1lbnRhdGlvblVybGAgfCDigJQgICAgICAgICAgICAgICAgICB8IGBvcmcub3BlbmNvbnRhaW5lcnMuaW1hZ2UuZG9jdW1lbnRhdGlvbmB8XG4gKiB8IGNhdGVnb3J5LCBrZXl3b3JkcywgaWNvbiwgY2hhbmdlbG9nIHwgc3BlYyB8IOKAlCAgICAgICAgICAgICAgfCDigJQgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB8XG4gKiB8IHJlYWRtZSAgICAgICAgICAgICB8IOKAlCAgICAgICAgICAgICAgICAgIHwgYFJFQURNRS5tZGAgICAgICAgIHwg4oCUICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfFxuICpcbiAqIEV2ZXJ5IHZhbHVlIOKAlCBkZXRlY3RlZCBvciB0eXBlZCDigJQgcGFzc2VzIHRoZSBPTkUgc2hhcmVkIHZhbGlkYXRvclxuICogKGFwaS1jb3JlIGB2YWxpZGF0ZUNhdGFsb2dGaWVsZGApLiBBIGRldGVjdGVkIHZhbHVlIHRoYXQgZmFpbHMgaXMgcmV0dXJuZWRcbiAqIEJMQU5LIFdJVEggVEhFIFJFQVNPTiwgbmV2ZXIgc2lsZW50bHkgZHJvcHBlZCwgYW5kIGlzIG5vdCBzdG9yZWQgdW5sZXNzIHRoZVxuICogdXNlciBzdXBwbGllcyBhIHZhbGlkIHJlcGxhY2VtZW50LlxuICpcbiAqIFB1cmUgYW5kIHNoYXJlZCBmcm9tIGFwaS1jb3JlOiB0aGUgcGx1Z2luIHNlcnZpY2UncyB1cGxvYWQgYW5kIGluc3BlY3RcbiAqIHJvdXRlcyBhbmQgdGhlIENMSSdzIGBwbHVnaW4gdmFsaWRhdGVgIC8gYHBsdWdpbiBwdWJsaXNoYCBydW4gdGhpcyBvbmVcbiAqIGRldGVjdGlvbiwgc28gdGhlIENMSSByZXBvcnRzIGV4YWN0bHkgd2hhdCB0aGUgc2VydmVyIHdpbGwgZGV0ZWN0LlxuICovXG5cbmltcG9ydCB7IE9DSV9MQUJFTFMsIHBhcnNlRG9ja2VyZmlsZSB9IGZyb20gJy4vZG9ja2VyZmlsZS1zdGF0aWMuanMnO1xuaW1wb3J0IHtcbiAgUExVR0lOX0NBVEFMT0dfRklFTERTLCBQTFVHSU5fU1VNTUFSWV9NQVgsXG4gIHR5cGUgTWV0YWRhdGFTb3VyY2UsIHR5cGUgTWV0YWRhdGFTb3VyY2VzLCB0eXBlIFBsdWdpbkNhdGFsb2dGaWVsZCxcbn0gZnJvbSAnLi4vdHlwZXMvcGx1Z2luLWNhdGFsb2cuanMnO1xuaW1wb3J0IHtcbiAgUGx1Z2luQ2F0YWxvZ0VkaXRzU2NoZW1hLCBjb250cmFjdEtleXNNZXNzYWdlLCBmaW5kQ29udHJhY3RLZXlzLCB2YWxpZGF0ZUNhdGFsb2dGaWVsZCwgdHlwZSBQbHVnaW5DYXRhbG9nRWRpdHMsXG59IGZyb20gJy4vcGx1Z2luLWNhdGFsb2ctbWV0YWRhdGEuanMnO1xuXG4vKiogQSBzb3VyY2UgYSB2YWx1ZSBjYW4gYmUgREVURUNURUQgZnJvbSAoYHVzZXJgIGlzIG9ubHkgZXZlciBhbiBlZGl0KS4gKi9cbmV4cG9ydCB0eXBlIERldGVjdGVkU291cmNlID0gRXhjbHVkZTxNZXRhZGF0YVNvdXJjZSwgJ3VzZXInPjtcblxuLyoqIE9uZSBkZXNjcmlwdGl2ZSBmaWVsZCBhcyBkZXRlY3RlZCBmcm9tIHRoZSBwYWNrYWdlLiAqL1xuZXhwb3J0IGludGVyZmFjZSBEZXRlY3RlZEZpZWxkIHtcbiAgZmllbGQ6IFBsdWdpbkNhdGFsb2dGaWVsZDtcbiAgLyoqIFRoZSB2YWxpZGF0ZWQgKG5vcm1hbGl6ZWQpIHZhbHVlLCBvciBudWxsIHdoZW4gbm9uZSB3YXMgZm91bmQgb3IgaXQgZmFpbGVkIHZhbGlkYXRpb24uICovXG4gIHZhbHVlOiB1bmtub3duO1xuICAvKiogV2hlcmUgdGhlIHdpbm5pbmcgY2FuZGlkYXRlIGNhbWUgZnJvbSwgb3IgbnVsbCB3aGVuIG5vIHNvdXJjZSBoYWQgb25lLiAqL1xuICBzb3VyY2U6IERldGVjdGVkU291cmNlIHwgbnVsbDtcbiAgLyoqIFdoeSB0aGUgd2lubmluZyBjYW5kaWRhdGUgd2FzIHJlZnVzZWQsIG9yIG51bGwuICovXG4gIGVycm9yOiBzdHJpbmcgfCBudWxsO1xufVxuXG4vKiogVGhlIHNwZWMgZmllbGRzIGRldGVjdGlvbiByZWFkcyAoYSBzdHJ1Y3R1cmFsIHN1YnNldCBvZiB0aGUgcGx1Z2luIHNwZWMpLiAqL1xuZXhwb3J0IGludGVyZmFjZSBDYXRhbG9nU3BlY0ZpZWxkcyB7XG4gIHJlYWRvbmx5IGRlc2NyaXB0aW9uPzogc3RyaW5nO1xuICByZWFkb25seSBzdW1tYXJ5Pzogc3RyaW5nO1xuICByZWFkb25seSBjYXRlZ29yeT86IHN0cmluZztcbiAgcmVhZG9ubHkga2V5d29yZHM/OiByZWFkb25seSBzdHJpbmdbXTtcbiAgcmVhZG9ubHkgbGljZW5zZT86IHN0cmluZztcbiAgcmVhZG9ubHkgaG9tZXBhZ2VVcmw/OiBzdHJpbmc7XG4gIHJlYWRvbmx5IHNvdXJjZVVybD86IHN0cmluZztcbiAgcmVhZG9ubHkgZG9jdW1lbnRhdGlvblVybD86IHN0cmluZztcbiAgcmVhZG9ubHkgaWNvbj86IHN0cmluZyB8IHsga2V5OiBzdHJpbmc7IGJhZGdlPzogc3RyaW5nIH07XG4gIHJlYWRvbmx5IGNoYW5nZWxvZz86IHN0cmluZztcbn1cblxuLyoqIFdoYXQgZGV0ZWN0aW9uIHJlYWRzOiB0aGUgc3BlYywgdGhlIHppcC1yb290IFJFQURNRSBhbmQgdGhlIHBsdWdpbidzIG93biBEb2NrZXJmaWxlLiAqL1xuZXhwb3J0IGludGVyZmFjZSBDYXRhbG9nSW5wdXRzIHtcbiAgc3BlYzogQ2F0YWxvZ1NwZWNGaWVsZHM7XG4gIHJlYWRtZU1kOiBzdHJpbmcgfCBudWxsO1xuICBkb2NrZXJmaWxlQ29udGVudDogc3RyaW5nIHwgbnVsbDtcbn1cblxuLyoqIFRoZSBhY2NlcHRlZC9lZGl0ZWQgdmFsdWVzIG9mIGV2ZXJ5IGRlc2NyaXB0aXZlIGZpZWxkLCBwbHVzIHRoZWlyIHByb3ZlbmFuY2UuICovXG5leHBvcnQgaW50ZXJmYWNlIFJlc29sdmVkQ2F0YWxvZyB7XG4gIHZhbHVlczogUmVjb3JkPFBsdWdpbkNhdGFsb2dGaWVsZCwgdW5rbm93bj47XG4gIHNvdXJjZXM6IE1ldGFkYXRhU291cmNlcztcbn1cbi8vIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG4vLyBSRUFETUUgcmVhZGluZ1xuLy8gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cblxuLyoqIFN0cmlwIGlubGluZSBtYXJrZG93biBkb3duIHRvIHJlYWRhYmxlIHRleHQgKGxpbmtzIOKGkiB0ZXh0LCBpbWFnZXMvZW1waGFzaXMvY29kZSBtYXJrcyByZW1vdmVkKS4gKi9cbmV4cG9ydCBmdW5jdGlvbiBzdHJpcElubGluZU1hcmtkb3duKHRleHQ6IHN0cmluZyk6IHN0cmluZyB7XG4gIHJldHVybiB0ZXh0XG4gICAgLnJlcGxhY2UoLyFcXFtbXlxcXV0qXFxdXFwoW14pXSpcXCkvZywgJycpIC8vIGltYWdlcyAvIGJhZGdlc1xuICAgIC5yZXBsYWNlKC9cXFsoW15cXF1dKilcXF1cXChbXildKlxcKS9nLCAnJDEnKSAvLyBsaW5rcyDihpIgdGV4dFxuICAgIC5yZXBsYWNlKC88W14+XSs+L2csICcnKSAvLyBpbmxpbmUgSFRNTFxuICAgIC5yZXBsYWNlKC8oXFwqXFwqfF9ffFxcKnxffGApL2csICcnKVxuICAgIC5yZXBsYWNlKC9cXHMrL2csICcgJylcbiAgICAudHJpbSgpO1xufVxuXG4vKiogTWFya2Rvd24gbGluZXMgb3V0c2lkZSBmZW5jZWQgY29kZSBibG9ja3MsIGluIG9yZGVyLiAqL1xuZnVuY3Rpb24gcHJvc2VMaW5lcyhtZDogc3RyaW5nKTogc3RyaW5nW10ge1xuICBjb25zdCBvdXQ6IHN0cmluZ1tdID0gW107XG4gIGxldCBmZW5jZWQgPSBmYWxzZTtcbiAgZm9yIChjb25zdCBsaW5lIG9mIG1kLnJlcGxhY2UoL1xcclxcbj8vZywgJ1xcbicpLnNwbGl0KCdcXG4nKSkge1xuICAgIGlmICgvXlxccyooYGBgfH5+fikvLnRlc3QobGluZSkpIHtcbiAgICAgIGZlbmNlZCA9ICFmZW5jZWQ7XG4gICAgICBvdXQucHVzaCgnJyk7XG4gICAgICBjb250aW51ZTtcbiAgICB9XG4gICAgb3V0LnB1c2goZmVuY2VkID8gJycgOiBsaW5lKTtcbiAgfVxuICByZXR1cm4gb3V0O1xufVxuXG4vKiogVGhlIFJFQURNRSdzIGZpcnN0IGxldmVsLTEgQVRYIGhlYWRpbmcgKGAjIFRpdGxlYCksIGFzIHBsYWluIHRleHQuICovXG5leHBvcnQgZnVuY3Rpb24gcmVhZG1lVGl0bGUobWQ6IHN0cmluZyk6IHN0cmluZyB8IG51bGwge1xuICBmb3IgKGNvbnN0IGxpbmUgb2YgcHJvc2VMaW5lcyhtZCkpIHtcbiAgICBjb25zdCBtID0gL14jXFxzKyguKz8pXFxzKiMqXFxzKiQvLmV4ZWMobGluZSk7XG4gICAgaWYgKG0pIHtcbiAgICAgIGNvbnN0IHRpdGxlID0gc3RyaXBJbmxpbmVNYXJrZG93bihtWzFdISk7XG4gICAgICByZXR1cm4gdGl0bGUgfHwgbnVsbDtcbiAgICB9XG4gIH1cbiAgcmV0dXJuIG51bGw7XG59XG5cbi8qKlxuICogVGhlIFJFQURNRSdzIGZpcnN0IHByb3NlIHBhcmFncmFwaDogdGhlIGZpcnN0IGJsb2NrIG9mIGNvbnNlY3V0aXZlIHRleHRcbiAqIGxpbmVzIHRoYXQgaXMgbm90IGEgaGVhZGluZywgYmFkZ2Ugcm93LCBsaXN0LCB0YWJsZSwgcXVvdGUsIHJ1bGUgb3IgSFRNTC5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHJlYWRtZUZpcnN0UGFyYWdyYXBoKG1kOiBzdHJpbmcpOiBzdHJpbmcgfCBudWxsIHtcbiAgY29uc3QgaXNTdHJ1Y3R1cmFsID0gKGw6IHN0cmluZyk6IGJvb2xlYW4gPT5cbiAgICAvXlxccyooI3w+fFstKitdXFxzfFxcZCtbLildXFxzfFxcfHw8fC0tLXxcXCpcXCpcXCp8PT09KS8udGVzdChsKTtcbiAgbGV0IHBhcmE6IHN0cmluZ1tdID0gW107XG4gIGZvciAoY29uc3QgbGluZSBvZiBbLi4ucHJvc2VMaW5lcyhtZCksICcnXSkge1xuICAgIGlmIChsaW5lLnRyaW0oKSA9PT0gJycgfHwgaXNTdHJ1Y3R1cmFsKGxpbmUpKSB7XG4gICAgICBpZiAocGFyYS5sZW5ndGggPiAwKSB7XG4gICAgICAgIGNvbnN0IHRleHQgPSBzdHJpcElubGluZU1hcmtkb3duKHBhcmEuam9pbignICcpKTtcbiAgICAgICAgaWYgKHRleHQpIHJldHVybiB0ZXh0O1xuICAgICAgfVxuICAgICAgcGFyYSA9IFtdO1xuICAgICAgY29udGludWU7XG4gICAgfVxuICAgIHBhcmEucHVzaChsaW5lLnRyaW0oKSk7XG4gIH1cbiAgcmV0dXJuIG51bGw7XG59XG5cbi8qKlxuICogVGhlIGZpcnN0IHNlbnRlbmNlIG9mIGB0ZXh0YCwgY2FwcGVkIGF0IHtAbGluayBQTFVHSU5fU1VNTUFSWV9NQVh9OiBjdXQgYXRcbiAqIHRoZSBmaXJzdCBgLmAvYCFgL2A/YCBmb2xsb3dlZCBieSB3aGl0ZXNwYWNlIChvciB0aGUgZW5kKSwgZWxzZSB0aGUgZmlyc3RcbiAqIGxpbmU7IGFuIG92ZXItbG9uZyBzZW50ZW5jZSBpcyBzaG9ydGVuZWQgb24gYSB3b3JkIGJvdW5kYXJ5IHdpdGggYOKApmAuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBmaXJzdFNlbnRlbmNlKHRleHQ6IHN0cmluZyk6IHN0cmluZyB8IG51bGwge1xuICBjb25zdCBmbGF0ID0gdGV4dC5yZXBsYWNlKC9cXHMrL2csICcgJykudHJpbSgpO1xuICBpZiAoIWZsYXQpIHJldHVybiBudWxsO1xuICBjb25zdCBtID0gL14oLis/Wy4hP10pKFxcc3wkKS8uZXhlYyhmbGF0KTtcbiAgY29uc3Qgc2VudGVuY2UgPSAobSA/IG1bMV0hIDogZmxhdCkudHJpbSgpO1xuICBpZiAoc2VudGVuY2UubGVuZ3RoIDw9IFBMVUdJTl9TVU1NQVJZX01BWCkgcmV0dXJuIHNlbnRlbmNlO1xuICBjb25zdCBjdXQgPSBzZW50ZW5jZS5zbGljZSgwLCBQTFVHSU5fU1VNTUFSWV9NQVggLSAxKTtcbiAgY29uc3QgYXRXb3JkID0gY3V0LmluY2x1ZGVzKCcgJykgPyBjdXQuc2xpY2UoMCwgY3V0Lmxhc3RJbmRleE9mKCcgJykpIDogY3V0O1xuICByZXR1cm4gYCR7YXRXb3JkLnJlcGxhY2UoL1tcXHMsOzpdKyQvLCAnJyl94oCmYDtcbn1cblxuLy8gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cbi8vIERldGVjdGlvblxuLy8gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cblxudHlwZSBDYW5kaWRhdGUgPSBbRGV0ZWN0ZWRTb3VyY2UsIHVua25vd25dO1xuXG5jb25zdCBub25FbXB0eSA9ICh2OiB1bmtub3duKTogYm9vbGVhbiA9PlxuICB2ICE9PSB1bmRlZmluZWQgJiYgdiAhPT0gbnVsbCAmJiAhKHR5cGVvZiB2ID09PSAnc3RyaW5nJyAmJiB2LnRyaW0oKSA9PT0gJycpICYmICEoQXJyYXkuaXNBcnJheSh2KSAmJiB2Lmxlbmd0aCA9PT0gMCk7XG5cbi8qKiBQaWNrIHRoZSBmaXJzdCBub24tZW1wdHkgY2FuZGlkYXRlIGFuZCB2YWxpZGF0ZSBpdCAoYmxhbmsgKyByZWFzb24gb24gZmFpbHVyZSkuICovXG5mdW5jdGlvbiBwaWNrKGZpZWxkOiBQbHVnaW5DYXRhbG9nRmllbGQsIGNhbmRpZGF0ZXM6IENhbmRpZGF0ZVtdKTogRGV0ZWN0ZWRGaWVsZCB7XG4gIGNvbnN0IHdpbm5lciA9IGNhbmRpZGF0ZXMuZmluZCgoWywgdl0pID0+IG5vbkVtcHR5KHYpKTtcbiAgaWYgKCF3aW5uZXIpIHJldHVybiB7IGZpZWxkLCB2YWx1ZTogbnVsbCwgc291cmNlOiBudWxsLCBlcnJvcjogbnVsbCB9O1xuICBjb25zdCBbc291cmNlLCByYXddID0gd2lubmVyO1xuICBjb25zdCBjaGVja2VkID0gdmFsaWRhdGVDYXRhbG9nRmllbGQoZmllbGQsIHJhdyk7XG4gIHJldHVybiBjaGVja2VkLm9rXG4gICAgPyB7IGZpZWxkLCB2YWx1ZTogY2hlY2tlZC52YWx1ZSwgc291cmNlLCBlcnJvcjogbnVsbCB9XG4gICAgOiB7IGZpZWxkLCB2YWx1ZTogbnVsbCwgc291cmNlLCBlcnJvcjogY2hlY2tlZC5lcnJvciB9O1xufVxuXG4vKiogVGhlIHN1bW1hcnkgZGVyaXZlZCBmcm9tIGEgZGVzY3JpcHRpb24sIGFzIGEgZGV0ZWN0ZWQgZmllbGQuICovXG5mdW5jdGlvbiBkZXJpdmVkU3VtbWFyeShkZXNjcmlwdGlvbjogdW5rbm93bik6IERldGVjdGVkRmllbGQge1xuICBjb25zdCBzZW50ZW5jZSA9IHR5cGVvZiBkZXNjcmlwdGlvbiA9PT0gJ3N0cmluZycgPyBmaXJzdFNlbnRlbmNlKGRlc2NyaXB0aW9uKSA6IG51bGw7XG4gIHJldHVybiBwaWNrKCdzdW1tYXJ5JywgW1snZGVyaXZlZCcsIHNlbnRlbmNlXV0pO1xufVxuXG4vKipcbiAqIERldGVjdCBldmVyeSBkZXNjcmlwdGl2ZSBmaWVsZCBmcm9tIHRoZSBwYWNrYWdlLCBpblxuICogYFBMVUdJTl9DQVRBTE9HX0ZJRUxEU2Agb3JkZXIuIFB1cmU7IG5ldmVyIHRocm93cy5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGRldGVjdENhdGFsb2dNZXRhZGF0YShpbnB1dHM6IENhdGFsb2dJbnB1dHMpOiBEZXRlY3RlZEZpZWxkW10ge1xuICBjb25zdCB7IHNwZWMgfSA9IGlucHV0cztcbiAgY29uc3QgcmVhZG1lID0gaW5wdXRzLnJlYWRtZU1kO1xuICBjb25zdCBsYWJlbHMgPSBwYXJzZURvY2tlcmZpbGUoaW5wdXRzLmRvY2tlcmZpbGVDb250ZW50KS5sYWJlbHM7XG4gIGNvbnN0IGxhYmVsID0gKGtleTogc3RyaW5nKTogc3RyaW5nIHwgdW5kZWZpbmVkID0+IGxhYmVsc1trZXldO1xuXG4gIGNvbnN0IGRlc2NyaXB0aW9uID0gcGljaygnZGVzY3JpcHRpb24nLCBbXG4gICAgWydzcGVjJywgc3BlYy5kZXNjcmlwdGlvbl0sXG4gICAgWydyZWFkbWUnLCByZWFkbWUgIT09IG51bGwgPyByZWFkbWVGaXJzdFBhcmFncmFwaChyZWFkbWUpIDogbnVsbF0sXG4gICAgWydkb2NrZXJmaWxlJywgbGFiZWwoT0NJX0xBQkVMUy5kZXNjcmlwdGlvbildLFxuICBdKTtcbiAgY29uc3Qgc3BlY1N1bW1hcnkgPSBwaWNrKCdzdW1tYXJ5JywgW1snc3BlYycsIHNwZWMuc3VtbWFyeV1dKTtcblxuICBjb25zdCBieUZpZWxkOiBSZWNvcmQ8UGx1Z2luQ2F0YWxvZ0ZpZWxkLCBEZXRlY3RlZEZpZWxkPiA9IHtcbiAgICBkaXNwbGF5TmFtZTogcGljaygnZGlzcGxheU5hbWUnLCBbXG4gICAgICBbJ3JlYWRtZScsIHJlYWRtZSAhPT0gbnVsbCA/IHJlYWRtZVRpdGxlKHJlYWRtZSkgOiBudWxsXSxcbiAgICAgIFsnZG9ja2VyZmlsZScsIGxhYmVsKE9DSV9MQUJFTFMudGl0bGUpXSxcbiAgICBdKSxcbiAgICBzdW1tYXJ5OiBzcGVjU3VtbWFyeS5zb3VyY2UgIT09IG51bGwgPyBzcGVjU3VtbWFyeSA6IGRlcml2ZWRTdW1tYXJ5KGRlc2NyaXB0aW9uLnZhbHVlKSxcbiAgICBkZXNjcmlwdGlvbixcbiAgICBjYXRlZ29yeTogcGljaygnY2F0ZWdvcnknLCBbWydzcGVjJywgc3BlYy5jYXRlZ29yeV1dKSxcbiAgICBrZXl3b3JkczogcGljaygna2V5d29yZHMnLCBbWydzcGVjJywgc3BlYy5rZXl3b3Jkc11dKSxcbiAgICBsaWNlbnNlOiBwaWNrKCdsaWNlbnNlJywgW1snc3BlYycsIHNwZWMubGljZW5zZV0sIFsnZG9ja2VyZmlsZScsIGxhYmVsKE9DSV9MQUJFTFMubGljZW5zZXMpXV0pLFxuICAgIGhvbWVwYWdlVXJsOiBwaWNrKCdob21lcGFnZVVybCcsIFtbJ3NwZWMnLCBzcGVjLmhvbWVwYWdlVXJsXSwgWydkb2NrZXJmaWxlJywgbGFiZWwoT0NJX0xBQkVMUy51cmwpXV0pLFxuICAgIHNvdXJjZVVybDogcGljaygnc291cmNlVXJsJywgW1snc3BlYycsIHNwZWMuc291cmNlVXJsXSwgWydkb2NrZXJmaWxlJywgbGFiZWwoT0NJX0xBQkVMUy5zb3VyY2UpXV0pLFxuICAgIGRvY3VtZW50YXRpb25Vcmw6IHBpY2soJ2RvY3VtZW50YXRpb25VcmwnLCBbWydzcGVjJywgc3BlYy5kb2N1bWVudGF0aW9uVXJsXSwgWydkb2NrZXJmaWxlJywgbGFiZWwoT0NJX0xBQkVMUy5kb2N1bWVudGF0aW9uKV1dKSxcbiAgICBpY29uOiBwaWNrKCdpY29uJywgW1snc3BlYycsIHNwZWMuaWNvbl1dKSxcbiAgICBjaGFuZ2Vsb2c6IHBpY2soJ2NoYW5nZWxvZycsIFtbJ3NwZWMnLCBzcGVjLmNoYW5nZWxvZ11dKSxcbiAgICByZWFkbWU6IHBpY2soJ3JlYWRtZScsIFtbJ3JlYWRtZScsIHJlYWRtZV1dKSxcbiAgfTtcbiAgcmV0dXJuIFBMVUdJTl9DQVRBTE9HX0ZJRUxEUy5tYXAoKGYpID0+IGJ5RmllbGRbZl0pO1xufVxuXG4vLyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxuLy8gQWNjZXB0IG9yIGVkaXRcbi8vIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG5cbi8qKlxuICogQXBwbHkgdGhlIHVzZXIncyBlZGl0cyBvdmVyIHRoZSBkZXRlY3RlZCB2YWx1ZXMuIEEga2V5IHByZXNlbnQgaW4gYGVkaXRzYFxuICogaXMgdGhlIHVzZXIncyAoYG51bGxgIGNsZWFycyBpdCkgYW5kIGlzIHJlY29yZGVkIGFzIGB1c2VyYDsgZXZlcnkgb3RoZXIgZmllbGRcbiAqIGtlZXBzIGl0cyBkZXRlY3RlZCB2YWx1ZSAobm9uZSB3aGVuIGl0IGZhaWxlZCB2YWxpZGF0aW9uKS4gYGVkaXRzYCBtdXN0XG4gKiBhbHJlYWR5IGhhdmUgcGFzc2VkIGBQbHVnaW5DYXRhbG9nRWRpdHNTY2hlbWFgLiBBIHN1bW1hcnkgdGhhdCB3YXMgREVSSVZFRFxuICogZnJvbSB0aGUgZGVzY3JpcHRpb24gaXMgcmUtZGVyaXZlZCB3aGVuIHRoZSB1c2VyIGVkaXRlZCB0aGUgZGVzY3JpcHRpb24uXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiByZXNvbHZlQ2F0YWxvZ01ldGFkYXRhKGRldGVjdGVkOiBEZXRlY3RlZEZpZWxkW10sIGVkaXRzOiBQbHVnaW5DYXRhbG9nRWRpdHMgPSB7fSk6IFJlc29sdmVkQ2F0YWxvZyB7XG4gIGNvbnN0IHZhbHVlcyA9IHt9IGFzIFJlY29yZDxQbHVnaW5DYXRhbG9nRmllbGQsIHVua25vd24+O1xuICBjb25zdCBzb3VyY2VzOiBNZXRhZGF0YVNvdXJjZXMgPSB7fTtcbiAgY29uc3Qgc2V0ID0gKGZpZWxkOiBQbHVnaW5DYXRhbG9nRmllbGQsIHZhbHVlOiB1bmtub3duLCBzb3VyY2U6IE1ldGFkYXRhU291cmNlIHwgbnVsbCk6IHZvaWQgPT4ge1xuICAgIHZhbHVlc1tmaWVsZF0gPSB2YWx1ZSA/PyBudWxsO1xuICAgIGlmIChzb3VyY2UgJiYgKHZhbHVlICE9PSBudWxsICYmIHZhbHVlICE9PSB1bmRlZmluZWQgfHwgc291cmNlID09PSAndXNlcicpKSBzb3VyY2VzW2ZpZWxkXSA9IHNvdXJjZTtcbiAgfTtcblxuICBmb3IgKGNvbnN0IGQgb2YgZGV0ZWN0ZWQpIHtcbiAgICBpZiAoT2JqZWN0LnByb3RvdHlwZS5oYXNPd25Qcm9wZXJ0eS5jYWxsKGVkaXRzLCBkLmZpZWxkKSkge1xuICAgICAgc2V0KGQuZmllbGQsIChlZGl0cyBhcyBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPilbZC5maWVsZF0sICd1c2VyJyk7XG4gICAgfSBlbHNlIHtcbiAgICAgIHNldChkLmZpZWxkLCBkLmVycm9yID8gbnVsbCA6IGQudmFsdWUsIGQuZXJyb3IgPyBudWxsIDogZC5zb3VyY2UpO1xuICAgIH1cbiAgfVxuXG4gIGNvbnN0IHN1bW1hcnlEZXRlY3RlZCA9IGRldGVjdGVkLmZpbmQoKGQpID0+IGQuZmllbGQgPT09ICdzdW1tYXJ5Jyk7XG4gIGNvbnN0IHN1bW1hcnlFZGl0ZWQgPSBPYmplY3QucHJvdG90eXBlLmhhc093blByb3BlcnR5LmNhbGwoZWRpdHMsICdzdW1tYXJ5Jyk7XG4gIGNvbnN0IGRlc2NyaXB0aW9uRWRpdGVkID0gT2JqZWN0LnByb3RvdHlwZS5oYXNPd25Qcm9wZXJ0eS5jYWxsKGVkaXRzLCAnZGVzY3JpcHRpb24nKTtcbiAgaWYgKCFzdW1tYXJ5RWRpdGVkICYmIGRlc2NyaXB0aW9uRWRpdGVkICYmIChzdW1tYXJ5RGV0ZWN0ZWQ/LnNvdXJjZSA9PT0gJ2Rlcml2ZWQnIHx8IHN1bW1hcnlEZXRlY3RlZD8uc291cmNlID09PSBudWxsKSkge1xuICAgIGNvbnN0IHJlZGVyaXZlZCA9IGRlcml2ZWRTdW1tYXJ5KHZhbHVlcy5kZXNjcmlwdGlvbik7XG4gICAgZGVsZXRlIHNvdXJjZXMuc3VtbWFyeTtcbiAgICBzZXQoJ3N1bW1hcnknLCByZWRlcml2ZWQuZXJyb3IgPyBudWxsIDogcmVkZXJpdmVkLnZhbHVlLCByZWRlcml2ZWQuZXJyb3IgPyBudWxsIDogcmVkZXJpdmVkLnNvdXJjZSk7XG4gIH1cbiAgcmV0dXJuIHsgdmFsdWVzLCBzb3VyY2VzIH07XG59XG5cbi8qKiBBIGRldGVjdGlvbiB3aXRoIGV2ZXJ5IHZhbHVlIGFjY2VwdGVkIChubyBlZGl0cykg4oCUIHNjcmlwdHMsIHRoZSBPZmZpY2lhbCBsb2FkZXIuICovXG5leHBvcnQgZnVuY3Rpb24gYWNjZXB0QWxsQ2F0YWxvZ01ldGFkYXRhKGRldGVjdGVkOiBEZXRlY3RlZEZpZWxkW10pOiBSZXNvbHZlZENhdGFsb2cge1xuICByZXR1cm4gcmVzb2x2ZUNhdGFsb2dNZXRhZGF0YShkZXRlY3RlZCwge30pO1xufVxuXG4vLyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxuLy8gRWRpdCBwYXlsb2Fkc1xuLy8gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cblxuLyoqXG4gKiBWYWxpZGF0ZSBhIGNhdGFsb2ctZWRpdCBwYXlsb2FkICh0aGUgdXBsb2FkJ3MgYG1ldGFkYXRhYCBwYXJ0LCBhbHJlYWR5XG4gKiBKU09OLWRlY29kZWQpLiBFeGVjdXRpb24tY29udHJhY3Qga2V5cyBhcmUgcmVmdXNlZCBieSBuYW1lIGJlZm9yZSB0aGVcbiAqIHN0cmljdCBzY2hlbWEgcnVucywgc28gdGhlIGNhbGxlciBsZWFybnMgZXhhY3RseSB3aGljaCBrZXlzIGNhbid0IGJlIGVkaXRlZC5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHBhcnNlQ2F0YWxvZ0VkaXRzKHJhdzogdW5rbm93bik6IHsgb2s6IHRydWU7IHZhbHVlOiBQbHVnaW5DYXRhbG9nRWRpdHMgfSB8IHsgb2s6IGZhbHNlOyBlcnJvcjogc3RyaW5nOyBjb250cmFjdEtleXM/OiBzdHJpbmdbXSB9IHtcbiAgaWYgKCFyYXcgfHwgdHlwZW9mIHJhdyAhPT0gJ29iamVjdCcgfHwgQXJyYXkuaXNBcnJheShyYXcpKSB7XG4gICAgcmV0dXJuIHsgb2s6IGZhbHNlLCBlcnJvcjogJ21ldGFkYXRhIG11c3QgYmUgYSBKU09OIG9iamVjdCcgfTtcbiAgfVxuICBjb25zdCBjb250cmFjdEtleXMgPSBmaW5kQ29udHJhY3RLZXlzKHJhdyk7XG4gIGlmIChjb250cmFjdEtleXMubGVuZ3RoID4gMCkgcmV0dXJuIHsgb2s6IGZhbHNlLCBlcnJvcjogY29udHJhY3RLZXlzTWVzc2FnZShjb250cmFjdEtleXMpLCBjb250cmFjdEtleXMgfTtcbiAgY29uc3QgcGFyc2VkID0gUGx1Z2luQ2F0YWxvZ0VkaXRzU2NoZW1hLnNhZmVQYXJzZShyYXcpO1xuICBpZiAoIXBhcnNlZC5zdWNjZXNzKSB7XG4gICAgcmV0dXJuIHtcbiAgICAgIG9rOiBmYWxzZSxcbiAgICAgIGVycm9yOiBgSW52YWxpZCBtZXRhZGF0YTogJHtwYXJzZWQuZXJyb3IuaXNzdWVzLm1hcCgoaSkgPT4gYCR7aS5wYXRoLmpvaW4oJy4nKSB8fCAnKHJvb3QpJ306ICR7aS5tZXNzYWdlfWApLmpvaW4oJzsgJyl9YCxcbiAgICB9O1xuICB9XG4gIHJldHVybiB7IG9rOiB0cnVlLCB2YWx1ZTogcGFyc2VkLmRhdGEgfTtcbn1cblxuLyoqIERlY29kZSB0aGUgdXBsb2FkJ3MgbXVsdGlwYXJ0IGBtZXRhZGF0YWAgcGFydCAoSlNPTiB0ZXh0KSwgdGhlbiB7QGxpbmsgcGFyc2VDYXRhbG9nRWRpdHN9LiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHBhcnNlQ2F0YWxvZ0VkaXRzUGFydCh0ZXh0OiBzdHJpbmcgfCB1bmRlZmluZWQpOiBSZXR1cm5UeXBlPHR5cGVvZiBwYXJzZUNhdGFsb2dFZGl0cz4ge1xuICBpZiAodGV4dCA9PT0gdW5kZWZpbmVkIHx8IHRleHQudHJpbSgpID09PSAnJykgcmV0dXJuIHsgb2s6IHRydWUsIHZhbHVlOiB7fSB9O1xuICBsZXQgcmF3OiB1bmtub3duO1xuICB0cnkge1xuICAgIHJhdyA9IEpTT04ucGFyc2UodGV4dCk7XG4gIH0gY2F0Y2gge1xuICAgIHJldHVybiB7IG9rOiBmYWxzZSwgZXJyb3I6ICdtZXRhZGF0YSBtdXN0IGJlIHZhbGlkIEpTT04nIH07XG4gIH1cbiAgcmV0dXJuIHBhcnNlQ2F0YWxvZ0VkaXRzKHJhdyk7XG59XG4iXX0=
@@ -0,0 +1,141 @@
1
+ /**
2
+ * Plugin CATALOG metadata: the descriptive fields a plugin version shows in the
3
+ * catalog, detected from the package and then accepted or edited by the user
4
+ * (docs/plugin-publishing.md).
5
+ *
6
+ * ONE validator for both paths: a value detected from the package (spec,
7
+ * README, the plugin's own Dockerfile labels) and a value typed into a form or
8
+ * sent by the CLI pass the same rules. Shared from api-core so the plugin
9
+ * service, the frontend and the CLI can't drift.
10
+ *
11
+ * Only DESCRIPTIVE fields live here. Execution-contract fields (commands, env,
12
+ * secrets, compute type, …) are spec-only — changing one is a new version with a
13
+ * new digest — and an edit payload naming one is refused
14
+ * ({@link findContractKeys}).
15
+ */
16
+ import { z } from 'zod';
17
+ import { type PluginCatalogField } from '../types/plugin-catalog.js';
18
+ /**
19
+ * Accepted SPDX license identifiers — a compact allowlist of the ids that
20
+ * cover effectively every published plugin, rather than the full ~700-entry
21
+ * SPDX list (an unfamiliar id is worth a human look). Case-sensitive, exactly
22
+ * as SPDX spells them. `LicenseRef-Proprietary` is the SPDX-sanctioned
23
+ * spelling for "not open source".
24
+ */
25
+ export declare const SPDX_LICENSE_IDS: ReadonlySet<string>;
26
+ /** True when `id` is an accepted SPDX identifier. */
27
+ export declare function isAllowedSpdxId(id: string): boolean;
28
+ /**
29
+ * URL shorteners refused in project links: a shortener hides the destination
30
+ * from the reviewer and can be re-pointed after approval.
31
+ */
32
+ export declare const URL_SHORTENER_HOSTS: ReadonlySet<string>;
33
+ /**
34
+ * Why `raw` is not an acceptable project URL, or `null` when it is: must parse,
35
+ * be `https:`, carry no userinfo, and not point at a known shortener (the host
36
+ * or any parent domain of it).
37
+ */
38
+ export declare function projectUrlProblem(raw: string): string | null;
39
+ /** Curated icon / badge key: a file name under `deploy/plugins/_icons/`. */
40
+ export declare const ICON_KEY_PATTERN: RegExp;
41
+ /** `https:` project URL, no shorteners, no credentials. */
42
+ export declare const ProjectUrlSchema: z.ZodString;
43
+ /** Curated icon / badge key. */
44
+ export declare const IconKeySchema: z.ZodString;
45
+ /**
46
+ * Icon as stored: `{ key, badge? }`. A bare key string is accepted and
47
+ * normalized first, so a bad key reports the key rule (not a bare union miss).
48
+ */
49
+ export declare const PluginIconSchema: z.ZodPreprocess<z.ZodObject<{
50
+ key: z.ZodString;
51
+ badge: z.ZodOptional<z.ZodString>;
52
+ }, z.core.$strict>>;
53
+ /**
54
+ * Per-field validators for every DESCRIPTIVE field. A detected value
55
+ * and a user-typed value both go through these.
56
+ */
57
+ export declare const PLUGIN_CATALOG_FIELD_SCHEMAS: {
58
+ readonly summary: z.ZodString;
59
+ readonly description: z.ZodString;
60
+ readonly displayName: z.ZodString;
61
+ readonly category: z.ZodEnum<{
62
+ ai: "ai";
63
+ artifact: "artifact";
64
+ deploy: "deploy";
65
+ infrastructure: "infrastructure";
66
+ language: "language";
67
+ monitoring: "monitoring";
68
+ notification: "notification";
69
+ quality: "quality";
70
+ security: "security";
71
+ testing: "testing";
72
+ }>;
73
+ readonly keywords: z.ZodArray<z.ZodString>;
74
+ readonly license: z.ZodString;
75
+ readonly homepageUrl: z.ZodString;
76
+ readonly sourceUrl: z.ZodString;
77
+ readonly documentationUrl: z.ZodString;
78
+ readonly icon: z.ZodPreprocess<z.ZodObject<{
79
+ key: z.ZodString;
80
+ badge: z.ZodOptional<z.ZodString>;
81
+ }, z.core.$strict>>;
82
+ readonly changelog: z.ZodString;
83
+ readonly readme: z.ZodString;
84
+ };
85
+ /**
86
+ * Catalog EDITS (the upload's `metadata` part, a `PUT /plugins/:id` body's
87
+ * descriptive keys, the CLI's `--metadata` file). `null` clears a field.
88
+ * Strict: an unknown key is an error, never silently dropped.
89
+ */
90
+ export declare const PluginCatalogEditsSchema: z.ZodObject<{
91
+ category: z.ZodOptional<z.ZodNullable<z.ZodEnum<{
92
+ ai: "ai";
93
+ artifact: "artifact";
94
+ deploy: "deploy";
95
+ infrastructure: "infrastructure";
96
+ language: "language";
97
+ monitoring: "monitoring";
98
+ notification: "notification";
99
+ quality: "quality";
100
+ security: "security";
101
+ testing: "testing";
102
+ }>>>;
103
+ changelog: z.ZodOptional<z.ZodNullable<z.ZodString>>;
104
+ description: z.ZodOptional<z.ZodNullable<z.ZodString>>;
105
+ displayName: z.ZodOptional<z.ZodNullable<z.ZodString>>;
106
+ documentationUrl: z.ZodOptional<z.ZodNullable<z.ZodString>>;
107
+ homepageUrl: z.ZodOptional<z.ZodNullable<z.ZodString>>;
108
+ icon: z.ZodOptional<z.ZodNullable<z.ZodPreprocess<z.ZodObject<{
109
+ key: z.ZodString;
110
+ badge: z.ZodOptional<z.ZodString>;
111
+ }, z.core.$strict>>>>;
112
+ keywords: z.ZodOptional<z.ZodNullable<z.ZodArray<z.ZodString>>>;
113
+ license: z.ZodOptional<z.ZodNullable<z.ZodString>>;
114
+ readme: z.ZodOptional<z.ZodNullable<z.ZodString>>;
115
+ sourceUrl: z.ZodOptional<z.ZodNullable<z.ZodString>>;
116
+ summary: z.ZodOptional<z.ZodNullable<z.ZodString>>;
117
+ }, z.core.$strict>;
118
+ export type PluginCatalogEdits = z.infer<typeof PluginCatalogEditsSchema>;
119
+ /**
120
+ * Validate one field's value. Returns the normalized value (trimmed text, an
121
+ * icon string as `{ key }`) or the reason it was refused — so a detected value
122
+ * that fails is shown BLANK WITH THE REASON rather than silently dropped.
123
+ */
124
+ export declare function validateCatalogField<F extends PluginCatalogField>(field: F, value: unknown): {
125
+ ok: true;
126
+ value: z.infer<typeof PLUGIN_CATALOG_FIELD_SCHEMAS[F]>;
127
+ } | {
128
+ ok: false;
129
+ error: string;
130
+ };
131
+ /**
132
+ * Keys that describe WHAT RUNS. They come only from the spec: changing one is a
133
+ * new version, a new digest and a review diff. A metadata edit
134
+ * naming any of them is refused with 400 — the refusal is the API's, not just
135
+ * the UI's. `name`/`version` key the pushed image and are immutable too.
136
+ */
137
+ export declare const PLUGIN_CONTRACT_FIELDS: readonly ['name', 'version', 'commands', 'installCommands', 'env', 'buildArgs', 'secrets', 'metadata', 'requiredMetadata', 'requiredVars', 'metadataTypes', 'varsTypes', 'network', 'networkEgress', 'computeType', 'pluginType', 'primaryOutputDirectory', 'smokeTest', 'timeout', 'failureBehavior', 'dockerfile', 'buildType'];
138
+ /** The execution-contract keys present in `payload` (empty when none). */
139
+ export declare function findContractKeys(payload: unknown): string[];
140
+ /** The message a contract-key refusal carries. */
141
+ export declare function contractKeysMessage(keys: readonly string[]): string;