@pipeline-builder/api-core 5.2.2 → 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 (91) 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/index.d.ts +1 -0
  6. package/lib/helpers/index.js +2 -1
  7. package/lib/helpers/sse-helpers.d.ts +33 -3
  8. package/lib/helpers/sse-helpers.js +91 -19
  9. package/lib/helpers/support-calendar.d.ts +69 -0
  10. package/lib/helpers/support-calendar.js +179 -0
  11. package/lib/middleware/auth.js +6 -3
  12. package/lib/middleware/deferred-quota-check.d.ts +5 -0
  13. package/lib/middleware/deferred-quota-check.js +33 -0
  14. package/lib/middleware/ecosystem-guard.d.ts +3 -3
  15. package/lib/middleware/ecosystem-guard.js +5 -5
  16. package/lib/middleware/index.d.ts +5 -2
  17. package/lib/middleware/index.js +6 -3
  18. package/lib/middleware/on-behalf.d.ts +37 -0
  19. package/lib/middleware/on-behalf.js +143 -0
  20. package/lib/middleware/permission-gates.d.ts +11 -0
  21. package/lib/middleware/permission-gates.js +7 -1
  22. package/lib/middleware/quota-exempt-routes.d.ts +36 -0
  23. package/lib/middleware/quota-exempt-routes.js +47 -0
  24. package/lib/middleware/route-table.d.ts +104 -0
  25. package/lib/middleware/route-table.js +72 -2
  26. package/lib/middleware/service-tokens.d.ts +8 -0
  27. package/lib/middleware/service-tokens.js +5 -3
  28. package/lib/middleware/step-up.js +11 -1
  29. package/lib/services/ai-call-weight.d.ts +24 -0
  30. package/lib/services/ai-call-weight.js +77 -0
  31. package/lib/services/alert-delivery.d.ts +99 -0
  32. package/lib/services/alert-delivery.js +132 -0
  33. package/lib/services/audit-context.d.ts +105 -0
  34. package/lib/services/audit-context.js +134 -0
  35. package/lib/services/index.d.ts +10 -2
  36. package/lib/services/index.js +10 -2
  37. package/lib/services/org-ai-client.d.ts +61 -0
  38. package/lib/services/org-ai-client.js +112 -0
  39. package/lib/services/pagerduty-inbound.d.ts +101 -0
  40. package/lib/services/pagerduty-inbound.js +195 -0
  41. package/lib/services/pagerduty.d.ts +109 -0
  42. package/lib/services/pagerduty.js +186 -0
  43. package/lib/services/quota-increment-batcher.d.ts +81 -0
  44. package/lib/services/quota-increment-batcher.js +166 -0
  45. package/lib/services/quota.d.ts +158 -14
  46. package/lib/services/quota.js +252 -22
  47. package/lib/services/remote-audit-client.d.ts +44 -1
  48. package/lib/services/remote-audit-client.js +106 -20
  49. package/lib/services/version-vuln-policy.d.ts +174 -0
  50. package/lib/services/version-vuln-policy.js +242 -0
  51. package/lib/types/ai-catalog.d.ts +63 -0
  52. package/lib/types/ai-catalog.js +82 -0
  53. package/lib/types/ask-proposals.js +6 -6
  54. package/lib/types/build-catalog.d.ts +154 -0
  55. package/lib/types/build-catalog.js +158 -0
  56. package/lib/types/common.d.ts +37 -3
  57. package/lib/types/common.js +20 -2
  58. package/lib/types/ecosystem-notifications.d.ts +5 -5
  59. package/lib/types/ecosystem-notifications.js +9 -3
  60. package/lib/types/error-codes.d.ts +13 -6
  61. package/lib/types/error-codes.js +18 -8
  62. package/lib/types/feature-flags.d.ts +71 -1
  63. package/lib/types/feature-flags.js +131 -11
  64. package/lib/types/index.d.ts +6 -4
  65. package/lib/types/index.js +12 -5
  66. package/lib/types/metadata-keys.d.ts +6 -0
  67. package/lib/types/metadata-keys.js +4 -1
  68. package/lib/types/permissions.d.ts +351 -3
  69. package/lib/types/permissions.js +610 -21
  70. package/lib/types/pipeline.d.ts +39 -0
  71. package/lib/types/pipeline.js +57 -1
  72. package/lib/types/plugin-health.d.ts +0 -2
  73. package/lib/types/plugin-health.js +1 -11
  74. package/lib/types/plugin-scan.d.ts +192 -42
  75. package/lib/types/plugin-scan.js +159 -43
  76. package/lib/types/quota-catalog.d.ts +247 -0
  77. package/lib/types/quota-catalog.js +122 -0
  78. package/lib/types/quota-tiers.d.ts +150 -0
  79. package/lib/types/quota-tiers.js +167 -2
  80. package/lib/types/remote-audit-actions.d.ts +1 -1
  81. package/lib/types/remote-audit-actions.js +217 -4
  82. package/lib/types/wire-vocabulary.js +8 -1
  83. package/lib/utils/index.d.ts +1 -1
  84. package/lib/utils/index.js +2 -2
  85. package/lib/utils/response.d.ts +35 -2
  86. package/lib/utils/response.js +42 -3
  87. package/lib/validation/ai-schemas.d.ts +27 -0
  88. package/lib/validation/ai-schemas.js +31 -5
  89. package/lib/validation/plugin-schemas.d.ts +15 -0
  90. package/lib/validation/plugin-schemas.js +28 -1
  91. package/package.json +31 -2
