@pipeline-builder/api-core 5.2.3 → 5.2.4

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 (81) hide show
  1. package/lib/constants/ai-providers.d.ts +3 -22
  2. package/lib/constants/ai-providers.js +6 -56
  3. package/lib/errors/app-errors.d.ts +14 -0
  4. package/lib/errors/app-errors.js +21 -1
  5. package/lib/helpers/sse-helpers.d.ts +33 -3
  6. package/lib/helpers/sse-helpers.js +91 -19
  7. package/lib/middleware/auth.js +6 -3
  8. package/lib/middleware/deferred-quota-check.d.ts +5 -0
  9. package/lib/middleware/deferred-quota-check.js +33 -0
  10. package/lib/middleware/ecosystem-guard.d.ts +3 -3
  11. package/lib/middleware/ecosystem-guard.js +5 -5
  12. package/lib/middleware/index.d.ts +5 -2
  13. package/lib/middleware/index.js +6 -3
  14. package/lib/middleware/on-behalf.d.ts +37 -0
  15. package/lib/middleware/on-behalf.js +143 -0
  16. package/lib/middleware/permission-gates.d.ts +11 -0
  17. package/lib/middleware/permission-gates.js +7 -1
  18. package/lib/middleware/quota-exempt-routes.d.ts +36 -0
  19. package/lib/middleware/quota-exempt-routes.js +47 -0
  20. package/lib/middleware/route-table.d.ts +104 -0
  21. package/lib/middleware/route-table.js +72 -2
  22. package/lib/middleware/service-tokens.d.ts +8 -0
  23. package/lib/middleware/service-tokens.js +2 -1
  24. package/lib/middleware/step-up.js +11 -1
  25. package/lib/services/ai-call-weight.d.ts +24 -0
  26. package/lib/services/ai-call-weight.js +77 -0
  27. package/lib/services/audit-context.d.ts +105 -0
  28. package/lib/services/audit-context.js +134 -0
  29. package/lib/services/index.d.ts +7 -2
  30. package/lib/services/index.js +7 -2
  31. package/lib/services/org-ai-client.d.ts +61 -0
  32. package/lib/services/org-ai-client.js +112 -0
  33. package/lib/services/quota-increment-batcher.d.ts +81 -0
  34. package/lib/services/quota-increment-batcher.js +166 -0
  35. package/lib/services/quota.d.ts +158 -14
  36. package/lib/services/quota.js +252 -22
  37. package/lib/services/remote-audit-client.d.ts +44 -1
  38. package/lib/services/remote-audit-client.js +106 -20
  39. package/lib/services/version-vuln-policy.d.ts +174 -0
  40. package/lib/services/version-vuln-policy.js +242 -0
  41. package/lib/types/ai-catalog.d.ts +63 -0
  42. package/lib/types/ai-catalog.js +82 -0
  43. package/lib/types/ask-proposals.js +6 -6
  44. package/lib/types/build-catalog.d.ts +154 -0
  45. package/lib/types/build-catalog.js +158 -0
  46. package/lib/types/common.d.ts +37 -3
  47. package/lib/types/common.js +20 -2
  48. package/lib/types/ecosystem-notifications.d.ts +5 -5
  49. package/lib/types/ecosystem-notifications.js +9 -3
  50. package/lib/types/error-codes.d.ts +13 -6
  51. package/lib/types/error-codes.js +18 -8
  52. package/lib/types/feature-flags.d.ts +6 -4
  53. package/lib/types/feature-flags.js +11 -6
  54. package/lib/types/index.d.ts +6 -4
  55. package/lib/types/index.js +12 -5
  56. package/lib/types/metadata-keys.d.ts +6 -0
  57. package/lib/types/metadata-keys.js +4 -1
  58. package/lib/types/permissions.d.ts +344 -3
  59. package/lib/types/permissions.js +596 -21
  60. package/lib/types/pipeline.d.ts +39 -0
  61. package/lib/types/pipeline.js +57 -1
  62. package/lib/types/plugin-health.d.ts +0 -2
  63. package/lib/types/plugin-health.js +1 -11
  64. package/lib/types/plugin-scan.d.ts +192 -42
  65. package/lib/types/plugin-scan.js +159 -43
  66. package/lib/types/quota-catalog.d.ts +247 -0
  67. package/lib/types/quota-catalog.js +122 -0
  68. package/lib/types/quota-tiers.d.ts +118 -0
  69. package/lib/types/quota-tiers.js +153 -2
  70. package/lib/types/remote-audit-actions.d.ts +1 -1
  71. package/lib/types/remote-audit-actions.js +131 -1
  72. package/lib/types/wire-vocabulary.js +8 -1
  73. package/lib/utils/index.d.ts +1 -1
  74. package/lib/utils/index.js +2 -2
  75. package/lib/utils/response.d.ts +35 -2
  76. package/lib/utils/response.js +42 -3
  77. package/lib/validation/ai-schemas.d.ts +27 -0
  78. package/lib/validation/ai-schemas.js +31 -5
  79. package/lib/validation/plugin-schemas.d.ts +15 -0
  80. package/lib/validation/plugin-schemas.js +28 -1
  81. package/package.json +31 -2
@@ -5,6 +5,7 @@ export { createCacheService, CacheService, } from './cache-service.js';
5
5
  export { withLeaderLock, createEnvRedisLock, leaderLockKey, DEFAULT_LEADER_LOCK_TTL_MS, } from './leader-lock.js';
6
6
  export { sendSystemNotification, SYSTEM_NOTIFY_PATH, } from './system-notification.js';
7
7
  export { createScheduler, } from './scheduler.js';
8
+ export { assessVersionVulns, versionScanFacts, scanFreshness, scanWarnings, lastScannedAt, scanStaleHours, severityOf, maxSeverity, severityAtLeast, VULN_SEVERITIES, setVulnPolicyComplianceClientForTests, } from './version-vuln-policy.js';
8
9
  export { createComplianceClient, } from './compliance-client.js';
9
10
  export { pluginRunsOwnImage, pluginComplianceTags, derivePluginImageCompliance, PLUGIN_IMAGE_COMPLIANCE_FIELDS, } from '../utils/plugin-compliance.js';
10
11
  export * from './compliance-event-subscriber.js';
@@ -22,8 +23,11 @@ export { resetCircuitBreakers, } from './circuit-breaker.js';
22
23
  export { createEnvRedisDurableEventBus, } from './durable-event-bus.js';
23
24
  export { getErrorRetryDecision, } from './retry-strategy.js';
24
25
  export { nextBackoffMs, retryForever, } from './retry-forever.js';
25
- export { getQuotaServiceAuthHeader, createQuotaService, incrementQuota, reserveQuota, sendQuotaReserveDenied, decrementQuota, } from './quota.js';
26
+ export { getQuotaServiceAuthHeader, createQuotaService, incrementQuota, reserveQuota, sendQuotaReserveDenied, decrementQuota, meteredQuotaTypeFor, callQuotaExemption, QUOTA_CHECK_TIMEOUT_MS, quotaAttributionFromRequest, } from './quota.js';
27
+ export { aiCallWeight, parseAiModelWeights, MAX_AI_CALL_WEIGHT, } from './ai-call-weight.js';
28
+ export { QuotaIncrementBatcher, flushQuotaIncrements, QUOTA_INCREMENT_FLUSH_MS, QUOTA_INCREMENT_BUFFER_MAX, MAX_GROUPS_PER_INCREMENT, } from './quota-increment-batcher.js';
26
29
  export { createRemoteAuditClient, wireAuthzDenialAuditor, recordAudit, } from './remote-audit-client.js';
30
+ export { runWithAuditContext, currentAuditContext, auditContextFromRequest, auditAuthBlock, sanitizeCorrelationId, sanitizeUserAgent, AUDIT_CORRELATION_HEADERS, } from './audit-context.js';
27
31
  export { auditSpoolKey, createEnvRedisAuditSpool, } from './audit-spool.js';
28
32
  export { resolveRedisConnection, describeRedisConnection, createRedisClient, createEnvRedisClient, createRedisReadyGate, incrWindow, RedisConfigError, } from './env-redis.js';
29
33
  export { createRedisTokenRevocationStore, createEnvRedisTokenRevocationStore, publishTokenRevocation, publishSessionRevocation, publishCredentialRevocation, } from './token-revocation.js';
@@ -34,4 +38,5 @@ export { alertDeliveryConfig, canDeliverAnywhere, deadmanConfig, reportAlertDeli
34
38
  export { verifyPagerDutySignature, onCallInboundConfig, fetchRotaCoverage, parseOnCallWebhook, ackLatencySeconds, PAGERDUTY_API_URL, } from './pagerduty-inbound.js';
35
39
  export { sendPagerDutyEvent, pagerDutyConfig, resolveEventsEndpoint, PAGERDUTY_EVENTS_URL, } from './pagerduty.js';
36
40
  export { createEcosystemNotifyClient, ECOSYSTEM_NOTIFY_PATH, } from './ecosystem-notify-client.js';
37
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvc2VydmljZXMvaW5kZXgudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsK0NBQStDO0FBQy9DLHNDQUFzQztBQUV0QyxPQUFPLEVBQ0wsY0FBYyxFQUNkLHdCQUF3QixFQUN4QixtQkFBbUIsRUFDbkIsOEJBQThCLEdBQy9CLE1BQU0sdUJBQXVCLENBQUM7QUFDL0IsT0FBTyxFQUNMLGtCQUFrQixFQUtsQixZQUFZLEdBQ2IsTUFBTSxvQkFBb0IsQ0FBQztBQUM1QixPQUFPLEVBQ0wsY0FBYyxFQUNkLGtCQUFrQixFQUNsQixhQUFhLEVBQ2IsMEJBQTBCLEdBSzNCLE1BQU0sa0JBQWtCLENBQUM7QUFDMUIsT0FBTyxFQUNMLHNCQUFzQixFQUN0QixrQkFBa0IsR0FFbkIsTUFBTSwwQkFBMEIsQ0FBQztBQUNsQyxPQUFPLEVBQ0wsZUFBZSxHQUdoQixNQUFNLGdCQUFnQixDQUFDO0FBQ3hCLE9BQU8sRUFDTCxzQkFBc0IsR0FHdkIsTUFBTSx3QkFBd0IsQ0FBQztBQUNoQyxPQUFPLEVBQ0wsa0JBQWtCLEVBQ2xCLG9CQUFvQixFQUNwQiwyQkFBMkIsRUFFM0IsOEJBQThCLEdBRS9CLE1BQU0sK0JBQStCLENBQUM7QUFDdkMsY0FBYyxrQ0FBa0MsQ0FBQztBQUNqRCxPQUFPLEVBR0wsWUFBWSxHQUNiLE1BQU0sb0JBQW9CLENBQUM7QUFDNUIsT0FBTyxFQUNMLHVCQUF1QixFQUN2QixnQkFBZ0IsRUFDaEIscUJBQXFCLEVBQ3JCLGtCQUFrQixHQUNuQixNQUFNLGtCQUFrQixDQUFDO0FBQzFCLE9BQU8sRUFDTCxvQkFBb0IsRUFDcEIsb0JBQW9CLEVBQ3BCLGVBQWUsRUFDZixTQUFTLEdBQ1YsTUFBTSxpQkFBaUIsQ0FBQztBQUN6QixpRkFBaUY7QUFDakYsOEVBQThFO0FBQzlFLGlGQUFpRjtBQUNqRiwrREFBK0Q7QUFDL0QsT0FBTyxFQUNMLFlBQVksRUFDWixlQUFlLEVBQ2YsZ0JBQWdCLEdBQ2pCLE1BQU0sbUJBQW1CLENBQUM7QUFDM0IsK0VBQStFO0FBQy9FLHlEQUF5RDtBQUN6RCxPQUFPLEVBQ0wsb0JBQW9CLEdBQ3JCLE1BQU0sc0JBQXNCLENBQUM7QUFDOUIsT0FBTyxFQUNMLDZCQUE2QixHQUc5QixNQUFNLHdCQUF3QixDQUFDO0FBQ2hDLE9BQU8sRUFDTCxxQkFBcUIsR0FDdEIsTUFBTSxxQkFBcUIsQ0FBQztBQUk3QixPQUFPLEVBQ0wsYUFBYSxFQUNiLFlBQVksR0FDYixNQUFNLG9CQUFvQixDQUFDO0FBQzVCLE9BQU8sRUFDTCx5QkFBeUIsRUFDekIsa0JBQWtCLEVBQ2xCLGNBQWMsRUFDZCxZQUFZLEVBQ1osc0JBQXNCLEVBQ3RCLGNBQWMsR0FHZixNQUFNLFlBQVksQ0FBQztBQUNwQixPQUFPLEVBQ0wsdUJBQXVCLEVBQ3ZCLHNCQUFzQixFQUN0QixXQUFXLEdBR1osTUFBTSwwQkFBMEIsQ0FBQztBQUNsQyxPQUFPLEVBQ0wsYUFBYSxFQUNiLHdCQUF3QixHQUV6QixNQUFNLGtCQUFrQixDQUFDO0FBQzFCLE9BQU8sRUFDTCxzQkFBc0IsRUFDdEIsdUJBQXVCLEVBQ3ZCLGlCQUFpQixFQUNqQixvQkFBb0IsRUFDcEIsb0JBQW9CLEVBQ3BCLFVBQVUsRUFDVixnQkFBZ0IsR0FFakIsTUFBTSxnQkFBZ0IsQ0FBQztBQUN4QixPQUFPLEVBQ0wsK0JBQStCLEVBQy9CLGtDQUFrQyxFQUNsQyxzQkFBc0IsRUFDdEIsd0JBQXdCLEVBQ3hCLDJCQUEyQixHQUM1QixNQUFNLHVCQUF1QixDQUFDO0FBQy9CLE9BQU8sRUFDTCwwQkFBMEIsRUFDMUIsdUJBQXVCLEVBQ3ZCLGdCQUFnQixHQUlqQixNQUFNLHVCQUF1QixDQUFDO0FBQy9CLE9BQU8sRUFDTCxtQkFBbUIsR0FDcEIsTUFBTSxtQkFBbUIsQ0FBQztBQUMzQixPQUFPLEVBQ0wsb0JBQW9CLEVBQ3BCLGtCQUFrQixFQUNsQixxQkFBcUIsR0FNdEIsTUFBTSw0QkFBNEIsQ0FBQztBQUNwQyxPQUFPLEVBQ0wsbUJBQW1CLEVBQ25CLGtCQUFrQixFQUNsQixhQUFhLEVBQ2IsMEJBQTBCLEVBQzFCLGlCQUFpQixFQUNqQixxQkFBcUIsRUFDckIsb0JBQW9CLEdBSXJCLE1BQU0scUJBQXFCLENBQUM7QUFDN0IsT0FBTyxFQUNMLHdCQUF3QixFQUN4QixtQkFBbUIsRUFDbkIsaUJBQWlCLEVBQ2pCLGtCQUFrQixFQUNsQixpQkFBaUIsRUFDakIsaUJBQWlCLEdBS2xCLE1BQU0sd0JBQXdCLENBQUM7QUFDaEMsT0FBTyxFQUNMLGtCQUFrQixFQUNsQixlQUFlLEVBQ2YscUJBQXFCLEVBQ3JCLG9CQUFvQixHQU9yQixNQUFNLGdCQUFnQixDQUFDO0FBQ3hCLE9BQU8sRUFDTCwyQkFBMkIsRUFDM0IscUJBQXFCLEdBRXRCLE1BQU0sOEJBQThCLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyIvLyBDb3B5cmlnaHQgMjAyNiBQaXBlbGluZSBCdWlsZGVyIENvbnRyaWJ1dG9yc1xuLy8gU1BEWC1MaWNlbnNlLUlkZW50aWZpZXI6IEFwYWNoZS0yLjBcblxuZXhwb3J0IHtcbiAgZXhjaGFuZ2VBcGlLZXksXG4gIHJlc2V0QXBpS2V5RXhjaGFuZ2VDYWNoZSxcbiAgQXBpS2V5UmVqZWN0ZWRFcnJvcixcbiAgQXBpS2V5RXhjaGFuZ2VVbmF2YWlsYWJsZUVycm9yLFxufSBmcm9tICcuL2FwaS1rZXktZXhjaGFuZ2UuanMnO1xuZXhwb3J0IHtcbiAgY3JlYXRlQ2FjaGVTZXJ2aWNlLFxuICB0eXBlIFJlZGlzQ2FjaGVDbGllbnQsXG4gIHR5cGUgQ2FjaGVJbnZhbGlkYXRpb25NZXNzYWdlLFxuICB0eXBlIENhY2hlSW52YWxpZGF0aW9uQnVzLFxuICB0eXBlIFJlZGlzSW52YWxpZGF0aW9uQ2xpZW50LFxuICBDYWNoZVNlcnZpY2UsXG59IGZyb20gJy4vY2FjaGUtc2VydmljZS5qcyc7XG5leHBvcnQge1xuICB3aXRoTGVhZGVyTG9jayxcbiAgY3JlYXRlRW52UmVkaXNMb2NrLFxuICBsZWFkZXJMb2NrS2V5LFxuICBERUZBVUxUX0xFQURFUl9MT0NLX1RUTF9NUyxcbiAgdHlwZSBMb2NrUmVkaXMsXG4gIHR5cGUgTGVhZGVyTG9ja1J1bixcbiAgdHlwZSBMZWFkZXJMb2NrT3B0aW9ucyxcbiAgdHlwZSBMZWFkZXJMb2NrQWJvcnRSZWFzb24sXG59IGZyb20gJy4vbGVhZGVyLWxvY2suanMnO1xuZXhwb3J0IHtcbiAgc2VuZFN5c3RlbU5vdGlmaWNhdGlvbixcbiAgU1lTVEVNX05PVElGWV9QQVRILFxuICB0eXBlIFN5c3RlbU5vdGlmaWNhdGlvbixcbn0gZnJvbSAnLi9zeXN0ZW0tbm90aWZpY2F0aW9uLmpzJztcbmV4cG9ydCB7XG4gIGNyZWF0ZVNjaGVkdWxlcixcbiAgdHlwZSBTY2hlZHVsZXJPcHRpb25zLFxuICB0eXBlIFNjaGVkdWxlcixcbn0gZnJvbSAnLi9zY2hlZHVsZXIuanMnO1xuZXhwb3J0IHtcbiAgY3JlYXRlQ29tcGxpYW5jZUNsaWVudCxcbiAgdHlwZSBDb21wbGlhbmNlQ2hlY2tSZXN1bHQsXG4gIHR5cGUgQ29tcGxpYW5jZVZpb2xhdGlvbixcbn0gZnJvbSAnLi9jb21wbGlhbmNlLWNsaWVudC5qcyc7XG5leHBvcnQge1xuICBwbHVnaW5SdW5zT3duSW1hZ2UsXG4gIHBsdWdpbkNvbXBsaWFuY2VUYWdzLFxuICBkZXJpdmVQbHVnaW5JbWFnZUNvbXBsaWFuY2UsXG4gIHR5cGUgUGx1Z2luQ29tcGxpYW5jZUF0dHJpYnV0ZXMsXG4gIFBMVUdJTl9JTUFHRV9DT01QTElBTkNFX0ZJRUxEUyxcbiAgdHlwZSBQbHVnaW5JbWFnZVJvdyxcbn0gZnJvbSAnLi4vdXRpbHMvcGx1Z2luLWNvbXBsaWFuY2UuanMnO1xuZXhwb3J0ICogZnJvbSAnLi9jb21wbGlhbmNlLWV2ZW50LXN1YnNjcmliZXIuanMnO1xuZXhwb3J0IHtcbiAgdHlwZSBFbnRpdHlFdmVudCxcbiAgdHlwZSBFbnRpdHlFdmVudFN1YnNjcmliZXIsXG4gIGVudGl0eUV2ZW50cyxcbn0gZnJvbSAnLi9lbnRpdHktZXZlbnRzLmpzJztcbmV4cG9ydCB7XG4gIGRlc3Ryb3lTaGFyZWRIdHRwQWdlbnRzLFxuICBjcmVhdGVTYWZlQ2xpZW50LFxuICBSZXNwb25zZVRvb0xhcmdlRXJyb3IsXG4gIEludGVybmFsSHR0cENsaWVudCxcbn0gZnJvbSAnLi9odHRwLWNsaWVudC5qcyc7XG5leHBvcnQge1xuICBzZXRQbGF0Zm9ybUp3a3NDYWNoZSxcbiAgSndrc1VuYXZhaWxhYmxlRXJyb3IsXG4gIFVua25vd25LaWRFcnJvcixcbiAgSndrc0NhY2hlLFxufSBmcm9tICcuL2p3a3MtY2FjaGUuanMnO1xuLy8gU2VydmljZS1rZXkgaW50ZXJuYWxzIHN0YXkgaW50ZXJuYWwuIFRoZSBwYWNrYWdlIHN1cmZhY2UgaXMgdGhlIHZlcmlmeS9pbnNwZWN0XG4vLyBzaWRlIHRoYXQgcGxhdGZvcm0ncyBKV1Qgb3B0aW9ucyBhbmQgdGhlIGF1dGggbWlkZGxld2FyZSBuZWVkOyBrZXkgTUFURVJJQUxcbi8vIGhhbmRsaW5nIChgc2lnblNlcnZpY2VKd3RgLCB0aGUgYnVuZGxlLCB0aGUgdGVzdCByZXNldCBob29rKSBpcyByZWFjaGFibGUgb25seVxuLy8gYnkgZGVlcCBpbXBvcnQgZnJvbSBpbnNpZGUgYXBpLWNvcmUgYW5kIGl0cyB0ZXN0aW5nIGhlbHBlcnMuXG5leHBvcnQge1xuICBpc1NlcnZpY2VLaWQsXG4gIHNlcnZpY2VJZGVudGl0eSxcbiAgdmVyaWZ5U2VydmljZUp3dCxcbn0gZnJvbSAnLi9zZXJ2aWNlLWtleXMuanMnO1xuLy8gVGhlIGJyZWFrZXIgaXMgd2lyZWQgYnkgdGhlIHNoYXJlZCBIVFRQIGNsaWVudDsgc2VydmljZXMgY29uc3VtZSBpdHMgRUZGRUNULFxuLy8gbm90IHRoZSBjbGFzcy4gT25seSB0aGUgb3BlcmF0aW9uYWwgc3VyZmFjZSBpcyBwdWJsaWMuXG5leHBvcnQge1xuICByZXNldENpcmN1aXRCcmVha2Vycyxcbn0gZnJvbSAnLi9jaXJjdWl0LWJyZWFrZXIuanMnO1xuZXhwb3J0IHtcbiAgY3JlYXRlRW52UmVkaXNEdXJhYmxlRXZlbnRCdXMsXG4gIHR5cGUgRXZlbnRTdWJzY3JpcHRpb24sXG4gIHR5cGUgRHVyYWJsZUV2ZW50QnVzLFxufSBmcm9tICcuL2R1cmFibGUtZXZlbnQtYnVzLmpzJztcbmV4cG9ydCB7XG4gIGdldEVycm9yUmV0cnlEZWNpc2lvbixcbn0gZnJvbSAnLi9yZXRyeS1zdHJhdGVneS5qcyc7XG5leHBvcnQgdHlwZSB7XG4gIFJldHJ5Q29uZmlnLFxufSBmcm9tICcuL3JldHJ5LXN0cmF0ZWd5LmpzJztcbmV4cG9ydCB7XG4gIG5leHRCYWNrb2ZmTXMsXG4gIHJldHJ5Rm9yZXZlcixcbn0gZnJvbSAnLi9yZXRyeS1mb3JldmVyLmpzJztcbmV4cG9ydCB7XG4gIGdldFF1b3RhU2VydmljZUF1dGhIZWFkZXIsXG4gIGNyZWF0ZVF1b3RhU2VydmljZSxcbiAgaW5jcmVtZW50UXVvdGEsXG4gIHJlc2VydmVRdW90YSxcbiAgc2VuZFF1b3RhUmVzZXJ2ZURlbmllZCxcbiAgZGVjcmVtZW50UXVvdGEsXG4gIHR5cGUgUXVvdGFSZXNlcnZlUmVzdWx0LFxuICB0eXBlIFF1b3RhU2VydmljZSxcbn0gZnJvbSAnLi9xdW90YS5qcyc7XG5leHBvcnQge1xuICBjcmVhdGVSZW1vdGVBdWRpdENsaWVudCxcbiAgd2lyZUF1dGh6RGVuaWFsQXVkaXRvcixcbiAgcmVjb3JkQXVkaXQsXG4gIHR5cGUgUmVtb3RlQXVkaXRFdmVudCxcbiAgdHlwZSBSZW1vdGVBdWRpdENsaWVudCxcbn0gZnJvbSAnLi9yZW1vdGUtYXVkaXQtY2xpZW50LmpzJztcbmV4cG9ydCB7XG4gIGF1ZGl0U3Bvb2xLZXksXG4gIGNyZWF0ZUVudlJlZGlzQXVkaXRTcG9vbCxcbiAgdHlwZSBBdWRpdFNwb29sLFxufSBmcm9tICcuL2F1ZGl0LXNwb29sLmpzJztcbmV4cG9ydCB7XG4gIHJlc29sdmVSZWRpc0Nvbm5lY3Rpb24sXG4gIGRlc2NyaWJlUmVkaXNDb25uZWN0aW9uLFxuICBjcmVhdGVSZWRpc0NsaWVudCxcbiAgY3JlYXRlRW52UmVkaXNDbGllbnQsXG4gIGNyZWF0ZVJlZGlzUmVhZHlHYXRlLFxuICBpbmNyV2luZG93LFxuICBSZWRpc0NvbmZpZ0Vycm9yLFxuICB0eXBlIFJlZGlzRXZhbENsaWVudCxcbn0gZnJvbSAnLi9lbnYtcmVkaXMuanMnO1xuZXhwb3J0IHtcbiAgY3JlYXRlUmVkaXNUb2tlblJldm9jYXRpb25TdG9yZSxcbiAgY3JlYXRlRW52UmVkaXNUb2tlblJldm9jYXRpb25TdG9yZSxcbiAgcHVibGlzaFRva2VuUmV2b2NhdGlvbixcbiAgcHVibGlzaFNlc3Npb25SZXZvY2F0aW9uLFxuICBwdWJsaXNoQ3JlZGVudGlhbFJldm9jYXRpb24sXG59IGZyb20gJy4vdG9rZW4tcmV2b2NhdGlvbi5qcyc7XG5leHBvcnQge1xuICBjcmVhdGVNZW1vcnlTc2VUaWNrZXRTdG9yZSxcbiAgY3JlYXRlRW52U3NlVGlja2V0U3RvcmUsXG4gIGVudlNzZVRpY2tldENhcHMsXG4gIHR5cGUgRW52U3NlVGlja2V0U3RvcmVDb25maWcsXG4gIHR5cGUgU3NlVGlja2V0U3RvcmUsXG4gIHR5cGUgU3NlVGlja2V0U3RvcmVDb25maWcsXG59IGZyb20gJy4vc3NlLXRpY2tldC1zdG9yZS5qcyc7XG5leHBvcnQge1xuICB3aXJlU2VydmljZVNlY3VyaXR5LFxufSBmcm9tICcuL3NlcnZpY2UtYm9vdC5qcyc7XG5leHBvcnQge1xuICBjcmVhdGVXZWJob29rQ2hhbm5lbCxcbiAgY3JlYXRlRW1haWxDaGFubmVsLFxuICBjcmVhdGVDaGFubmVsUmVnaXN0cnksXG4gIHR5cGUgTm90aWZpY2F0aW9uUHJpb3JpdHksXG4gIHR5cGUgTm90aWZpY2F0aW9uTWVzc2FnZSxcbiAgdHlwZSBDaGFubmVsVGFyZ2V0LFxuICB0eXBlIERlbGl2ZXJ5UmVzdWx0LFxuICB0eXBlIE5vdGlmaWNhdGlvbkNoYW5uZWwsXG59IGZyb20gJy4vbm90aWZpY2F0aW9uLWNoYW5uZWxzLmpzJztcbmV4cG9ydCB7XG4gIGFsZXJ0RGVsaXZlcnlDb25maWcsXG4gIGNhbkRlbGl2ZXJBbnl3aGVyZSxcbiAgZGVhZG1hbkNvbmZpZyxcbiAgcmVwb3J0QWxlcnREZWxpdmVyeVBvc3R1cmUsXG4gIHNsYWNrQWxlcnRzQ29uZmlnLFxuICBzdGFydERlYWRtYW5IZWFydGJlYXQsXG4gIHN0b3BEZWFkbWFuSGVhcnRiZWF0LFxuICB0eXBlIERlYWRtYW5Db25maWcsXG4gIHR5cGUgQWxlcnREZWxpdmVyeUNvbmZpZyxcbiAgdHlwZSBTbGFja0FsZXJ0c0NvbmZpZyxcbn0gZnJvbSAnLi9hbGVydC1kZWxpdmVyeS5qcyc7XG5leHBvcnQge1xuICB2ZXJpZnlQYWdlckR1dHlTaWduYXR1cmUsXG4gIG9uQ2FsbEluYm91bmRDb25maWcsXG4gIGZldGNoUm90YUNvdmVyYWdlLFxuICBwYXJzZU9uQ2FsbFdlYmhvb2ssXG4gIGFja0xhdGVuY3lTZWNvbmRzLFxuICBQQUdFUkRVVFlfQVBJX1VSTCxcbiAgdHlwZSBPbkNhbGxJbmJvdW5kQ29uZmlnLFxuICB0eXBlIE9uQ2FsbFdlYmhvb2tFdmVudCxcbiAgdHlwZSBPbkNhbGxXZWJob29rRXZlbnRUeXBlLFxuICB0eXBlIFJvdGFDb3ZlcmFnZSxcbn0gZnJvbSAnLi9wYWdlcmR1dHktaW5ib3VuZC5qcyc7XG5leHBvcnQge1xuICBzZW5kUGFnZXJEdXR5RXZlbnQsXG4gIHBhZ2VyRHV0eUNvbmZpZyxcbiAgcmVzb2x2ZUV2ZW50c0VuZHBvaW50LFxuICBQQUdFUkRVVFlfRVZFTlRTX1VSTCxcbiAgdHlwZSBPbkNhbGxQcm92aWRlcixcbiAgdHlwZSBQYWdlckR1dHlBY3Rpb24sXG4gIHR5cGUgUGFnZXJEdXR5Q29uZmlnLFxuICB0eXBlIFBhZ2VyRHV0eUV2ZW50LFxuICB0eXBlIFBhZ2VyRHV0eVJlc3VsdCxcbiAgdHlwZSBQYWdlckR1dHlTZXZlcml0eSxcbn0gZnJvbSAnLi9wYWdlcmR1dHkuanMnO1xuZXhwb3J0IHtcbiAgY3JlYXRlRWNvc3lzdGVtTm90aWZ5Q2xpZW50LFxuICBFQ09TWVNURU1fTk9USUZZX1BBVEgsXG4gIHR5cGUgRWNvc3lzdGVtTm90aWZ5Q2xpZW50LFxufSBmcm9tICcuL2Vjb3N5c3RlbS1ub3RpZnktY2xpZW50LmpzJztcbiJdfQ==
41
+ export { fetchOrgAIAccess, fetchOrgAIKey, assertOrgAIEnabled, requireOrgAIEnabled, resetOrgAICache, ORG_AI_ACCESS_PATH, ORG_AI_KEYS_PATH, } from './org-ai-client.js';
42
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvc2VydmljZXMvaW5kZXgudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsK0NBQStDO0FBQy9DLHNDQUFzQztBQUV0QyxPQUFPLEVBQ0wsY0FBYyxFQUNkLHdCQUF3QixFQUN4QixtQkFBbUIsRUFDbkIsOEJBQThCLEdBQy9CLE1BQU0sdUJBQXVCLENBQUM7QUFDL0IsT0FBTyxFQUNMLGtCQUFrQixFQUtsQixZQUFZLEdBQ2IsTUFBTSxvQkFBb0IsQ0FBQztBQUM1QixPQUFPLEVBQ0wsY0FBYyxFQUNkLGtCQUFrQixFQUNsQixhQUFhLEVBQ2IsMEJBQTBCLEdBSzNCLE1BQU0sa0JBQWtCLENBQUM7QUFDMUIsT0FBTyxFQUNMLHNCQUFzQixFQUN0QixrQkFBa0IsR0FFbkIsTUFBTSwwQkFBMEIsQ0FBQztBQUNsQyxPQUFPLEVBQ0wsZUFBZSxHQUdoQixNQUFNLGdCQUFnQixDQUFDO0FBQ3hCLE9BQU8sRUFDTCxrQkFBa0IsRUFDbEIsZ0JBQWdCLEVBQ2hCLGFBQWEsRUFDYixZQUFZLEVBQ1osYUFBYSxFQUNiLGNBQWMsRUFDZCxVQUFVLEVBQ1YsV0FBVyxFQUNYLGVBQWUsRUFDZixlQUFlLEVBQ2YscUNBQXFDLEdBU3RDLE1BQU0sMEJBQTBCLENBQUM7QUFDbEMsT0FBTyxFQUNMLHNCQUFzQixHQUd2QixNQUFNLHdCQUF3QixDQUFDO0FBQ2hDLE9BQU8sRUFDTCxrQkFBa0IsRUFDbEIsb0JBQW9CLEVBQ3BCLDJCQUEyQixFQUUzQiw4QkFBOEIsR0FFL0IsTUFBTSwrQkFBK0IsQ0FBQztBQUN2QyxjQUFjLGtDQUFrQyxDQUFDO0FBQ2pELE9BQU8sRUFHTCxZQUFZLEdBQ2IsTUFBTSxvQkFBb0IsQ0FBQztBQUM1QixPQUFPLEVBQ0wsdUJBQXVCLEVBQ3ZCLGdCQUFnQixFQUNoQixxQkFBcUIsRUFDckIsa0JBQWtCLEdBQ25CLE1BQU0sa0JBQWtCLENBQUM7QUFDMUIsT0FB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Q2xCLG1CQUFtQixFQUNuQixlQUFlLEVBQ2Ysa0JBQWtCLEVBQ2xCLGdCQUFnQixHQUVqQixNQUFNLG9CQUFvQixDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiLy8gQ29weXJpZ2h0IDIwMjYgUGlwZWxpbmUgQnVpbGRlciBDb250cmlidXRvcnNcbi8vIFNQRFgtTGljZW5zZS1JZGVudGlmaWVyOiBBcGFjaGUtMi4wXG5cbmV4cG9ydCB7XG4gIGV4Y2hhbmdlQXBpS2V5LFxuICByZXNldEFwaUtleUV4Y2hhbmdlQ2FjaGUsXG4gIEFwaUtleVJlamVjdGVkRXJyb3IsXG4gIEFwaUtleUV4Y2hhbmdlVW5hdmFpbGFibGVFcnJvcixcbn0gZnJvbSAnLi9hcGkta2V5LWV4Y2hhbmdlLmpzJztcbmV4cG9ydCB7XG4gIGNyZWF0ZUNhY2hlU2VydmljZSxcbiAgdHlwZSBSZWRpc0NhY2hlQ2xpZW50LFxuICB0eXBlIENhY2hlSW52YWxpZGF0aW9uTWVzc2FnZSxcbiAgdHlwZSBDYWNoZUludmFsaWRhdGlvbkJ1cyxcbiAgdHlwZSBSZWRpc0ludmFsaWRhdGlvbkNsaWVudCxcbiAgQ2FjaGVTZXJ2aWNlLFxufSBmcm9tICcuL2NhY2hlLXNlcnZpY2UuanMnO1xuZXhwb3J0IHtcbiAgd2l0aExlYWRlckxvY2ssXG4gIGNyZWF0ZUVudlJlZGlzTG9jayxcbiAgbGVhZGVyTG9ja0tleSxcbiAgREVGQVVMVF9MRUFERVJfTE9DS19UVExfTVMsXG4gIHR5cGUgTG9ja1JlZGlzLFxuICB0eXBlIExlYWRlckxvY2tSdW4sXG4gIHR5cGUgTGVhZGVyTG9ja09wdGlvbnMsXG4gIHR5cGUgTGVhZGVyTG9ja0Fib3J0UmVhc29uLFxufSBmcm9tICcuL2xlYWRlci1sb2NrLmpzJztcbmV4cG9ydCB7XG4gIHNlbmRTeXN0ZW1Ob3RpZmljYXRpb24sXG4gIFNZU1RFTV9OT1RJRllfUEFUSCxcbiAgdHlwZSBTeXN0ZW1Ob3RpZmljYXRpb24sXG59IGZyb20gJy4vc3lzdGVtLW5vdGlmaWNhdGlvbi5qcyc7XG5leHBvcnQge1xuICBjcmVhdGVTY2hlZHVsZXIsXG4gIHR5cGUgU2NoZWR1bGVyT3B0aW9ucyxcbiAgdHlwZSBTY2hlZHVsZXIsXG59IGZyb20gJy4vc2NoZWR1bGVyLmpzJztcbmV4cG9ydCB7XG4gIGFzc2Vzc1ZlcnNpb25WdWxucyxcbiAgdmVyc2lvblNjYW5GYWN0cyxcbiAgc2NhbkZyZXNobmVzcyxcbiAgc2Nhbldhcm5pbmdzLFxuICBsYXN0U2Nhbm5lZEF0LFxuICBzY2FuU3RhbGVIb3VycyxcbiAgc2V2ZXJpdHlPZixcbiAgbWF4U2V2ZXJpdHksXG4gIHNldmVyaXR5QXRMZWFzdCxcbiAgVlVMTl9TRVZFUklUSUVTLFxuICBzZXRWdWxuUG9saWN5Q29tcGxpYW5jZUNsaWVudEZvclRlc3RzLFxuICB0eXBlIFZ1bG5TZXZlcml0eSxcbiAgdHlwZSBWdWxuV2FybmluZyxcbiAgdHlwZSBTY2FubmVkUmVjb3JkLFxuICB0eXBlIFZ1bG5Db25zdW1wdGlvblBvbGljeSxcbiAgdHlwZSBWdWxuQWNjZXB0YW5jZSxcbiAgdHlwZSBWZXJzaW9uU2NhbkZhY3RzLFxuICB0eXBlIFZlcnNpb25WdWxuSW5wdXQsXG4gIHR5cGUgVmVyc2lvblZ1bG5Bc3Nlc3NtZW50LFxufSBmcm9tICcuL3ZlcnNpb24tdnVsbi1wb2xpY3kuanMnO1xuZXhwb3J0IHtcbiAgY3JlYXRlQ29tcGxpYW5jZUNsaWVudCxcbiAgdHlwZSBDb21wbGlhbmNlQ2hlY2tSZXN1bHQsXG4gIHR5cGUgQ29tcGxpYW5jZVZpb2xhdGlvbixcbn0gZnJvbSAnLi9jb21wbGlhbmNlLWNsaWVudC5qcyc7XG5leHBvcnQge1xuICBwbHVnaW5SdW5zT3duSW1hZ2UsXG4gIHBsdWdpbkNvbXBsaWFuY2VUYWdzLFxuICBkZXJpdmVQbHVnaW5JbWFnZUNvbXBsaWFuY2UsXG4gIHR5cGUgUGx1Z2luQ29tcGxpYW5jZUF0dHJpYnV0ZXMsXG4gIFBMVUdJTl9JTUFHRV9DT01QTElBTkNFX0ZJRUxEUyxcbiAgdHlwZSBQbHVnaW5JbWFnZVJvdyxcbn0gZnJvbSAnLi4vdXRpbHMvcGx1Z2luLWNvbXBsaWFuY2UuanMnO1xuZXhwb3J0ICogZnJvbSAnLi9jb21wbGlhbmNlLWV2ZW50LXN1YnNjcmliZXIuanMnO1xuZXhwb3J0IHtcbiAgdHlwZSBFbnRpdHlFdmVudCxcbiAgdHlwZSBFbnRpdHlFdmVudFN1YnNjcmliZXIsXG4gIGVudGl0eUV2ZW50cyxcbn0gZnJvbSAnLi9lbnRpdHktZXZlbnRzLmpzJztcbmV4cG9ydCB7XG4gIGRlc3Ryb3lTaGFyZWRIdHRwQWdlbnRzLFxuICBjcmVhdGVTYWZlQ2xpZW50LFxuICBSZXNwb25zZVRvb0xhcmdlRXJyb3IsXG4gIEludGVybmFsSHR0cENsaWVudCxcbn0gZnJvbSAnLi9odHRwLWNsaWVudC5qcyc7XG5leHBvcnQge1xuICBzZXRQbGF0Zm9ybUp3a3NDYWNoZSxcbiAgSndrc1VuYXZhaWxhYmxlRXJyb3IsXG4gIFVua25vd25LaWRFcnJvcixcbiAgSndrc0NhY2hlLFxufSBmcm9tICcuL2p3a3MtY2FjaGUuanMnO1xuLy8gU2VydmljZS1rZXkgaW50ZXJuYWxzIHN0YXkgaW50ZXJuYWwuIFRoZSBwYWNrYWdlIHN1cmZhY2UgaXMgdGhlIHZlcmlmeS9pbnNwZWN0XG4vLyBzaWRlIHRoYXQgcGxhdGZvcm0ncyBKV1Qgb3B0aW9ucyBhbmQgdGhlIGF1dGggbWlkZGxld2FyZSBuZWVkOyBrZXkgTUFURVJJQUxcbi8vIGhhbmRsaW5nIChgc2lnblNlcnZpY2VKd3RgLCB0aGUgYnVuZGxlLCB0aGUgdGVzdCByZXNldCBob29rKSBpcyByZWFjaGFibGUgb25seVxuLy8gYnkgZGVlcCBpbXBvcnQgZnJvbSBpbnNpZGUgYXBpLWNvcmUgYW5kIGl0cyB0ZXN0aW5nIGhlbHBlcnMuXG5leHBvcnQge1xuICBpc1NlcnZpY2VLaWQsXG4gIHNlcnZpY2VJZGVudGl0eSxcbiAgdmVyaWZ5U2VydmljZUp3dCxcbn0gZnJvbSAnLi9zZXJ2aWNlLWtleXMuanMnO1xuLy8gVGhlIGJyZWFrZXIgaXMgd2lyZWQgYnkgdGhlIHNoYXJlZCBIVFRQIGNsaWVudDsgc2VydmljZXMgY29uc3VtZSBpdHMgRUZGRUNULFxuLy8gbm90IHRoZSBjbGFzcy4gT25seSB0aGUgb3BlcmF0aW9uYWwgc3VyZmFjZSBpcyBwdWJsaWMuXG5leHBvcnQge1xuICByZXNldENpcmN1aXRCcmVha2Vycyxcbn0gZnJvbSAnLi9jaXJjdWl0LWJyZWFrZXIuanMnO1xuZXhwb3J0IHtcbiAgY3JlYXRlRW52UmVkaXNEdXJhYmxlRXZlbnRCdXMsXG4gIHR5cGUgRXZlbnRTdWJzY3JpcHRpb24sXG4gIHR5cGUgRHVyYWJsZUV2ZW50QnVzLFxufSBmcm9tICcuL2R1cmFibGUtZXZlbnQtYnVzLmpzJztcbmV4cG9ydCB7XG4gIGdldEVycm9yUmV0cnlEZWNpc2lvbixcbn0gZnJvbSAnLi9yZXRyeS1zdHJhdGVneS5qcyc7XG5leHBvcnQgdHlwZSB7XG4gIFJldHJ5Q29uZmlnLFxufSBmcm9tICcuL3JldHJ5LXN0cmF0ZWd5LmpzJztcbmV4cG9ydCB7XG4gIG5leHRCYWNrb2ZmTXMsXG4gIHJldHJ5Rm9yZXZlcixcbn0gZnJvbSAnLi9yZXRyeS1mb3JldmVyLmpzJztcbmV4cG9ydCB7XG4gIGdldFF1b3RhU2VydmljZUF1dGhIZWFkZXIsXG4gIGNyZWF0ZVF1b3RhU2VydmljZSxcbiAgaW5jcmVtZW50UXVvdGEsXG4gIHJlc2VydmVRdW90YSxcbiAgc2VuZFF1b3RhUmVzZXJ2ZURlbmllZCxcbiAgZGVjcmVtZW50UXVvdGEsXG4gIG1ldGVyZWRRdW90YVR5cGVGb3IsXG4gIGNhbGxRdW90YUV4ZW1wdGlvbixcbiAgUVVPVEFfQ0hFQ0tfVElNRU9VVF9NUyxcbiAgcXVvdGFBdHRyaWJ1dGlvbkZyb21SZXF1ZXN0LFxuICB0eXBlIEFpS2V5U291cmNlLFxuICB0eXBlIEFpTGltaXRDb2RlLFxuICB0eXBlIENhbGxRdW90YUV4ZW1wdGlvbixcbiAgdHlwZSBRdW90YVJlc2VydmVSZXN1bHQsXG4gIHR5cGUgUXVvdGFUb2tlblVzYWdlLFxuICB0eXBlIFF1b3RhU2VydmljZSxcbiAgdHlwZSBRdW90YVVzYWdlQXR0cmlidXRpb24sXG59IGZyb20gJy4vcXVvdGEuanMnO1xuZXhwb3J0IHtcbiAgYWlDYWxsV2VpZ2h0LFxuICBwYXJzZUFpTW9kZWxXZWlnaHRzLFxuICBNQVhfQUlfQ0FMTF9XRUlHSFQsXG59IGZyb20gJy4vYWktY2FsbC13ZWlnaHQuanMnO1xuZXhwb3J0IHtcbiAgUXVvdGFJbmNyZW1lbnRCYXRjaGVyLFxuICBmbHVzaFF1b3RhSW5jcmVtZW50cyxcbiAgUVVPVEFfSU5DUkVNRU5UX0ZMVVNIX01TLFxuICBRVU9UQV9JTkNSRU1FTlRfQlVGRkVSX01BWCxcbiAgTUFYX0dST1VQU19QRVJfSU5DUkVNRU5ULFxuICB0eXBlIE1ldGVyZWRJbmNyZW1lbnRHcm91cCxcbn0gZnJvbSAnLi9xdW90YS1pbmNyZW1lbnQtYmF0Y2hlci5qcyc7XG5leHBvcnQge1xuICBjcmVhdGVSZW1vdGVBdWRpdENsaWVudCxcbiAgd2lyZUF1dGh6RGVuaWFsQXVkaXRvcixcbiAgcmVjb3JkQXVkaXQsXG4gIHR5cGUgUmVtb3RlQXVkaXRFdmVudCxcbiAgdHlwZSBSZW1vdGVBdWRpdFdpcmVFdmVudCxcbiAgdHlwZSBSZW1vdGVBdWRpdENsaWVudCxcbn0gZnJvbSAnLi9yZW1vdGUtYXVkaXQtY2xpZW50LmpzJztcbmV4cG9ydCB7XG4gIHJ1bldpdGhBdWRpdENvbnRleHQsXG4gIGN1cnJlbnRBdWRpdENvbnRleHQsXG4gIGF1ZGl0Q29udGV4dEZyb21SZXF1ZXN0LFxuICBhdWRpdEF1dGhCbG9jayxcbiAgc2FuaXRpemVDb3JyZWxhdGlvbklkLFxuICBzYW5pdGl6ZVVzZXJBZ2VudCxcbiAgQVVESVRfQ09SUkVMQVRJT05fSEVBREVSUyxcbiAgdHlwZSBBdWRpdENvbnRleHQsXG4gIHR5cGUgQXVkaXRDb3JyZWxhdGlvbixcbiAgdHlwZSBBdWRpdEpvYkNvbnRleHQsXG4gIHR5cGUgQXVkaXRBdXRoQmxvY2ssXG59IGZyb20gJy4vYXVkaXQtY29udGV4dC5qcyc7XG5leHBvcnQge1xuICBhdWRpdFNwb29sS2V5LFxuICBjcmVhdGVFbnZSZWRpc0F1ZGl0U3Bvb2wsXG4gIHR5cGUgQXVkaXRTcG9vbCxcbn0gZnJvbSAnLi9hdWRpdC1zcG9vbC5qcyc7XG5leHBvcnQge1xuICByZXNvbHZlUmVkaXNDb25uZWN0aW9uLFxuICBkZXNjcmliZVJlZGlzQ29ubmVjdGlvbixcbiAgY3JlYXRlUmVkaXNDbGllbnQsXG4gIGNyZWF0ZUVudlJlZGlzQ2xpZW50LFxuICBjcmVhdGVSZWRpc1JlYWR5R2F0ZSxcbiAgaW5jcldpbmRvdyxcbiAgUmVkaXNDb25maWdFcnJvcixcbiAgdHlwZSBSZWRpc0V2YWxDbGllbnQsXG59IGZyb20gJy4vZW52LXJlZGlzLmpzJztcbmV4cG9ydCB7XG4gIGNyZWF0ZVJlZGlzVG9rZW5SZXZvY2F0aW9uU3RvcmUsXG4gIGNyZWF0ZUVudlJlZGlzVG9rZW5SZXZvY2F0aW9uU3RvcmUsXG4gIHB1Ymxpc2hUb2tlblJldm9jYXRpb24sXG4gIHB1Ymxpc2hTZXNzaW9uUmV2b2NhdGlvbixcbiAgcHVibGlzaENyZWRlbnRpYWxSZXZvY2F0aW9uLFxufSBmcm9tICcuL3Rva2VuLXJldm9jYXRpb24uanMnO1xuZXhwb3J0IHtcbiAgY3JlYXRlTWVtb3J5U3NlVGlja2V0U3RvcmUsXG4gIGNyZWF0ZUVudlNzZVRpY2tldFN0b3JlLFxuICBlbnZTc2VUaWNrZXRDYXBzLFxuICB0eXBlIEVudlNzZVRpY2tldFN0b3JlQ29uZmlnLFxuICB0eXBlIFNzZVRpY2tldFN0b3JlLFxuICB0eXBlIFNzZVRpY2tldFN0b3JlQ29uZmlnLFxufSBmcm9tICcuL3NzZS10aWNrZXQtc3RvcmUuanMnO1xuZXhwb3J0IHtcbiAgd2lyZVNlcnZpY2VTZWN1cml0eSxcbn0gZnJvbSAnLi9zZXJ2aWNlLWJvb3QuanMnO1xuZXhwb3J0IHtcbiAgY3JlYXRlV2ViaG9va0NoYW5uZWwsXG4gIGNyZWF0ZUVtYWlsQ2hhbm5lbCxcbiAgY3JlYXRlQ2hhbm5lbFJlZ2lzdHJ5LFxuICB0eXBlIE5vdGlmaWNhdGlvblByaW9yaXR5LFxuICB0eXBlIE5vdGlmaWNhdGlvbk1lc3NhZ2UsXG4gIHR5cGUgQ2hhbm5lbFRhcmdldCxcbiAgdHlwZSBEZWxpdmVyeVJlc3VsdCxcbiAgdHlwZSBOb3RpZmljYXRpb25DaGFubmVsLFxufSBmcm9tICcuL25vdGlmaWNhdGlvbi1jaGFubmVscy5qcyc7XG5leHBvcnQge1xuICBhbGVydERlbGl2ZXJ5Q29uZmlnLFxuICBjYW5EZWxpdmVyQW55d2hlcmUsXG4gIGRlYWRtYW5Db25maWcsXG4gIHJlcG9ydEFsZXJ0RGVsaXZlcnlQb3N0dXJlLFxuICBzbGFja0FsZXJ0c0NvbmZpZyxcbiAgc3RhcnREZWFkbWFuSGVhcnRiZWF0LFxuICBzdG9wRGVhZG1hbkhlYXJ0YmVhdCxcbiAgdHlwZSBEZWFkbWFuQ29uZmlnLFxuICB0eXBlIEFsZXJ0RGVsaXZlcnlDb25maWcsXG4gIHR5cGUgU2xhY2tBbGVydHNDb25maWcsXG59IGZyb20gJy4vYWxlcnQtZGVsaXZlcnkuanMnO1xuZXhwb3J0IHtcbiAgdmVyaWZ5UGFnZXJEdXR5U2lnbmF0dXJlLFxuICBvbkNhbGxJbmJvdW5kQ29uZmlnLFxuICBmZXRjaFJvdGFDb3ZlcmFnZSxcbiAgcGFyc2VPbkNhbGxXZWJob29rLFxuICBhY2tMYXRlbmN5U2Vjb25kcyxcbiAgUEFHRVJEVVRZX0FQSV9VUkwsXG4gIHR5cGUgT25DYWxsSW5ib3VuZENvbmZpZyxcbiAgdHlwZSBPbkNhbGxXZWJob29rRXZlbnQsXG4gIHR5cGUgT25DYWxsV2ViaG9va0V2ZW50VHlwZSxcbiAgdHlwZSBSb3RhQ292ZXJhZ2UsXG59IGZyb20gJy4vcGFnZXJkdXR5LWluYm91bmQuanMnO1xuZXhwb3J0IHtcbiAgc2VuZFBhZ2VyRHV0eUV2ZW50LFxuICBwYWdlckR1dHlDb25maWcsXG4gIHJlc29sdmVFdmVudHNFbmRwb2ludCxcbiAgUEFHRVJEVVRZX0VWRU5UU19VUkwsXG4gIHR5cGUgT25DYWxsUHJvdmlkZXIsXG4gIHR5cGUgUGFnZXJEdXR5QWN0aW9uLFxuICB0eXBlIFBhZ2VyRHV0eUNvbmZpZyxcbiAgdHlwZSBQYWdlckR1dHlFdmVudCxcbiAgdHlwZSBQYWdlckR1dHlSZXN1bHQsXG4gIHR5cGUgUGFnZXJEdXR5U2V2ZXJpdHksXG59IGZyb20gJy4vcGFnZXJkdXR5LmpzJztcbmV4cG9ydCB7XG4gIGNyZWF0ZUVjb3N5c3RlbU5vdGlmeUNsaWVudCxcbiAgRUNPU1lTVEVNX05PVElGWV9QQVRILFxuICB0eXBlIEVjb3N5c3RlbU5vdGlmeUNsaWVudCxcbn0gZnJvbSAnLi9lY29zeXN0ZW0tbm90aWZ5LWNsaWVudC5qcyc7XG5leHBvcnQge1xuICBmZXRjaE9yZ0FJQWNjZXNzLFxuICBmZXRjaE9yZ0FJS2V5LFxuICBhc3NlcnRPcmdBSUVuYWJsZWQsXG4gIHJlcXVpcmVPcmdBSUVuYWJsZWQsXG4gIHJlc2V0T3JnQUlDYWNoZSxcbiAgT1JHX0FJX0FDQ0VTU19QQVRILFxuICBPUkdfQUlfS0VZU19QQVRILFxuICB0eXBlIE9yZ0FJQWNjZXNzLFxufSBmcm9tICcuL29yZy1haS1jbGllbnQuanMnO1xuIl19
@@ -0,0 +1,61 @@
1
+ /**
2
+ * The org half of every AI call: is AI switched on for this organization, which
3
+ * providers has it configured its OWN key for, and — when the call is going to
4
+ * use one — the decrypted key.
5
+ *
6
+ * Platform holds both facts (the org's `aiEnabled` switch and its encrypted
7
+ * `aiProviderKeys`), so they are two INTERNAL reads on platform, gated by
8
+ * `requireInternalService` to the four AI callers (ask, pipeline, plugin,
9
+ * reporting) and by the mesh on the Istio targets:
10
+ *
11
+ * - `GET /internal/ai/access/:orgId` → `{ aiEnabled, providers: string[] }`
12
+ * - `GET /internal/ai/keys/:orgId/:provider` → `{ provider, apiKey }` (audited on platform)
13
+ *
14
+ * KEY MATERIAL HANDLING. A key fetched here is held in process memory for at most
15
+ * {@link ORG_AI_KEY_TTL_MS} (so a rotated or cleared key stops being used within
16
+ * that window, and platform's read audit is not one row per model call), is never
17
+ * logged, never written to Redis or any shared cache, and never placed in an error
18
+ * message. Callers hand it straight to a model factory.
19
+ *
20
+ * FAILURE IS NOT A FALLBACK. An unreachable platform makes {@link fetchOrgAIAccess}
21
+ * throw an {@link AIConfigurationError} rather than answer "enabled, no org keys":
22
+ * that answer would silently bill the platform's key for an org that configured its
23
+ * own, and would run AI for an org whose administrators switched it off.
24
+ */
25
+ import type { NextFunction, Request, Response } from 'express';
26
+ /** Platform paths (exported for the platform route-coverage + mesh declarations). */
27
+ export declare const ORG_AI_ACCESS_PATH = "/internal/ai/access";
28
+ export declare const ORG_AI_KEYS_PATH = "/internal/ai/keys";
29
+ /** How long an org's switch + configured-provider list is reused (default 30s). */
30
+ export declare const ORG_AI_ACCESS_TTL_MS: number;
31
+ /** How long a decrypted org key is held in memory (default 60s; 0 disables caching). */
32
+ export declare const ORG_AI_KEY_TTL_MS: number;
33
+ /** An org's AI posture, as platform reports it. */
34
+ export interface OrgAIAccess {
35
+ /** False when the org's administrators switched AI features off. */
36
+ aiEnabled: boolean;
37
+ /** Provider ids the org has configured its OWN key for (catalog ids). */
38
+ providers: string[];
39
+ }
40
+ /**
41
+ * The org's AI switch and the providers it has its own key for. Cached
42
+ * {@link ORG_AI_ACCESS_TTL_MS}. Throws {@link AIConfigurationError} (503) when platform
43
+ * cannot answer — see the module comment for why that is not "enabled".
44
+ */
45
+ export declare function fetchOrgAIAccess(orgId: string): Promise<OrgAIAccess>;
46
+ /**
47
+ * The org's decrypted key for `provider`. Call ONLY after {@link fetchOrgAIAccess}
48
+ * listed the provider. Throws {@link AIConfigurationError} when the key cannot be
49
+ * loaded — the caller must then fail the request, never fall back to the platform key.
50
+ */
51
+ export declare function fetchOrgAIKey(orgId: string, provider: string): Promise<string>;
52
+ /** Throw {@link AIDisabledError} (403 `AI_DISABLED`) when the org switched AI off. */
53
+ export declare function assertOrgAIEnabled(orgId: string): Promise<OrgAIAccess>;
54
+ /**
55
+ * Route guard: refuse every AI entry point for an org whose administrators switched
56
+ * AI off (403 `AI_DISABLED`), or whose settings platform cannot confirm (503). Mount
57
+ * AFTER auth and BEFORE any quota reservation, so a disabled org is never charged.
58
+ */
59
+ export declare function requireOrgAIEnabled(req: Request, res: Response, next: NextFunction): Promise<void>;
60
+ /** Drop the cached org AI posture + keys (tests; an org whose settings just changed). */
61
+ export declare function resetOrgAICache(orgId?: string): void;
@@ -0,0 +1,112 @@
1
+ // Copyright 2026 Pipeline Builder Contributors
2
+ // SPDX-License-Identifier: Apache-2.0
3
+ import { createSafeClient } from './http-client.js';
4
+ import { serviceIdentity } from './service-keys.js';
5
+ import { AIConfigurationError, AIDisabledError } from '../errors/app-errors.js';
6
+ import { getServiceAuthHeader } from '../middleware/service-tokens.js';
7
+ import { ErrorCode } from '../types/error-codes.js';
8
+ import { envInt } from '../utils/env.js';
9
+ import { sendError } from '../utils/response.js';
10
+ import { serviceEndpoint } from '../utils/service-registry.js';
11
+ /** Platform paths (exported for the platform route-coverage + mesh declarations). */
12
+ export const ORG_AI_ACCESS_PATH = '/internal/ai/access';
13
+ export const ORG_AI_KEYS_PATH = '/internal/ai/keys';
14
+ /** How long an org's switch + configured-provider list is reused (default 30s). */
15
+ export const ORG_AI_ACCESS_TTL_MS = envInt('ORG_AI_ACCESS_TTL_MS', 30_000, { min: 0 });
16
+ /** How long a decrypted org key is held in memory (default 60s; 0 disables caching). */
17
+ export const ORG_AI_KEY_TTL_MS = envInt('ORG_AI_KEY_TTL_MS', 60_000, { min: 0, max: 300_000 });
18
+ const accessCache = new Map();
19
+ const keyCache = new Map();
20
+ let client;
21
+ function platform() {
22
+ client ??= createSafeClient({ ...serviceEndpoint('platform'), timeout: 5_000 });
23
+ return client;
24
+ }
25
+ /** A service token scoped to the org being asked about — platform binds the read to it. */
26
+ function authFor(orgId) {
27
+ return { Authorization: getServiceAuthHeader({ serviceName: serviceIdentity(), orgId, role: 'member' }) };
28
+ }
29
+ /**
30
+ * The org's AI switch and the providers it has its own key for. Cached
31
+ * {@link ORG_AI_ACCESS_TTL_MS}. Throws {@link AIConfigurationError} (503) when platform
32
+ * cannot answer — see the module comment for why that is not "enabled".
33
+ */
34
+ export async function fetchOrgAIAccess(orgId) {
35
+ const hit = accessCache.get(orgId);
36
+ if (hit && hit.expiresAt > Date.now())
37
+ return hit.value;
38
+ const response = await platform().get(`${ORG_AI_ACCESS_PATH}/${encodeURIComponent(orgId)}`, { headers: authFor(orgId) });
39
+ const body = response?.body;
40
+ const data = body?.data ?? body;
41
+ if (!response || response.statusCode !== 200 || typeof data?.aiEnabled !== 'boolean') {
42
+ throw new AIConfigurationError('The organization\'s AI settings could not be read, so no AI request was made. Try again shortly.');
43
+ }
44
+ const value = {
45
+ aiEnabled: data.aiEnabled,
46
+ providers: Array.isArray(data.providers) ? data.providers.filter((p) => typeof p === 'string') : [],
47
+ };
48
+ if (ORG_AI_ACCESS_TTL_MS > 0)
49
+ accessCache.set(orgId, { value, expiresAt: Date.now() + ORG_AI_ACCESS_TTL_MS });
50
+ return value;
51
+ }
52
+ /**
53
+ * The org's decrypted key for `provider`. Call ONLY after {@link fetchOrgAIAccess}
54
+ * listed the provider. Throws {@link AIConfigurationError} when the key cannot be
55
+ * loaded — the caller must then fail the request, never fall back to the platform key.
56
+ */
57
+ export async function fetchOrgAIKey(orgId, provider) {
58
+ const cacheKey = `${orgId}\u0000${provider}`;
59
+ const hit = keyCache.get(cacheKey);
60
+ if (hit && hit.expiresAt > Date.now())
61
+ return hit.value;
62
+ const response = await platform().get(`${ORG_AI_KEYS_PATH}/${encodeURIComponent(orgId)}/${encodeURIComponent(provider)}`, { headers: authFor(orgId) });
63
+ const apiKey = response?.body?.data?.apiKey ?? response?.body?.apiKey;
64
+ if (!response || response.statusCode !== 200 || typeof apiKey !== 'string' || apiKey.length === 0) {
65
+ // Status only: the body is never echoed, and the key is never in a message.
66
+ throw new AIConfigurationError(`The organization's ${provider} API key could not be loaded, so the request was not sent. `
67
+ + 'It was NOT retried on the platform\'s key — re-save the key in Settings, or try again shortly.');
68
+ }
69
+ if (ORG_AI_KEY_TTL_MS > 0)
70
+ keyCache.set(cacheKey, { value: apiKey, expiresAt: Date.now() + ORG_AI_KEY_TTL_MS });
71
+ return apiKey;
72
+ }
73
+ /** Throw {@link AIDisabledError} (403 `AI_DISABLED`) when the org switched AI off. */
74
+ export async function assertOrgAIEnabled(orgId) {
75
+ const access = await fetchOrgAIAccess(orgId);
76
+ if (!access.aiEnabled)
77
+ throw new AIDisabledError();
78
+ return access;
79
+ }
80
+ /**
81
+ * Route guard: refuse every AI entry point for an org whose administrators switched
82
+ * AI off (403 `AI_DISABLED`), or whose settings platform cannot confirm (503). Mount
83
+ * AFTER auth and BEFORE any quota reservation, so a disabled org is never charged.
84
+ */
85
+ export async function requireOrgAIEnabled(req, res, next) {
86
+ const orgId = req.user?.organizationId;
87
+ if (!orgId) {
88
+ sendError(res, 403, 'No organization associated with this request', ErrorCode.INSUFFICIENT_PERMISSIONS);
89
+ return;
90
+ }
91
+ try {
92
+ await assertOrgAIEnabled(String(orgId));
93
+ next();
94
+ }
95
+ catch (err) {
96
+ const e = err;
97
+ sendError(res, e.statusCode ?? 503, e.message, e.code);
98
+ }
99
+ }
100
+ /** Drop the cached org AI posture + keys (tests; an org whose settings just changed). */
101
+ export function resetOrgAICache(orgId) {
102
+ if (orgId === undefined) {
103
+ accessCache.clear();
104
+ keyCache.clear();
105
+ return;
106
+ }
107
+ accessCache.delete(orgId);
108
+ for (const k of keyCache.keys())
109
+ if (k.startsWith(`${orgId}\u0000`))
110
+ keyCache.delete(k);
111
+ }
112
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoib3JnLWFpLWNsaWVudC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9zZXJ2aWNlcy9vcmctYWktY2xpZW50LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLCtDQUErQztBQUMvQyxzQ0FBc0M7QUE0QnRDLE9BQU8sRUFBRSxnQkFBZ0IsRUFBRSxNQUFNLGtCQUFrQixDQUFDO0FBQ3BELE9BQU8sRUFBRSxlQUFlLEVBQUUsTUFBTSxtQkFBbUIsQ0FBQztBQUNwRCxPQUFPLEVBQUUsb0JBQW9CLEVBQUUsZUFBZSxFQUFFLE1BQU0seUJBQXlCLENBQUM7QUFDaEYsT0FBTyxFQUFFLG9CQUFvQixFQUFFLE1BQU0saUNBQWlDLENBQUM7QUFDdkUsT0FBTyxFQUFFLFNBQVMsRUFBRSxNQUFNLHlCQUF5QixDQUFDO0FBQ3BELE9BQU8sRUFBRSxNQUFNLEVBQUUsTUFBTSxpQkFBaUIsQ0FBQztBQUN6QyxPQUFPLEVBQUUsU0FBUyxFQUFFLE1BQU0sc0JBQXNCLENBQUM7QUFDakQsT0FBTyxFQUFFLGVBQWUsRUFBRSxNQUFNLDhCQUE4QixDQUFDO0FBRS9ELHFGQUFxRjtBQUNyRixNQUFNLENBQUMsTUFBTSxrQkFBa0IsR0FBRyxxQkFBcUIsQ0FBQztBQUN4RCxNQUFNLENBQUMsTUFBTSxnQkFBZ0IsR0FBRyxtQkFBbUIsQ0FBQztBQUVwRCxtRkFBbUY7QUFDbkYsTUFBTSxDQUFDLE1BQU0sb0JBQW9CLEdBQUcsTUFBTSxDQUFDLHNCQUFzQixFQUFFLE1BQU0sRUFBRSxFQUFFLEdBQUcsRUFBRSxDQUFDLEVBQUUsQ0FBQyxDQUFDO0FBQ3ZGLHdGQUF3RjtBQUN4RixNQUFNLENBQUMsTUFBTSxpQkFBaUIsR0FBRyxNQUFNLENBQUMsbUJBQW1CLEVBQUUsTUFBTSxFQUFFLEVBQUUsR0FBRyxFQUFFLENBQUMsRUFBRSxHQUFHLEVBQUUsT0FBTyxFQUFFLENBQUMsQ0FBQztBQVkvRixNQUFNLFdBQVcsR0FBRyxJQUFJLEdBQUcsRUFBK0Is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LHdCQUF3QixDQUFDLENBQUM7UUFDeEcsT0FBTztJQUNULENBQUM7SUFDRCxJQUFJLENBQUM7UUFDSCxNQUFNLGtCQUFrQixDQUFDLE1BQU0sQ0FBQyxLQUFLLENBQUMsQ0FBQyxDQUFDO1FBQ3hDLElBQUksRUFBRSxDQUFDO0lBQ1QsQ0FBQztJQUFDLE9BQU8sR0FBRyxFQUFFLENBQUM7UUFDYixNQUFNLENBQUMsR0FBRyxHQUE2QyxDQUFDO1FBQ3hELFNBQVMsQ0FBQyxHQUFHLEVBQUUsQ0FBQyxDQUFDLFVBQVUsSUFBSSxHQUFHLEVBQUUsQ0FBQyxDQUFDLE9BQU8sRUFBRSxDQUFDLENBQUMsSUFBSSxDQUFDLENBQUM7SUFDekQsQ0FBQztBQUNILENBQUM7QUFFRCx5RkFBeUY7QUFDekYsTUFBTSxVQUFVLGVBQWUsQ0FBQyxLQUFjO0lBQzVDLElBQUksS0FBSyxLQUFLLFNBQVMsRUFBRSxDQUFDO1FBQ3hCLFdBQVcsQ0FBQyxLQUFLLEVBQUUsQ0FBQztRQUNwQixRQUFRLENBQUMsS0FBSyxFQUFFLENBQUM7UUFDakIsT0FBTztJQUNULENBQUM7SUFDRCxXQUFXLENBQUMsTUFBTSxDQUFDLEtBQUssQ0FBQyxDQUFDO0lBQzFCLEtBQUssTUFBTSxDQUFDLElBQUksUUFBUSxDQUFDLElBQUksRUFBRTtRQUFFLElBQUksQ0FBQyxDQUFDLFVBQVUsQ0FBQyxHQUFHLEtBQUssUUFBUSxDQUFDO1lBQUUsUUFBUSxDQUFDLE1BQU0sQ0FBQyxDQUFDLENBQUMsQ0FBQztBQUMxRixDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiLy8gQ29weXJpZ2h0IDIwMjYgUGlwZWxpbmUgQnVpbGRlciBDb250cmlidXRvcnNcbi8vIFNQRFgtTGljZW5zZS1JZGVudGlmaWVyOiBBcGFjaGUtMi4wXG5cbi8qKlxuICogVGhlIG9yZyBoYWxmIG9mIGV2ZXJ5IEFJIGNhbGw6IGlzIEFJIHN3aXRjaGVkIG9uIGZvciB0aGlzIG9yZ2FuaXphdGlvbiwgd2hpY2hcbiAqIHByb3ZpZGVycyBoYXMgaXQgY29uZmlndXJlZCBpdHMgT1dOIGtleSBmb3IsIGFuZCDigJQgd2hlbiB0aGUgY2FsbCBpcyBnb2luZyB0b1xuICogdXNlIG9uZSDigJQgdGhlIGRlY3J5cHRlZCBrZXkuXG4gKlxuICogUGxhdGZvcm0gaG9sZHMgYm90aCBmYWN0cyAodGhlIG9yZydzIGBhaUVuYWJsZWRgIHN3aXRjaCBhbmQgaXRzIGVuY3J5cHRlZFxuICogYGFpUHJvdmlkZXJLZXlzYCksIHNvIHRoZXkgYXJlIHR3byBJTlRFUk5BTCByZWFkcyBvbiBwbGF0Zm9ybSwgZ2F0ZWQgYnlcbiAqIGByZXF1aXJlSW50ZXJuYWxTZXJ2aWNlYCB0byB0aGUgZm91ciBBSSBjYWxsZXJzIChhc2ssIHBpcGVsaW5lLCBwbHVnaW4sXG4gKiByZXBvcnRpbmcpIGFuZCBieSB0aGUgbWVzaCBvbiB0aGUgSXN0aW8gdGFyZ2V0czpcbiAqXG4gKiAgLSBgR0VUIC9pbnRlcm5hbC9haS9hY2Nlc3MvOm9yZ0lkYCAgICAgICAgIOKGkiBgeyBhaUVuYWJsZWQsIHByb3ZpZGVyczogc3RyaW5nW10gfWBcbiAqICAtIGBHRVQgL2ludGVybmFsL2FpL2tleXMvOm9yZ0lkLzpwcm92aWRlcmAg4oaSIGB7IHByb3ZpZGVyLCBhcGlLZXkgfWAgKGF1ZGl0ZWQgb24gcGxhdGZvcm0pXG4gKlxuICogS0VZIE1BVEVSSUFMIEhBTkRMSU5HLiBBIGtleSBmZXRjaGVkIGhlcmUgaXMgaGVsZCBpbiBwcm9jZXNzIG1lbW9yeSBmb3IgYXQgbW9zdFxuICoge0BsaW5rIE9SR19BSV9LRVlfVFRMX01TfSAoc28gYSByb3RhdGVkIG9yIGNsZWFyZWQga2V5IHN0b3BzIGJlaW5nIHVzZWQgd2l0aGluXG4gKiB0aGF0IHdpbmRvdywgYW5kIHBsYXRmb3JtJ3MgcmVhZCBhdWRpdCBpcyBub3Qgb25lIHJvdyBwZXIgbW9kZWwgY2FsbCksIGlzIG5ldmVyXG4gKiBsb2dnZWQsIG5ldmVyIHdyaXR0ZW4gdG8gUmVkaXMgb3IgYW55IHNoYXJlZCBjYWNoZSwgYW5kIG5ldmVyIHBsYWNlZCBpbiBhbiBlcnJvclxuICogbWVzc2FnZS4gQ2FsbGVycyBoYW5kIGl0IHN0cmFpZ2h0IHRvIGEgbW9kZWwgZmFjdG9yeS5cbiAqXG4gKiBGQUlMVVJFIElTIE5PVCBBIEZBTExCQUNLLiBBbiB1bnJlYWNoYWJsZSBwbGF0Zm9ybSBtYWtlcyB7QGxpbmsgZmV0Y2hPcmdBSUFjY2Vzc31cbiAqIHRocm93IGFuIHtAbGluayBBSUNvbmZpZ3VyYXRpb25FcnJvcn0gcmF0aGVyIHRoYW4gYW5zd2VyIFwiZW5hYmxlZCwgbm8gb3JnIGtleXNcIjpcbiAqIHRoYXQgYW5zd2VyIHdvdWxkIHNpbGVudGx5IGJpbGwgdGhlIHBsYXRmb3JtJ3Mga2V5IGZvciBhbiBvcmcgdGhhdCBjb25maWd1cmVkIGl0c1xuICogb3duLCBhbmQgd291bGQgcnVuIEFJIGZvciBhbiBvcmcgd2hvc2UgYWRtaW5pc3RyYXRvcnMgc3dpdGNoZWQgaXQgb2ZmLlxuICovXG5cbmltcG9ydCB0eXBlIHsgTmV4dEZ1bmN0aW9uLCBSZXF1ZXN0LCBSZXNwb25zZSB9IGZyb20gJ2V4cHJlc3MnO1xuaW1wb3J0IHsgY3JlYXRlU2FmZUNsaWVudCB9IGZyb20gJy4vaHR0cC1jbGllbnQuanMnO1xuaW1wb3J0IHsgc2VydmljZUlkZW50aXR5IH0gZnJvbSAnLi9zZXJ2aWNlLWtleXMuanMnO1xuaW1wb3J0IHsgQUlDb25maWd1cmF0aW9uRXJyb3IsIEFJRGlzYWJsZWRFcnJvciB9IGZyb20gJy4uL2Vycm9ycy9hcHAtZXJyb3JzLmpzJztcbmltcG9ydCB7IGdldFNlcnZpY2VBdXRoSGVhZGVyIH0gZnJvbSAnLi4vbWlkZGxld2FyZS9zZXJ2aWNlLXRva2Vucy5qcyc7XG5pbXBvcnQgeyBFcnJvckNvZGUgfSBmcm9tICcuLi90eXBlcy9lcnJvci1jb2Rlcy5qcyc7XG5pbXBvcnQgeyBlbnZJbnQgfSBmcm9tICcuLi91dGlscy9lbnYuanMnO1xuaW1wb3J0IHsgc2VuZEVycm9yIH0gZnJvbSAnLi4vdXRpbHMvcmVzcG9uc2UuanMnO1xuaW1wb3J0IHsgc2VydmljZUVuZHBvaW50IH0gZnJvbSAnLi4vdXRpbHMvc2VydmljZS1yZWdpc3RyeS5qcyc7XG5cbi8qKiBQbGF0Zm9ybSBwYXRocyAoZXhwb3J0ZWQgZm9yIHRoZSBwbGF0Zm9ybSByb3V0ZS1jb3ZlcmFnZSArIG1lc2ggZGVjbGFyYXRpb25zKS4gKi9cbmV4cG9ydCBjb25zdCBPUkdfQUlfQUNDRVNTX1BBVEggPSAnL2ludGVybmFsL2FpL2FjY2Vzcyc7XG5leHBvcnQgY29uc3QgT1JHX0FJX0tFWVNfUEFUSCA9ICcvaW50ZXJuYWwvYWkva2V5cyc7XG5cbi8qKiBIb3cgbG9uZyBhbiBvcmcncyBzd2l0Y2ggKyBjb25maWd1cmVkLXByb3ZpZGVyIGxpc3QgaXMgcmV1c2VkIChkZWZhdWx0IDMwcykuICovXG5leHBvcnQgY29uc3QgT1JHX0FJX0FDQ0VTU19UVExfTVMgPSBlbnZJbnQoJ09SR19BSV9BQ0NFU1NfVFRMX01TJywgMzBfMDAwLCB7IG1pbjogMCB9KTtcbi8qKiBIb3cgbG9uZyBhIGRlY3J5cHRlZCBvcmcga2V5IGlzIGhlbGQgaW4gbWVtb3J5IChkZWZhdWx0IDYwczsgMCBkaXNhYmxlcyBjYWNoaW5nKS4gKi9cbmV4cG9ydCBjb25zdCBPUkdfQUlfS0VZX1RUTF9NUyA9IGVudkludCgnT1JHX0FJX0tFWV9UVExfTVMnLCA2MF8wMDAsIHsgbWluOiAwLCBtYXg6IDMwMF8wMDAgfSk7XG5cbi8qKiBBbiBvcmcncyBBSSBwb3N0dXJlLCBhcyBwbGF0Zm9ybSByZXBvcnRzIGl0LiAqL1xuZXhwb3J0IGludGVyZmFjZSBPcmdBSUFjY2VzcyB7XG4gIC8qKiBGYWxzZSB3aGVuIHRoZSBvcmcncyBhZG1pbmlzdHJhdG9ycyBzd2l0Y2hlZCBBSSBmZWF0dXJlcyBvZmYuICovXG4gIGFpRW5hYmxlZDogYm9vbGVhbjtcbiAgLyoqIFByb3ZpZGVyIGlkcyB0aGUgb3JnIGhhcyBjb25maWd1cmVkIGl0cyBPV04ga2V5IGZvciAoY2F0YWxvZyBpZHMpLiAqL1xuICBwcm92aWRlcnM6IHN0cmluZ1tdO1xufVxuXG5pbnRlcmZhY2UgQ2FjaGVkPFQ+IHsgdmFsdWU6IFQ7IGV4cGlyZXNBdDogbnVtYmVyIH1cblxuY29uc3QgYWNjZXNzQ2FjaGUgPSBuZXcgTWFwPHN0cmluZywgQ2FjaGVkPE9yZ0FJQWNjZXNzPj4oKTtcbmNvbnN0IGtleUNhY2hlID0gbmV3IE1hcDxzdHJpbmcsIENhY2hlZDxzdHJpbmc+PigpO1xuXG5sZXQgY2xpZW50OiBSZXR1cm5UeXBlPHR5cGVvZiBjcmVhdGVTYWZlQ2xpZW50PiB8IHVuZGVmaW5lZDtcbmZ1bmN0aW9uIHBsYXRmb3JtKCk6IFJldHVyblR5cGU8dHlwZW9mIGNyZWF0ZVNhZmVDbGllbnQ+IHtcbiAgY2xpZW50ID8/PSBjcmVhdGVTYWZlQ2xpZW50KHsgLi4uc2VydmljZUVuZHBvaW50KCdwbGF0Zm9ybScpLCB0aW1lb3V0OiA1XzAwMCB9KTtcbiAgcmV0dXJuIGNsaWVudDtcbn1cblxuLyoqIEEgc2VydmljZSB0b2tlbiBzY29wZWQgdG8gdGhlIG9yZyBiZWluZyBhc2tlZCBhYm91dCDigJQgcGxhdGZvcm0gYmluZHMgdGhlIHJlYWQgdG8gaXQuICovXG5mdW5jdGlvbiBhdXRoRm9yKG9yZ0lkOiBzdHJpbmcpOiBSZWNvcmQ8c3RyaW5nLCBzdHJpbmc+IHtcbiAgcmV0dXJuIHsgQXV0aG9yaXphdGlvbjogZ2V0U2VydmljZUF1dGhIZWFkZXIoeyBzZXJ2aWNlTmFtZTogc2VydmljZUlkZW50aXR5KCksIG9yZ0lkLCByb2xlOiAnbWVtYmVyJyB9KSB9O1xufVxuXG4vKipcbiAqIFRoZSBvcmcncyBBSSBzd2l0Y2ggYW5kIHRoZSBwcm92aWRlcnMgaXQgaGFzIGl0cyBvd24ga2V5IGZvci4gQ2FjaGVkXG4gKiB7QGxpbmsgT1JHX0FJX0FDQ0VTU19UVExfTVN9LiBUaHJvd3Mge0BsaW5rIEFJQ29uZmlndXJhdGlvbkVycm9yfSAoNTAzKSB3aGVuIHBsYXRmb3JtXG4gKiBjYW5ub3QgYW5zd2VyIOKAlCBzZWUgdGhlIG1vZHVsZSBjb21tZW50IGZvciB3aHkgdGhhdCBpcyBub3QgXCJlbmFibGVkXCIuXG4gKi9cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBmZXRjaE9yZ0FJQWNjZXNzKG9yZ0lkOiBzdHJpbmcpOiBQcm9taXNlPE9yZ0FJQWNjZXNzPiB7XG4gIGNvbnN0IGhpdCA9IGFjY2Vzc0NhY2hlLmdldChvcmdJZCk7XG4gIGlmIChoaXQgJiYgaGl0LmV4cGlyZXNBdCA+IERhdGUubm93KCkpIHJldHVybiBoaXQudmFsdWU7XG5cbiAgY29uc3QgcmVzcG9uc2UgPSBhd2FpdCBwbGF0Zm9ybSgpLmdldDx7IGRhdGE/OiBQYXJ0aWFsPE9yZ0FJQWNjZXNzPiB9ICYgUGFydGlhbDxPcmdBSUFjY2Vzcz4+KFxuICAgIGAke09SR19BSV9BQ0NFU1NfUEFUSH0vJHtlbmNvZGVVUklDb21wb25lbnQob3JnSWQpfWAsIHsgaGVhZGVyczogYXV0aEZvcihvcmdJZCkgfSxcbiAgKTtcbiAgY29uc3QgYm9keSA9IHJlc3BvbnNlPy5ib2R5O1xuICBjb25zdCBkYXRhID0gYm9keT8uZGF0YSA/PyBib2R5O1xuICBpZiAoIXJlc3BvbnNlIHx8IHJlc3BvbnNlLnN0YXR1c0NvZGUgIT09IDIwMCB8fCB0eXBlb2YgZGF0YT8uYWlFbmFibGVkICE9PSAnYm9vbGVhbicpIHtcbiAgICB0aHJvdyBuZXcgQUlDb25maWd1cmF0aW9uRXJyb3IoJ1RoZSBvcmdhbml6YXRpb25cXCdzIEFJIHNldHRpbmdzIGNvdWxkIG5vdCBiZSByZWFkLCBzbyBubyBBSSByZXF1ZXN0IHdhcyBtYWRlLiBUcnkgYWdhaW4gc2hvcnRseS4nKTtcbiAgfVxuICBjb25zdCB2YWx1ZTogT3JnQUlBY2Nlc3MgPSB7XG4gICAgYWlFbmFibGVkOiBkYXRhLmFpRW5hYmxlZCxcbiAgICBwcm92aWRlcnM6IEFycmF5LmlzQXJyYXkoZGF0YS5wcm92aWRlcnMpID8gZGF0YS5wcm92aWRlcnMuZmlsdGVyKChwKTogcCBpcyBzdHJpbmcgPT4gdHlwZW9mIHAgPT09ICdzdHJpbmcnKSA6IFtdLFxuICB9O1xuICBpZiAoT1JHX0FJX0FDQ0VTU19UVExfTVMgPiAwKSBhY2Nlc3NDYWNoZS5zZXQob3JnSWQsIHsgdmFsdWUsIGV4cGlyZXNBdDogRGF0ZS5ub3coKSArIE9SR19BSV9BQ0NFU1NfVFRMX01TIH0pO1xuICByZXR1cm4gdmFsdWU7XG59XG5cbi8qKlxuICogVGhlIG9yZydzIGRlY3J5cHRlZCBrZXkgZm9yIGBwcm92aWRlcmAuIENhbGwgT05MWSBhZnRlciB7QGxpbmsgZmV0Y2hPcmdBSUFjY2Vzc31cbiAqIGxpc3RlZCB0aGUgcHJvdmlkZXIuIFRocm93cyB7QGxpbmsgQUlDb25maWd1cmF0aW9uRXJyb3J9IHdoZW4gdGhlIGtleSBjYW5ub3QgYmVcbiAqIGxvYWRlZCDigJQgdGhlIGNhbGxlciBtdXN0IHRoZW4gZmFpbCB0aGUgcmVxdWVzdCwgbmV2ZXIgZmFsbCBiYWNrIHRvIHRoZSBwbGF0Zm9ybSBrZXkuXG4gKi9cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBmZXRjaE9yZ0FJS2V5KG9yZ0lkOiBzdHJpbmcsIHByb3ZpZGVyOiBzdHJpbmcpOiBQcm9taXNlPHN0cmluZz4ge1xuICBjb25zdCBjYWNoZUtleSA9IGAke29yZ0lkfVxcdTAwMDAke3Byb3ZpZGVyfWA7XG4gIGNvbnN0IGhpdCA9IGtleUNhY2hlLmdldChjYWNoZUtleSk7XG4gIGlmIChoaXQgJiYgaGl0LmV4cGlyZXNBdCA+IERhdGUubm93KCkpIHJldHVybiBoaXQudmFsdWU7XG5cbiAgY29uc3QgcmVzcG9uc2UgPSBhd2FpdCBwbGF0Zm9ybSgpLmdldDx7IGRhdGE/OiB7IGFwaUtleT86IHVua25vd24gfTsgYXBpS2V5PzogdW5rbm93biB9PihcbiAgICBgJHtPUkdfQUlfS0VZU19QQVRIfS8ke2VuY29kZVVSSUNvbXBvbmVudChvcmdJZCl9LyR7ZW5jb2RlVVJJQ29tcG9uZW50KHByb3ZpZGVyKX1gLCB7IGhlYWRlcnM6IGF1dGhGb3Iob3JnSWQpIH0sXG4gICk7XG4gIGNvbnN0IGFwaUtleSA9IHJlc3BvbnNlPy5ib2R5Py5kYXRhPy5hcGlLZXkgPz8gcmVzcG9uc2U/LmJvZHk/LmFwaUtleTtcbiAgaWYgKCFyZXNwb25zZSB8fCByZXNwb25zZS5zdGF0dXNDb2RlICE9PSAyMDAgfHwgdHlwZW9mIGFwaUtleSAhPT0gJ3N0cmluZycgfHwgYXBpS2V5Lmxlbmd0aCA9PT0gMCkge1xuICAgIC8vIFN0YXR1cyBvbmx5OiB0aGUgYm9keSBpcyBuZXZlciBlY2hvZWQsIGFuZCB0aGUga2V5IGlzIG5ldmVyIGluIGEgbWVzc2FnZS5cbiAgICB0aHJvdyBuZXcgQUlDb25maWd1cmF0aW9uRXJyb3IoXG4gICAgICBgVGhlIG9yZ2FuaXphdGlvbidzICR7cHJvdmlkZXJ9IEFQSSBrZXkgY291bGQgbm90IGJlIGxvYWRlZCwgc28gdGhlIHJlcXVlc3Qgd2FzIG5vdCBzZW50LiBgXG4gICAgICArICdJdCB3YXMgTk9UIHJldHJpZWQgb24gdGhlIHBsYXRmb3JtXFwncyBrZXkg4oCUIHJlLXNhdmUgdGhlIGtleSBpbiBTZXR0aW5ncywgb3IgdHJ5IGFnYWluIHNob3J0bHkuJyxcbiAgICApO1xuICB9XG4gIGlmIChPUkdfQUlfS0VZX1RUTF9NUyA+IDApIGtleUNhY2hlLnNldChjYWNoZUtleSwgeyB2YWx1ZTogYXBpS2V5LCBleHBpcmVzQXQ6IERhdGUubm93KCkgKyBPUkdfQUlfS0VZX1RUTF9NUyB9KTtcbiAgcmV0dXJuIGFwaUtleTtcbn1cblxuLyoqIFRocm93IHtAbGluayBBSURpc2FibGVkRXJyb3J9ICg0MDMgYEFJX0RJU0FCTEVEYCkgd2hlbiB0aGUgb3JnIHN3aXRjaGVkIEFJIG9mZi4gKi9cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBhc3NlcnRPcmdBSUVuYWJsZWQob3JnSWQ6IHN0cmluZyk6IFByb21pc2U8T3JnQUlBY2Nlc3M+IHtcbiAgY29uc3QgYWNjZXNzID0gYXdhaXQgZmV0Y2hPcmdBSUFjY2VzcyhvcmdJZCk7XG4gIGlmICghYWNjZXNzLmFpRW5hYmxlZCkgdGhyb3cgbmV3IEFJRGlzYWJsZWRFcnJvcigpO1xuICByZXR1cm4gYWNjZXNzO1xufVxuXG4vKipcbiAqIFJvdXRlIGd1YXJkOiByZWZ1c2UgZXZlcnkgQUkgZW50cnkgcG9pbnQgZm9yIGFuIG9yZyB3aG9zZSBhZG1pbmlzdHJhdG9ycyBzd2l0Y2hlZFxuICogQUkgb2ZmICg0MDMgYEFJX0RJU0FCTEVEYCksIG9yIHdob3NlIHNldHRpbmdzIHBsYXRmb3JtIGNhbm5vdCBjb25maXJtICg1MDMpLiBNb3VudFxuICogQUZURVIgYXV0aCBhbmQgQkVGT1JFIGFueSBxdW90YSByZXNlcnZhdGlvbiwgc28gYSBkaXNhYmxlZCBvcmcgaXMgbmV2ZXIgY2hhcmdlZC5cbiAqL1xuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIHJlcXVpcmVPcmdBSUVuYWJsZWQocmVxOiBSZXF1ZXN0LCByZXM6IFJlc3BvbnNlLCBuZXh0OiBOZXh0RnVuY3Rpb24pOiBQcm9taXNlPHZvaWQ+IHtcbiAgY29uc3Qgb3JnSWQgPSByZXEudXNlcj8ub3JnYW5pemF0aW9uSWQ7XG4gIGlmICghb3JnSWQpIHtcbiAgICBzZW5kRXJyb3IocmVzLCA0MDMsICdObyBvcmdhbml6YXRpb24gYXNzb2NpYXRlZCB3aXRoIHRoaXMgcmVxdWVzdCcsIEVycm9yQ29kZS5JTlNVRkZJQ0lFTlRfUEVSTUlTU0lPTlMpO1xuICAgIHJldHVybjtcbiAgfVxuICB0cnkge1xuICAgIGF3YWl0IGFzc2VydE9yZ0FJRW5hYmxlZChTdHJpbmcob3JnSWQpKTtcbiAgICBuZXh0KCk7XG4gIH0gY2F0Y2ggKGVycikge1xuICAgIGNvbnN0IGUgPSBlcnIgYXMgQUlEaXNhYmxlZEVycm9yIHwgQUlDb25maWd1cmF0aW9uRXJyb3I7XG4gICAgc2VuZEVycm9yKHJlcywgZS5zdGF0dXNDb2RlID8/IDUwMywgZS5tZXNzYWdlLCBlLmNvZGUpO1xuICB9XG59XG5cbi8qKiBEcm9wIHRoZSBjYWNoZWQgb3JnIEFJIHBvc3R1cmUgKyBrZXlzICh0ZXN0czsgYW4gb3JnIHdob3NlIHNldHRpbmdzIGp1c3QgY2hhbmdlZCkuICovXG5leHBvcnQgZnVuY3Rpb24gcmVzZXRPcmdBSUNhY2hlKG9yZ0lkPzogc3RyaW5nKTogdm9pZCB7XG4gIGlmIChvcmdJZCA9PT0gdW5kZWZpbmVkKSB7XG4gICAgYWNjZXNzQ2FjaGUuY2xlYXIoKTtcbiAgICBrZXlDYWNoZS5jbGVhcigpO1xuICAgIHJldHVybjtcbiAgfVxuICBhY2Nlc3NDYWNoZS5kZWxldGUob3JnSWQpO1xuICBmb3IgKGNvbnN0IGsgb2Yga2V5Q2FjaGUua2V5cygpKSBpZiAoay5zdGFydHNXaXRoKGAke29yZ0lkfVxcdTAwMDBgKSkga2V5Q2FjaGUuZGVsZXRlKGspO1xufVxuIl19
@@ -0,0 +1,81 @@
1
+ /**
2
+ * Per-pod aggregation of METERING increments (apiCalls / automationCalls).
3
+ *
4
+ * Metering used to be one POST to the quota service per successful request,
5
+ * and each POST was a conditional `findOneAndUpdate` on the org's hot document,
6
+ * a team counter update, a ledger insert and a threshold check. At the request
7
+ * rates the meter exists for, the quota service was doing more work than the
8
+ * request it was counting.
9
+ *
10
+ * Increments are now summed in memory per (org, quota type) and, inside that,
11
+ * per attribution group (principal, key, route pattern, pipeline), then sent
12
+ * every `QUOTA_INCREMENT_FLUSH_MS` (default 1000) as ONE metered increment per
13
+ * (org, type) carrying its groups. The quota service applies the sum atomically
14
+ * against the (pooled) cap with partial admission: the counter moves by as much
15
+ * as fits and never past the limit, and the rest is recorded as `overshoot` in
16
+ * the ledger (api/quota `incrementMetered`).
17
+ *
18
+ * Guarantees, and their limits:
19
+ * - the counter may LAG real usage by up to one flush interval (plus the HTTP
20
+ * hop); enforcement is unaffected beyond that lag, because the counter
21
+ * still never exceeds the cap;
22
+ * - the buffer is bounded (`QUOTA_INCREMENT_BUFFER_MAX` attribution groups).
23
+ * Reaching it flushes immediately; only while a flush is already in flight
24
+ * is a NEW group dropped, counted on `quota_increment_dropped_total`;
25
+ * - a flush that fails is counted on `quota_increment_failures_total` (the
26
+ * QuotaIncrementFailures alert) and NOT retried: the POST may have landed,
27
+ * and a retry would double-count;
28
+ * - graceful shutdown flushes: `runServer` awaits {@link flushQuotaIncrements}
29
+ * after the HTTP server has drained, and a SIGTERM flush covers processes
30
+ * with their own shutdown path.
31
+ *
32
+ * Reservations (aiCalls, pipelines, plugins …) never come through here — they
33
+ * need the synchronous answer and keep `reserveQuota`.
34
+ */
35
+ import type { QuotaService, QuotaUsageAttribution } from './quota.js';
36
+ import type { QuotaType } from '../types/common.js';
37
+ /** Flush interval (ms). `0` disables batching: every increment is sent on its own. */
38
+ export declare const QUOTA_INCREMENT_FLUSH_MS: number;
39
+ /** Most attribution groups held between flushes, across every org. */
40
+ export declare const QUOTA_INCREMENT_BUFFER_MAX: number;
41
+ /** Most groups one metered increment carries (the quota service enforces the same bound). */
42
+ export declare const MAX_GROUPS_PER_INCREMENT = 500;
43
+ /** One attribution group of a metered increment: who spent `amount` units. */
44
+ export interface MeteredIncrementGroup {
45
+ amount: number;
46
+ attribution?: Omit<QuotaUsageAttribution, 'requestId'>;
47
+ }
48
+ /** Sends one (org, type)'s groups. Resolves when the quota service answered (or not). */
49
+ export type MeteredIncrementSender = (orgId: string, quotaType: QuotaType, groups: MeteredIncrementGroup[]) => Promise<void>;
50
+ /** A per-pod increment aggregator over one sender. Exported for tests. */
51
+ export declare class QuotaIncrementBatcher {
52
+ private readonly send;
53
+ private readonly opts;
54
+ private buffer;
55
+ private groupCount;
56
+ private inFlight;
57
+ private timer;
58
+ constructor(send: MeteredIncrementSender, opts?: {
59
+ flushMs: number;
60
+ maxGroups: number;
61
+ });
62
+ /** Units waiting for the next flush (tests, metrics). */
63
+ pendingUnits(): number;
64
+ /** Count `amount` units for (org, type). Never throws, never awaits. */
65
+ add(orgId: string, quotaType: QuotaType, attribution?: QuotaUsageAttribution, amount?: number): void;
66
+ /** Send everything buffered now. Resolves once every POST has settled. */
67
+ flush(): Promise<void>;
68
+ /** Stop the timer (tests; process teardown). Buffered units stay until {@link flush}. */
69
+ stop(): void;
70
+ private arm;
71
+ private dispatch;
72
+ private sendSafely;
73
+ }
74
+ /** The batcher feeding `quotaService.incrementMetered`. */
75
+ export declare function batcherFor(quotaService: QuotaService, sender: MeteredIncrementSender): QuotaIncrementBatcher;
76
+ /**
77
+ * Flush every pod-local batcher. Called by `runServer` once the HTTP server has
78
+ * stopped accepting and in-flight requests have finished (their `finish`
79
+ * meters are then all buffered). Never rejects.
80
+ */
81
+ export declare function flushQuotaIncrements(): Promise<void>;
@@ -0,0 +1,166 @@
1
+ // Copyright 2026 Pipeline Builder Contributors
2
+ // SPDX-License-Identifier: Apache-2.0
3
+ import { runConcurrent } from '../utils/concurrency.js';
4
+ import { envInt } from '../utils/env.js';
5
+ import { createLogger } from '../utils/logger.js';
6
+ import { emitCounter } from '../utils/metric-emitter.js';
7
+ const logger = createLogger('quota-increment-batcher');
8
+ /** Flush interval (ms). `0` disables batching: every increment is sent on its own. */
9
+ export const QUOTA_INCREMENT_FLUSH_MS = envInt('QUOTA_INCREMENT_FLUSH_MS', 1000, { min: 0, max: 60_000 });
10
+ /** Most attribution groups held between flushes, across every org. */
11
+ export const QUOTA_INCREMENT_BUFFER_MAX = envInt('QUOTA_INCREMENT_BUFFER_MAX', 10_000, { min: 1 });
12
+ /** Most groups one metered increment carries (the quota service enforces the same bound). */
13
+ export const MAX_GROUPS_PER_INCREMENT = 500;
14
+ /** Concurrent POSTs per flush. */
15
+ const FLUSH_CONCURRENCY = 8;
16
+ /** The attribution a group aggregates on — everything but the per-request id. */
17
+ function groupAttribution(a) {
18
+ if (!a)
19
+ return undefined;
20
+ const { requestId: _requestId, ...rest } = a;
21
+ return Object.keys(rest).length > 0 ? rest : undefined;
22
+ }
23
+ function groupKey(a) {
24
+ return a ? JSON.stringify([a.principalType, a.principalId, a.keyId, a.route, a.pipelineId]) : '';
25
+ }
26
+ /** A per-pod increment aggregator over one sender. Exported for tests. */
27
+ export class QuotaIncrementBatcher {
28
+ send;
29
+ opts;
30
+ buffer = new Map();
31
+ groupCount = 0;
32
+ inFlight = null;
33
+ timer = null;
34
+ constructor(send, opts = { flushMs: QUOTA_INCREMENT_FLUSH_MS, maxGroups: QUOTA_INCREMENT_BUFFER_MAX }) {
35
+ this.send = send;
36
+ this.opts = opts;
37
+ }
38
+ /** Units waiting for the next flush (tests, metrics). */
39
+ pendingUnits() {
40
+ let n = 0;
41
+ for (const s of this.buffer.values())
42
+ for (const g of s.groups.values())
43
+ n += g.amount;
44
+ return n;
45
+ }
46
+ /** Count `amount` units for (org, type). Never throws, never awaits. */
47
+ add(orgId, quotaType, attribution, amount = 1) {
48
+ const attr = groupAttribution(attribution);
49
+ if (this.opts.flushMs === 0) {
50
+ this.dispatch(orgId, quotaType, [{ amount, ...(attr && { attribution: attr }) }]);
51
+ return;
52
+ }
53
+ const seriesKey = `${orgId}\u0000${quotaType}`;
54
+ const key = groupKey(attr);
55
+ const existing = this.buffer.get(seriesKey)?.groups.get(key);
56
+ if (existing) {
57
+ existing.amount += amount;
58
+ return;
59
+ }
60
+ if (this.groupCount >= this.opts.maxGroups) {
61
+ if (this.inFlight) {
62
+ emitCounter('quota_increment_dropped_total', { quotaType }, amount);
63
+ return;
64
+ }
65
+ void this.flush();
66
+ }
67
+ let series = this.buffer.get(seriesKey);
68
+ if (!series) {
69
+ series = { orgId, quotaType, groups: new Map() };
70
+ this.buffer.set(seriesKey, series);
71
+ }
72
+ series.groups.set(key, { amount, ...(attr && { attribution: attr }) });
73
+ this.groupCount += 1;
74
+ this.arm();
75
+ }
76
+ /** Send everything buffered now. Resolves once every POST has settled. */
77
+ async flush() {
78
+ if (this.buffer.size === 0)
79
+ return this.inFlight ?? undefined;
80
+ const batch = [...this.buffer.values()];
81
+ this.buffer = new Map();
82
+ this.groupCount = 0;
83
+ const previous = this.inFlight;
84
+ const run = (async () => {
85
+ await runConcurrent(batch, FLUSH_CONCURRENCY, async (series) => {
86
+ const groups = [...series.groups.values()];
87
+ for (let i = 0; i < groups.length; i += MAX_GROUPS_PER_INCREMENT) {
88
+ await this.sendSafely(series.orgId, series.quotaType, groups.slice(i, i + MAX_GROUPS_PER_INCREMENT));
89
+ }
90
+ });
91
+ if (previous)
92
+ await previous;
93
+ })();
94
+ this.inFlight = run;
95
+ try {
96
+ await run;
97
+ }
98
+ finally {
99
+ if (this.inFlight === run)
100
+ this.inFlight = null;
101
+ }
102
+ }
103
+ /** Stop the timer (tests; process teardown). Buffered units stay until {@link flush}. */
104
+ stop() {
105
+ if (this.timer)
106
+ clearInterval(this.timer);
107
+ this.timer = null;
108
+ }
109
+ arm() {
110
+ if (this.timer)
111
+ return;
112
+ this.timer = setInterval(() => { void this.flush(); }, this.opts.flushMs);
113
+ this.timer.unref?.();
114
+ armShutdownFlush();
115
+ }
116
+ dispatch(orgId, quotaType, groups) {
117
+ void this.sendSafely(orgId, quotaType, groups);
118
+ }
119
+ async sendSafely(orgId, quotaType, groups) {
120
+ try {
121
+ await this.send(orgId, quotaType, groups);
122
+ }
123
+ catch (err) {
124
+ logger.warn('Metered quota increment failed', { orgId, quotaType, error: String(err) });
125
+ emitCounter('quota_increment_failures_total', { reason: 'exception', quotaType });
126
+ }
127
+ }
128
+ }
129
+ /** One batcher per quota client, so a test's fake client never shares a buffer. */
130
+ const batchers = new WeakMap();
131
+ /** The live batchers, for the shutdown flush (a WeakMap cannot be iterated). */
132
+ const live = new Set();
133
+ /** The batcher feeding `quotaService.incrementMetered`. */
134
+ export function batcherFor(quotaService, sender) {
135
+ let b = batchers.get(quotaService);
136
+ if (!b) {
137
+ b = new QuotaIncrementBatcher(sender);
138
+ batchers.set(quotaService, b);
139
+ live.add(b);
140
+ }
141
+ return b;
142
+ }
143
+ /**
144
+ * Flush every pod-local batcher. Called by `runServer` once the HTTP server has
145
+ * stopped accepting and in-flight requests have finished (their `finish`
146
+ * meters are then all buffered). Never rejects.
147
+ */
148
+ export async function flushQuotaIncrements() {
149
+ await Promise.all([...live].map((b) => b.flush().catch(() => undefined)));
150
+ }
151
+ let shutdownArmed = false;
152
+ /**
153
+ * SIGTERM flush for processes that don't shut down through `runServer`.
154
+ *
155
+ * Armed only when the process ALREADY handles SIGTERM (every service registers
156
+ * its shutdown at startup, before the first request is metered): adding the
157
+ * first listener would switch off Node's default exit-on-SIGTERM for a process
158
+ * that relied on it (a CLI, a test worker).
159
+ */
160
+ function armShutdownFlush() {
161
+ if (shutdownArmed || process.listenerCount('SIGTERM') === 0)
162
+ return;
163
+ shutdownArmed = true;
164
+ process.once('SIGTERM', () => { void flushQuotaIncrements(); });
165
+ }
166
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicXVvdGEtaW5jcmVtZW50LWJhdGNoZXIuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvc2VydmljZXMvcXVvdGEtaW5jcmVtZW50LWJhdGNoZXIudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsK0NBQStDO0FBQy9DLHNDQUFzQztBQXVDdEMsT0FBTyxFQUFFLGFBQWEsRUFBRSxNQUFNLHlCQUF5QixDQUFDO0FBQ3hELE9BQU8sRUFBRSxNQUFNLEVBQUUsTUFBTSxpQkFBaUIsQ0FBQztBQUN6QyxPQUFPLEVBQUUsWUFBWSxFQUFFLE1BQU0sb0JBQW9CLENBQUM7QUFDbEQsT0FBTyxFQUFFLFdBQVcsRUFBRSxNQUFNLDRCQUE0QixDQUFDO0FBRXpELE1BQU0sTUFBTSxHQUFHLFlBQVksQ0FBQyx5QkFBeUIsQ0FBQyxDQUFDO0FBRXZELHNGQUFzRjtBQUN0RixNQUFNLENBQUMsTUFBTSx3QkFBd0IsR0FBRyxNQUFNLENBQUMsMEJBQTBCLEVBQUUsSUFBSSxFQUFFLEVBQUUsR0FBRyxFQUFFLENBQUMsRUFBRSxHQUFHLEVBQUUsTUFBTSxFQUFFLENBQUMsQ0FBQztBQUUxRyxzRUFBc0U7QUFDdEUsTUFBTSxDQUFDLE1BQU0sMEJBQTBCLEdBQUcsTUFBTSxDQUFDLDRCQUE0QixFQUFFLE1BQU0sRUFBRSxFQUFFLEdBQUcsRUFBRSxDQUFDLEVBQUUsQ0FBQyxDQUFDO0FBRW5HLDZGQUE2RjtBQUM3RixNQUFNLENBQUMsTUFBTSx3QkFBd0IsR0FBRyxHQUFHLENBQUM7QUFFNUMsa0NBQWtDO0FBQ2xDLE1BQU0saUJBQWlCLEdBQUcsQ0FBQyxDQUFDO0FBaUI1QixpRkFBaUY7QUFDakYsU0FBUyxnQkFBZ0IsQ0FBQyxDQUFvQztJQUM1RCxJQUFJLENBQUMsQ0FBQztRQUFFLE9BQU8sU0FBUyxDQUFDO0lBQ3pCLE1BQU0sRUFBRSxTQUFTLEVBQUUsVUFBVSxFQUFFLEdBQUcsSUFBSSxFQUFFLEdBQUcsQ0FBQyxDQUFDO0lBQzdDLE9B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b0I7SUFDeEMsTUFBTSxPQUFPLENBQUMsR0FBRyxDQUFDLENBQUMsR0FBRyxJQUFJLENBQUMsQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLEVBQUUsRUFBRSxDQUFDLENBQUMsQ0FBQyxLQUFLLEVBQUUsQ0FBQyxLQUFLLENBQUMsR0FBRyxFQUFFLENBQUMsU0FBUyxDQUFDLENBQUMsQ0FBQyxDQUFDO0FBQzVFLENBQUM7QUFFRCxJQUFJLGFBQWEsR0FBRyxLQUFLLENBQUM7QUFFMUI7Ozs7Ozs7R0FPRztBQUNILFNBQVMsZ0JBQWdCO0lBQ3ZCLElBQUksYUFBYSxJQUFJLE9BQU8sQ0FBQyxhQUFhLENBQUMsU0FBUyxDQUFDLEtBQUssQ0FBQztRQUFFLE9BQU87SUFDcEUsYUFBYSxHQUFHLElBQUksQ0FBQztJQUNyQixPQUFPLENBQUMsSUFBSSxDQUFDLFNBQVMsRUFBRSxHQUFHLEVBQUUsR0FBRyxLQUFLLG9CQUFvQixFQUFFLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQztBQUNsRSxDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiLy8gQ29weXJpZ2h0IDIwMjYgUGlwZWxpbmUgQnVpbGRlciBDb250cmlidXRvcnNcbi8vIFNQRFgtTGljZW5zZS1JZGVudGlmaWVyOiBBcGFjaGUtMi4wXG5cbi8qKlxuICogUGVyLXBvZCBhZ2dyZWdhdGlvbiBvZiBNRVRFUklORyBpbmNyZW1lbnRzIChhcGlDYWxscyAvIGF1dG9tYXRpb25DYWxscykuXG4gKlxuICogTWV0ZXJpbmcgdXNlZCB0byBiZSBvbmUgUE9TVCB0byB0aGUgcXVvdGEgc2VydmljZSBwZXIgc3VjY2Vzc2Z1bCByZXF1ZXN0LFxuICogYW5kIGVhY2ggUE9TVCB3YXMgYSBjb25kaXRpb25hbCBgZmluZE9uZUFuZFVwZGF0ZWAgb24gdGhlIG9yZydzIGhvdCBkb2N1bWVudCxcbiAqIGEgdGVhbSBjb3VudGVyIHVwZGF0ZSwgYSBsZWRnZXIgaW5zZXJ0IGFuZCBhIHRocmVzaG9sZCBjaGVjay4gQXQgdGhlIHJlcXVlc3RcbiAqIHJhdGVzIHRoZSBtZXRlciBleGlzdHMgZm9yLCB0aGUgcXVvdGEgc2VydmljZSB3YXMgZG9pbmcgbW9yZSB3b3JrIHRoYW4gdGhlXG4gKiByZXF1ZXN0IGl0IHdhcyBjb3VudGluZy5cbiAqXG4gKiBJbmNyZW1lbnRzIGFyZSBub3cgc3VtbWVkIGluIG1lbW9yeSBwZXIgKG9yZywgcXVvdGEgdHlwZSkgYW5kLCBpbnNpZGUgdGhhdCxcbiAqIHBlciBhdHRyaWJ1dGlvbiBncm91cCAocHJpbmNpcGFsLCBrZXksIHJvdXRlIHBhdHRlcm4sIHBpcGVsaW5lKSwgdGhlbiBzZW50XG4gKiBldmVyeSBgUVVPVEFfSU5DUkVNRU5UX0ZMVVNIX01TYCAoZGVmYXVsdCAxMDAwKSBhcyBPTkUgbWV0ZXJlZCBpbmNyZW1lbnQgcGVyXG4gKiAob3JnLCB0eXBlKSBjYXJyeWluZyBpdHMgZ3JvdXBzLiBUaGUgcXVvdGEgc2VydmljZSBhcHBsaWVzIHRoZSBzdW0gYXRvbWljYWxseVxuICogYWdhaW5zdCB0aGUgKHBvb2xlZCkgY2FwIHdpdGggcGFydGlhbCBhZG1pc3Npb246IHRoZSBjb3VudGVyIG1vdmVzIGJ5IGFzIG11Y2hcbiAqIGFzIGZpdHMgYW5kIG5ldmVyIHBhc3QgdGhlIGxpbWl0LCBhbmQgdGhlIHJlc3QgaXMgcmVjb3JkZWQgYXMgYG92ZXJzaG9vdGAgaW5cbiAqIHRoZSBsZWRnZXIgKGFwaS9xdW90YSBgaW5jcmVtZW50TWV0ZXJlZGApLlxuICpcbiAqIEd1YXJhbnRlZXMsIGFuZCB0aGVpciBsaW1pdHM6XG4gKiAgLSB0aGUgY291bnRlciBtYXkgTEFHIHJlYWwgdXNhZ2UgYnkgdXAgdG8gb25lIGZsdXNoIGludGVydmFsIChwbHVzIHRoZSBIVFRQXG4gKiAgICBob3ApOyBlbmZvcmNlbWVudCBpcyB1bmFmZmVjdGVkIGJleW9uZCB0aGF0IGxhZywgYmVjYXVzZSB0aGUgY291bnRlclxuICogICAgc3RpbGwgbmV2ZXIgZXhjZWVkcyB0aGUgY2FwO1xuICogIC0gdGhlIGJ1ZmZlciBpcyBib3VuZGVkIChgUVVPVEFfSU5DUkVNRU5UX0JVRkZFUl9NQVhgIGF0dHJpYnV0aW9uIGdyb3VwcykuXG4gKiAgICBSZWFjaGluZyBpdCBmbHVzaGVzIGltbWVkaWF0ZWx5OyBvbmx5IHdoaWxlIGEgZmx1c2ggaXMgYWxyZWFkeSBpbiBmbGlnaHRcbiAqICAgIGlzIGEgTkVXIGdyb3VwIGRyb3BwZWQsIGNvdW50ZWQgb24gYHF1b3RhX2luY3JlbWVudF9kcm9wcGVkX3RvdGFsYDtcbiAqICAtIGEgZmx1c2ggdGhhdCBmYWlscyBpcyBjb3VudGVkIG9uIGBxdW90YV9pbmNyZW1lbnRfZmFpbHVyZXNfdG90YWxgICh0aGVcbiAqICAgIFF1b3RhSW5jcmVtZW50RmFpbHVyZXMgYWxlcnQpIGFuZCBOT1QgcmV0cmllZDogdGhlIFBPU1QgbWF5IGhhdmUgbGFuZGVkLFxuICogICAgYW5kIGEgcmV0cnkgd291bGQgZG91YmxlLWNvdW50O1xuICogIC0gZ3JhY2VmdWwgc2h1dGRvd24gZmx1c2hlczogYHJ1blNlcnZlcmAgYXdhaXRzIHtAbGluayBmbHVzaFF1b3RhSW5jcmVtZW50c31cbiAqICAgIGFmdGVyIHRoZSBIVFRQIHNlcnZlciBoYXMgZHJhaW5lZCwgYW5kIGEgU0lHVEVSTSBmbHVzaCBjb3ZlcnMgcHJvY2Vzc2VzXG4gKiAgICB3aXRoIHRoZWlyIG93biBzaHV0ZG93biBwYXRoLlxuICpcbiAqIFJlc2VydmF0aW9ucyAoYWlDYWxscywgcGlwZWxpbmVzLCBwbHVnaW5zIOKApikgbmV2ZXIgY29tZSB0aHJvdWdoIGhlcmUg4oCUIHRoZXlcbiAqIG5lZWQgdGhlIHN5bmNocm9ub3VzIGFuc3dlciBhbmQga2VlcCBgcmVzZXJ2ZVF1b3RhYC5cbiAqL1xuXG5pbXBvcnQgdHlwZSB7IFF1b3RhU2VydmljZSwgUXVvdGFVc2FnZUF0dHJpYnV0aW9uIH0gZnJvbSAnLi9xdW90YS5qcyc7XG5pbXBvcnQgdHlwZSB7IFF1b3RhVHlwZSB9IGZyb20gJy4uL3R5cGVzL2NvbW1vbi5qcyc7XG5pbXBvcnQgeyBydW5Db25jdXJyZW50IH0gZnJvbSAnLi4vdXRpbHMvY29uY3VycmVuY3kuanMnO1xuaW1wb3J0IHsgZW52SW50IH0gZnJvbSAnLi4vdXRpbHMvZW52LmpzJztcbmltcG9ydCB7IGNyZWF0ZUxvZ2dlciB9IGZyb20gJy4uL3V0aWxzL2xvZ2dlci5qcyc7XG5pbXBvcnQgeyBlbWl0Q291bnRlciB9IGZyb20gJy4uL3V0aWxzL21ldHJpYy1lbWl0dGVyLmpzJztcblxuY29uc3QgbG9nZ2VyID0gY3JlYXRlTG9nZ2VyKCdxdW90YS1pbmNyZW1lbnQtYmF0Y2hlcicpO1xuXG4vKiogRmx1c2ggaW50ZXJ2YWwgKG1zKS4gYDBgIGRpc2FibGVzIGJhdGNoaW5nOiBldmVyeSBpbmNyZW1lbnQgaXMgc2VudCBvbiBpdHMgb3duLiAqL1xuZXhwb3J0IGNvbnN0IFFVT1RBX0lOQ1JFTUVOVF9GTFVTSF9NUyA9IGVudkludCgnUVVPVEFfSU5DUkVNRU5UX0ZMVVNIX01TJywgMTAwMCwgeyBtaW46IDAsIG1heDogNjBfMDAwIH0pO1xuXG4vKiogTW9zdCBhdHRyaWJ1dGlvbiBncm91cHMgaGVsZCBiZXR3ZWVuIGZsdXNoZXMsIGFjcm9zcyBldmVyeSBvcmcuICovXG5leHBvcnQgY29uc3QgUVVPVEFfSU5DUkVNRU5UX0JVRkZFUl9NQVggPSBlbnZJbnQoJ1FVT1RBX0lOQ1JFTUVOVF9CVUZGRVJfTUFYJywgMTBfMDAwLCB7IG1pbjogMSB9KTtcblxuLyoqIE1vc3QgZ3JvdXBzIG9uZSBtZXRlcmVkIGluY3JlbWVudCBjYXJyaWVzICh0aGUgcXVvdGEgc2VydmljZSBlbmZvcmNlcyB0aGUgc2FtZSBib3VuZCkuICovXG5leHBvcnQgY29uc3QgTUFYX0dST1VQU19QRVJfSU5DUkVNRU5UID0gNTAwO1xuXG4vKiogQ29uY3VycmVudCBQT1NUcyBwZXIgZmx1c2guICovXG5jb25zdCBGTFVTSF9DT05DVVJSRU5DWSA9IDg7XG5cbi8qKiBPbmUgYXR0cmlidXRpb24gZ3JvdXAgb2YgYSBtZXRlcmVkIGluY3JlbWVudDogd2hvIHNwZW50IGBhbW91bnRgIHVuaXRzLiAqL1xuZXhwb3J0IGludGVyZmFjZSBNZXRlcmVkSW5jcmVtZW50R3JvdXAge1xuICBhbW91bnQ6IG51bWJlcjtcbiAgYXR0cmlidXRpb24/OiBPbWl0PFF1b3RhVXNhZ2VBdHRyaWJ1dGlvbiwgJ3JlcXVlc3RJZCc+O1xufVxuXG4vKiogU2VuZHMgb25lIChvcmcsIHR5cGUpJ3MgZ3JvdXBzLiBSZXNvbHZlcyB3aGVuIHRoZSBxdW90YSBzZXJ2aWNlIGFuc3dlcmVkIChvciBub3QpLiAqL1xuZXhwb3J0IHR5cGUgTWV0ZXJlZEluY3JlbWVudFNlbmRlciA9IChvcmdJZDogc3RyaW5nLCBxdW90YVR5cGU6IFF1b3RhVHlwZSwgZ3JvdXBzOiBNZXRlcmVkSW5jcmVtZW50R3JvdXBbXSkgPT4gUHJvbWlzZTx2b2lkPjtcblxuaW50ZXJmYWNlIFBlbmRpbmdTZXJpZXMge1xuICBvcmdJZDogc3RyaW5nO1xuICBxdW90YVR5cGU6IFF1b3RhVHlwZTtcbiAgZ3JvdXBzOiBNYXA8c3RyaW5nLCBNZXRlcmVkSW5jcmVtZW50R3JvdXA+O1xufVxuXG4vKiogVGhlIGF0dHJpYnV0aW9uIGEgZ3JvdXAgYWdncmVnYXRlcyBvbiDigJQgZXZlcnl0aGluZyBidXQgdGhlIHBlci1yZXF1ZXN0IGlkLiAqL1xuZnVuY3Rpb24gZ3JvdXBBdHRyaWJ1dGlvbihhOiBRdW90YVVzYWdlQXR0cmlidXRpb24gfCB1bmRlZmluZWQpOiBNZXRlcmVkSW5jcmVtZW50R3JvdXBbJ2F0dHJpYnV0aW9uJ10ge1xuICBpZiAoIWEpIHJldHVybiB1bmRlZmluZWQ7XG4gIGNvbnN0IHsgcmVxdWVzdElkOiBfcmVxdWVzdElkLCAuLi5yZXN0IH0gPSBhO1xuICByZXR1cm4gT2JqZWN0LmtleXMocmVzdCkubGVuZ3RoID4gMCA/IHJlc3QgOiB1bmRlZmluZWQ7XG59XG5cbmZ1bmN0aW9uIGdyb3VwS2V5KGE6IE1ldGVyZWRJbmNyZW1lbnRHcm91cFsnYXR0cmlidXRpb24nXSk6IHN0cmluZyB7XG4gIHJldHVybiBhID8gSlNPTi5zdHJpbmdpZnkoW2EucHJpbmNpcGFsVHlwZSwgYS5wcmluY2lwYWxJZCwgYS5rZXlJZCwgYS5yb3V0ZSwgYS5waXBlbGluZUlkXSkgOiAnJztcbn1cblxuLyoqIEEgcGVyLXBvZCBpbmNyZW1lbnQgYWdncmVnYXRvciBvdmVyIG9uZSBzZW5kZXIuIEV4cG9ydGVkIGZvciB0ZXN0cy4gKi9cbmV4cG9ydCBjbGFzcyBRdW90YUluY3JlbWVudEJhdGNoZXIge1xuICBwcml2YXRlIGJ1ZmZlciA9IG5ldyBNYXA8c3RyaW5nLCBQZW5kaW5nU2VyaWVzPigpO1xuICBwcml2YXRlIGdyb3VwQ291bnQgPSAwO1xuICBwcml2YXRlIGluRmxpZ2h0OiBQcm9taXNlPHZvaWQ+IHwgbnVsbCA9IG51bGw7XG4gIHByaXZhdGUgdGltZXI6IE5vZGVKUy5UaW1lb3V0IHwgbnVsbCA9IG51bGw7XG5cbiAgY29uc3RydWN0b3IoXG4gICAgcHJpdmF0ZSByZWFkb25seSBzZW5kOiBNZXRlcmVkSW5jcmVtZW50U2VuZGVyLFxuICAgIHByaXZhdGUgcmVhZG9ubHkgb3B0czogeyBmbHVzaE1zOiBudW1iZXI7IG1heEdyb3VwczogbnVtYmVyIH0gPSB7IGZsdXNoTXM6IFFVT1RBX0lOQ1JFTUVOVF9GTFVTSF9NUywgbWF4R3JvdXBzOiBRVU9UQV9JTkNSRU1FTlRfQlVGRkVSX01BWCB9LFxuICApIHt9XG5cbiAgLyoqIFVuaXRzIHdhaXRpbmcgZm9yIHRoZSBuZXh0IGZsdXNoICh0ZXN0cywgbWV0cmljcykuICovXG4gIHBlbmRpbmdVbml0cygpOiBudW1iZXIge1xuICAgIGxldCBuID0gMDtcbiAgICBmb3IgKGNvbnN0IHMgb2YgdGhpcy5idWZmZXIudmFsdWVzKCkpIGZvciAoY29uc3QgZyBvZiBzLmdyb3Vwcy52YWx1ZXMoKSkgbiArPSBnLmFtb3VudDtcbiAgICByZXR1cm4gbjtcbiAgfVxuXG4gIC8qKiBDb3VudCBgYW1vdW50YCB1bml0cyBmb3IgKG9yZywgdHlwZSkuIE5ldmVyIHRocm93cywgbmV2ZXIgYXdhaXRzLiAqL1xuICBhZGQob3JnSWQ6IHN0cmluZywgcXVvdGFUeXBlOiBRdW90YVR5cGUsIGF0dHJpYnV0aW9uPzogUXVvdGFVc2FnZUF0dHJpYnV0aW9uLCBhbW91bnQ6IG51bWJlciA9IDEpOiB2b2lkIHtcbiAgICBjb25zdCBhdHRyID0gZ3JvdXBBdHRyaWJ1dGlvbihhdHRyaWJ1dGlvbik7XG4gICAgaWYgKHRoaXMub3B0cy5mbHVzaE1zID09PSAwKSB7XG4gICAgICB0aGlzLmRpc3BhdGNoKG9yZ0lkLCBxdW90YVR5cGUsIFt7IGFtb3VudCwgLi4uKGF0dHIgJiYgeyBhdHRyaWJ1dGlvbjogYXR0ciB9KSB9XSk7XG4gICAgICByZXR1cm47XG4gICAgfVxuICAgIGNvbnN0IHNlcmllc0tleSA9IGAke29yZ0lkfVxcdTAwMDAke3F1b3RhVHlwZX1gO1xuICAgIGNvbnN0IGtleSA9IGdyb3VwS2V5KGF0dHIpO1xuICAgIGNvbnN0IGV4aXN0aW5nID0gdGhpcy5idWZmZXIuZ2V0KHNlcmllc0tleSk/Lmdyb3Vwcy5nZXQoa2V5KTtcbiAgICBpZiAoZXhpc3RpbmcpIHtcbiAgICAgIGV4aXN0aW5nLmFtb3VudCArPSBhbW91bnQ7XG4gICAgICByZXR1cm47XG4gICAgfVxuICAgIGlmICh0aGlzLmdyb3VwQ291bnQgPj0gdGhpcy5vcHRzLm1heEdyb3Vwcykge1xuICAgICAgaWYgKHRoaXMuaW5GbGlnaHQpIHtcbiAgICAgICAgZW1pdENvdW50ZXIoJ3F1b3RhX2luY3JlbWVudF9kcm9wcGVkX3RvdGFsJywgeyBxdW90YVR5cGUgfSwgYW1vdW50KTtcbiAgICAgICAgcmV0dXJuO1xuICAgICAgfVxuICAgICAgdm9pZCB0aGlzLmZsdXNoKCk7XG4gICAgfVxuICAgIGxldCBzZXJpZXMgPSB0aGlzLmJ1ZmZlci5nZXQoc2VyaWVzS2V5KTtcbiAgICBpZiAoIXNlcmllcykge1xuICAgICAgc2VyaWVzID0geyBvcmdJZCwgcXVvdGFUeXBlLCBncm91cHM6IG5ldyBNYXAoKSB9O1xuICAgICAgdGhpcy5idWZmZXIuc2V0KHNlcmllc0tleSwgc2VyaWVzKTtcbiAgICB9XG4gICAgc2VyaWVzLmdyb3Vwcy5zZXQoa2V5LCB7IGFtb3VudCwgLi4uKGF0dHIgJiYgeyBhdHRyaWJ1dGlvbjogYXR0ciB9KSB9KTtcbiAgICB0aGlzLmdyb3VwQ291bnQgKz0gMTtcbiAgICB0aGlzLmFybSgpO1xuICB9XG5cbiAgLyoqIFNlbmQgZXZlcnl0aGluZyBidWZmZXJlZCBub3cuIFJlc29sdmVzIG9uY2UgZXZlcnkgUE9TVCBoYXMgc2V0dGxlZC4gKi9cbiAgYXN5bmMgZmx1c2goKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgaWYgKHRoaXMuYnVmZmVyLnNpemUgPT09IDApIHJldHVybiB0aGlzLmluRmxpZ2h0ID8/IHVuZGVmaW5lZDtcbiAgICBjb25zdCBiYXRjaCA9IFsuLi50aGlzLmJ1ZmZlci52YWx1ZXMoKV07XG4gICAgdGhpcy5idWZmZXIgPSBuZXcgTWFwKCk7XG4gICAgdGhpcy5ncm91cENvdW50ID0gMDtcbiAgICBjb25zdCBwcmV2aW91cyA9IHRoaXMuaW5GbGlnaHQ7XG4gICAgY29uc3QgcnVuID0gKGFzeW5jICgpID0+IHtcbiAgICAgIGF3YWl0IHJ1bkNvbmN1cnJlbnQoYmF0Y2gsIEZMVVNIX0NPTkNVUlJFTkNZLCBhc3luYyAoc2VyaWVzKSA9PiB7XG4gICAgICAgIGNvbnN0IGdyb3VwcyA9IFsuLi5zZXJpZXMuZ3JvdXBzLnZhbHVlcygpXTtcbiAgICAgICAgZm9yIChsZXQgaSA9IDA7IGkgPCBncm91cHMubGVuZ3RoOyBpICs9IE1BWF9HUk9VUFNfUEVSX0lOQ1JFTUVOVCkge1xuICAgICAgICAgIGF3YWl0IHRoaXMuc2VuZFNhZmVseShzZXJpZXMub3JnSWQsIHNlcmllcy5xdW90YVR5cGUsIGdyb3Vwcy5zbGljZShpLCBpICsgTUFYX0dST1VQU19QRVJfSU5DUkVNRU5UKSk7XG4gICAgICAgIH1cbiAgICAgIH0pO1xuICAgICAgaWYgKHByZXZpb3VzKSBhd2FpdCBwcmV2aW91cztcbiAgICB9KSgpO1xuICAgIHRoaXMuaW5GbGlnaHQgPSBydW47XG4gICAgdHJ5IHtcbiAgICAgIGF3YWl0IHJ1bjtcbiAgICB9IGZpbmFsbHkge1xuICAgICAgaWYgKHRoaXMuaW5GbGlnaHQgPT09IHJ1bikgdGhpcy5pbkZsaWdodCA9IG51bGw7XG4gICAgfVxuICB9XG5cbiAgLyoqIFN0b3AgdGhlIHRpbWVyICh0ZXN0czsgcHJvY2VzcyB0ZWFyZG93bikuIEJ1ZmZlcmVkIHVuaXRzIHN0YXkgdW50aWwge0BsaW5rIGZsdXNofS4gKi9cbiAgc3RvcCgpOiB2b2lkIHtcbiAgICBpZiAodGhpcy50aW1lcikgY2xlYXJJbnRlcnZhbCh0aGlzLnRpbWVyKTtcbiAgICB0aGlzLnRpbWVyID0gbnVsbDtcbiAgfVxuXG4gIHByaXZhdGUgYXJtKCk6IHZvaWQge1xuICAgIGlmICh0aGlzLnRpbWVyKSByZXR1cm47XG4gICAgdGhpcy50aW1lciA9IHNldEludGVydmFsKCgpID0+IHsgdm9pZCB0aGlzLmZsdXNoKCk7IH0sIHRoaXMub3B0cy5mbHVzaE1zKTtcbiAgICB0aGlzLnRpbWVyLnVucmVmPy4oKTtcbiAgICBhcm1TaHV0ZG93bkZsdXNoKCk7XG4gIH1cblxuICBwcml2YXRlIGRpc3BhdGNoKG9yZ0lkOiBzdHJpbmcsIHF1b3RhVHlwZTogUXVvdGFUeXBlLCBncm91cHM6IE1ldGVyZWRJbmNyZW1lbnRHcm91cFtdKTogdm9pZCB7XG4gICAgdm9pZCB0aGlzLnNlbmRTYWZlbHkob3JnSWQsIHF1b3RhVHlwZSwgZ3JvdXBzKTtcbiAgfVxuXG4gIHByaXZhdGUgYXN5bmMgc2VuZFNhZmVseShvcmdJZDogc3RyaW5nLCBxdW90YVR5cGU6IFF1b3RhVHlwZSwgZ3JvdXBzOiBNZXRlcmVkSW5jcmVtZW50R3JvdXBbXSk6IFByb21pc2U8dm9pZD4ge1xuICAgIHRyeSB7XG4gICAgICBhd2FpdCB0aGlzLnNlbmQob3JnSWQsIHF1b3RhVHlwZSwgZ3JvdXBzKTtcbiAgICB9IGNhdGNoIChlcnIpIHtcbiAgICAgIGxvZ2dlci53YXJuKCdNZXRlcmVkIHF1b3RhIGluY3JlbWVudCBmYWlsZWQnLCB7IG9yZ0lkLCBxdW90YVR5cGUsIGVycm9yOiBTdHJpbmcoZXJyKSB9KTtcbiAgICAgIGVtaXRDb3VudGVyKCdxdW90YV9pbmNyZW1lbnRfZmFpbHVyZXNfdG90YWwnLCB7IHJlYXNvbjogJ2V4Y2VwdGlvbicsIHF1b3RhVHlwZSB9KTtcbiAgICB9XG4gIH1cbn1cblxuLyoqIE9uZSBiYXRjaGVyIHBlciBxdW90YSBjbGllbnQsIHNvIGEgdGVzdCdzIGZha2UgY2xpZW50IG5ldmVyIHNoYXJlcyBhIGJ1ZmZlci4gKi9cbmNvbnN0IGJhdGNoZXJzID0gbmV3IFdlYWtNYXA8UXVvdGFTZXJ2aWNlLCBRdW90YUluY3JlbWVudEJhdGNoZXI+KCk7XG5cbi8qKiBUaGUgbGl2ZSBiYXRjaGVycywgZm9yIHRoZSBzaHV0ZG93biBmbHVzaCAoYSBXZWFrTWFwIGNhbm5vdCBiZSBpdGVyYXRlZCkuICovXG5jb25zdCBsaXZlID0gbmV3IFNldDxRdW90YUluY3JlbWVudEJhdGNoZXI+KCk7XG5cbi8qKiBUaGUgYmF0Y2hlciBmZWVkaW5nIGBxdW90YVNlcnZpY2UuaW5jcmVtZW50TWV0ZXJlZGAuICovXG5leHBvcnQgZnVuY3Rpb24gYmF0Y2hlckZvcihxdW90YVNlcnZpY2U6IFF1b3RhU2VydmljZSwgc2VuZGVyOiBNZXRlcmVkSW5jcmVtZW50U2VuZGVyKTogUXVvdGFJbmNyZW1lbnRCYXRjaGVyIHtcbiAgbGV0IGIgPSBiYXRjaGVycy5nZXQocXVvdGFTZXJ2aWNlKTtcbiAgaWYgKCFiKSB7XG4gICAgYiA9IG5ldyBRdW90YUluY3JlbWVudEJhdGNoZXIoc2VuZGVyKTtcbiAgICBiYXRjaGVycy5zZXQocXVvdGFTZXJ2aWNlLCBiKTtcbiAgICBsaXZlLmFkZChiKTtcbiAgfVxuICByZXR1cm4gYjtcbn1cblxuLyoqXG4gKiBGbHVzaCBldmVyeSBwb2QtbG9jYWwgYmF0Y2hlci4gQ2FsbGVkIGJ5IGBydW5TZXJ2ZXJgIG9uY2UgdGhlIEhUVFAgc2VydmVyIGhhc1xuICogc3RvcHBlZCBhY2NlcHRpbmcgYW5kIGluLWZsaWdodCByZXF1ZXN0cyBoYXZlIGZpbmlzaGVkICh0aGVpciBgZmluaXNoYFxuICogbWV0ZXJzIGFyZSB0aGVuIGFsbCBidWZmZXJlZCkuIE5ldmVyIHJlamVjdHMuXG4gKi9cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBmbHVzaFF1b3RhSW5jcmVtZW50cygpOiBQcm9taXNlPHZvaWQ+IHtcbiAgYXdhaXQgUHJvbWlzZS5hbGwoWy4uLmxpdmVdLm1hcCgoYikgPT4gYi5mbHVzaCgpLmNhdGNoKCgpID0+IHVuZGVmaW5lZCkpKTtcbn1cblxubGV0IHNodXRkb3duQXJtZWQgPSBmYWxzZTtcblxuLyoqXG4gKiBTSUdURVJNIGZsdXNoIGZvciBwcm9jZXNzZXMgdGhhdCBkb24ndCBzaHV0IGRvd24gdGhyb3VnaCBgcnVuU2VydmVyYC5cbiAqXG4gKiBBcm1lZCBvbmx5IHdoZW4gdGhlIHByb2Nlc3MgQUxSRUFEWSBoYW5kbGVzIFNJR1RFUk0gKGV2ZXJ5IHNlcnZpY2UgcmVnaXN0ZXJzXG4gKiBpdHMgc2h1dGRvd24gYXQgc3RhcnR1cCwgYmVmb3JlIHRoZSBmaXJzdCByZXF1ZXN0IGlzIG1ldGVyZWQpOiBhZGRpbmcgdGhlXG4gKiBmaXJzdCBsaXN0ZW5lciB3b3VsZCBzd2l0Y2ggb2ZmIE5vZGUncyBkZWZhdWx0IGV4aXQtb24tU0lHVEVSTSBmb3IgYSBwcm9jZXNzXG4gKiB0aGF0IHJlbGllZCBvbiBpdCAoYSBDTEksIGEgdGVzdCB3b3JrZXIpLlxuICovXG5mdW5jdGlvbiBhcm1TaHV0ZG93bkZsdXNoKCk6IHZvaWQge1xuICBpZiAoc2h1dGRvd25Bcm1lZCB8fCBwcm9jZXNzLmxpc3RlbmVyQ291bnQoJ1NJR1RFUk0nKSA9PT0gMCkgcmV0dXJuO1xuICBzaHV0ZG93bkFybWVkID0gdHJ1ZTtcbiAgcHJvY2Vzcy5vbmNlKCdTSUdURVJNJywgKCkgPT4geyB2b2lkIGZsdXNoUXVvdGFJbmNyZW1lbnRzKCk7IH0pO1xufVxuIl19