@@ -1,25 +1,6 @@
1
- /** Metadata for a single AI model. */
2
- export interface AIModelInfo {
3
- /** Model identifier used in API calls (e.g. "claude-sonnet-5"). */
4
- id: string;
5
- /** Human-readable display name (e.g. "Claude Sonnet 5"). */
6
- name: string;
7
- }
8
- /** Metadata for an AI provider with its available models. */
9
- export interface AIProviderInfo {
10
- /** Provider identifier (e.g. "anthropic", "openai", "google"). */
11
- id: string;
12
- /** Human-readable display name (e.g. "Anthropic"). */
13
- name: string;
14
- /** Models available for this provider. */
15
- models: AIModelInfo[];
16
- }
17
- /**
18
- * Standard AI provider catalog — single source of truth for all supported
19
- * providers and their models. Used by both backend services and frontend
20
- * components.
21
- */
22
- export declare const AI_PROVIDER_CATALOG: Record<string, AIProviderInfo>;
1
+ import { type AIModelInfo, type AIProviderInfo } from '../types/ai-catalog.js';
2
+ export { AI_PROVIDER_CATALOG, AI_PROVIDER_NAMES, AI_PROVIDER_MODELS, AI_KEY_PROVIDER_IDS, isKeylessProviderId } from '../types/ai-catalog.js';
3
+ export type { AIModelInfo, AIProviderInfo } from '../types/ai-catalog.js';
23
4
  /**
24
5
  * Environment variable names for each AI provider's API key.
25
6
  * Used by backend services to initialize the provider registry.
@@ -1,60 +1,10 @@
1
1
  // Copyright 2026 Pipeline Builder Contributors
2
2
  // SPDX-License-Identifier: Apache-2.0
3
- // Catalog
4
- /**
5
- * Standard AI provider catalog — single source of truth for all supported
6
- * providers and their models. Used by both backend services and frontend
7
- * components.
8
- */
9
- export const AI_PROVIDER_CATALOG = {
10
- 'anthropic': {
11
- id: 'anthropic',
12
- name: 'Anthropic',
13
- models: [
14
- { id: 'claude-sonnet-5', name: 'Claude Sonnet 5' },
15
- { id: 'claude-opus-5', name: 'Claude Opus 5' },
16
- { id: 'claude-haiku-4-5-20251001', name: 'Claude Haiku 4.5' },
17
- ],
18
- },
19
- 'openai': {
20
- id: 'openai',
21
- name: 'OpenAI',
22
- models: [
23
- { id: 'gpt-5.6-sol', name: 'GPT-5.6 Sol' },
24
- { id: 'gpt-5.6-terra', name: 'GPT-5.6 Terra' },
25
- { id: 'gpt-5.6-luna', name: 'GPT-5.6 Luna' },
26
- ],
27
- },
28
- 'google': {
29
- id: 'google',
30
- name: 'Google',
31
- models: [
32
- { id: 'gemini-3.7-flash', name: 'Gemini 3.7 Flash' },
33
- { id: 'gemini-3.1-pro-preview', name: 'Gemini 3.1 Pro' },
34
- ],
35
- },
36
- 'xai': {
37
- id: 'xai',
38
- name: 'xAI (Grok)',
39
- models: [
40
- { id: 'grok-4.6', name: 'Grok 4.6' },
41
- { id: 'grok-4.5', name: 'Grok 4.5' },
42
- { id: 'grok-4.3', name: 'Grok 4.3' },
43
- ],
44
- },
45
- 'amazon-bedrock': {
46
- id: 'amazon-bedrock',
47
- name: 'Amazon Bedrock',
48
- // Bedrock ids are region-scoped cross-region inference profiles; the `us.`
49
- // prefix targets US regions — swap the prefix (eu./apac./…) to match your
50
- // deploy region, and confirm availability in the Bedrock console.
51
- models: [
52
- { id: 'us.anthropic.claude-sonnet-4-5-20250929-v1:0', name: 'Claude Sonnet 4.5' },
53
- { id: 'us.amazon.nova-pro-v1:0', name: 'Amazon Nova Pro' },
54
- { id: 'us.amazon.nova-lite-v1:0', name: 'Amazon Nova Lite' },
55
- ],
56
- },
57
- };
3
+ import { AI_PROVIDER_CATALOG } from '../types/ai-catalog.js';
4
+ // The catalog itself is data-only and lives in `types/ai-catalog.ts` (the
5
+ // browser-safe `./ai-catalog` subpath); re-exported here so server code keeps one
6
+ // import site for everything AI-provider.
7
+ export { AI_PROVIDER_CATALOG, AI_PROVIDER_NAMES, AI_PROVIDER_MODELS, AI_KEY_PROVIDER_IDS, isKeylessProviderId } from '../types/ai-catalog.js';
58
8
  /**
59
9
  * Environment variable names for each AI provider's API key.
60
10
  * Used by backend services to initialize the provider registry.
@@ -126,4 +76,4 @@ export function getAIProviderModels(providerId) {
126
76
  }
127
77
  return AI_PROVIDER_CATALOG[providerId]?.models ?? [];
128
78
  }
129
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYWktcHJvdmlkZXJzLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL2NvbnN0YW50cy9haS1wcm92aWRlcnMudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsK0NBQStDO0FBQy9DLHNDQUFzQztBQXNCdEMsVUFBVTtBQUVWOzs7O0dBSUc7QUFDSCxNQUFNLENBQUMsTUFBTSxtQkFBbUIsR0FBbUM7SUFDakUsV0FBVyxFQUFFO1FBQ1gsRUFBRSxFQUFFLFdBQVc7UUFDZixJQUFJLEVBQUUsV0FBVztRQUNqQixNQUFNLEVBQUU7WUFDTixFQUFFLEVBQUUsRUFBRSxpQkFBaUIsRUFBRSxJQUFJLEVBQUUsaUJBQWlCLEVBQUU7WUFDbEQsRUFBRSxFQUFFLEVBQUUsZUFBZSxFQUFFLElBQUksRUFBRSxlQUFlLEVBQUU7WUFDOUMsRUFBRSxFQUFFLEVBQUUsMkJBQTJCLEVBQUUsSUFBSSxFQUFFLGtCQUFrQixFQUFFO1NBQzlEO0tBQ0Y7SUFDRCxRQUFRLEVBQUU7UUFDUixFQUFFLEVBQUUsUUFBUTtRQUNaLElBQUksRUFBRSxRQUFRO1FBQ2QsTUFBTSxFQUFFO1lBQ04sRUFBRSxFQUFFLEVBQUUsYUFBYSxFQUFFLElBQUksRUFBRSxhQUFhLEVBQUU7WUFDMUMsRUFBRSxFQUFFLEVBQUUsZUFBZSxFQUFFLElBQUksRUFBRSxlQUFlLEVBQUU7WUFDOUMsRUFBRSxFQUFFLEVBQUUsY0FBYyxFQUFFLElBQUksRUFBRSxjQUFjLEVBQUU7U0FDN0M7S0FDRjtJQUNELFFBQVEsRUFBRTtRQUNSLEVBQUUsRUFBRSxRQUFRO1FBQ1osSUFBSSxFQUFFLFFBQVE7UUFDZCxNQUFNLEVBQUU7WUFDTixFQUFFLEVBQUUsRUFBRSxrQkFBa0IsRUFBRSxJQUFJLEVBQUUsa0JBQWtCLEVBQUU7WUFDcEQsRUFBRSxFQUFFLEVBQUUsd0JBQXdCLEVBQUUsSUFBSSxFQUFFLGdCQUFnQixFQUFFO1NBQ3pEO0tBQ0Y7SUFDRCxLQUFLLEVBQUU7UUFDTCxFQUFF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QUFDLHNCQUFzQixJQUFJLGlDQUFpQztRQUM3RSxNQUFNLEVBQUUsTUFBTSxDQUFDLE1BQU0sR0FBRyxDQUFDLENBQUMsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxDQUFDLENBQUMsQ0FBQyxFQUFFLEVBQUUsRUFBRSxPQUFPLEVBQUUsSUFBSSxFQUFFLGFBQWEsRUFBRSxDQUFDO0tBQzVFLENBQUM7QUFDSixDQUFDO0FBRUQsVUFBVTtBQUVWOzs7OztHQUtHO0FBQ0gsTUFBTSxVQUFVLG1CQUFtQixDQUFDLFVBQWtCO0lBQ3BELElBQUksVUFBVSxLQUFLLDZCQUE2QixFQUFFLENBQUM7UUFDakQsT0FBTywyQkFBMkIsRUFBRSxFQUFFLE1BQU0sSUFBSSxFQUFFLENBQUM7SUFDckQsQ0FBQztJQUNELE9BQU8sbUJBQW1CLENBQUMsVUFBVSxDQUFDLEVBQUUsTUFBTSxJQUFJLEVBQUUsQ0FBQztBQUN2RCxDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiLy8gQ29weXJpZ2h0IDIwMjYgUGlwZWxpbmUgQnVpbGRlciBDb250cmlidXRvcnNcbi8vIFNQRFgtTGljZW5zZS1JZGVudGlmaWVyOiBBcGFjaGUtMi4wXG5cbi8vIFR5cGVzXG5cbi8qKiBNZXRhZGF0YSBmb3IgYSBzaW5nbGUgQUkgbW9kZWwuICovXG5leHBvcnQgaW50ZXJmYWNlIEFJTW9kZWxJbmZvIHtcbiAgLyoqIE1vZGVsIGlkZW50aWZpZXIgdXNlZCBpbiBBUEkgY2FsbHMgKGUuZy4gXCJjbGF1ZGUtc29ubmV0LTVcIikuICovXG4gIGlkOiBzdHJpbmc7XG4gIC8qKiBIdW1hbi1yZWFkYWJsZSBkaXNwbGF5IG5hbWUgKGUuZy4gXCJDbGF1ZGUgU29ubmV0IDVcIikuICovXG4gIG5hbWU6IHN0cmluZztcbn1cblxuLyoqIE1ldGFkYXRhIGZvciBhbiBBSSBwcm92aWRlciB3aXRoIGl0cyBhdmFpbGFibGUgbW9kZWxzLiAqL1xuZXhwb3J0IGludGVyZmFjZSBBSVByb3ZpZGVySW5mbyB7XG4gIC8qKiBQcm92aWRlciBpZGVudGlmaWVyIChlLmcuIFwiYW50aHJvcGljXCIsIFwib3BlbmFpXCIsIFwiZ29vZ2xlXCIpLiAqL1xuICBpZDogc3RyaW5nO1xuICAvKiogSHVtYW4tcmVhZGFibGUgZGlzcGxheSBuYW1lIChlLmcuIFwiQW50aHJvcGljXCIpLiAqL1xuICBuYW1lOiBzdHJpbmc7XG4gIC8qKiBNb2RlbHMgYXZhaWxhYmxlIGZvciB0aGlzIHByb3ZpZGVyLiAqL1xuICBtb2RlbHM6IEFJTW9kZWxJbmZvW107XG59XG5cbi8vIENhdGFsb2dcblxuLyoqXG4gKiBTdGFuZGFyZCBBSSBwcm92aWRlciBjYXRhbG9nIOKAlCBzaW5nbGUgc291cmNlIG9mIHRydXRoIGZvciBhbGwgc3VwcG9ydGVkXG4gKiBwcm92aWRlcnMgYW5kIHRoZWlyIG1vZGVscy4gVXNlZCBieSBib3RoIGJhY2tlbmQgc2VydmljZXMgYW5kIGZyb250ZW5kXG4gKiBjb21wb25lbnRzLlxuICovXG5leHBvcnQgY29uc3QgQUlfUFJPVklERVJfQ0FUQUxPRzogUmVjb3JkPHN0cmluZywgQUlQcm92aWRlckluZm8+ID0ge1xuICAnYW50aHJvcGljJzoge1xuICAgIGlkOiAnYW50aHJvcGljJyxcbiAgICBuYW1lOiAnQW50aHJvcGljJyxcbiAgICBtb2RlbHM6IFtcbiAgICAgIHsgaWQ6ICdjbGF1ZGUtc29ubmV0LTUnLCBuYW1lOiAnQ2xhdWRlIFNvbm5ldCA1JyB9LFxuICAgICAgeyBpZDogJ2NsYXVkZS1vcHVzLTUnLCBuYW1lOiAnQ2xhdWRlIE9wdXMgNScgfSxcbiAgICAgIHsgaWQ6ICdjbGF1ZGUtaGFpa3UtNC01LTIwMjUxMDAxJywgbmFtZTogJ0NsYXVkZSBIYWlrdSA0LjUnIH0sXG4gICAgXSxcbiAgfSxcbiAgJ29wZW5haSc6IHtcbiAgICBpZDogJ29wZW5haScsXG4gICAgbmFtZTogJ09wZW5BSScsXG4gICAgbW9kZWxzOiBbXG4gICAgICB7IGlkOiAnZ3B0LTUuNi1zb2wnLCBuYW1lOiAnR1BULTUuNiBTb2wnIH0sXG4gICAgICB7IGlkOiAnZ3B0LTUuNi10ZXJyYScsIG5hbWU6ICdHUFQtNS42IFRlcnJhJyB9LFxuICAgICAgeyBpZDogJ2dwdC01LjYtbHVuYScsIG5hbWU6ICdHUFQtNS42IEx1bmEnIH0sXG4gICAgXSxcbiAgfSxcbiAgJ2dvb2dsZSc6IHtcbiAgICBpZDogJ2dvb2dsZScsXG4gICAgbmFtZTogJ0dvb2dsZScsXG4gICAgbW9kZWxzOiBbXG4gICAgICB7IGlkOiAnZ2VtaW5pLTMuNy1mbGFzaCcsIG5hbWU6ICdHZW1pbmkgMy43IEZsYXNoJyB9LFxuICAgICAgeyBpZDogJ2dlbWluaS0zLjEtcHJvLXByZXZpZXcnLCBuYW1lOiAnR2VtaW5pIDMuMSBQcm8nIH0sXG4gICAgXSxcbiAgfSxcbiAgJ3hhaSc6IHtcbiAgICBpZDogJ3hhaScsXG4gICAgbmFtZTogJ3hBSSAoR3JvayknLFxuICAgIG1vZGVsczogW1xuICAgICAgeyBpZDogJ2dyb2stNC42JywgbmFtZTogJ0dyb2sgNC42JyB9LFxuICAgICAgeyBpZDogJ2dyb2stNC41JywgbmFtZTogJ0dyb2sgNC41JyB9LFxuICAgICAgeyBpZDogJ2dyb2stNC4zJywgbmFtZTogJ0dyb2sgNC4zJyB9LFxuICAgIF0sXG4gIH0sXG4gICdhbWF6b24tYmVkcm9jayc6IHtcbiAgICBpZDogJ2FtYXpvbi1iZWRyb2NrJyxcbiAgICBuYW1lOiAnQW1hem9uIEJlZHJvY2snLFxuICAgIC8vIEJlZHJvY2sgaWRzIGFyZSByZWdpb24tc2NvcGVkIGNyb3NzLXJlZ2lvbiBpbmZlcmVuY2UgcHJvZmlsZXM7IHRoZSBgdXMuYFxuICAgIC8vIHByZWZpeCB0YXJnZXRzIFVTIHJlZ2lvbnMg4oCUIHN3YXAgdGhlIHByZWZpeCAoZXUuL2FwYWMuL+KApikgdG8gbWF0Y2ggeW91clxuICAgIC8vIGRlcGxveSByZWdpb24sIGFuZCBjb25maXJtIGF2YWlsYWJpbGl0eSBpbiB0aGUgQmVkcm9jayBjb25zb2xlLlxuICAgIG1vZGVsczogW1xuICAgICAgeyBpZDogJ3VzLmFudGhyb3BpYy5jbGF1ZGUtc29ubmV0LTQtNS0yMDI1MDkyOS12MTowJywgbmFtZTogJ0NsYXVkZSBTb25uZXQgNC41JyB9LFxuICAgICAgeyBpZDogJ3VzLmFtYXpvbi5ub3ZhLXByby12MTowJywgbmFtZTogJ0FtYXpvbiBOb3ZhIFBybycgfSxcbiAgICAgIHsgaWQ6ICd1cy5hbWF6b24ubm92YS1saXRlLXYxOjAnLCBuYW1lOiAnQW1hem9uIE5vdmEgTGl0ZScgfSxcbiAgICBdLFxuICB9LFxufTtcblxuLyoqXG4gKiBFbnZpcm9ubWVudCB2YXJpYWJsZSBuYW1lcyBmb3IgZWFjaCBBSSBwcm92aWRlcidzIEFQSSBrZXkuXG4gKiBVc2VkIGJ5IGJhY2tlbmQgc2VydmljZXMgdG8gaW5pdGlhbGl6ZSB0aGUgcHJvdmlkZXIgcmVnaXN0cnkuXG4gKi9cbmV4cG9ydCBjb25zdCBBSV9QUk9WSURFUl9FTlZfVkFSUzogUmVjb3JkPHN0cmluZywgc3RyaW5nPiA9IHtcbiAgJ2FudGhyb3BpYyc6ICdBTlRIUk9QSUNfQVBJX0tFWScsXG4gICdvcGVuYWknOiAnT1BFTkFJX0FQSV9LRVknLFxuICAnZ29vZ2xlJzogJ0dPT0dMRV9HRU5FUkFUSVZFX0FJX0FQSV9LRVknLFxuICAneGFpJzogJ1hBSV9BUElfS0VZJyxcbiAgJ2FtYXpvbi1iZWRyb2NrJzogJ0FXU19BQ0NFU1NfS0VZX0lEJyxcbn07XG5cbi8qKlxuICogUHJvdmlkZXIgaWQgZm9yIGEgc2VsZi1ob3N0ZWQsIE9wZW5BSS1jb21wYXRpYmxlIGVuZHBvaW50IOKAlCBhIERvY2tlciBtb2RlbCBpbWFnZVxuICogKE9sbGFtYSwgRG9ja2VyIE1vZGVsIFJ1bm5lciwgdkxMTSkgb3IgYW55IG90aGVyIHNlcnZlciB0aGF0IHNwZWFrcyB0aGUgT3BlbkFJXG4gKiBjaGF0IEFQSS4gVW5saWtlIHRoZSBmaXhlZCBwcm92aWRlcnMgYWJvdmUsIHRoaXMgb25lIGlzIE5PVCBpbiB0aGUgc3RhdGljIGNhdGFsb2c6XG4gKiBpdHMgZW5kcG9pbnQgYW5kIG1vZGVsIGxpc3QgYXJlIGRlcGxveW1lbnQtZGVmaW5lZCBhbmQgcmVzb2x2ZWQgZnJvbSBlbnYgYXRcbiAqIHJ1bnRpbWUgYnkge0BsaW5rIGdldE9wZW5BSUNvbXBhdGlibGVQcm92aWRlcn0uXG4gKi9cbmV4cG9ydCBjb25zdCBPUEVOQUlfQ09NUEFUSUJMRV9QUk9WSURFUl9JRCA9ICdvcGVuYWktY29tcGF0aWJsZSc7XG5cbi8qKlxuICogUGFyc2UgYSBgaWRbfERpc3BsYXkgTmFtZV1bLGlkMlt8TmFtZTJdXWAgZW52IHN0cmluZyBpbnRvIG1vZGVsIG1ldGFkYXRhLiBUaGVcbiAqIGlkL25hbWUgc2VwYXJhdG9yIGlzIGB8YCAoTk9UIGA6YCkgYmVjYXVzZSBtb2RlbCBpZHMgY29tbW9ubHkgY29udGFpbiBjb2xvbnMg4oCUXG4gKiBlLmcuIE9sbGFtYSB0YWdzIChgcXdlbjIuNS1jb2Rlcjo3YmApIGFuZCBCZWRyb2NrIGluZmVyZW5jZSBwcm9maWxlcy5cbiAqL1xuZnVuY3Rpb24gcGFyc2VNb2RlbExpc3QocmF3OiBzdHJpbmcpOiBBSU1vZGVsSW5mb1tdIHtcbiAgcmV0dXJuIHJhd1xuICAgIC5zcGxpdCgnLCcpXG4gICAgLm1hcCgocykgPT4gcy50cmltKCkpXG4gICAgLmZpbHRlcihCb29sZWFuKVxuICAgIC5tYXAoKGVudHJ5KSA9PiB7XG4gICAgICBjb25zdCBpZHggPSBlbnRyeS5pbmRleE9mKCd8Jyk7XG4gICAgICBjb25zdCBpZCA9IChpZHggPT09IC0xID8gZW50cnkgOiBlbnRyeS5zbGljZSgwLCBpZHgpKS50cmltKCk7XG4gICAgICBjb25zdCBuYW1lID0gKGlkeCA9PT0gLTEgPyAnJyA6IGVudHJ5LnNsaWNlKGlkeCArIDEpKS50cmltKCkgfHwgaWQ7XG4gICAgICByZXR1cm4geyBpZCwgbmFtZSB9O1xuICAgIH0pXG4gICAgLmZpbHRlcigobSkgPT4gbS5pZC5sZW5ndGggPiAwKTtcbn1cblxuLyoqXG4gKiBSZXNvbHZlIHRoZSBPcGVuQUktY29tcGF0aWJsZSAobG9jYWwgLyBzZWxmLWhvc3RlZCkgcHJvdmlkZXIgZnJvbSBlbnYsIG9yIGBudWxsYFxuICogd2hlbiBubyBlbmRwb2ludCBpcyBjb25maWd1cmVkLiBFbmFibGVkIGJ5IGBPUEVOQUlfQ09NUEFUSUJMRV9CQVNFX1VSTGA7IHRoZSBtb2RlbFxuICogbGlzdCBjb21lcyBmcm9tIGBPUEVOQUlfQ09NUEFUSUJMRV9NT0RFTFNgIChjb21tYSBsaXN0IG9mIGBpZFt8RGlzcGxheSBOYW1lXWApLFxuICogZmFsbGluZyBiYWNrIHRvIGBPUEVOQUlfQ09NUEFUSUJMRV9NT0RFTGAsIHRoZW4gYSBnZW5lcmljIGBsb2NhbGAgaWQuIFRoZSBkaXNwbGF5XG4gKiBuYW1lIGlzIG92ZXJyaWRhYmxlIHZpYSBgT1BFTkFJX0NPTVBBVElCTEVfTkFNRWAuXG4gKlxuICogQHJldHVybnMgUHJvdmlkZXIgaW5mbyBmb3IgdGhlIGNvbmZpZ3VyZWQgbG9jYWwgZW5kcG9pbnQsIG9yIG51bGwgaWYgdW5zZXRcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGdldE9wZW5BSUNvbXBhdGlibGVQcm92aWRlcigpOiBBSVByb3ZpZGVySW5mbyB8IG51bGwge1xuICBjb25zdCBiYXNlVVJMID0gcHJvY2Vzcy5lbnYuT1BFTkFJX0NPTVBBVElCTEVfQkFTRV9VUkw7XG4gIGlmICghYmFzZVVSTCkgcmV0dXJuIG51bGw7XG4gIGNvbnN0IHJhdyA9IHByb2Nlc3MuZW52Lk9QRU5BSV9DT01QQVRJQkxFX01PREVMUyA/PyBwcm9jZXNzLmVudi5PUEVOQUlfQ09NUEFUSUJMRV9NT0RFTCA/PyAnbG9jYWx8TG9jYWwgbW9kZWwnO1xuICBjb25zdCBtb2RlbHMgPSBwYXJzZU1vZGVsTGlzdChyYXcpO1xuICByZXR1cm4ge1xuICAgIGlkOiBPUEVOQUlfQ09NUEFUSUJMRV9QUk9WSURFUl9JRCxcbiAgICBuYW1lOiBwcm9jZXNzLmVudi5PUEVOQUlfQ09NUEFUSUJMRV9OQU1FIHx8ICdMb2NhbCBtb2RlbCAoT3BlbkFJLWNvbXBhdGlibGUpJyxcbiAgICBtb2RlbHM6IG1vZGVscy5sZW5ndGggPiAwID8gbW9kZWxzIDogW3sgaWQ6ICdsb2NhbCcsIG5hbWU6ICdMb2NhbCBtb2RlbCcgfV0sXG4gIH07XG59XG5cbi8vIEhlbHBlcnNcblxuLyoqXG4gKiBHZXQgdGhlIG1vZGVsIGxpc3QgZm9yIGEgZ2l2ZW4gcHJvdmlkZXIgSUQuXG4gKlxuICogQHBhcmFtIHByb3ZpZGVySWQgLSBQcm92aWRlciBpZGVudGlmaWVyIChlLmcuIFwiYW50aHJvcGljXCIpXG4gKiBAcmV0dXJucyBBcnJheSBvZiBtb2RlbHMsIG9yIGVtcHR5IGFycmF5IGlmIHRoZSBwcm92aWRlciBpcyB1bmtub3duXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBnZXRBSVByb3ZpZGVyTW9kZWxzKHByb3ZpZGVySWQ6IHN0cmluZyk6IEFJTW9kZWxJbmZvW10ge1xuICBpZiAocHJvdmlkZXJJZCA9PT0gT1BFTkFJX0NPTVBBVElCTEVfUFJPVklERVJfSUQpIHtcbiAgICByZXR1cm4gZ2V0T3BlbkFJQ29tcGF0aWJsZVByb3ZpZGVyKCk/Lm1vZGVscyA/PyBbXTtcbiAgfVxuICByZXR1cm4gQUlfUFJPVklERVJfQ0FUQUxPR1twcm92aWRlcklkXT8ubW9kZWxzID8/IFtdO1xufVxuIl19
79
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYWktcHJvdmlkZXJzLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL2NvbnN0YW50cy9haS1wcm92aWRlcnMudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsK0NBQStDO0FBQy9DLHNDQUFzQztBQUV0QyxPQUFPLEVBQUUsbUJBQW1CLEVBQXlDLE1BQU0sd0JBQXdCLENBQUM7QUFFcEcsMEVBQTBFO0FBQzFFLGtGQUFrRjtBQUNsRiwwQ0FBMEM7QUFDMUMsT0FBTyxFQUFFLG1CQUFtQixFQUFFLGlCQUFpQixFQUFFLGtCQUFrQixFQUFFLG1CQUFtQixFQUFFLG1CQUFtQixFQUFFLE1BQU0sd0JBQXdCLENBQUM7QUFHOUk7OztHQUdHO0FBQ0gsTUFBTSxDQUFDLE1BQU0sb0JBQW9CLEdBQTJCO0lBQzFELFdBQVcsRUFBRSxtQkFBbUI7SUFDaEMsUUFBUSxFQUFFLGdCQUFnQjtJQUMxQixRQUFRLEVBQUUsOEJBQThCO0lBQ3hDLEtBQUssRUFBRSxhQUFhO0lBQ3BCLGdCQUFnQixFQUFFLG1CQUFtQjtDQUN0QyxDQUFDO0FBRUY7Ozs7OztHQU1HO0FBQ0gsTUFBTSxDQUFDLE1BQU0sNkJBQTZCLEdBQUcsbUJBQW1CLENBQUM7QUFFakU7Ozs7R0FJRztBQUNILFNBQVMsY0FBYyxDQUFDLEdBQVc7SUFDakMsT0FBTyxHQUFHO1NBQ1AsS0FBSyxDQUFDLEdBQUcsQ0FBQztTQUNWLEdBQUcsQ0FBQyxDQUFDLENBQUMsRUFBRSxFQUFFLENBQUMsQ0FBQyxDQUFDLElBQUksRUFBRSxDQUFDO1NBQ3BCLE1BQU0sQ0FBQyxPQUFPLENBQUM7U0FDZixHQUFHLENBQUMsQ0FBQyxLQUFLLEVBQUUsRUFBRTtRQUNiLE1BQU0sR0FBRyxHQUFHLEtBQUssQ0FBQyxPQUFPLENBQUMsR0FBRyxDQUFDLENBQUM7UUFDL0IsTUFBTSxFQUFFLEdBQUcsQ0FBQyxHQUFHLEtBQUssQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLEtBQUssQ0FBQyxDQUFDLENBQUMsS0FBSyxDQUFDLEtBQUssQ0FBQyxDQUFDLEVBQUUsR0FBRyxDQUFDLENBQUMsQ0FBQyxJQUFJLEVBQUUsQ0FBQztRQUM3RCxNQUFNLElBQUksR0FBRyxDQUFDLEdBQUcsS0FBSyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDLENBQUMsQ0FBQyxLQUFLLENBQUMsS0FBSyxDQUFDLEdBQUcsR0FBRyxDQUFDLENBQUMsQ0FBQyxDQUFDLElBQUksRUFBRSxJQUFJLEVBQUUsQ0FBQztRQUNuRSxPQUFPLEVBQUUsRUFBRSxFQUFFLElBQUksRUFBRSxDQUFDO0lBQ3RCLENBQUMsQ0FBQztTQUNELE1BQU0sQ0FBQyxDQUFDLENBQUMsRUFBRSxFQUFFLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxNQUFNLEdBQUcsQ0FBQyxDQUFDLENBQUM7QUFDcEMsQ0FBQztBQUVEOzs7Ozs7OztHQVFHO0FBQ0gsTUFBTSxVQUFVLDJCQUEyQjtJQUN6QyxNQUFNLE9BQU8sR0FBRyxPQUFPLENBQUMsR0FBRyxDQUFDLDBCQUEwQixDQUFDO0lBQ3ZELElBQUksQ0FBQyxPQUFPO1FBQUUsT0FBTyxJQUFJLENBQUM7SUFDMUIsTUFBTSxHQUFHLEdBQUcsT0FBTyxDQUFDLEdBQUcsQ0FBQyx3QkFBd0IsSUFBSSxPQUFPLENBQUMsR0FBRyxDQUFDLHVCQUF1QixJQUFJLG1CQUFtQixDQUFDO0lBQy9HLE1BQU0sTUFBTSxHQUFHLGNBQWMsQ0FBQyxHQUFHLENBQUMsQ0FBQztJQUNuQyxPQUFPO1FBQ0wsRUFBRSxFQUFFLDZCQUE2QjtRQUNqQyxJQUFJLEVBQUUsT0FBTyxDQUFDLEdBQUcsQ0FBQyxzQkFBc0IsSUFBSSxpQ0FBaUM7UUFDN0UsTUFBTSxFQUFFLE1BQU0sQ0FBQyxNQUFNLEdBQUcsQ0FBQyxDQUFDLENBQUMsQ0FBQyxNQUFNLENBQUMsQ0FBQyxDQUFDLENBQUMsRUFBRSxFQUFFLEVBQUUsT0FBTyxFQUFFLElBQUksRUFBRSxhQUFhLEVBQUUsQ0FBQztLQUM1RSxDQUFDO0FBQ0osQ0FBQztBQUVELFVBQVU7QUFFVjs7Ozs7R0FLRztBQUNILE1BQU0sVUFBVSxtQkFBbUIsQ0FBQyxVQUFrQjtJQUNwRCxJQUFJLFVBQVUsS0FBSyw2QkFBNkIsRUFBRSxDQUFDO1FBQ2pELE9BQU8sMkJBQTJCLEVBQUUsRUFBRSxNQUFNLElBQUksRUFBRSxDQUFDO0lBQ3JELENBQUM7SUFDRCxPQUFPLG1CQUFtQixDQUFDLFVBQVUsQ0FBQyxFQUFFLE1BQU0sSUFBSSxFQUFFLENBQUM7QUFDdkQsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbIi8vIENvcHlyaWdodCAyMDI2IFBpcGVsaW5lIEJ1aWxkZXIgQ29udHJpYnV0b3JzXG4vLyBTUERYLUxpY2Vuc2UtSWRlbnRpZmllcjogQXBhY2hlLTIuMFxuXG5pbXBvcnQgeyBBSV9QUk9WSURFUl9DQVRBTE9HLCB0eXBlIEFJTW9kZWxJbmZvLCB0eXBlIEFJUHJvdmlkZXJJbmZvIH0gZnJvbSAnLi4vdHlwZXMvYWktY2F0YWxvZy5qcyc7XG5cbi8vIFRoZSBjYXRhbG9nIGl0c2VsZiBpcyBkYXRhLW9ubHkgYW5kIGxpdmVzIGluIGB0eXBlcy9haS1jYXRhbG9nLnRzYCAodGhlXG4vLyBicm93c2VyLXNhZmUgYC4vYWktY2F0YWxvZ2Agc3VicGF0aCk7IHJlLWV4cG9ydGVkIGhlcmUgc28gc2VydmVyIGNvZGUga2VlcHMgb25lXG4vLyBpbXBvcnQgc2l0ZSBmb3IgZXZlcnl0aGluZyBBSS1wcm92aWRlci5cbmV4cG9ydCB7IEFJX1BST1ZJREVSX0NBVEFMT0csIEFJX1BST1ZJREVSX05BTUVTLCBBSV9QUk9WSURFUl9NT0RFTFMsIEFJX0tFWV9QUk9WSURFUl9JRFMsIGlzS2V5bGVzc1Byb3ZpZGVySWQgfSBmcm9tICcuLi90eXBlcy9haS1jYXRhbG9nLmpzJztcbmV4cG9ydCB0eXBlIHsgQUlNb2RlbEluZm8sIEFJUHJvdmlkZXJJbmZvIH0gZnJvbSAnLi4vdHlwZXMvYWktY2F0YWxvZy5qcyc7XG5cbi8qKlxuICogRW52aXJvbm1lbnQgdmFyaWFibGUgbmFtZXMgZm9yIGVhY2ggQUkgcHJvdmlkZXIncyBBUEkga2V5LlxuICogVXNlZCBieSBiYWNrZW5kIHNlcnZpY2VzIHRvIGluaXRpYWxpemUgdGhlIHByb3ZpZGVyIHJlZ2lzdHJ5LlxuICovXG5leHBvcnQgY29uc3QgQUlfUFJPVklERVJfRU5WX1ZBUlM6IFJlY29yZDxzdHJpbmcsIHN0cmluZz4gPSB7XG4gICdhbnRocm9waWMnOiAnQU5USFJPUElDX0FQSV9LRVknLFxuICAnb3BlbmFpJzogJ09QRU5BSV9BUElfS0VZJyxcbiAgJ2dvb2dsZSc6ICdHT09HTEVfR0VORVJBVElWRV9BSV9BUElfS0VZJyxcbiAgJ3hhaSc6ICdYQUlfQVBJX0tFWScsXG4gICdhbWF6b24tYmVkcm9jayc6ICdBV1NfQUNDRVNTX0tFWV9JRCcsXG59O1xuXG4vKipcbiAqIFByb3ZpZGVyIGlkIGZvciBhIHNlbGYtaG9zdGVkLCBPcGVuQUktY29tcGF0aWJsZSBlbmRwb2ludCDigJQgYSBEb2NrZXIgbW9kZWwgaW1hZ2VcbiAqIChPbGxhbWEsIERvY2tlciBNb2RlbCBSdW5uZXIsIHZMTE0pIG9yIGFueSBvdGhlciBzZXJ2ZXIgdGhhdCBzcGVha3MgdGhlIE9wZW5BSVxuICogY2hhdCBBUEkuIFVubGlrZSB0aGUgZml4ZWQgcHJvdmlkZXJzIGFib3ZlLCB0aGlzIG9uZSBpcyBOT1QgaW4gdGhlIHN0YXRpYyBjYXRhbG9nOlxuICogaXRzIGVuZHBvaW50IGFuZCBtb2RlbCBsaXN0IGFyZSBkZXBsb3ltZW50LWRlZmluZWQgYW5kIHJlc29sdmVkIGZyb20gZW52IGF0XG4gKiBydW50aW1lIGJ5IHtAbGluayBnZXRPcGVuQUlDb21wYXRpYmxlUHJvdmlkZXJ9LlxuICovXG5leHBvcnQgY29uc3QgT1BFTkFJX0NPTVBBVElCTEVfUFJPVklERVJfSUQgPSAnb3BlbmFpLWNvbXBhdGlibGUnO1xuXG4vKipcbiAqIFBhcnNlIGEgYGlkW3xEaXNwbGF5IE5hbWVdWyxpZDJbfE5hbWUyXV1gIGVudiBzdHJpbmcgaW50byBtb2RlbCBtZXRhZGF0YS4gVGhlXG4gKiBpZC9uYW1lIHNlcGFyYXRvciBpcyBgfGAgKE5PVCBgOmApIGJlY2F1c2UgbW9kZWwgaWRzIGNvbW1vbmx5IGNvbnRhaW4gY29sb25zIOKAlFxuICogZS5nLiBPbGxhbWEgdGFncyAoYHF3ZW4yLjUtY29kZXI6N2JgKSBhbmQgQmVkcm9jayBpbmZlcmVuY2UgcHJvZmlsZXMuXG4gKi9cbmZ1bmN0aW9uIHBhcnNlTW9kZWxMaXN0KHJhdzogc3RyaW5nKTogQUlNb2RlbEluZm9bXSB7XG4gIHJldHVybiByYXdcbiAgICAuc3BsaXQoJywnKVxuICAgIC5tYXAoKHMpID0+IHMudHJpbSgpKVxuICAgIC5maWx0ZXIoQm9vbGVhbilcbiAgICAubWFwKChlbnRyeSkgPT4ge1xuICAgICAgY29uc3QgaWR4ID0gZW50cnkuaW5kZXhPZignfCcpO1xuICAgICAgY29uc3QgaWQgPSAoaWR4ID09PSAtMSA/IGVudHJ5IDogZW50cnkuc2xpY2UoMCwgaWR4KSkudHJpbSgpO1xuICAgICAgY29uc3QgbmFtZSA9IChpZHggPT09IC0xID8gJycgOiBlbnRyeS5zbGljZShpZHggKyAxKSkudHJpbSgpIHx8IGlkO1xuICAgICAgcmV0dXJuIHsgaWQsIG5hbWUgfTtcbiAgICB9KVxuICAgIC5maWx0ZXIoKG0pID0+IG0uaWQubGVuZ3RoID4gMCk7XG59XG5cbi8qKlxuICogUmVzb2x2ZSB0aGUgT3BlbkFJLWNvbXBhdGlibGUgKGxvY2FsIC8gc2VsZi1ob3N0ZWQpIHByb3ZpZGVyIGZyb20gZW52LCBvciBgbnVsbGBcbiAqIHdoZW4gbm8gZW5kcG9pbnQgaXMgY29uZmlndXJlZC4gRW5hYmxlZCBieSBgT1BFTkFJX0NPTVBBVElCTEVfQkFTRV9VUkxgOyB0aGUgbW9kZWxcbiAqIGxpc3QgY29tZXMgZnJvbSBgT1BFTkFJX0NPTVBBVElCTEVfTU9ERUxTYCAoY29tbWEgbGlzdCBvZiBgaWRbfERpc3BsYXkgTmFtZV1gKSxcbiAqIGZhbGxpbmcgYmFjayB0byBgT1BFTkFJX0NPTVBBVElCTEVfTU9ERUxgLCB0aGVuIGEgZ2VuZXJpYyBgbG9jYWxgIGlkLiBUaGUgZGlzcGxheVxuICogbmFtZSBpcyBvdmVycmlkYWJsZSB2aWEgYE9QRU5BSV9DT01QQVRJQkxFX05BTUVgLlxuICpcbiAqIEByZXR1cm5zIFByb3ZpZGVyIGluZm8gZm9yIHRoZSBjb25maWd1cmVkIGxvY2FsIGVuZHBvaW50LCBvciBudWxsIGlmIHVuc2V0XG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBnZXRPcGVuQUlDb21wYXRpYmxlUHJvdmlkZXIoKTogQUlQcm92aWRlckluZm8gfCBudWxsIHtcbiAgY29uc3QgYmFzZVVSTCA9IHByb2Nlc3MuZW52Lk9QRU5BSV9DT01QQVRJQkxFX0JBU0VfVVJMO1xuICBpZiAoIWJhc2VVUkwpIHJldHVybiBudWxsO1xuICBjb25zdCByYXcgPSBwcm9jZXNzLmVudi5PUEVOQUlfQ09NUEFUSUJMRV9NT0RFTFMgPz8gcHJvY2Vzcy5lbnYuT1BFTkFJX0NPTVBBVElCTEVfTU9ERUwgPz8gJ2xvY2FsfExvY2FsIG1vZGVsJztcbiAgY29uc3QgbW9kZWxzID0gcGFyc2VNb2RlbExpc3QocmF3KTtcbiAgcmV0dXJuIHtcbiAgICBpZDogT1BFTkFJX0NPTVBBVElCTEVfUFJPVklERVJfSUQsXG4gICAgbmFtZTogcHJvY2Vzcy5lbnYuT1BFTkFJX0NPTVBBVElCTEVfTkFNRSB8fCAnTG9jYWwgbW9kZWwgKE9wZW5BSS1jb21wYXRpYmxlKScsXG4gICAgbW9kZWxzOiBtb2RlbHMubGVuZ3RoID4gMCA/IG1vZGVscyA6IFt7IGlkOiAnbG9jYWwnLCBuYW1lOiAnTG9jYWwgbW9kZWwnIH1dLFxuICB9O1xufVxuXG4vLyBIZWxwZXJzXG5cbi8qKlxuICogR2V0IHRoZSBtb2RlbCBsaXN0IGZvciBhIGdpdmVuIHByb3ZpZGVyIElELlxuICpcbiAqIEBwYXJhbSBwcm92aWRlcklkIC0gUHJvdmlkZXIgaWRlbnRpZmllciAoZS5nLiBcImFudGhyb3BpY1wiKVxuICogQHJldHVybnMgQXJyYXkgb2YgbW9kZWxzLCBvciBlbXB0eSBhcnJheSBpZiB0aGUgcHJvdmlkZXIgaXMgdW5rbm93blxuICovXG5leHBvcnQgZnVuY3Rpb24gZ2V0QUlQcm92aWRlck1vZGVscyhwcm92aWRlcklkOiBzdHJpbmcpOiBBSU1vZGVsSW5mb1tdIHtcbiAgaWYgKHByb3ZpZGVySWQgPT09IE9QRU5BSV9DT01QQVRJQkxFX1BST1ZJREVSX0lEKSB7XG4gICAgcmV0dXJuIGdldE9wZW5BSUNvbXBhdGlibGVQcm92aWRlcigpPy5tb2RlbHMgPz8gW107XG4gIH1cbiAgcmV0dXJuIEFJX1BST1ZJREVSX0NBVEFMT0dbcHJvdmlkZXJJZF0/Lm1vZGVscyA/PyBbXTtcbn1cbiJdfQ==
@@ -31,3 +31,17 @@ export declare class ValidationError extends AppError {
31
31
  export declare class ConflictError extends AppError {
32
32
  constructor(message: string, code?: ErrorCode, details?: Record<string, unknown>);
33
33
  }
34
+ /** 403 — the organization's administrators switched AI features off. */
35
+ export declare class AIDisabledError extends AppError {
36
+ constructor(message?: string);
37
+ }
38
+ /**
39
+ * An AI request could not be served AS ASKED — the org's own provider key could not
40
+ * be loaded, a bring-your-own key named a keyless provider, nothing is configured.
41
+ * The message is written by us and names configuration, never a secret, so it is
42
+ * safe to show; `handleAIError` surfaces it verbatim with this status. Thrown
43
+ * INSTEAD of silently serving the request on the platform's key.
44
+ */
45
+ export declare class AIConfigurationError extends AppError {
46
+ constructor(message: string, statusCode?: number, code?: ErrorCode);
47
+ }
@@ -50,4 +50,24 @@ export class ConflictError extends AppError {
50
50
  this.name = 'ConflictError';
51
51
  }
52
52
  }
53
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYXBwLWVycm9ycy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9lcnJvcnMvYXBwLWVycm9ycy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSwrQ0FBK0M7QUFDL0Msc0NBQXNDO0FBRXRDLE9BQU8sRUFBRSxTQUFTLEVBQUUscUJBQXFCLEVBQUUsTUFBTSx5QkFBeUIsQ0FBQztBQUUzRTs7O0dBR0c7QUFDSCxNQUFNLE9BQU8sUUFBUyxTQUFRLEtBQUs7SUFFZixVQUFVO0lBQ1YsSUFBSTtJQUdKLE9BQU87SUFMekIsWUFDa0IsVUFBa0IsRUFDbEIsSUFBZSxFQUMvQixPQUFlO0lBQ2YsZ0ZBQWdGO0lBQ2hFLE9BQWlDO1FBRWpELEtBQUssQ0FBQyxPQUFPLENBQUMsQ0FBQzswQkFOQyxVQUFVO29CQUNWLElBQUk7dUJBR0osT0FBTztRQUd2QixJQUFJLENBQUMsSUFBSSxHQUFHLFVBQVUsQ0FBQztJQUN6QixDQUFDO0NBQ0Y7QUFFRCxnQ0FBZ0M7QUFDaEMsTUFBTSxPQUFPLGFBQWMsU0FBUSxRQUFRO0lBQ3pDLFlBQVksT0FBZTtRQUN6QixLQUFLLENBQUMscUJBQXFCLENBQUMsU0FBUyxDQUFDLFNBQVMsQ0FBQyxFQUFFLFNBQVMsQ0FBQyxTQUFTLEVBQUUsT0FBTyxDQUFDLENBQUM7UUFDaEYsSUFBSSxDQUFDLElBQUksR0FBRyxlQUFlLENBQUM7SUFDOUIsQ0FBQztDQUNGO0FBRUQsc0NBQXNDO0FBQ3RDLE1BQU0sT0FBTyxjQUFlLFNBQVEsUUFBUTtJQUMxQyxZQUFZLE9BQWU7UUFDekIsS0FBSyxDQUFDLHFCQUFxQixDQUFDLFNBQVMsQ0FBQyx3QkFBd0IsQ0FBQyxFQUFFLFNBQVMsQ0FBQyx3QkFBd0IsRUFBRSxPQUFPLENBQUMsQ0FBQztRQUM5RyxJQUFJLENBQUMsSUFBSSxHQUFHLGdCQUFnQixDQUFDO0lBQy9CLENBQUM7Q0FDRjtBQUVELHNDQUFzQztBQUN0QyxNQUFNLE9BQU8sZUFBZ0IsU0FBUSxRQUFRO0lBQzNDLFlBQVksT0FBZTtRQUN6QixLQUFLLENBQUMscUJBQXFCLENBQUMsU0FBUyxDQUFDLGdCQUFnQixDQUFDLEVBQUUsU0FBUyxDQUFDLGdCQUFnQixFQUFFLE9BQU8sQ0FBQyxDQUFDO1FBQzlGLElBQUksQ0FBQyxJQUFJLEdBQUcsaUJBQWlCLENBQUM7SUFDaEMsQ0FBQztDQUNGO0FBRUQ7OztvRUFHb0U7QUFDcEUsTUFBTSxPQUFPLGFBQWMsU0FBUSxRQUFRO0lBQ3pDLFlBQVksT0FBZSxFQUFFLElBQUksR0FBYyxTQUFTLENBQUMsUUFBUSxFQUFFLE9BQWlDO1FBQ2xHLEtBQUssQ0FBQyxxQkFBcUIsQ0FBQyxTQUFTLENBQUMsUUFBUSxDQUFDLEVBQUUsSUFBSSxFQUFFLE9BQU8sRUFBRSxPQUFPLENBQUMsQ0FBQztRQUN6RSxJQUFJLENBQUMsSUFBSSxHQUFHLGVBQWUsQ0FBQztJQUM5QixDQUFDO0NBQ0YiLCJzb3VyY2VzQ29udGVudCI6WyIvLyBDb3B5cmlnaHQgMjAyNiBQaXBlbGluZSBCdWlsZGVyIENvbnRyaWJ1dG9yc1xuLy8gU1BEWC1MaWNlbnNlLUlkZW50aWZpZXI6IEFwYWNoZS0yLjBcblxuaW1wb3J0IHsgRXJyb3JDb2RlLCBnZXRTdGF0dXNGb3JFcnJvckNvZGUgfSBmcm9tICcuLi90eXBlcy9lcnJvci1jb2Rlcy5qcyc7XG5cbi8qKlxuICogQmFzZSBhcHBsaWNhdGlvbiBlcnJvciB3aXRoIEhUVFAgc3RhdHVzIGNvZGUgYW5kIGVycm9yIGNvZGUuXG4gKiBFeHRlbmQgdGhpcyBmb3IgZG9tYWluLXNwZWNpZmljIGVycm9yIHR5cGVzLlxuICovXG5leHBvcnQgY2xhc3MgQXBwRXJyb3IgZXh0ZW5kcyBFcnJvciB7XG4gIGNvbnN0cnVjdG9yKFxuICAgIHB1YmxpYyByZWFkb25seSBzdGF0dXNDb2RlOiBudW1iZXIsXG4gICAgcHVibGljIHJlYWRvbmx5IGNvZGU6IEVycm9yQ29kZSxcbiAgICBtZXNzYWdlOiBzdHJpbmcsXG4gICAgLyoqIFN0cnVjdHVyZWQgY29udGV4dCBzZW50IHdpdGggdGhlIGVycm9yIHJlc3BvbnNlIChlLmcuIHRoZSBmYWlsaW5nIGdhdGVzKS4gKi9cbiAgICBwdWJsaWMgcmVhZG9ubHkgZGV0YWlscz86IFJlY29yZDxzdHJpbmcsIHVua25vd24+LFxuICApIHtcbiAgICBzdXBlcihtZXNzYWdlKTtcbiAgICB0aGlzLm5hbWUgPSAnQXBwRXJyb3InO1xuICB9XG59XG5cbi8qKiA0MDQg4oCUIFJlc291cmNlIG5vdCBmb3VuZC4gKi9cbmV4cG9ydCBjbGFzcyBOb3RGb3VuZEVycm9yIGV4dGVuZHMgQXBwRXJyb3Ige1xuICBjb25zdHJ1Y3RvcihtZXNzYWdlOiBzdHJpbmcpIHtcbiAgICBzdXBlcihnZXRTdGF0dXNGb3JFcnJvckNvZGUoRXJyb3JDb2RlLk5PVF9GT1VORCksIEVycm9yQ29kZS5OT1RfRk9VTkQsIG1lc3NhZ2UpO1xuICAgIHRoaXMubmFtZSA9ICdOb3RGb3VuZEVycm9yJztcbiAgfVxufVxuXG4vKiogNDAzIOKAlCBJbnN1ZmZpY2llbnQgcGVybWlzc2lvbnMuICovXG5leHBvcnQgY2xhc3MgRm9yYmlkZGVuRXJyb3IgZXh0ZW5kcyBBcHBFcnJvciB7XG4gIGNvbnN0cnVjdG9yKG1lc3NhZ2U6IHN0cmluZykge1xuICAgIHN1cGVyKGdldFN0YXR1c0ZvckVycm9yQ29kZShFcnJvckNvZGUuSU5TVUZGSUNJRU5UX1BFUk1JU1NJT05TKSwgRXJyb3JDb2RlLklOU1VGRklDSUVOVF9QRVJNSVNTSU9OUywgbWVzc2FnZSk7XG4gICAgdGhpcy5uYW1lID0gJ0ZvcmJpZGRlbkVycm9yJztcbiAgfVxufVxuXG4vKiogNDAwIOKAlCBWYWxpZGF0aW9uIC8gYmFkIHJlcXVlc3QuICovXG5leHBvcnQgY2xhc3MgVmFsaWRhdGlvbkVycm9yIGV4dGVuZHMgQXBwRXJyb3Ige1xuICBjb25zdHJ1Y3RvcihtZXNzYWdlOiBzdHJpbmcpIHtcbiAgICBzdXBlcihnZXRTdGF0dXNGb3JFcnJvckNvZGUoRXJyb3JDb2RlLlZBTElEQVRJT05fRVJST1IpLCBFcnJvckNvZGUuVkFMSURBVElPTl9FUlJPUiwgbWVzc2FnZSk7XG4gICAgdGhpcy5uYW1lID0gJ1ZhbGlkYXRpb25FcnJvcic7XG4gIH1cbn1cblxuLyoqIDQwOSDigJQgQ29uZmxpY3QgLyBkdXBsaWNhdGUuIGBjb2RlYCBuYXJyb3dzIHRoZSBjb25mbGljdCBmb3IgY2xpZW50c1xuICogIChlLmcuIGBQTFVHSU5fVkVSU0lPTl9GUk9aRU5gKTsgaXQgbXVzdCBiZSBhIDQwOS1tYXBwZWQgY29kZS4gYGRldGFpbHNgXG4gKiAgY2FycmllcyB3aGF0IHRoZSBjbGllbnQgbmVlZHMgdG8gcmVzb2x2ZSBpdCDigJQgZm9yIGEgdGFrZW4gcGlwZWxpbmUgc2xvdCxcbiAqICB0aGUgTk9STUFMSVpFRCBuYW1lcyB0aGF0IGNvbGxpZGVkIGFuZCB0aGUgaWQgdG8gUFVUIGluc3RlYWQuICovXG5leHBvcnQgY2xhc3MgQ29uZmxpY3RFcnJvciBleHRlbmRzIEFwcEVycm9yIHtcbiAgY29uc3RydWN0b3IobWVzc2FnZTogc3RyaW5nLCBjb2RlOiBFcnJvckNvZGUgPSBFcnJvckNvZGUuQ09ORkxJQ1QsIGRldGFpbHM/OiBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPikge1xuICAgIHN1cGVyKGdldFN0YXR1c0ZvckVycm9yQ29kZShFcnJvckNvZGUuQ09ORkxJQ1QpLCBjb2RlLCBtZXNzYWdlLCBkZXRhaWxzKTtcbiAgICB0aGlzLm5hbWUgPSAnQ29uZmxpY3RFcnJvcic7XG4gIH1cbn1cbiJdfQ==
53
+ /** 403 — the organization's administrators switched AI features off. */
54
+ export class AIDisabledError extends AppError {
55
+ constructor(message = 'AI features are turned off for this organization. An organization administrator can turn them back on in Settings.') {
56
+ super(getStatusForErrorCode(ErrorCode.AI_DISABLED), ErrorCode.AI_DISABLED, message);
57
+ this.name = 'AIDisabledError';
58
+ }
59
+ }
60
+ /**
61
+ * An AI request could not be served AS ASKED — the org's own provider key could not
62
+ * be loaded, a bring-your-own key named a keyless provider, nothing is configured.
63
+ * The message is written by us and names configuration, never a secret, so it is
64
+ * safe to show; `handleAIError` surfaces it verbatim with this status. Thrown
65
+ * INSTEAD of silently serving the request on the platform's key.
66
+ */
67
+ export class AIConfigurationError extends AppError {
68
+ constructor(message, statusCode = 503, code = ErrorCode.SERVICE_UNAVAILABLE) {
69
+ super(statusCode, code, message);
70
+ this.name = 'AIConfigurationError';
71
+ }
72
+ }
73
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYXBwLWVycm9ycy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9lcnJvcnMvYXBwLWVycm9ycy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSwrQ0FBK0M7QUFDL0Msc0NBQXNDO0FBRXRDLE9BQU8sRUFBRSxTQUFTLEVBQUUscUJBQXFCLEVBQUUsTUFBTSx5QkFBeUIsQ0FBQztBQUUzRTs7O0dBR0c7QUFDSCxNQUFNLE9BQU8sUUFBUyxTQUFRLEtBQUs7SUFFZixVQUFVO0lBQ1YsSUFBSTtJQUdKLE9BQU87SUFMekIsWUFDa0IsVUFBa0IsRUFDbEIsSUFBZSxFQUMvQixPQUFlO0lBQ2YsZ0ZBQWdGO0lBQ2hFLE9BQWlDO1FBRWpELEtBQUssQ0FBQyxPQUFPLENBQUMsQ0FBQzswQkFOQyxVQUFVO29CQUNWLElBQUk7dUJBR0osT0FBTztRQUd2QixJQUFJLENBQUMsSUFBSSxHQUFHLFVBQVUsQ0FBQztJQUN6QixDQUFDO0NBQ0Y7QUFFRCxnQ0FBZ0M7QUFDaEMsTUFBTSxPQUFPLGFBQWMsU0FBUSxRQUFRO0lBQ3pDLFlBQVksT0FBZTtRQUN6QixLQUFLLENBQUMscUJBQXFCLENBQUMsU0FBUyxDQUFDLFNBQVMsQ0FBQyxFQUFFLFNBQVMsQ0FBQyxTQUFTLEVBQUUsT0FBTyxDQUFDLENBQUM7UUFDaEYsSUFBSSxDQUFDLElBQUksR0FBRyxlQUFlLENBQUM7SUFDOUIsQ0FBQztDQUNGO0FBRUQsc0NBQXNDO0FBQ3RDLE1BQU0sT0FBTyxjQUFlLFNBQVEsUUFBUTtJQUMxQyxZQUFZLE9BQWU7UUFDekIsS0FBSyxDQUFDLHFCQUFxQixDQUFDLFNBQVMsQ0FBQyx3QkFBd0IsQ0FBQyxFQUFFLFNBQVMsQ0FBQyx3QkFBd0IsRUFBRSxPQUFPLENBQUMsQ0FBQztRQUM5RyxJQUFJLENBQUMsSUFBSSxHQUFHLGdCQUFnQixDQUFDO0lBQy9CLENBQUM7Q0FDRjtBQUVELHNDQUFzQztBQUN0QyxNQUFNLE9BQU8sZUFBZ0IsU0FBUSxRQUFRO0lBQzNDLFlBQVksT0FBZTtRQUN6QixLQUFLLENBQUMscUJBQXFCLENBQUMsU0FBUyxDQUFDLGdCQUFnQixDQUFDLEVBQUUsU0FBUyxDQUFDLGdCQUFnQixFQUFFLE9BQU8sQ0FBQyxDQUFDO1FBQzlGLElBQUksQ0FBQyxJQUFJLEdBQUcsaUJBQWlCLENBQUM7SUFDaEMsQ0FBQztDQUNGO0FBRUQ7OztvRUFHb0U7QUFDcEUsTUFBTSxPQUFPLGFBQWMsU0FBUSxRQUFRO0lBQ3pDLFlBQVksT0FBZSxFQUFFLElBQUksR0FBYyxTQUFTLENBQUMsUUFBUSxFQUFFLE9BQWlDO1FBQ2xHLEtBQUssQ0FBQyxxQkFBcUIsQ0FBQyxTQUFTLENBQUMsUUFBUSxDQUFDLEVBQUUsSUFBSSxFQUFFLE9BQU8sRUFBRSxPQUFPLENBQUMsQ0FBQztRQUN6RSxJQUFJLENBQUMsSUFBSSxHQUFHLGVBQWUsQ0FBQztJQUM5QixDQUFDO0NBQ0Y7QUFFRCx3RUFBd0U7QUFDeEUsTUFBTSxPQUFPLGVBQWdCLFNBQVEsUUFBUTtJQUMzQyxZQUFZLE9BQU8sR0FBRyxvSEFBb0g7UUFDeEksS0FBSyxDQUFDLHFCQUFxQixDQUFDLFNBQVMsQ0FBQyxXQUFXLENBQUMsRUFBRSxTQUFTLENBQUMsV0FBVyxFQUFFLE9BQU8sQ0FBQyxDQUFDO1FBQ3BGLElBQUksQ0FBQyxJQUFJLEdBQUcsaUJBQWlCLENBQUM7SUFDaEMsQ0FBQztDQUNGO0FBRUQ7Ozs7OztHQU1HO0FBQ0gsTUFBTSxPQUFPLG9CQUFxQixTQUFRLFFBQVE7SUFDaEQsWUFBWSxPQUFlLEVBQUUsVUFBVSxHQUFHLEdBQUcsRUFBRSxJQUFJLEdBQWMsU0FBUyxDQUFDLG1CQUFtQjtRQUM1RixLQUFLLENBQUMsVUFBVSxFQUFFLElBQUksRUFBRSxPQUFPLENBQUMsQ0FBQztRQUNqQyxJQUFJLENBQUMsSUFBSSxHQUFHLHNCQUFzQixDQUFDO0lBQ3JDLENBQUM7Q0FDRiIsInNvdXJjZXNDb250ZW50IjpbIi8vIENvcHlyaWdodCAyMDI2IFBpcGVsaW5lIEJ1aWxkZXIgQ29udHJpYnV0b3JzXG4vLyBTUERYLUxpY2Vuc2UtSWRlbnRpZmllcjogQXBhY2hlLTIuMFxuXG5pbXBvcnQgeyBFcnJvckNvZGUsIGdldFN0YXR1c0ZvckVycm9yQ29kZSB9IGZyb20gJy4uL3R5cGVzL2Vycm9yLWNvZGVzLmpzJztcblxuLyoqXG4gKiBCYXNlIGFwcGxpY2F0aW9uIGVycm9yIHdpdGggSFRUUCBzdGF0dXMgY29kZSBhbmQgZXJyb3IgY29kZS5cbiAqIEV4dGVuZCB0aGlzIGZvciBkb21haW4tc3BlY2lmaWMgZXJyb3IgdHlwZXMuXG4gKi9cbmV4cG9ydCBjbGFzcyBBcHBFcnJvciBleHRlbmRzIEVycm9yIHtcbiAgY29uc3RydWN0b3IoXG4gICAgcHVibGljIHJlYWRvbmx5IHN0YXR1c0NvZGU6IG51bWJlcixcbiAgICBwdWJsaWMgcmVhZG9ubHkgY29kZTogRXJyb3JDb2RlLFxuICAgIG1lc3NhZ2U6IHN0cmluZyxcbiAgICAvKiogU3RydWN0dXJlZCBjb250ZXh0IHNlbnQgd2l0aCB0aGUgZXJyb3IgcmVzcG9uc2UgKGUuZy4gdGhlIGZhaWxpbmcgZ2F0ZXMpLiAqL1xuICAgIHB1YmxpYyByZWFkb25seSBkZXRhaWxzPzogUmVjb3JkPHN0cmluZywgdW5rbm93bj4sXG4gICkge1xuICAgIHN1cGVyKG1lc3NhZ2UpO1xuICAgIHRoaXMubmFtZSA9ICdBcHBFcnJvcic7XG4gIH1cbn1cblxuLyoqIDQwNCDigJQgUmVzb3VyY2Ugbm90IGZvdW5kLiAqL1xuZXhwb3J0IGNsYXNzIE5vdEZvdW5kRXJyb3IgZXh0ZW5kcyBBcHBFcnJvciB7XG4gIGNvbnN0cnVjdG9yKG1lc3NhZ2U6IHN0cmluZykge1xuICAgIHN1cGVyKGdldFN0YXR1c0ZvckVycm9yQ29kZShFcnJvckNvZGUuTk9UX0ZPVU5EKSwgRXJyb3JDb2RlLk5PVF9GT1VORCwgbWVzc2FnZSk7XG4gICAgdGhpcy5uYW1lID0gJ05vdEZvdW5kRXJyb3InO1xuICB9XG59XG5cbi8qKiA0MDMg4oCUIEluc3VmZmljaWVudCBwZXJtaXNzaW9ucy4gKi9cbmV4cG9ydCBjbGFzcyBGb3JiaWRkZW5FcnJvciBleHRlbmRzIEFwcEVycm9yIHtcbiAgY29uc3RydWN0b3IobWVzc2FnZTogc3RyaW5nKSB7XG4gICAgc3VwZXIoZ2V0U3RhdHVzRm9yRXJyb3JDb2RlKEVycm9yQ29kZS5JTlNVRkZJQ0lFTlRfUEVSTUlTU0lPTlMpLCBFcnJvckNvZGUuSU5TVUZGSUNJRU5UX1BFUk1JU1NJT05TLCBtZXNzYWdlKTtcbiAgICB0aGlzLm5hbWUgPSAnRm9yYmlkZGVuRXJyb3InO1xuICB9XG59XG5cbi8qKiA0MDAg4oCUIFZhbGlkYXRpb24gLyBiYWQgcmVxdWVzdC4gKi9cbmV4cG9ydCBjbGFzcyBWYWxpZGF0aW9uRXJyb3IgZXh0ZW5kcyBBcHBFcnJvciB7XG4gIGNvbnN0cnVjdG9yKG1lc3NhZ2U6IHN0cmluZykge1xuICAgIHN1cGVyKGdldFN0YXR1c0ZvckVycm9yQ29kZShFcnJvckNvZGUuVkFMSURBVElPTl9FUlJPUiksIEVycm9yQ29kZS5WQUxJREFUSU9OX0VSUk9SLCBtZXNzYWdlKTtcbiAgICB0aGlzLm5hbWUgPSAnVmFsaWRhdGlvbkVycm9yJztcbiAgfVxufVxuXG4vKiogNDA5IOKAlCBDb25mbGljdCAvIGR1cGxpY2F0ZS4gYGNvZGVgIG5hcnJvd3MgdGhlIGNvbmZsaWN0IGZvciBjbGllbnRzXG4gKiAgKGUuZy4gYFBMVUdJTl9WRVJTSU9OX0ZST1pFTmApOyBpdCBtdXN0IGJlIGEgNDA5LW1hcHBlZCBjb2RlLiBgZGV0YWlsc2BcbiAqICBjYXJyaWVzIHdoYXQgdGhlIGNsaWVudCBuZWVkcyB0byByZXNvbHZlIGl0IOKAlCBmb3IgYSB0YWtlbiBwaXBlbGluZSBzbG90LFxuICogIHRoZSBOT1JNQUxJWkVEIG5hbWVzIHRoYXQgY29sbGlkZWQgYW5kIHRoZSBpZCB0byBQVVQgaW5zdGVhZC4gKi9cbmV4cG9ydCBjbGFzcyBDb25mbGljdEVycm9yIGV4dGVuZHMgQXBwRXJyb3Ige1xuICBjb25zdHJ1Y3RvcihtZXNzYWdlOiBzdHJpbmcsIGNvZGU6IEVycm9yQ29kZSA9IEVycm9yQ29kZS5DT05GTElDVCwgZGV0YWlscz86IFJlY29yZDxzdHJpbmcsIHVua25vd24+KSB7XG4gICAgc3VwZXIoZ2V0U3RhdHVzRm9yRXJyb3JDb2RlKEVycm9yQ29kZS5DT05GTElDVCksIGNvZGUsIG1lc3NhZ2UsIGRldGFpbHMpO1xuICAgIHRoaXMubmFtZSA9ICdDb25mbGljdEVycm9yJztcbiAgfVxufVxuXG4vKiogNDAzIOKAlCB0aGUgb3JnYW5pemF0aW9uJ3MgYWRtaW5pc3RyYXRvcnMgc3dpdGNoZWQgQUkgZmVhdHVyZXMgb2ZmLiAqL1xuZXhwb3J0IGNsYXNzIEFJRGlzYWJsZWRFcnJvciBleHRlbmRzIEFwcEVycm9yIHtcbiAgY29uc3RydWN0b3IobWVzc2FnZSA9ICdBSSBmZWF0dXJlcyBhcmUgdHVybmVkIG9mZiBmb3IgdGhpcyBvcmdhbml6YXRpb24uIEFuIG9yZ2FuaXphdGlvbiBhZG1pbmlzdHJhdG9yIGNhbiB0dXJuIHRoZW0gYmFjayBvbiBpbiBTZXR0aW5ncy4nKSB7XG4gICAgc3VwZXIoZ2V0U3RhdHVzRm9yRXJyb3JDb2RlKEVycm9yQ29kZS5BSV9ESVNBQkxFRCksIEVycm9yQ29kZS5BSV9ESVNBQkxFRCwgbWVzc2FnZSk7XG4gICAgdGhpcy5uYW1lID0gJ0FJRGlzYWJsZWRFcnJvcic7XG4gIH1cbn1cblxuLyoqXG4gKiBBbiBBSSByZXF1ZXN0IGNvdWxkIG5vdCBiZSBzZXJ2ZWQgQVMgQVNLRUQg4oCUIHRoZSBvcmcncyBvd24gcHJvdmlkZXIga2V5IGNvdWxkIG5vdFxuICogYmUgbG9hZGVkLCBhIGJyaW5nLXlvdXItb3duIGtleSBuYW1lZCBhIGtleWxlc3MgcHJvdmlkZXIsIG5vdGhpbmcgaXMgY29uZmlndXJlZC5cbiAqIFRoZSBtZXNzYWdlIGlzIHdyaXR0ZW4gYnkgdXMgYW5kIG5hbWVzIGNvbmZpZ3VyYXRpb24sIG5ldmVyIGEgc2VjcmV0LCBzbyBpdCBpc1xuICogc2FmZSB0byBzaG93OyBgaGFuZGxlQUlFcnJvcmAgc3VyZmFjZXMgaXQgdmVyYmF0aW0gd2l0aCB0aGlzIHN0YXR1cy4gVGhyb3duXG4gKiBJTlNURUFEIG9mIHNpbGVudGx5IHNlcnZpbmcgdGhlIHJlcXVlc3Qgb24gdGhlIHBsYXRmb3JtJ3Mga2V5LlxuICovXG5leHBvcnQgY2xhc3MgQUlDb25maWd1cmF0aW9uRXJyb3IgZXh0ZW5kcyBBcHBFcnJvciB7XG4gIGNvbnN0cnVjdG9yKG1lc3NhZ2U6IHN0cmluZywgc3RhdHVzQ29kZSA9IDUwMywgY29kZTogRXJyb3JDb2RlID0gRXJyb3JDb2RlLlNFUlZJQ0VfVU5BVkFJTEFCTEUpIHtcbiAgICBzdXBlcihzdGF0dXNDb2RlLCBjb2RlLCBtZXNzYWdlKTtcbiAgICB0aGlzLm5hbWUgPSAnQUlDb25maWd1cmF0aW9uRXJyb3InO1xuICB9XG59XG4iXX0=
@@ -1,4 +1,5 @@
1
1
  export * from './crud-helpers.js';
2
+ export { businessCalendar, responseDueAt, SUPPORT_TARGET_MEASURES, type BusinessCalendar, type SupportTargetKind, } from './support-calendar.js';
2
3
  export { requireVisibilityWriteAccess, checkVisibilityWriteAccess, checkWriteAccess, rejectForbiddenBulkRows, resolveVisibility, type VisibilityWriteTarget, type VisibilityWriteVerdict, type WriteAccess, type BulkWriteRow, } from './access-helpers.js';
3
4
  export { loadAndRestore, loadAndPurge, type RestorableService, type PurgeableService, type TombstoneAuthorizer, type TombstoneRouteOptions, } from './restore-helpers.js';
4
5
  export * from './sse-helpers.js';
@@ -1,10 +1,11 @@
1
1
  // Copyright 2026 Pipeline Builder Contributors
2
2
  // SPDX-License-Identifier: Apache-2.0
3
3
  export * from './crud-helpers.js';
4
+ export { businessCalendar, responseDueAt, SUPPORT_TARGET_MEASURES, } from './support-calendar.js';
4
5
  export { requireVisibilityWriteAccess, checkVisibilityWriteAccess, checkWriteAccess, rejectForbiddenBulkRows, resolveVisibility, } from './access-helpers.js';
5
6
  export { loadAndRestore, loadAndPurge, } from './restore-helpers.js';
6
7
  export * from './sse-helpers.js';
7
8
  export * from './org-hierarchy.js';
8
9
  export { fetchParentOrgId, fetchOrgDescendants, fetchOrgNames, fetchOrgMembership, } from './org-hierarchy-http.js';
9
10
  export * from './content-disposition.js';
10
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvaGVscGVycy9pbmRleC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSwrQ0FBK0M7QUFDL0Msc0NBQXNDO0FBRXRDLGNBQWMsbUJBQW1CLENBQUM7QUFDbEMsT0FBTyxFQUNMLDRCQUE0QixFQUM1QiwwQkFBMEIsRUFDMUIsZ0JBQWdCLEVBQ2hCLHVCQUF1QixFQUN2QixpQkFBaUIsR0FLbEIsTUFBTSxxQkFBcUIsQ0FBQztBQUM3QixPQUFPLEVBQ0wsY0FBYyxFQUNkLFlBQVksR0FLYixNQUFNLHNCQUFzQixDQUFDO0FBQzlCLGNBQWMsa0JBQWtCLENBQUM7QUFDakMsY0FBYyxvQkFBb0IsQ0FBQztBQUNuQyxPQUFPLEVBQ0wsZ0JBQWdCLEVBQ2hCLG1CQUFtQixFQUNuQixhQUFhLEVBQ2Isa0JBQWtCLEdBQ25CLE1BQU0seUJBQXlCLENBQUM7QUFDakMsY0FBYywwQkFBMEIsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbIi8vIENvcHlyaWdodCAyMDI2IFBpcGVsaW5lIEJ1aWxkZXIgQ29udHJpYnV0b3JzXG4vLyBTUERYLUxpY2Vuc2UtSWRlbnRpZmllcjogQXBhY2hlLTIuMFxuXG5leHBvcnQgKiBmcm9tICcuL2NydWQtaGVscGVycy5qcyc7XG5leHBvcnQge1xuICByZXF1aXJlVmlzaWJpbGl0eVdyaXRlQWNjZXNzLFxuICBjaGVja1Zpc2liaWxpdHlXcml0ZUFjY2VzcyxcbiAgY2hlY2tXcml0ZUFjY2VzcyxcbiAgcmVqZWN0Rm9yYmlkZGVuQnVsa1Jvd3MsXG4gIHJlc29sdmVWaXNpYmlsaXR5LFxuICB0eXBlIFZpc2liaWxpdHlXcml0ZVRhcmdldCxcbiAgdHlwZSBWaXNpYmlsaXR5V3JpdGVWZXJkaWN0LFxuICB0eXBlIFdyaXRlQWNjZXNzLFxuICB0eXBlIEJ1bGtXcml0ZVJvdyxcbn0gZnJvbSAnLi9hY2Nlc3MtaGVscGVycy5qcyc7XG5leHBvcnQge1xuICBsb2FkQW5kUmVzdG9yZSxcbiAgbG9hZEFuZFB1cmdlLFxuICB0eXBlIFJlc3RvcmFibGVTZXJ2aWNlLFxuICB0eXBlIFB1cmdlYWJsZVNlcnZpY2UsXG4gIHR5cGUgVG9tYnN0b25lQXV0aG9yaXplcixcbiAgdHlwZSBUb21ic3RvbmVSb3V0ZU9wdGlvbnMsXG59IGZyb20gJy4vcmVzdG9yZS1oZWxwZXJzLmpzJztcbmV4cG9ydCAqIGZyb20gJy4vc3NlLWhlbHBlcnMuanMnO1xuZXhwb3J0ICogZnJvbSAnLi9vcmctaGllcmFyY2h5LmpzJztcbmV4cG9ydCB7XG4gIGZldGNoUGFyZW50T3JnSWQsXG4gIGZldGNoT3JnRGVzY2VuZGFudHMsXG4gIGZldGNoT3JnTmFtZXMsXG4gIGZldGNoT3JnTWVtYmVyc2hpcCxcbn0gZnJvbSAnLi9vcmctaGllcmFyY2h5LWh0dHAuanMnO1xuZXhwb3J0ICogZnJvbSAnLi9jb250ZW50LWRpc3Bvc2l0aW9uLmpzJztcbiJdfQ==
11
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvaGVscGVycy9pbmRleC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSwrQ0FBK0M7QUFDL0Msc0NBQXNDO0FBRXRDLGNBQWMsbUJBQW1CLENBQUM7QUFDbEMsT0FBTyxFQUNMLGdCQUFnQixFQUNoQixhQUFhLEVBQ2IsdUJBQXVCLEdBR3hCLE1BQU0sdUJBQXVCLENBQUM7QUFDL0IsT0FBTyxFQUNMLDRCQUE0QixFQUM1QiwwQkFBMEIsRUFDMUIsZ0JBQWdCLEVBQ2hCLHVCQUF1QixFQUN2QixpQkFBaUIsR0FLbEIsTUFBTSxxQkFBcUIsQ0FBQztBQUM3QixPQUFPLEVBQ0wsY0FBYyxFQUNkLFlBQVksR0FLYixNQUFNLHNCQUFzQixDQUFDO0FBQzlCLGNBQWMsa0JBQWtCLENBQUM7QUFDakMsY0FBYyxvQkFBb0IsQ0FBQztBQUNuQyxPQUFPLEVBQ0wsZ0JBQWdCLEVBQ2hCLG1CQUFtQixFQUNuQixhQUFhLEVBQ2Isa0JBQWtCLEdBQ25CLE1BQU0seUJBQXlCLENBQUM7QUFDakMsY0FBYywwQkFBMEIsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbIi8vIENvcHlyaWdodCAyMDI2IFBpcGVsaW5lIEJ1aWxkZXIgQ29udHJpYnV0b3JzXG4vLyBTUERYLUxpY2Vuc2UtSWRlbnRpZmllcjogQXBhY2hlLTIuMFxuXG5leHBvcnQgKiBmcm9tICcuL2NydWQtaGVscGVycy5qcyc7XG5leHBvcnQge1xuICBidXNpbmVzc0NhbGVuZGFyLFxuICByZXNwb25zZUR1ZUF0LFxuICBTVVBQT1JUX1RBUkdFVF9NRUFTVVJFUyxcbiAgdHlwZSBCdXNpbmVzc0NhbGVuZGFyLFxuICB0eXBlIFN1cHBvcnRUYXJnZXRLaW5kLFxufSBmcm9tICcuL3N1cHBvcnQtY2FsZW5kYXIuanMnO1xuZXhwb3J0IHtcbiAgcmVxdWlyZVZpc2liaWxpdHlXcml0ZUFjY2VzcyxcbiAgY2hlY2tWaXNpYmlsaXR5V3JpdGVBY2Nlc3MsXG4gIGNoZWNrV3JpdGVBY2Nlc3MsXG4gIHJlamVjdEZvcmJpZGRlbkJ1bGtSb3dzLFxuICByZXNvbHZlVmlzaWJpbGl0eSxcbiAgdHlwZSBWaXNpYmlsaXR5V3JpdGVUYXJnZXQsXG4gIHR5cGUgVmlzaWJpbGl0eVdyaXRlVmVyZGljdCxcbiAgdHlwZSBXcml0ZUFjY2VzcyxcbiAgdHlwZSBCdWxrV3JpdGVSb3csXG59IGZyb20gJy4vYWNjZXNzLWhlbHBlcnMuanMnO1xuZXhwb3J0IHtcbiAgbG9hZEFuZFJlc3RvcmUsXG4gIGxvYWRBbmRQdXJnZSxcbiAgdHlwZSBSZXN0b3JhYmxlU2VydmljZSxcbiAgdHlwZSBQdXJnZWFibGVTZXJ2aWNlLFxuICB0eXBlIFRvbWJzdG9uZUF1dGhvcml6ZXIsXG4gIHR5cGUgVG9tYnN0b25lUm91dGVPcHRpb25zLFxufSBmcm9tICcuL3Jlc3RvcmUtaGVscGVycy5qcyc7XG5leHBvcnQgKiBmcm9tICcuL3NzZS1oZWxwZXJzLmpzJztcbmV4cG9ydCAqIGZyb20gJy4vb3JnLWhpZXJhcmNoeS5qcyc7XG5leHBvcnQge1xuICBmZXRjaFBhcmVudE9yZ0lkLFxuICBmZXRjaE9yZ0Rlc2NlbmRhbnRzLFxuICBmZXRjaE9yZ05hbWVzLFxuICBmZXRjaE9yZ01lbWJlcnNoaXAsXG59IGZyb20gJy4vb3JnLWhpZXJhcmNoeS1odHRwLmpzJztcbmV4cG9ydCAqIGZyb20gJy4vY29udGVudC1kaXNwb3NpdGlvbi5qcyc7XG4iXX0=
@@ -1,4 +1,5 @@
1
1
  import type { Request, Response } from 'express';
2
+ import { ErrorCode } from '../types/error-codes.js';
2
3
  /**
3
4
  * Set the four standard SSE response headers (does NOT flush — the caller flushes
4
5
  * after any additional per-endpoint setup like `res.setTimeout`). The single
@@ -41,9 +42,38 @@ export interface SseStream {
41
42
  * client-disconnect signal (see {@link clientAbortSignal}).
42
43
  */
43
44
  export declare function initSSEStream(_req: Request, res: Response, timeoutMs: number): SseStream;
45
+ /** How an AI failure is answered: an HTTP status, a code, and a message WE wrote. */
46
+ export interface AIErrorResponse {
47
+ status: number;
48
+ code: ErrorCode;
49
+ /** Safe to show: never raw provider response text. */
50
+ message: string;
51
+ /** Seconds, from the provider's own `Retry-After` when it sent one. */
52
+ retryAfterSeconds?: number;
53
+ }
54
+ /**
55
+ * Classify an AI failure into the response a caller sends.
56
+ *
57
+ * Provider failures are matched on the provider's HTTP STATUS (`APICallError.statusCode`),
58
+ * never on message text, and answered with a sentence of ours: a provider's error body
59
+ * can carry account ids, request ids, quota details or an echo of the prompt, and none
60
+ * of it belongs in a response or an SSE frame. The full error still goes to the
61
+ * caller's log line.
62
+ *
63
+ * - 429 → 429 (with the provider's `Retry-After`): the provider is rate limiting.
64
+ * - 529 / 5xx → 503 (with `Retry-After`): the provider is overloaded or down.
65
+ * - 401 / 403 → 502: the provider refused the credential (a BYO or org key is wrong).
66
+ * - a timeout signal → 504.
67
+ * - an {@link AppError} (AIDisabledError, AIConfigurationError, …) → its own status and message.
68
+ * - otherwise the configuration messages the registry writes (they name env vars,
69
+ * never values) keep their text; anything else gets `fallbackMessage`.
70
+ */
71
+ export declare function classifyAIError(error: unknown, fallbackMessage: string): AIErrorResponse;
44
72
  /**
45
- * Classify AI generation errors and send the appropriate HTTP response or SSE event.
46
- * If headers are already sent (streaming), writes an SSE error event and ends the response.
73
+ * Answer an AI generation failure: an HTTP error before the stream started, or an
74
+ * SSE `error` event (then end) once it has. Takes the ERROR, not its message — the
75
+ * provider status is what decides the answer (see {@link classifyAIError}); a string
76
+ * is still accepted for the registry's configuration messages.
47
77
  */
48
- export declare function handleAIError(res: Response, message: string, fallbackMessage: string): void;
78
+ export declare function handleAIError(res: Response, error: unknown, fallbackMessage: string): void;
49
79
  export {};
@@ -1,6 +1,8 @@
1
1
  // Copyright 2026 Pipeline Builder Contributors
2
2
  // SPDX-License-Identifier: Apache-2.0
3
- import { sendBadRequest, sendInternalError } from '../utils/response.js';
3
+ import { AppError } from '../errors/app-errors.js';
4
+ import { ErrorCode } from '../types/error-codes.js';
5
+ import { errorMessage, sendError } from '../utils/response.js';
4
6
  /**
5
7
  * Set the four standard SSE response headers (does NOT flush — the caller flushes
6
8
  * after any additional per-endpoint setup like `res.setTimeout`). The single
@@ -60,28 +62,98 @@ export function initSSEStream(_req, res, timeoutMs) {
60
62
  },
61
63
  };
62
64
  }
65
+ /** `Retry-After` as seconds — either form the header allows (delta-seconds or an HTTP date). */
66
+ function retryAfterSeconds(headers) {
67
+ const raw = headers?.['retry-after'] ?? headers?.['Retry-After'];
68
+ if (!raw)
69
+ return undefined;
70
+ const asNumber = Number(raw);
71
+ if (Number.isFinite(asNumber) && asNumber >= 0)
72
+ return Math.ceil(asNumber);
73
+ const at = Date.parse(raw);
74
+ return Number.isNaN(at) ? undefined : Math.max(0, Math.ceil((at - Date.now()) / 1000));
75
+ }
76
+ /** True for an abort that came from a TIMEOUT signal rather than a client disconnect. */
77
+ function isTimeout(error) {
78
+ const e = error;
79
+ return e?.name === 'TimeoutError' || e?.cause?.name === 'TimeoutError';
80
+ }
63
81
  /**
64
- * Classify AI generation errors and send the appropriate HTTP response or SSE event.
65
- * If headers are already sent (streaming), writes an SSE error event and ends the response.
82
+ * Classify an AI failure into the response a caller sends.
83
+ *
84
+ * Provider failures are matched on the provider's HTTP STATUS (`APICallError.statusCode`),
85
+ * never on message text, and answered with a sentence of ours: a provider's error body
86
+ * can carry account ids, request ids, quota details or an echo of the prompt, and none
87
+ * of it belongs in a response or an SSE frame. The full error still goes to the
88
+ * caller's log line.
89
+ *
90
+ * - 429 → 429 (with the provider's `Retry-After`): the provider is rate limiting.
91
+ * - 529 / 5xx → 503 (with `Retry-After`): the provider is overloaded or down.
92
+ * - 401 / 403 → 502: the provider refused the credential (a BYO or org key is wrong).
93
+ * - a timeout signal → 504.
94
+ * - an {@link AppError} (AIDisabledError, AIConfigurationError, …) → its own status and message.
95
+ * - otherwise the configuration messages the registry writes (they name env vars,
96
+ * never values) keep their text; anything else gets `fallbackMessage`.
66
97
  */
67
- export function handleAIError(res, message, fallbackMessage) {
68
- if (!res.headersSent) {
69
- if (message.includes('not configured') || message.includes('API key')) {
70
- // Surface the ORIGINAL message. It names the MISSING CONFIGURATION —
71
- // "no provider API key is set and OPENAI_COMPATIBLE_BASE_URL is unset",
72
- // or which env var a named provider wants — never a secret VALUE, so it
73
- // is safe to show and it is the only thing that makes this error
74
- // actionable. The generic replacement also mis-described the common case:
75
- // it said "for the requested provider" when no provider was requested at
76
- // all, pointing operators at a provider bug instead of at configuration.
77
- return sendInternalError(res, message);
98
+ export function classifyAIError(error, fallbackMessage) {
99
+ if (error instanceof AppError) {
100
+ return { status: error.statusCode, code: error.code, message: error.message };
101
+ }
102
+ const providerStatus = typeof error?.statusCode === 'number'
103
+ ? error.statusCode
104
+ : undefined;
105
+ if (providerStatus !== undefined) {
106
+ const retryAfter = retryAfterSeconds(error.responseHeaders);
107
+ const withRetry = retryAfter !== undefined ? { retryAfterSeconds: retryAfter } : {};
108
+ if (providerStatus === 429) {
109
+ return { status: 429, code: ErrorCode.RATE_LIMIT_EXCEEDED, message: 'The AI provider is rate limiting requests. Try again shortly.', ...withRetry };
78
110
  }
79
- if (message.includes('not available for provider')) {
80
- return sendBadRequest(res, message);
111
+ if (providerStatus === 529 || providerStatus >= 500) {
112
+ return { status: 503, code: ErrorCode.SERVICE_UNAVAILABLE, message: 'The AI provider is temporarily unavailable. Try again shortly.', ...withRetry };
81
113
  }
82
- return sendInternalError(res, fallbackMessage, { details: message });
114
+ if (providerStatus === 401 || providerStatus === 403) {
115
+ return { status: 502, code: ErrorCode.INTERNAL_ERROR, message: 'The AI provider rejected the API key used for this request. Check the key in Settings, or the one you supplied.' };
116
+ }
117
+ return { status: 502, code: ErrorCode.INTERNAL_ERROR, message: fallbackMessage };
118
+ }
119
+ if (isTimeout(error)) {
120
+ return { status: 504, code: ErrorCode.SERVICE_UNAVAILABLE, message: 'The AI provider did not respond in time. Try again, or ask for something smaller.' };
121
+ }
122
+ const message = typeof error === 'string' ? error : errorMessage(error);
123
+ if (message.includes('not configured') || message.includes('API key')) {
124
+ // Surface the ORIGINAL message. Only the registry's own configuration errors
125
+ // reach here (a provider's response carries a status and was handled above):
126
+ // they name the MISSING CONFIGURATION — "no provider API key is set and
127
+ // OPENAI_COMPATIBLE_BASE_URL is unset", or which env var a named provider
128
+ // wants — never a secret VALUE, and are the only thing that makes this error
129
+ // actionable.
130
+ return { status: 500, code: ErrorCode.INTERNAL_ERROR, message };
131
+ }
132
+ if (message.includes('not available for provider')) {
133
+ return { status: 400, code: ErrorCode.VALIDATION_ERROR, message };
134
+ }
135
+ return { status: 500, code: ErrorCode.INTERNAL_ERROR, message: fallbackMessage };
136
+ }
137
+ /**
138
+ * Answer an AI generation failure: an HTTP error before the stream started, or an
139
+ * SSE `error` event (then end) once it has. Takes the ERROR, not its message — the
140
+ * provider status is what decides the answer (see {@link classifyAIError}); a string
141
+ * is still accepted for the registry's configuration messages.
142
+ */
143
+ export function handleAIError(res, error, fallbackMessage) {
144
+ const answer = classifyAIError(error, fallbackMessage);
145
+ if (!res.headersSent) {
146
+ if (answer.retryAfterSeconds !== undefined)
147
+ res.setHeader('Retry-After', String(answer.retryAfterSeconds));
148
+ return sendError(res, answer.status, answer.message, answer.code);
83
149
  }
84
- res.write(`data: ${JSON.stringify({ type: 'error', message })}\n\n`);
150
+ res.write(`data: ${JSON.stringify({
151
+ type: 'error',
152
+ message: answer.message,
153
+ code: answer.code,
154
+ status: answer.status,
155
+ ...(answer.retryAfterSeconds !== undefined ? { retryAfterSeconds: answer.retryAfterSeconds } : {}),
156
+ })}\n\n`);
85
157
  res.end();
86
158
  }
87
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic3NlLWhlbHBlcnMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvaGVscGVycy9zc2UtaGVscGVycy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSwrQ0FBK0M7QUFDL0Msc0NBQXNDO0FBR3RDLE9BQU8sRUFBRSxjQUFjLEVBQUUsaUJBQWlCLEVBQUUsTUFBTSxzQkFBc0IsQ0FBQztBQUV6RTs7Ozs7R0FLRztBQUNILE1BQU0sVUFBVSxlQUFlLENBQUMsR0FBYTtJQUMzQyxHQUFHLENBQUMsU0FBUyxDQUFDLGNBQWMsRUFBRSxtQkFBbUIsQ0FBQyxDQUFDO0lBQ25ELEdBQUcsQ0FBQyxTQUFTLENBQUMsZUFBZSxFQUFFLFVBQVUsQ0FBQyxDQUFDO0lBQzNDLEdBQUcsQ0FBQyxTQUFTLENBQUMsWUFBWSxFQUFFLFlBQVksQ0FBQyxDQUFDO0lBQzFDLEdBQUcsQ0FBQyxTQUFTLENBQUMsbUJBQW1CLEVBQUUsSUFBSSxDQUFDLENBQUM7QUFDM0MsQ0FBQztBQVFEOzs7Ozs7Ozs7OztHQVdHO0FBQ0gsTUFBTSxVQUFVLGlCQUFpQixDQUFDLEdBQXFCO0lBQ3JELE1BQU0sVUFBVSxHQUFHLElBQUksZUFBZSxFQUFFLENBQUM7SUFDekMsR0FBRyxDQUFDLEVBQUUsQ0FBQyxPQUFPLEVBQUUsR0FBRyxFQUFFO1FBQ25CLElBQUksQ0FBQyxHQUFHLENBQUMsZ0JBQWdCO1lBQUUsVUFBVSxDQUFDLEtBQUssRUFBRSxDQUFDO0lBQ2hELENBQUMsQ0FBQyxDQUFDO0lBQ0gsT0FBTyxVQUFVLENBQUMsTUFBTSxDQUFDO0FBQzNCLENBQUM7QUFlRDs7O0dBR0c7QUFDSCxNQUFNLFVBQVUsYUFBYSxDQUFDLElBQWEsRUFBRSxHQUFhLEVBQUUsU0FBaUI7SUFDM0UsZUFBZSxDQUFDLEdBQUcsQ0FBQyxDQUFDO0lBQ3JCLEdBQUcsQ0FBQyxVQUFVLENBQUMsU0FBUyxDQUFDLENBQUM7SUFDMUIsR0FBRyxDQUFDLFlBQVksRUFBRSxDQUFDO0lBQ25CLE1BQU0sTUFBTSxHQUFHLGlCQUFpQixDQUFDLEdBQUcsQ0FBQyxDQUFDO0lBQ3RDLE1BQU0sSUFBSSxHQUFHLENBQUMsS0FBYyxFQUFRLEVBQUU7UUFDcEMsSUFBSSxNQUFNLENBQUMsT0FBTztZQUFFLE9BQU87UUFDM0IsR0FBRyxDQUFDLEtBQUssQ0FBQyxTQUFTLElBQUksQ0FBQyxTQUFTLENBQUMsS0FBSyxDQUFDLE1BQU0sQ0FBQyxDQUFDO0lBQ2xELENBQUMsQ0FBQztJQUNGLE9BQU87UUFDTCxNQUFNO1FBQ04sT0FBTyxFQUFFLEdBQUcsRUFBRSxDQUFDLE1BQU0sQ0FBQyxPQUFPO1FBQzdCLElBQUk7UUFDSixJQUFJLEVBQUUsQ0FBQyxLQUFlLEVBQVEsRUFBRTtZQUM5QixJQUFJLE1BQU0sQ0FBQyxPQUFPO2dCQUFFLE9BQU87WUFDM0IsSUFBSSxLQUFLLEtBQUssU0FBUztnQkFBRSxJQUFJLENBQUMsS0FBSyxDQUFDLENBQUM7WUFDckMsR0FBRyxDQUFDLEtBQUssQ0FBQyxrQkFBa0IsQ0FBQyxDQUFDO1FBQ2hDLENBQUM7S0FDRixDQUFDO0FBQ0osQ0FBQztBQUVEOzs7R0FHRztBQUNILE1BQU0sVUFBVSxhQUFhLENBQUMsR0FBYSxFQUFFLE9BQWUsRUFBRSxlQUF1QjtJQUNuRixJQUFJLENBQUMsR0FBRyxDQUFDLFdBQVcsRUFBRSxDQUFDO1FBQ3JCLElBQUksT0FBTyxDQUFDLFFBQVEsQ0FBQyxnQkFBZ0IsQ0FBQyxJQUFJLE9BQU8sQ0FBQyxRQUFRLENBQUMsU0FBUyxDQUFDLEVBQUUsQ0FBQztZQUN0RSxxRUFBcUU7WUFDckUsd0VBQXdFO1lBQ3hFLHdFQUF3RTtZQUN4RSxpRUFBaUU7WUFDakUsMEVBQTBFO1lBQzFFLHlFQUF5RTtZQUN6RSx5RUFBeUU7WUFDekUsT0FBTyxpQkFBaUIsQ0FBQyxHQUFHLEVBQUUsT0FBTyxDQUFDLENBQUM7UUFDekMsQ0FBQztRQUNELElBQUksT0FBTyxDQUFDLFFBQVEsQ0FBQyw0QkFBNEIsQ0FBQyxFQUFFLENBQUM7WUFDbkQsT0FBTyxjQUFjLENBQUMsR0FBRyxFQUFFLE9BQU8sQ0FBQyxDQUFDO1FBQ3RDLENBQUM7UUFDRCxPQUFPLGlCQUFpQixDQUFDLEdBQUcsRUFBRSxlQUFlLEVBQUUsRUFBRSxPQUFPLEVBQUUsT0FBTyxFQUFFLENBQUMsQ0FBQztJQUN2RSxDQUFDO0lBQ0QsR0FBRyxDQUFDLEtBQUssQ0FBQyxTQUFTLElBQUksQ0FBQyxTQUFTLENBQUMsRUFBRSxJQUFJLEVBQUUsT0FBTyxFQUFFLE9BQU8sRUFBRSxDQUFDLE1BQU0sQ0FBQyxDQUFDO0lBQ3JFLEdBQUcsQ0FBQyxHQUFHLEVBQUUsQ0FBQztBQUNaLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyIvLyBDb3B5cmlnaHQgMjAyNiBQaXBlbGluZSBCdWlsZGVyIENvbnRyaWJ1dG9yc1xuLy8gU1BEWC1MaWNlbnNlLUlkZW50aWZpZXI6IEFwYWNoZS0yLjBcblxuaW1wb3J0IHR5cGUgeyBSZXF1ZXN0LCBSZXNwb25zZSB9IGZyb20gJ2V4cHJlc3MnO1xuaW1wb3J0IHsgc2VuZEJhZFJlcXVlc3QsIHNlbmRJbnRlcm5hbEVycm9yIH0gZnJvbSAnLi4vdXRpbHMvcmVzcG9uc2UuanMnO1xuXG4vKipcbiAqIFNldCB0aGUgZm91ciBzdGFuZGFyZCBTU0UgcmVzcG9uc2UgaGVhZGVycyAoZG9lcyBOT1QgZmx1c2gg4oCUIHRoZSBjYWxsZXIgZmx1c2hlc1xuICogYWZ0ZXIgYW55IGFkZGl0aW9uYWwgcGVyLWVuZHBvaW50IHNldHVwIGxpa2UgYHJlcy5zZXRUaW1lb3V0YCkuIFRoZSBzaW5nbGVcbiAqIHNvdXJjZSBvZiB0cnV0aCBmb3IgdGhlIGB0ZXh0L2V2ZW50LXN0cmVhbWAgKyBuby1jYWNoZSArIGtlZXAtYWxpdmUgK1xuICogYFgtQWNjZWwtQnVmZmVyaW5nOiBub2AgKGRpc2FibGUgbmdpbnggYnVmZmVyaW5nKSBibG9jay5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHdyaXRlU3NlSGVhZGVycyhyZXM6IFJlc3BvbnNlKTogdm9pZCB7XG4gIHJlcy5zZXRIZWFkZXIoJ0NvbnRlbnQtVHlwZScsICd0ZXh0L2V2ZW50LXN0cmVhbScpO1xuICByZXMuc2V0SGVhZGVyKCdDYWNoZS1Db250cm9sJywgJ25vLWNhY2hlJyk7XG4gIHJlcy5zZXRIZWFkZXIoJ0Nvbm5lY3Rpb24nLCAna2VlcC1hbGl2ZScpO1xuICByZXMuc2V0SGVhZGVyKCdYLUFjY2VsLUJ1ZmZlcmluZycsICdubycpO1xufVxuXG4vKiogVGhlIHNsaWNlIG9mIGFuIEV4cHJlc3MvTm9kZSByZXNwb25zZSBuZWVkZWQgdG8gb2JzZXJ2ZSBhIGNsaWVudCBkaXNjb25uZWN0LiAqL1xuaW50ZXJmYWNlIENsb3NhYmxlUmVzcG9uc2Uge1xuICBvbihldmVudDogJ2Nsb3NlJywgbGlzdGVuZXI6ICgpID0+IHZvaWQpOiB1bmtub3duO1xuICByZWFkb25seSB3cml0YWJsZUZpbmlzaGVkOiBib29sZWFuO1xufVxuXG4vKipcbiAqIEFuIEFib3J0U2lnbmFsIHRoYXQgZmlyZXMgd2hlbiB0aGUgY2xpZW50IGRpc2Nvbm5lY3RzIGJlZm9yZSB0aGUgcmVzcG9uc2VcbiAqIGZpbmlzaGVkIOKAlCBjYW5jZWxzIGEgcHJvdmlkZXIgY2FsbCAoYXZvaWRzIHdhc3RlZCBzcGVuZCkgYW5kIHRlbGxzIHRoZSByb3V0ZVxuICogdG8gc3RvcCB3cml0aW5nLlxuICpcbiAqIERpc2Nvbm5lY3QgaXMgZGV0ZWN0ZWQgb24gdGhlIFJFU1BPTlNFOiBgcmVzYCBlbWl0cyAnY2xvc2UnIHdoZW4gdGhlXG4gKiB1bmRlcmx5aW5nIGNvbm5lY3Rpb24gZ29lcyBhd2F5LCBhbmQgYHdyaXRhYmxlRmluaXNoZWRgIHRlbGxzIGFuIGVhcmx5IGNsb3NlXG4gKiAoY2xpZW50IGdvbmUpIGZyb20gdGhlIG5vcm1hbCBjbG9zZSBhZnRlciBgcmVzLmVuZCgpYC4gVGhlIHJlcXVlc3QncyBvd25cbiAqICdjbG9zZScgaXMgbm90IGEgZGlzY29ubmVjdCBzaWduYWwg4oCUIG9uIGN1cnJlbnQgTm9kZSBpdCBmaXJlcyBvbmNlIHRoZSByZXF1ZXN0XG4gKiBCT0RZIGhhcyBiZWVuIGNvbnN1bWVkIChleHByZXNzLmpzb24oKSBkb2VzIHRoYXQgYmVmb3JlIHRoZSBoYW5kbGVyIHJ1bnMpLCBzb1xuICogYSBkaXNjb25uZWN0IHdvdWxkIG5ldmVyIGJlIG9ic2VydmVkLlxuICovXG5leHBvcnQgZnVuY3Rpb24gY2xpZW50QWJvcnRTaWduYWwocmVzOiBDbG9zYWJsZVJlc3BvbnNlKTogQWJvcnRTaWduYWwge1xuICBjb25zdCBjb250cm9sbGVyID0gbmV3IEFib3J0Q29udHJvbGxlcigpO1xuICByZXMub24oJ2Nsb3NlJywgKCkgPT4ge1xuICAgIGlmICghcmVzLndyaXRhYmxlRmluaXNoZWQpIGNvbnRyb2xsZXIuYWJvcnQoKTtcbiAgfSk7XG4gIHJldHVybiBjb250cm9sbGVyLnNpZ25hbDtcbn1cblxuLyoqIEFuIG9wZW4gU1NFIHJlc3BvbnNlLiAqL1xuZXhwb3J0IGludGVyZmFjZSBTc2VTdHJlYW0ge1xuICAvKiogQWJvcnRlZCB3aGVuIHRoZSBjbGllbnQgZGlzY29ubmVjdHMgYmVmb3JlIHRoZSBzdHJlYW0gZmluaXNoZWQuICovXG4gIHJlYWRvbmx5IHNpZ25hbDogQWJvcnRTaWduYWw7XG4gIC8qKiBUcnVlIG9uY2UgdGhlIGNsaWVudCBoYXMgZGlzY29ubmVjdGVkLiAqL1xuICBhYm9ydGVkKCk6IGJvb2xlYW47XG4gIC8qKiBXcml0ZSBvbmUgYGRhdGE6YCBmcmFtZSBjYXJyeWluZyBgZXZlbnRgIGFzIEpTT04uIEEgbm8tb3AgYWZ0ZXIgYSBkaXNjb25uZWN0LiAqL1xuICBzZW5kKGV2ZW50OiB1bmtub3duKTogdm9pZDtcbiAgLyoqIFdyaXRlIHRoZSB0ZXJtaW5hbCBgZGF0YTogW0RPTkVdYCBmcmFtZSAocHJlY2VkZWQgYnkgYGV2ZW50YCwgd2hlbiBnaXZlbikuXG4gICAqICBBIG5vLW9wIGFmdGVyIGEgZGlzY29ubmVjdC4gVGhlIGNhbGxlciBzdGlsbCBlbmRzIHRoZSByZXNwb25zZS4gKi9cbiAgZG9uZShldmVudD86IHVua25vd24pOiB2b2lkO1xufVxuXG4vKipcbiAqIFNldCBTU0UgcmVzcG9uc2UgaGVhZGVycywgZmx1c2gsIGFuZCByZXR1cm4gdGhlIHN0cmVhbSdzIHdyaXRlciBwbHVzIGl0c1xuICogY2xpZW50LWRpc2Nvbm5lY3Qgc2lnbmFsIChzZWUge0BsaW5rIGNsaWVudEFib3J0U2lnbmFsfSkuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBpbml0U1NFU3RyZWFtKF9yZXE6IFJlcXVlc3QsIHJlczogUmVzcG9uc2UsIHRpbWVvdXRNczogbnVtYmVyKTogU3NlU3RyZWFtIHtcbiAgd3JpdGVTc2VIZWFkZXJzKHJlcyk7XG4gIHJlcy5zZXRUaW1lb3V0KHRpbWVvdXRNcyk7XG4gIHJlcy5mbHVzaEhlYWRlcnMoKTtcbiAgY29uc3Qgc2lnbmFsID0gY2xpZW50QWJvcnRTaWduYWwocmVzKTtcbiAgY29uc3Qgc2VuZCA9IChldmVudDogdW5rbm93bik6IHZvaWQgPT4ge1xuICAgIGlmIChzaWduYWwuYWJvcnRlZCkgcmV0dXJuO1xuICAgIHJlcy53cml0ZShgZGF0YTogJHtKU09OLnN0cmluZ2lmeShldmVudCl9XFxuXFxuYCk7XG4gIH07XG4gIHJldHVybiB7XG4gICAgc2lnbmFsLFxuICAgIGFib3J0ZWQ6ICgpID0+IHNpZ25hbC5hYm9ydGVkLFxuICAgIHNlbmQsXG4gICAgZG9uZTogKGV2ZW50PzogdW5rbm93bik6IHZvaWQgPT4ge1xuICAgICAgaWYgKHNpZ25hbC5hYm9ydGVkKSByZXR1cm47XG4gICAgICBpZiAoZXZlbnQgIT09IHVuZGVmaW5lZCkgc2VuZChldmVudCk7XG4gICAgICByZXMud3JpdGUoJ2RhdGE6IFtET05FXVxcblxcbicpO1xuICAgIH0sXG4gIH07XG59XG5cbi8qKlxuICogQ2xhc3NpZnkgQUkgZ2VuZXJhdGlvbiBlcnJvcnMgYW5kIHNlbmQgdGhlIGFwcHJvcHJpYXRlIEhUVFAgcmVzcG9uc2Ugb3IgU1NFIGV2ZW50LlxuICogSWYgaGVhZGVycyBhcmUgYWxyZWFkeSBzZW50IChzdHJlYW1pbmcpLCB3cml0ZXMgYW4gU1NFIGVycm9yIGV2ZW50IGFuZCBlbmRzIHRoZSByZXNwb25zZS5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGhhbmRsZUFJRXJyb3IocmVzOiBSZXNwb25zZSwgbWVzc2FnZTogc3RyaW5nLCBmYWxsYmFja01lc3NhZ2U6IHN0cmluZyk6IHZvaWQge1xuICBpZiAoIXJlcy5oZWFkZXJzU2VudCkge1xuICAgIGlmIChtZXNzYWdlLmluY2x1ZGVzKCdub3QgY29uZmlndXJlZCcpIHx8IG1lc3NhZ2UuaW5jbHVkZXMoJ0FQSSBrZXknKSkge1xuICAgICAgLy8gU3VyZmFjZSB0aGUgT1JJR0lOQUwgbWVzc2FnZS4gSXQgbmFtZXMgdGhlIE1JU1NJTkcgQ09ORklHVVJBVElPTiDigJRcbiAgICAgIC8vIFwibm8gcHJvdmlkZXIgQVBJIGtleSBpcyBzZXQgYW5kIE9QRU5BSV9DT01QQVRJQkxFX0JBU0VfVVJMIGlzIHVuc2V0XCIsXG4gICAgICAvLyBvciB3aGljaCBlbnYgdmFyIGEgbmFtZWQgcHJvdmlkZXIgd2FudHMg4oCUIG5ldmVyIGEgc2VjcmV0IFZBTFVFLCBzbyBpdFxuICAgICAgLy8gaXMgc2FmZSB0byBzaG93IGFuZCBpdCBpcyB0aGUgb25seSB0aGluZyB0aGF0IG1ha2VzIHRoaXMgZXJyb3JcbiAgICAgIC8vIGFjdGlvbmFibGUuIFRoZSBnZW5lcmljIHJlcGxhY2VtZW50IGFsc28gbWlzLWRlc2NyaWJlZCB0aGUgY29tbW9uIGNhc2U6XG4gICAgICAvLyBpdCBzYWlkIFwiZm9yIHRoZSByZXF1ZXN0ZWQgcHJvdmlkZXJcIiB3aGVuIG5vIHByb3ZpZGVyIHdhcyByZXF1ZXN0ZWQgYXRcbiAgICAgIC8vIGFsbCwgcG9pbnRpbmcgb3BlcmF0b3JzIGF0IGEgcHJvdmlkZXIgYnVnIGluc3RlYWQgb2YgYXQgY29uZmlndXJhdGlvbi5cbiAgICAgIHJldHVybiBzZW5kSW50ZXJuYWxFcnJvcihyZXMsIG1lc3NhZ2UpO1xuICAgIH1cbiAgICBpZiAobWVzc2FnZS5pbmNsdWRlcygnbm90IGF2YWlsYWJsZSBmb3IgcHJvdmlkZXInKSkge1xuICAgICAgcmV0dXJuIHNlbmRCYWRSZXF1ZXN0KHJlcywgbWVzc2FnZSk7XG4gICAgfVxuICAgIHJldHVybiBzZW5kSW50ZXJuYWxFcnJvcihyZXMsIGZhbGxiYWNrTWVzc2FnZSwgeyBkZXRhaWxzOiBtZXNzYWdlIH0pO1xuICB9XG4gIHJlcy53cml0ZShgZGF0YTogJHtKU09OLnN0cmluZ2lmeSh7IHR5cGU6ICdlcnJvcicsIG1lc3NhZ2UgfSl9XFxuXFxuYCk7XG4gIHJlcy5lbmQoKTtcbn1cbiJdfQ==
159
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic3NlLWhlbHBlcnMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvaGVscGVycy9zc2UtaGVscGVycy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSwrQ0FBK0M7QUFDL0Msc0NBQXNDO0FBR3RDLE9BQU8sRUFBRSxRQUFRLEVBQUUsTUFBTSx5QkFBeUIsQ0FBQztBQUNuRCxPQUFPLEVBQUUsU0FBUyxFQUFFLE1BQU0seUJBQXlCLENBQUM7QUFDcEQsT0FBTyxFQUFFLFlBQVksRUFBRSxTQUFTLEVBQUUsTUFBTSxzQkFBc0IsQ0FBQztBQUUvRDs7Ozs7R0FLRztBQUNILE1BQU0sVUFBVSxlQUFlLENBQUMsR0FBYTtJQUMzQyxHQUFHLENBQUMsU0FBUyxDQUFDLGNBQWMsRUFBRSxtQkFBbUIsQ0FBQyxDQUFDO0lBQ25ELEdBQUcsQ0FBQyxTQUFTLENBQUMsZUFBZSxFQUFFLFVBQVUsQ0FBQyxDQUFDO0lBQzNDLEdBQUcsQ0FBQyxTQUFTLENBQUMsWUFBWSxFQUFFLFlBQVksQ0FBQyxDQUFDO0lBQzFDLEdBQUcsQ0FBQyxTQUFTLENBQUMsbUJBQW1CLEVBQUUsSUFBSSxDQUFDLENBQUM7QUFDM0MsQ0FBQztBQVFEOzs7Ozs7Ozs7OztHQVdHO0FBQ0gsTUFBTSxVQUFVLGlCQUFpQixDQUFDLEdBQXFCO0lBQ3JELE1BQU0sVUFBVSxHQUFHLElBQUksZUFBZSxFQUFFLENBQUM7SUFDekMsR0FBRyxDQUFDLEVBQUUsQ0FBQyxPQUFPLEVBQUUsR0FBRyxFQUFFO1FBQ25CLElBQUksQ0FBQyxHQUFHLENBQUMsZ0JBQWdCO1lBQUUsVUFBVSxDQUFDLEtBQUssRUFBRSxDQUFDO0lBQ2hELENBQUMsQ0FBQyxDQUFDO0lBQ0gsT0FBTyxVQUFVLENBQUMsTUFBTSxDQUFDO0FBQzNCLENBQUM7QUFlRDs7O0dBR0c7QUFDSCxNQUFNLFVBQVUsYUFBYSxDQUFDLElBQWEsRUFBRSxHQUFhLEVBQUUsU0FBaUI7SUFDM0UsZUFBZSxDQUFDLEdBQUcs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LElBQUksQ0FBQyxTQUFTLENBQUM7UUFDaEMsSUFBSSxFQUFFLE9BQU87UUFDYixPQUFPLEVBQUUsTUFBTSxDQUFDLE9BQU87UUFDdkIsSUFBSSxFQUFFLE1BQU0sQ0FBQyxJQUFJO1FBQ2pCLE1BQU0sRUFBRSxNQUFNLENBQUMsTUFBTTtRQUNyQixHQUFHLENBQUMsTUFBTSxDQUFDLGlCQUFpQixLQUFLLFNBQVMsQ0FBQyxDQUFDLENBQUMsRUFBRSxpQkFBaUIsRUFBRSxNQUFNLENBQUMsaUJBQWlCLEVBQUUsQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDO0tBQ25HLENBQUMsTUFBTSxDQUFDLENBQUM7SUFDVixHQUFHLENBQUMsR0FBRyxFQUFFLENBQUM7QUFDWixDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiLy8gQ29weXJpZ2h0IDIwMjYgUGlwZWxpbmUgQnVpbGRlciBDb250cmlidXRvcnNcbi8vIFNQRFgtTGljZW5zZS1JZGVudGlmaWVyOiBBcGFjaGUtMi4wXG5cbmltcG9ydCB0eXBlIHsgUmVxdWVzdCwgUmVzcG9uc2UgfSBmcm9tICdleHByZXNzJztcbmltcG9ydCB7IEFwcEVycm9yIH0gZnJvbSAnLi4vZXJyb3JzL2FwcC1lcnJvcnMuanMnO1xuaW1wb3J0IHsgRXJyb3JDb2RlIH0gZnJvbSAnLi4vdHlwZXMvZXJyb3ItY29kZXMuanMnO1xuaW1wb3J0IHsgZXJyb3JNZXNzYWdlLCBzZW5kRXJyb3IgfSBmcm9tICcuLi91dGlscy9yZXNwb25zZS5qcyc7XG5cbi8qKlxuICogU2V0IHRoZSBmb3VyIHN0YW5kYXJkIFNTRSByZXNwb25zZSBoZWFkZXJzIChkb2VzIE5PVCBmbHVzaCDigJQgdGhlIGNhbGxlciBmbHVzaGVzXG4gKiBhZnRlciBhbnkgYWRkaXRpb25hbCBwZXItZW5kcG9pbnQgc2V0dXAgbGlrZSBgcmVzLnNldFRpbWVvdXRgKS4gVGhlIHNpbmdsZVxuICogc291cmNlIG9mIHRydXRoIGZvciB0aGUgYHRleHQvZXZlbnQtc3RyZWFtYCArIG5vLWNhY2hlICsga2VlcC1hbGl2ZSArXG4gKiBgWC1BY2NlbC1CdWZmZXJpbmc6IG5vYCAoZGlzYWJsZSBuZ2lueCBidWZmZXJpbmcpIGJsb2NrLlxuICovXG5leHBvcnQgZnVuY3Rpb24gd3JpdGVTc2VIZWFkZXJzKHJlczogUmVzcG9uc2UpOiB2b2lkIHtcbiAgcmVzLnNldEhlYWRlcignQ29udGVudC1UeXBlJywgJ3RleHQvZXZlbnQtc3RyZWFtJyk7XG4gIHJlcy5zZXRIZWFkZXIoJ0NhY2hlLUNvbnRyb2wnLCAnbm8tY2FjaGUnKTtcbiAgcmVzLnNldEhlYWRlcignQ29ubmVjdGlvbicsICdrZWVwLWFsaXZlJyk7XG4gIHJlcy5zZXRIZWFkZXIoJ1gtQWNjZWwtQnVmZmVyaW5nJywgJ25vJyk7XG59XG5cbi8qKiBUaGUgc2xpY2Ugb2YgYW4gRXhwcmVzcy9Ob2RlIHJlc3BvbnNlIG5lZWRlZCB0byBvYnNlcnZlIGEgY2xpZW50IGRpc2Nvbm5lY3QuICovXG5pbnRlcmZhY2UgQ2xvc2FibGVSZXNwb25zZSB7XG4gIG9uKGV2ZW50OiAnY2xvc2UnLCBsaXN0ZW5lcjogKCkgPT4gdm9pZCk6IHVua25vd247XG4gIHJlYWRvbmx5IHdyaXRhYmxlRmluaXNoZWQ6IGJvb2xlYW47XG59XG5cbi8qKlxuICogQW4gQWJvcnRTaWduYWwgdGhhdCBmaXJlcyB3aGVuIHRoZSBjbGllbnQgZGlzY29ubmVjdHMgYmVmb3JlIHRoZSByZXNwb25zZVxuICogZmluaXNoZWQg4oCUIGNhbmNlbHMgYSBwcm92aWRlciBjYWxsIChhdm9pZHMgd2FzdGVkIHNwZW5kKSBhbmQgdGVsbHMgdGhlIHJvdXRlXG4gKiB0byBzdG9wIHdyaXRpbmcuXG4gKlxuICogRGlzY29ubmVjdCBpcyBkZXRlY3RlZCBvbiB0aGUgUkVTUE9OU0U6IGByZXNgIGVtaXRzICdjbG9zZScgd2hlbiB0aGVcbiAqIHVuZGVybHlpbmcgY29ubmVjdGlvbiBnb2VzIGF3YXksIGFuZCBgd3JpdGFibGVGaW5pc2hlZGAgdGVsbHMgYW4gZWFybHkgY2xvc2VcbiAqIChjbGllbnQgZ29uZSkgZnJvbSB0aGUgbm9ybWFsIGNsb3NlIGFmdGVyIGByZXMuZW5kKClgLiBUaGUgcmVxdWVzdCdzIG93blxuICogJ2Nsb3NlJyBpcyBub3QgYSBkaXNjb25uZWN0IHNpZ25hbCDigJQgb24gY3VycmVudCBOb2RlIGl0IGZpcmVzIG9uY2UgdGhlIHJlcXVlc3RcbiAqIEJPRFkgaGFzIGJlZW4gY29uc3VtZWQgKGV4cHJlc3MuanNvbigpIGRvZXMgdGhhdCBiZWZvcmUgdGhlIGhhbmRsZXIgcnVucyksIHNvXG4gKiBhIGRpc2Nvbm5lY3Qgd291bGQgbmV2ZXIgYmUgb2JzZXJ2ZWQuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBjbGllbnRBYm9ydFNpZ25hbChyZXM6IENsb3NhYmxlUmVzcG9uc2UpOiBBYm9ydFNpZ25hbCB7XG4gIGNvbnN0IGNvbnRyb2xsZXIgPSBuZXcgQWJvcnRDb250cm9sbGVyKCk7XG4gIHJlcy5vbignY2xvc2UnLCAoKSA9PiB7XG4gICAgaWYgKCFyZXMud3JpdGFibGVGaW5pc2hlZCkgY29udHJvbGxlci5hYm9ydCgpO1xuICB9KTtcbiAgcmV0dXJuIGNvbnRyb2xsZXIuc2lnbmFsO1xufVxuXG4vKiogQW4gb3BlbiBTU0UgcmVzcG9uc2UuICovXG5leHBvcnQgaW50ZXJmYWNlIFNzZVN0cmVhbSB7XG4gIC8qKiBBYm9ydGVkIHdoZW4gdGhlIGNsaWVudCBkaXNjb25uZWN0cyBiZWZvcmUgdGhlIHN0cmVhbSBmaW5pc2hlZC4gKi9cbiAgcmVhZG9ubHkgc2lnbmFsOiBBYm9ydFNpZ25hbDtcbiAgLyoqIFRydWUgb25jZSB0aGUgY2xpZW50IGhhcyBkaXNjb25uZWN0ZWQuICovXG4gIGFib3J0ZWQoKTogYm9vbGVhbjtcbiAgLyoqIFdyaXRlIG9uZSBgZGF0YTpgIGZyYW1lIGNhcnJ5aW5nIGBldmVudGAgYXMgSlNPTi4gQSBuby1vcCBhZnRlciBhIGRpc2Nvbm5lY3QuICovXG4gIHNlbmQoZXZlbnQ6IHVua25vd24pOiB2b2lkO1xuICAvKiogV3JpdGUgdGhlIHRlcm1pbmFsIGBkYXRhOiBbRE9ORV1gIGZyYW1lIChwcmVjZWRlZCBieSBgZXZlbnRgLCB3aGVuIGdpdmVuKS5cbiAgICogIEEgbm8tb3AgYWZ0ZXIgYSBkaXNjb25uZWN0LiBUaGUgY2FsbGVyIHN0aWxsIGVuZHMgdGhlIHJlc3BvbnNlLiAqL1xuICBkb25lKGV2ZW50PzogdW5rbm93bik6IHZvaWQ7XG59XG5cbi8qKlxuICogU2V0IFNTRSByZXNwb25zZSBoZWFkZXJzLCBmbHVzaCwgYW5kIHJldHVybiB0aGUgc3RyZWFtJ3Mgd3JpdGVyIHBsdXMgaXRzXG4gKiBjbGllbnQtZGlzY29ubmVjdCBzaWduYWwgKHNlZSB7QGxpbmsgY2xpZW50QWJvcnRTaWduYWx9KS5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGluaXRTU0VTdHJlYW0oX3JlcTogUmVxdWVzdCwgcmVzOiBSZXNwb25zZSwgdGltZW91dE1zOiBudW1iZXIpOiBTc2VTdHJlYW0ge1xuICB3cml0ZVNzZUhlYWRlcnMocmVzKTtcbiAgcmVzLnNldFRpbWVvdXQodGltZW91dE1zKTtcbiAgcmVzLmZsdXNoSGVhZGVycygpO1xuICBjb25zdCBzaWduYWwgPSBjbGllbnRBYm9ydFNpZ25hbChyZXMpO1xuICBjb25zdCBzZW5kID0gKGV2ZW50OiB1bmtub3duKTogdm9pZCA9PiB7XG4gICAgaWYgKHNpZ25hbC5hYm9ydGVkKSByZXR1cm47XG4gICAgcmVzLndyaXRlKGBkYXRhOiAke0pTT04uc3RyaW5naWZ5KGV2ZW50KX1cXG5cXG5gKTtcbiAgfTtcbiAgcmV0dXJuIHtcbiAgICBzaWduYWwsXG4gICAgYWJvcnRlZDogKCkgPT4gc2lnbmFsLmFib3J0ZWQsXG4gICAgc2VuZCxcbiAgICBkb25lOiAoZXZlbnQ/OiB1bmtub3duKTogdm9pZCA9PiB7XG4gICAgICBpZiAoc2lnbmFsLmFib3J0ZWQpIHJldHVybjtcbiAgICAgIGlmIChldmVudCAhPT0gdW5kZWZpbmVkKSBzZW5kKGV2ZW50KTtcbiAgICAgIHJlcy53cml0ZSgnZGF0YTogW0RPTkVdXFxuXFxuJyk7XG4gICAgfSxcbiAgfTtcbn1cblxuLyoqIEhvdyBhbiBBSSBmYWlsdXJlIGlzIGFuc3dlcmVkOiBhbiBIVFRQIHN0YXR1cywgYSBjb2RlLCBhbmQgYSBtZXNzYWdlIFdFIHdyb3RlLiAqL1xuZXhwb3J0IGludGVyZmFjZSBBSUVycm9yUmVzcG9uc2Uge1xuICBzdGF0dXM6IG51bWJlcjtcbiAgY29kZTogRXJyb3JDb2RlO1xuICAvKiogU2FmZSB0byBzaG93OiBuZXZlciByYXcgcHJvdmlkZXIgcmVzcG9uc2UgdGV4dC4gKi9cbiAgbWVzc2FnZTogc3RyaW5nO1xuICAvKiogU2Vjb25kcywgZnJvbSB0aGUgcHJvdmlkZXIncyBvd24gYFJldHJ5LUFmdGVyYCB3aGVuIGl0IHNlbnQgb25lLiAqL1xuICByZXRyeUFmdGVyU2Vjb25kcz86IG51bWJlcjtcbn1cblxuLyoqIFRoZSBmaWVsZHMgb2YgYW4gYWktc2RrIGBBUElDYWxsRXJyb3JgIHRoaXMgY2xhc3NpZmllciByZWFkcyAoZHVjay10eXBlZDogYXBpLWNvcmUgZG9lcyBub3QgZGVwZW5kIG9uIGBhaWApLiAqL1xuaW50ZXJmYWNlIFByb3ZpZGVyQ2FsbEVycm9yIHtcbiAgc3RhdHVzQ29kZT86IHVua25vd247XG4gIHJlc3BvbnNlSGVhZGVycz86IFJlY29yZDxzdHJpbmcsIHN0cmluZyB8IHVuZGVmaW5lZD47XG59XG5cbi8qKiBgUmV0cnktQWZ0ZXJgIGFzIHNlY29uZHMg4oCUIGVpdGhlciBmb3JtIHRoZSBoZWFkZXIgYWxsb3dzIChkZWx0YS1zZWNvbmRzIG9yIGFuIEhUVFAgZGF0ZSkuICovXG5mdW5jdGlvbiByZXRyeUFmdGVyU2Vjb25kcyhoZWFkZXJzOiBSZWNvcmQ8c3RyaW5nLCBzdHJpbmcgfCB1bmRlZmluZWQ+IHwgdW5kZWZpbmVkKTogbnVtYmVyIHwgdW5kZWZpbmVkIHtcbiAgY29uc3QgcmF3ID0gaGVhZGVycz8uWydyZXRyeS1hZnRlciddID8/IGhlYWRlcnM/LlsnUmV0cnktQWZ0ZXInXTtcbiAgaWYgKCFyYXcpIHJldHVybiB1bmRlZmluZWQ7XG4gIGNvbnN0IGFzTnVtYmVyID0gTnVtYmVyKHJhdyk7XG4gIGlmIChOdW1iZXIuaXNGaW5pdGUoYXNOdW1iZXIpICYmIGFzTnVtYmVyID49IDApIHJldHVybiBNYXRoLmNlaWwoYXNOdW1iZXIpO1xuICBjb25zdCBhdCA9IERhdGUucGFyc2UocmF3KTtcbiAgcmV0dXJuIE51bWJlci5pc05hTihhdCkgPyB1bmRlZmluZWQgOiBNYXRoLm1heCgwLCBNYXRoLmNlaWwoKGF0IC0gRGF0ZS5ub3coKSkgLyAxMDAwKSk7XG59XG5cbi8qKiBUcnVlIGZvciBhbiBhYm9ydCB0aGF0IGNhbWUgZnJvbSBhIFRJTUVPVVQgc2lnbmFsIHJhdGhlciB0aGFuIGEgY2xpZW50IGRpc2Nvbm5lY3QuICovXG5mdW5jdGlvbiBpc1RpbWVvdXQoZXJyb3I6IHVua25vd24pOiBib29sZWFuIHtcbiAgY29uc3QgZSA9IGVycm9yIGFzIHsgbmFtZT86IHVua25vd247IGNhdXNlPzogeyBuYW1lPzogdW5rbm93biB9IH0gfCBudWxsO1xuICByZXR1cm4gZT8ubmFtZSA9PT0gJ1RpbWVvdXRFcnJvcicgfHwgZT8uY2F1c2U/Lm5hbWUgPT09ICdUaW1lb3V0RXJyb3InO1xufVxuXG4vKipcbiAqIENsYXNzaWZ5IGFuIEFJIGZhaWx1cmUgaW50byB0aGUgcmVzcG9uc2UgYSBjYWxsZXIgc2VuZHMuXG4gKlxuICogUHJvdmlkZXIgZmFpbHVyZXMgYXJlIG1hdGNoZWQgb24gdGhlIHByb3ZpZGVyJ3MgSFRUUCBTVEFUVVMgKGBBUElDYWxsRXJyb3Iuc3RhdHVzQ29kZWApLFxuICogbmV2ZXIgb24gbWVzc2FnZSB0ZXh0LCBhbmQgYW5zd2VyZWQgd2l0aCBhIHNlbnRlbmNlIG9mIG91cnM6IGEgcHJvdmlkZXIncyBlcnJvciBib2R5XG4gKiBjYW4gY2FycnkgYWNjb3VudCBpZHMsIHJlcXVlc3QgaWRzLCBxdW90YSBkZXRhaWxzIG9yIGFuIGVjaG8gb2YgdGhlIHByb21wdCwgYW5kIG5vbmVcbiAqIG9mIGl0IGJlbG9uZ3MgaW4gYSByZXNwb25zZSBvciBhbiBTU0UgZnJhbWUuIFRoZSBmdWxsIGVycm9yIHN0aWxsIGdvZXMgdG8gdGhlXG4gKiBjYWxsZXIncyBsb2cgbGluZS5cbiAqXG4gKiAgLSA0Mjkg4oaSIDQyOSAod2l0aCB0aGUgcHJvdmlkZXIncyBgUmV0cnktQWZ0ZXJgKTogdGhlIHByb3ZpZGVyIGlzIHJhdGUgbGltaXRpbmcuXG4gKiAgLSA1MjkgLyA1eHgg4oaSIDUwMyAod2l0aCBgUmV0cnktQWZ0ZXJgKTogdGhlIHByb3ZpZGVyIGlzIG92ZXJsb2FkZWQgb3IgZG93bi5cbiAqICAtIDQwMSAvIDQwMyDihpIgNTAyOiB0aGUgcHJvdmlkZXIgcmVmdXNlZCB0aGUgY3JlZGVudGlhbCAoYSBCWU8gb3Igb3JnIGtleSBpcyB3cm9uZykuXG4gKiAgLSBhIHRpbWVvdXQgc2lnbmFsIOKGkiA1MDQuXG4gKiAgLSBhbiB7QGxpbmsgQXBwRXJyb3J9IChBSURpc2FibGVkRXJyb3IsIEFJQ29uZmlndXJhdGlvbkVycm9yLCDigKYpIOKGkiBpdHMgb3duIHN0YXR1cyBhbmQgbWVzc2FnZS5cbiAqICAtIG90aGVyd2lzZSB0aGUgY29uZmlndXJhdGlvbiBtZXNzYWdlcyB0aGUgcmVnaXN0cnkgd3JpdGVzICh0aGV5IG5hbWUgZW52IHZhcnMsXG4gKiAgICBuZXZlciB2YWx1ZXMpIGtlZXAgdGhlaXIgdGV4dDsgYW55dGhpbmcgZWxzZSBnZXRzIGBmYWxsYmFja01lc3NhZ2VgLlxuICovXG5leHBvcnQgZnVuY3Rpb24gY2xhc3NpZnlBSUVycm9yKGVycm9yOiB1bmtub3duLCBmYWxsYmFja01lc3NhZ2U6IHN0cmluZyk6IEFJRXJyb3JSZXNwb25zZSB7XG4gIGlmIChlcnJvciBpbnN0YW5jZW9mIEFwcEVycm9yKSB7XG4gICAgcmV0dXJuIHsgc3RhdHVzOiBlcnJvci5zdGF0dXNDb2RlLCBjb2RlOiBlcnJvci5jb2RlLCBtZXNzYWdlOiBlcnJvci5tZXNzYWdlIH07XG4gIH1cbiAgY29uc3QgcHJvdmlkZXJTdGF0dXMgPSB0eXBlb2YgKGVycm9yIGFzIFByb3ZpZGVyQ2FsbEVycm9yIHwgbnVsbCk/LnN0YXR1c0NvZGUgPT09ICdudW1iZXInXG4gICAgPyAoZXJyb3IgYXMgUHJvdmlkZXJDYWxsRXJyb3IpLnN0YXR1c0NvZGUgYXMgbnVtYmVyXG4gICAgOiB1bmRlZmluZWQ7XG4gIGlmIChwcm92aWRlclN0YXR1cyAhPT0gdW5kZWZpbmVkKSB7XG4gICAgY29uc3QgcmV0cnlBZnRlciA9IHJldHJ5QWZ0ZXJTZWNvbmRzKChlcnJvciBhcyBQcm92aWRlckNhbGxFcnJvcikucmVzcG9uc2VIZWFkZXJzKTtcbiAgICBjb25zdCB3aXRoUmV0cnkgPSByZXRyeUFmdGVyICE9PSB1bmRlZmluZWQgPyB7IHJldHJ5QWZ0ZXJTZWNvbmRzOiByZXRyeUFmdGVyIH0gOiB7fTtcbiAgICBpZiAocHJvdmlkZXJTdGF0dXMgPT09IDQyOSkge1xuICAgICAgcmV0dXJuIHsgc3RhdHVzOiA0MjksIGNvZGU6IEVycm9yQ29kZS5SQVRFX0xJTUlUX0VYQ0VFREVELCBtZXNzYWdlOiAnVGhlIEFJIHByb3ZpZGVyIGlzIHJhdGUgbGltaXRpbmcgcmVxdWVzdHMuIFRyeSBhZ2FpbiBzaG9ydGx5LicsIC4uLndpdGhSZXRyeSB9O1xuICAgIH1cbiAgICBpZiAocHJvdmlkZXJTdGF0dXMgPT09IDUyOSB8fCBwcm92aWRlclN0YXR1cyA+PSA1MDApIHtcbiAgICAgIHJldHVybiB7IHN0YXR1czogNTAzLCBjb2RlOiBFcnJvckNvZGUuU0VSVklDRV9VTkFWQUlMQUJMRSwgbWVzc2FnZTogJ1RoZSBBSSBwcm92aWRlciBpcyB0ZW1wb3JhcmlseSB1bmF2YWlsYWJsZS4gVHJ5IGFnYWluIHNob3J0bHkuJywgLi4ud2l0aFJldHJ5IH07XG4gICAgfVxuICAgIGlmIChwcm92aWRlclN0YXR1cyA9PT0gNDAxIHx8IHByb3ZpZGVyU3RhdHVzID09PSA0MDMpIHtcbiAgICAgIHJldHVybiB7IHN0YXR1czogNTAyLCBjb2RlOiBFcnJvckNvZGUuSU5URVJOQUxfRVJST1IsIG1lc3NhZ2U6ICdUaGUgQUkgcHJvdmlkZXIgcmVqZWN0ZWQgdGhlIEFQSSBrZXkgdXNlZCBmb3IgdGhpcyByZXF1ZXN0LiBDaGVjayB0aGUga2V5IGluIFNldHRpbmdzLCBvciB0aGUgb25lIHlvdSBzdXBwbGllZC4nIH07XG4gICAgfVxuICAgIHJldHVybiB7IHN0YXR1czogNTAyLCBjb2RlOiBFcnJvckNvZGUuSU5URVJOQUxfRVJST1IsIG1lc3NhZ2U6IGZhbGxiYWNrTWVzc2FnZSB9O1xuICB9XG4gIGlmIChpc1RpbWVvdXQoZXJyb3IpKSB7XG4gICAgcmV0dXJuIHsgc3RhdHVzOiA1MDQsIGNvZGU6IEVycm9yQ29kZS5TRVJWSUNFX1VOQVZBSUxBQkxFLCBtZXNzYWdlOiAnVGhlIEFJIHByb3ZpZGVyIGRpZCBub3QgcmVzcG9uZCBpbiB0aW1lLiBUcnkgYWdhaW4sIG9yIGFzayBmb3Igc29tZXRoaW5nIHNtYWxsZXIuJyB9O1xuICB9XG5cbiAgY29uc3QgbWVzc2FnZSA9IHR5cGVvZiBlcnJvciA9PT0gJ3N0cmluZycgPyBlcnJvciA6IGVycm9yTWVzc2FnZShlcnJvcik7XG4gIGlmIChtZXNzYWdlLmluY2x1ZGVzKCdub3QgY29uZmlndXJlZCcpIHx8IG1lc3NhZ2UuaW5jbHVkZXMoJ0FQSSBrZXknKSkge1xuICAgIC8vIFN1cmZhY2UgdGhlIE9SSUdJTkFMIG1lc3NhZ2UuIE9ubHkgdGhlIHJlZ2lzdHJ5J3Mgb3duIGNvbmZpZ3VyYXRpb24gZXJyb3JzXG4gICAgLy8gcmVhY2ggaGVyZSAoYSBwcm92aWRlcidzIHJlc3BvbnNlIGNhcnJpZXMgYSBzdGF0dXMgYW5kIHdhcyBoYW5kbGVkIGFib3ZlKTpcbiAgICAvLyB0aGV5IG5hbWUgdGhlIE1JU1NJTkcgQ09ORklHVVJBVElPTiDigJQgXCJubyBwcm92aWRlciBBUEkga2V5IGlzIHNldCBhbmRcbiAgICAvLyBPUEVOQUlfQ09NUEFUSUJMRV9CQVNFX1VSTCBpcyB1bnNldFwiLCBvciB3aGljaCBlbnYgdmFyIGEgbmFtZWQgcHJvdmlkZXJcbiAgICAvLyB3YW50cyDigJQgbmV2ZXIgYSBzZWNyZXQgVkFMVUUsIGFuZCBhcmUgdGhlIG9ubHkgdGhpbmcgdGhhdCBtYWtlcyB0aGlzIGVycm9yXG4gICAgLy8gYWN0aW9uYWJsZS5cbiAgICByZXR1cm4geyBzdGF0dXM6IDUwMCwgY29kZTogRXJyb3JDb2RlLklOVEVSTkFMX0VSUk9SLCBtZXNzYWdlIH07XG4gIH1cbiAgaWYgKG1lc3NhZ2UuaW5jbHVkZXMoJ25vdCBhdmFpbGFibGUgZm9yIHByb3ZpZGVyJykpIHtcbiAgICByZXR1cm4geyBzdGF0dXM6IDQwMCwgY29kZTogRXJyb3JDb2RlLlZBTElEQVRJT05fRVJST1IsIG1lc3NhZ2UgfTtcbiAgfVxuICByZXR1cm4geyBzdGF0dXM6IDUwMCwgY29kZTogRXJyb3JDb2RlLklOVEVSTkFMX0VSUk9SLCBtZXNzYWdlOiBmYWxsYmFja01lc3NhZ2UgfTtcbn1cblxuLyoqXG4gKiBBbnN3ZXIgYW4gQUkgZ2VuZXJhdGlvbiBmYWlsdXJlOiBhbiBIVFRQIGVycm9yIGJlZm9yZSB0aGUgc3RyZWFtIHN0YXJ0ZWQsIG9yIGFuXG4gKiBTU0UgYGVycm9yYCBldmVudCAodGhlbiBlbmQpIG9uY2UgaXQgaGFzLiBUYWtlcyB0aGUgRVJST1IsIG5vdCBpdHMgbWVzc2FnZSDigJQgdGhlXG4gKiBwcm92aWRlciBzdGF0dXMgaXMgd2hhdCBkZWNpZGVzIHRoZSBhbnN3ZXIgKHNlZSB7QGxpbmsgY2xhc3NpZnlBSUVycm9yfSk7IGEgc3RyaW5nXG4gKiBpcyBzdGlsbCBhY2NlcHRlZCBmb3IgdGhlIHJlZ2lzdHJ5J3MgY29uZmlndXJhdGlvbiBtZXNzYWdlcy5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGhhbmRsZUFJRXJyb3IocmVzOiBSZXNwb25zZSwgZXJyb3I6IHVua25vd24sIGZhbGxiYWNrTWVzc2FnZTogc3RyaW5nKTogdm9pZCB7XG4gIGNvbnN0IGFuc3dlciA9IGNsYXNzaWZ5QUlFcnJvcihlcnJvciwgZmFsbGJhY2tNZXNzYWdlKTtcbiAgaWYgKCFyZXMuaGVhZGVyc1NlbnQpIHtcbiAgICBpZiAoYW5zd2VyLnJldHJ5QWZ0ZXJTZWNvbmRzICE9PSB1bmRlZmluZWQpIHJlcy5zZXRIZWFkZXIoJ1JldHJ5LUFmdGVyJywgU3RyaW5nKGFuc3dlci5yZXRyeUFmdGVyU2Vjb25kcykpO1xuICAgIHJldHVybiBzZW5kRXJyb3IocmVzLCBhbnN3ZXIuc3RhdHVzLCBhbnN3ZXIubWVzc2FnZSwgYW5zd2VyLmNvZGUpO1xuICB9XG4gIHJlcy53cml0ZShgZGF0YTogJHtKU09OLnN0cmluZ2lmeSh7XG4gICAgdHlwZTogJ2Vycm9yJyxcbiAgICBtZXNzYWdlOiBhbnN3ZXIubWVzc2FnZSxcbiAgICBjb2RlOiBhbnN3ZXIuY29kZSxcbiAgICBzdGF0dXM6IGFuc3dlci5zdGF0dXMsXG4gICAgLi4uKGFuc3dlci5yZXRyeUFmdGVyU2Vjb25kcyAhPT0gdW5kZWZpbmVkID8geyByZXRyeUFmdGVyU2Vjb25kczogYW5zd2VyLnJldHJ5QWZ0ZXJTZWNvbmRzIH0gOiB7fSksXG4gIH0pfVxcblxcbmApO1xuICByZXMuZW5kKCk7XG59XG4iXX0=
@@ -0,0 +1,69 @@
1
+ /** How a level's target is measured. */
2
+ export type SupportTargetKind =
3
+ /** N working days, ending at the close of the Nth. */
4
+ {
5
+ kind: 'business-days';
6
+ days: number;
7
+ }
8
+ /** N hours of wall clock, with no calendar applied at all. */
9
+ | {
10
+ kind: 'elapsed-hours';
11
+ hours: number;
12
+ };
13
+ /**
14
+ * The measure behind each level's published target.
15
+ *
16
+ * Premium is `elapsed-hours` on purpose, and that is the whole of its 24×7
17
+ * claim: its clock does not stop for nights, weekends or holidays, so no
18
+ * calendar is consulted. It is also why premium is the one level whose target
19
+ * the wall-clock histogram can check directly.
20
+ */
21
+ export declare const SUPPORT_TARGET_MEASURES: Readonly<Record<string, SupportTargetKind>>;
22
+ /** The resolved business calendar. */
23
+ export interface BusinessCalendar {
24
+ /** IANA zone. Never a fixed abbreviation — see {@link businessCalendar}. */
25
+ timeZone: string;
26
+ /** Working weekdays, 0 = Sunday … 6 = Saturday. */
27
+ days: readonly number[];
28
+ /** The hour (0–23) at which a working day CLOSES, in `timeZone`. */
29
+ endHour: number;
30
+ /** Non-working dates, `YYYY-MM-DD` in `timeZone`. */
31
+ holidays: ReadonlySet<string>;
32
+ }
33
+ /**
34
+ * The instant a first response is due, or null for a level with no target.
35
+ *
36
+ * For a business-day target: the close of the Nth working day AFTER the one the
37
+ * case was opened on. A case opened on a Friday with a next-business-day target
38
+ * is due at Monday's close, not Saturday's — Saturday is not a working day, so
39
+ * it is not counted. A case opened ON a non-working day starts counting from the
40
+ * next working day, which is the reading that favours the customer and is the
41
+ * only one that can be explained in a sentence.
42
+ *
43
+ * The day of opening is never itself the deadline, however early the case
44
+ * arrives. "Next business day" has to mean tomorrow, not "later today" — a case
45
+ * opened at 09:01 and one opened at 16:59 are owed the same thing, and anything
46
+ * else turns the target into an hours clock by the back door.
47
+ */
48
+ export declare function responseDueAt(openedAt: Date, level: string, cal?: BusinessCalendar): Date | null;
49
+ /**
50
+ * The configured calendar.
51
+ *
52
+ * `SUPPORT_BUSINESS_HOURS_TZ` takes an **IANA zone**, default
53
+ * `America/New_York`, and NOT a fixed abbreviation like `EST`. `EST` is
54
+ * permanently UTC−5, so an `EST` setting would put the desk an hour out for the
55
+ * eight months of the year that are EDT — the same reason
56
+ * `ASK_SCHEDULE_TIMEZONE` takes an IANA zone for its cron windows. An
57
+ * unrecognised zone falls back to UTC rather than throwing, because a bad
58
+ * timezone must not stop cases being opened; it is validated here so the
59
+ * fallback is deliberate rather than an exception thrown from `Intl` deep inside
60
+ * a request.
61
+ *
62
+ * Every stored timestamp stays UTC. The zone is applied only to derive a
63
+ * deadline.
64
+ *
65
+ * Holidays are an explicit operator-maintained list rather than a library: a
66
+ * library pulls both a dependency and a holiday POLICY that cannot be explained
67
+ * to a customer disputing a deadline.
68
+ */
69
+ export declare function businessCalendar(): BusinessCalendar;