@pipeline-builder/api-core 3.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (122) hide show
  1. package/LICENSE +202 -0
  2. package/README.md +51 -0
  3. package/lib/constants/ai-providers.d.ts +41 -0
  4. package/lib/constants/ai-providers.js +88 -0
  5. package/lib/constants/http-status.d.ts +24 -0
  6. package/lib/constants/http-status.js +29 -0
  7. package/lib/constants/index.d.ts +3 -0
  8. package/lib/constants/index.js +22 -0
  9. package/lib/constants/time.d.ts +10 -0
  10. package/lib/constants/time.js +16 -0
  11. package/lib/errors/app-errors.d.ts +30 -0
  12. package/lib/errors/app-errors.js +62 -0
  13. package/lib/errors/index.d.ts +1 -0
  14. package/lib/errors/index.js +20 -0
  15. package/lib/helpers/access-helpers.d.ts +40 -0
  16. package/lib/helpers/access-helpers.js +56 -0
  17. package/lib/helpers/crud-helpers.d.ts +16 -0
  18. package/lib/helpers/crud-helpers.js +34 -0
  19. package/lib/helpers/index.d.ts +4 -0
  20. package/lib/helpers/index.js +23 -0
  21. package/lib/helpers/mask-helpers.d.ts +33 -0
  22. package/lib/helpers/mask-helpers.js +54 -0
  23. package/lib/helpers/sse-helpers.d.ts +13 -0
  24. package/lib/helpers/sse-helpers.js +40 -0
  25. package/lib/index.d.ts +57 -0
  26. package/lib/index.js +86 -0
  27. package/lib/middleware/auth.d.ts +50 -0
  28. package/lib/middleware/auth.js +171 -0
  29. package/lib/middleware/index.d.ts +1 -0
  30. package/lib/middleware/index.js +20 -0
  31. package/lib/openapi/extend-zod.d.ts +1 -0
  32. package/lib/openapi/extend-zod.js +8 -0
  33. package/lib/openapi/index.d.ts +2 -0
  34. package/lib/openapi/index.js +10 -0
  35. package/lib/openapi/registry.d.ts +17 -0
  36. package/lib/openapi/registry.js +42 -0
  37. package/lib/openapi/routes/billing-routes.d.ts +1 -0
  38. package/lib/openapi/routes/billing-routes.js +69 -0
  39. package/lib/openapi/routes/index.d.ts +5 -0
  40. package/lib/openapi/routes/index.js +22 -0
  41. package/lib/openapi/routes/message-routes.d.ts +1 -0
  42. package/lib/openapi/routes/message-routes.js +108 -0
  43. package/lib/openapi/routes/pipeline-routes.d.ts +1 -0
  44. package/lib/openapi/routes/pipeline-routes.js +90 -0
  45. package/lib/openapi/routes/plugin-routes.d.ts +1 -0
  46. package/lib/openapi/routes/plugin-routes.js +99 -0
  47. package/lib/openapi/routes/quota-routes.d.ts +1 -0
  48. package/lib/openapi/routes/quota-routes.js +65 -0
  49. package/lib/openapi/schema-registry.d.ts +25 -0
  50. package/lib/openapi/schema-registry.js +95 -0
  51. package/lib/routes/health.d.ts +47 -0
  52. package/lib/routes/health.js +81 -0
  53. package/lib/routes/index.d.ts +1 -0
  54. package/lib/routes/index.js +20 -0
  55. package/lib/services/admin-audit.d.ts +13 -0
  56. package/lib/services/admin-audit.js +31 -0
  57. package/lib/services/cache-service.d.ts +108 -0
  58. package/lib/services/cache-service.js +212 -0
  59. package/lib/services/compliance-client.d.ts +46 -0
  60. package/lib/services/compliance-client.js +102 -0
  61. package/lib/services/compliance-event-subscriber.d.ts +11 -0
  62. package/lib/services/compliance-event-subscriber.js +60 -0
  63. package/lib/services/compliance-queue.d.ts +11 -0
  64. package/lib/services/compliance-queue.js +38 -0
  65. package/lib/services/entity-events.d.ts +44 -0
  66. package/lib/services/entity-events.js +63 -0
  67. package/lib/services/http-client.d.ts +108 -0
  68. package/lib/services/http-client.js +285 -0
  69. package/lib/services/index.d.ts +10 -0
  70. package/lib/services/index.js +40 -0
  71. package/lib/services/quota.d.ts +59 -0
  72. package/lib/services/quota.js +137 -0
  73. package/lib/services/retry-strategy.d.ts +74 -0
  74. package/lib/services/retry-strategy.js +127 -0
  75. package/lib/types/billing.d.ts +47 -0
  76. package/lib/types/billing.js +5 -0
  77. package/lib/types/common.d.ts +161 -0
  78. package/lib/types/common.js +53 -0
  79. package/lib/types/error-codes.d.ts +38 -0
  80. package/lib/types/error-codes.js +77 -0
  81. package/lib/types/feature-flags.d.ts +38 -0
  82. package/lib/types/feature-flags.js +107 -0
  83. package/lib/types/http.d.ts +37 -0
  84. package/lib/types/http.js +5 -0
  85. package/lib/types/index.d.ts +7 -0
  86. package/lib/types/index.js +26 -0
  87. package/lib/types/pipeline.d.ts +70 -0
  88. package/lib/types/pipeline.js +44 -0
  89. package/lib/types/quota-tiers.d.ts +23 -0
  90. package/lib/types/quota-tiers.js +26 -0
  91. package/lib/utils/alias-resolver.d.ts +16 -0
  92. package/lib/utils/alias-resolver.js +49 -0
  93. package/lib/utils/headers.d.ts +18 -0
  94. package/lib/utils/headers.js +24 -0
  95. package/lib/utils/identity.d.ts +61 -0
  96. package/lib/utils/identity.js +75 -0
  97. package/lib/utils/index.d.ts +7 -0
  98. package/lib/utils/index.js +26 -0
  99. package/lib/utils/logger.d.ts +28 -0
  100. package/lib/utils/logger.js +77 -0
  101. package/lib/utils/object.d.ts +13 -0
  102. package/lib/utils/object.js +21 -0
  103. package/lib/utils/params.d.ts +89 -0
  104. package/lib/utils/params.js +148 -0
  105. package/lib/utils/response.d.ts +142 -0
  106. package/lib/utils/response.js +237 -0
  107. package/lib/validation/ai-schemas.d.ts +61 -0
  108. package/lib/validation/ai-schemas.js +81 -0
  109. package/lib/validation/common-schemas.d.ts +72 -0
  110. package/lib/validation/common-schemas.js +58 -0
  111. package/lib/validation/index.d.ts +6 -0
  112. package/lib/validation/index.js +25 -0
  113. package/lib/validation/message-schemas.d.ts +79 -0
  114. package/lib/validation/message-schemas.js +42 -0
  115. package/lib/validation/middleware.d.ts +60 -0
  116. package/lib/validation/middleware.js +77 -0
  117. package/lib/validation/pipeline-schemas.d.ts +135 -0
  118. package/lib/validation/pipeline-schemas.js +85 -0
  119. package/lib/validation/plugin-schemas.d.ts +127 -0
  120. package/lib/validation/plugin-schemas.js +84 -0
  121. package/openapi.yaml +292 -0
  122. package/package.json +127 -0
@@ -0,0 +1,38 @@
1
+ "use strict";
2
+ // Copyright 2026 Pipeline Builder Contributors
3
+ // SPDX-License-Identifier: Apache-2.0
4
+ Object.defineProperty(exports, "__esModule", { value: true });
5
+ exports.registerComplianceQueueBackend = registerComplianceQueueBackend;
6
+ exports.enqueueComplianceEvent = enqueueComplianceEvent;
7
+ const logger_1 = require("../utils/logger");
8
+ const logger = (0, logger_1.createLogger)('compliance-queue');
9
+ /**
10
+ * Pluggable compliance event queue.
11
+ * Services register a backend (BullMQ, SQS, or in-memory) at startup.
12
+ * If no backend is registered, events are logged and discarded.
13
+ */
14
+ let enqueueFn = null;
15
+ function registerComplianceQueueBackend(fn) {
16
+ enqueueFn = fn;
17
+ logger.info('Compliance queue backend registered');
18
+ }
19
+ async function enqueueComplianceEvent(event) {
20
+ if (!enqueueFn) {
21
+ logger.debug('Compliance event discarded (no queue backend registered)', {
22
+ eventType: event.eventType, target: event.target, entityId: event.entityId,
23
+ });
24
+ return;
25
+ }
26
+ try {
27
+ await enqueueFn(event);
28
+ logger.debug('Compliance event enqueued', { eventType: event.eventType, target: event.target, entityId: event.entityId });
29
+ }
30
+ catch (err) {
31
+ logger.warn('Failed to enqueue compliance event', {
32
+ eventType: event.eventType,
33
+ entityId: event.entityId,
34
+ error: err instanceof Error ? err.message : String(err),
35
+ });
36
+ }
37
+ }
38
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY29tcGxpYW5jZS1xdWV1ZS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9zZXJ2aWNlcy9jb21wbGlhbmNlLXF1ZXVlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7QUFBQSwrQ0FBK0M7QUFDL0Msc0NBQXNDOztBQXVCdEMsd0VBR0M7QUFFRCx3REFpQkM7QUEzQ0QsNENBQStDO0FBRS9DLE1BQU0sTUFBTSxHQUFHLElBQUEscUJBQVksRUFBQyxrQkFBa0IsQ0FBQyxDQUFDO0FBWWhEOzs7O0dBSUc7QUFDSCxJQUFJLFNBQVMsR0FBdUQsSUFBSSxDQUFDO0FBRXpFLFNBQWdCLDhCQUE4QixDQUFDLEVBQTZDO0lBQzFGLFNBQVMsR0FBRyxFQUFFLENBQUM7SUFDZixNQUFNLENBQUMsSUFBSSxDQUFDLHFDQUFxQyxDQUFDLENBQUM7QUFDckQsQ0FBQztBQUVNLEtBQUssVUFBVSxzQkFBc0IsQ0FBQyxLQUFzQjtJQUNqRSxJQUFJLENBQUMsU0FBUyxFQUFFLENBQUM7UUFDZixNQUFNLENBQUMsS0FBSyxDQUFDLDBEQUEwRCxFQUFFO1lBQ3ZFLFNBQVMsRUFBRSxLQUFLLENBQUMsU0FBUyxFQUFFLE1BQU0sRUFBRSxLQUFLLENBQUMsTUFBTSxFQUFFLFFBQVEsRUFBRSxLQUFLLENBQUMsUUFBUTtTQUMzRSxDQUFDLENBQUM7UUFDSCxPQUFPO0lBQ1QsQ0FBQztJQUNELElBQUksQ0FBQztRQUNILE1BQU0sU0FBUyxDQUFDLEtBQUssQ0FBQyxDQUFDO1FBQ3ZCLE1BQU0sQ0FBQyxLQUFLLENBQUMsMkJBQTJCLEVBQUUsRUFBRSxTQUFTLEVBQUUsS0FBSyxDQUFDLFNBQVMsRUFBRSxNQUFNLEVBQUUsS0FBSyxDQUFDLE1BQU0sRUFBRSxRQUFRLEVBQUUsS0FBSyxDQUFDLFFBQVEsRUFBRSxDQUFDLENBQUM7SUFDNUgsQ0FBQztJQUFDLE9BQU8sR0FBRyxFQUFFLENBQUM7UUFDYixNQUFNLENBQUMsSUFBSSxDQUFDLG9DQUFvQyxFQUFFO1lBQ2hELFNBQVMsRUFBRSxLQUFLLENBQUMsU0FBUztZQUMxQixRQUFRLEVBQUUsS0FBSyxDQUFDLFFBQVE7WUFDeEIsS0FBSyxFQUFFLEdBQUcsWUFBWSxLQUFLLENBQUMsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxPQUFPLENBQUMsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxHQUFHLENBQUM7U0FDeEQsQ0FBQyxDQUFDO0lBQ0wsQ0FBQztBQUNILENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyIvLyBDb3B5cmlnaHQgMjAyNiBQaXBlbGluZSBCdWlsZGVyIENvbnRyaWJ1dG9yc1xuLy8gU1BEWC1MaWNlbnNlLUlkZW50aWZpZXI6IEFwYWNoZS0yLjBcblxuaW1wb3J0IHsgY3JlYXRlTG9nZ2VyIH0gZnJvbSAnLi4vdXRpbHMvbG9nZ2VyJztcblxuY29uc3QgbG9nZ2VyID0gY3JlYXRlTG9nZ2VyKCdjb21wbGlhbmNlLXF1ZXVlJyk7XG5cbmV4cG9ydCBpbnRlcmZhY2UgQ29tcGxpYW5jZUV2ZW50IHtcbiAgZXZlbnRUeXBlOiAndmFsaWRhdGUnIHwgJ3NjYW4nIHwgJ25vdGlmeSc7XG4gIHRhcmdldDogJ3BsdWdpbicgfCAncGlwZWxpbmUnO1xuICBlbnRpdHlJZDogc3RyaW5nO1xuICBvcmdJZDogc3RyaW5nO1xuICB1c2VySWQ6IHN0cmluZztcbiAgYXR0cmlidXRlczogUmVjb3JkPHN0cmluZywgdW5rbm93bj47XG4gIHRpbWVzdGFtcDogc3RyaW5nO1xufVxuXG4vKipcbiAqIFBsdWdnYWJsZSBjb21wbGlhbmNlIGV2ZW50IHF1ZXVlLlxuICogU2VydmljZXMgcmVnaXN0ZXIgYSBiYWNrZW5kIChCdWxsTVEsIFNRUywgb3IgaW4tbWVtb3J5KSBhdCBzdGFydHVwLlxuICogSWYgbm8gYmFja2VuZCBpcyByZWdpc3RlcmVkLCBldmVudHMgYXJlIGxvZ2dlZCBhbmQgZGlzY2FyZGVkLlxuICovXG5sZXQgZW5xdWV1ZUZuOiAoKGV2ZW50OiBDb21wbGlhbmNlRXZlbnQpID0+IFByb21pc2U8dm9pZD4pIHwgbnVsbCA9IG51bGw7XG5cbmV4cG9ydCBmdW5jdGlvbiByZWdpc3RlckNvbXBsaWFuY2VRdWV1ZUJhY2tlbmQoZm46IChldmVudDogQ29tcGxpYW5jZUV2ZW50KSA9PiBQcm9taXNlPHZvaWQ+KTogdm9pZCB7XG4gIGVucXVldWVGbiA9IGZuO1xuICBsb2dnZXIuaW5mbygnQ29tcGxpYW5jZSBxdWV1ZSBiYWNrZW5kIHJlZ2lzdGVyZWQnKTtcbn1cblxuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIGVucXVldWVDb21wbGlhbmNlRXZlbnQoZXZlbnQ6IENvbXBsaWFuY2VFdmVudCk6IFByb21pc2U8dm9pZD4ge1xuICBpZiAoIWVucXVldWVGbikge1xuICAgIGxvZ2dlci5kZWJ1ZygnQ29tcGxpYW5jZSBldmVudCBkaXNjYXJkZWQgKG5vIHF1ZXVlIGJhY2tlbmQgcmVnaXN0ZXJlZCknLCB7XG4gICAgICBldmVudFR5cGU6IGV2ZW50LmV2ZW50VHlwZSwgdGFyZ2V0OiBldmVudC50YXJnZXQsIGVudGl0eUlkOiBldmVudC5lbnRpdHlJZCxcbiAgICB9KTtcbiAgICByZXR1cm47XG4gIH1cbiAgdHJ5IHtcbiAgICBhd2FpdCBlbnF1ZXVlRm4oZXZlbnQpO1xuICAgIGxvZ2dlci5kZWJ1ZygnQ29tcGxpYW5jZSBldmVudCBlbnF1ZXVlZCcsIHsgZXZlbnRUeXBlOiBldmVudC5ldmVudFR5cGUsIHRhcmdldDogZXZlbnQudGFyZ2V0LCBlbnRpdHlJZDogZXZlbnQuZW50aXR5SWQgfSk7XG4gIH0gY2F0Y2ggKGVycikge1xuICAgIGxvZ2dlci53YXJuKCdGYWlsZWQgdG8gZW5xdWV1ZSBjb21wbGlhbmNlIGV2ZW50Jywge1xuICAgICAgZXZlbnRUeXBlOiBldmVudC5ldmVudFR5cGUsXG4gICAgICBlbnRpdHlJZDogZXZlbnQuZW50aXR5SWQsXG4gICAgICBlcnJvcjogZXJyIGluc3RhbmNlb2YgRXJyb3IgPyBlcnIubWVzc2FnZSA6IFN0cmluZyhlcnIpLFxuICAgIH0pO1xuICB9XG59XG4iXX0=
@@ -0,0 +1,44 @@
1
+ export type EntityEventType = 'created' | 'updated' | 'deleted';
2
+ export type EntityTarget = 'plugin' | 'pipeline' | 'message' | 'organization' | 'user';
3
+ export interface EntityEvent {
4
+ /** The type of mutation that occurred */
5
+ eventType: EntityEventType;
6
+ /** The entity type that was mutated */
7
+ target: EntityTarget;
8
+ /** The entity's unique ID */
9
+ entityId: string;
10
+ /** The organization that owns this entity */
11
+ orgId: string;
12
+ /** The user who performed the mutation */
13
+ userId: string;
14
+ /** When the event occurred */
15
+ timestamp: Date;
16
+ /** Snapshot of entity attributes (for compliance evaluation) */
17
+ attributes: Record<string, unknown>;
18
+ }
19
+ export interface EntityEventSubscriber {
20
+ onEntityEvent(event: EntityEvent): Promise<void>;
21
+ }
22
+ declare class EntityEventEmitter {
23
+ private subscribers;
24
+ /**
25
+ * Register a subscriber to receive entity events.
26
+ */
27
+ subscribe(subscriber: EntityEventSubscriber): void;
28
+ /**
29
+ * Remove a subscriber.
30
+ */
31
+ unsubscribe(subscriber: EntityEventSubscriber): void;
32
+ /**
33
+ * Emit an entity event to all subscribers.
34
+ * Fire-and-forget: errors are caught and logged, never thrown.
35
+ */
36
+ emit(event: EntityEvent): void;
37
+ /**
38
+ * Get the current subscriber count (for testing/diagnostics).
39
+ */
40
+ get subscriberCount(): number;
41
+ }
42
+ /** Singleton entity event emitter — shared across the process */
43
+ export declare const entityEvents: EntityEventEmitter;
44
+ export {};
@@ -0,0 +1,63 @@
1
+ "use strict";
2
+ // Copyright 2026 Pipeline Builder Contributors
3
+ // SPDX-License-Identifier: Apache-2.0
4
+ Object.defineProperty(exports, "__esModule", { value: true });
5
+ exports.entityEvents = void 0;
6
+ /**
7
+ * Lightweight in-process event emitter for entity lifecycle events.
8
+ *
9
+ * Services emit events after mutations (create/update/delete) via CrudService hooks.
10
+ * Subscribers react asynchronously to entity changes.
11
+ *
12
+ * Active subscribers:
13
+ * - **Compliance event subscriber** (`registerComplianceEventSubscriber()`) — forwards
14
+ * entity events to the compliance service for post-mutation rule evaluation.
15
+ * Registered at startup in plugin and pipeline service index.ts.
16
+ *
17
+ * Design:
18
+ * - Fire-and-forget: emit() never throws, subscriber errors are logged
19
+ * - In-process only: no network, no Redis, no infrastructure
20
+ * - Subscribers run async: never block the original request
21
+ */
22
+ const logger_1 = require("../utils/logger");
23
+ const logger = (0, logger_1.createLogger)('entity-events');
24
+ class EntityEventEmitter {
25
+ subscribers = [];
26
+ /**
27
+ * Register a subscriber to receive entity events.
28
+ */
29
+ subscribe(subscriber) {
30
+ this.subscribers.push(subscriber);
31
+ }
32
+ /**
33
+ * Remove a subscriber.
34
+ */
35
+ unsubscribe(subscriber) {
36
+ this.subscribers = this.subscribers.filter((s) => s !== subscriber);
37
+ }
38
+ /**
39
+ * Emit an entity event to all subscribers.
40
+ * Fire-and-forget: errors are caught and logged, never thrown.
41
+ */
42
+ emit(event) {
43
+ for (const subscriber of this.subscribers) {
44
+ subscriber.onEntityEvent(event).catch((err) => {
45
+ logger.debug('Entity event subscriber failed', {
46
+ target: event.target,
47
+ eventType: event.eventType,
48
+ entityId: event.entityId,
49
+ error: err instanceof Error ? err.message : String(err),
50
+ });
51
+ });
52
+ }
53
+ }
54
+ /**
55
+ * Get the current subscriber count (for testing/diagnostics).
56
+ */
57
+ get subscriberCount() {
58
+ return this.subscribers.length;
59
+ }
60
+ }
61
+ /** Singleton entity event emitter — shared across the process */
62
+ exports.entityEvents = new EntityEventEmitter();
63
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZW50aXR5LWV2ZW50cy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9zZXJ2aWNlcy9lbnRpdHktZXZlbnRzLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7QUFBQSwrQ0FBK0M7QUFDL0Msc0NBQXNDOzs7QUFFdEM7Ozs7Ozs7Ozs7Ozs7OztHQWVHO0FBRUgsNENBQStDO0FBRS9DLE1BQU0sTUFBTSxHQUFHLElBQUEscUJBQVksRUFBQyxlQUFlLENBQUMsQ0FBQztBQTBCN0MsTUFBTSxrQkFBa0I7SUFDZCxXQUFXLEdBQTRCLEVBQUUsQ0FBQztJQUVsRDs7T0FFRztJQUNILFNBQVMsQ0FBQyxVQUFpQztRQUN6QyxJQUFJLENBQUMsV0FBVyxDQUFDLElBQUksQ0FBQyxVQUFVLENBQUMsQ0FBQztJQUNwQyxDQUFDO0lBRUQ7O09BRUc7SUFDSCxXQUFXLENBQUMsVUFBaUM7UUFDM0MsSUFBSSxDQUFDLFdBQVcsR0FBRyxJQUFJLENBQUMsV0FBVyxDQUFDLE1BQU0sQ0FBQyxDQUFDLENBQUMsRUFBRSxFQUFFLENBQUMsQ0FBQyxLQUFLLFVBQVUsQ0FBQyxDQUFDO0lBQ3RFLENBQUM7SUFFRDs7O09BR0c7SUFDSCxJQUFJLENBQUMsS0FBa0I7UUFDckIsS0FBSyxNQUFNLFVBQVUsSUFBSSxJQUFJLENBQUMsV0FBVyxFQUFFLENBQUM7WUFDMUMsVUFBVSxDQUFDLGFBQWEsQ0FBQyxLQUFLLENBQUMsQ0FBQyxLQUFLLENBQUMsQ0FBQyxHQUFHLEVBQUUsRUFBRTtnQkFDNUMsTUFBTSxDQUFDLEtBQUssQ0FBQyxnQ0FBZ0MsRUFBRTtvQkFDN0MsTUFBTSxFQUFFLEtBQUssQ0FBQyxNQUFNO29CQUNwQixTQUFTLEVBQUUsS0FBSyxDQUFDLFNBQVM7b0JBQzFCLFFBQVEsRUFBRSxLQUFLLENBQUMsUUFBUTtvQkFDeEIsS0FBSyxFQUFFLEdBQUcsWUFBWSxLQUFLLENBQUMsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxPQUFPLENBQUMsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxHQUFHLENBQUM7aUJBQ3hELENBQUMsQ0FBQztZQUNMLENBQUMsQ0FBQyxDQUFDO1FBQ0wsQ0FBQztJQUNILENBQUM7SUFFRDs7T0FFRztJQUNILElBQUksZUFBZTtRQUNqQixPQUFPLElBQUksQ0FBQyxXQUFXLENBQUMsTUFBTSxDQUFDO0lBQ2pDLENBQUM7Q0FDRjtBQUVELGlFQUFpRTtBQUNwRCxRQUFBLFlBQVksR0FBRyxJQUFJLGtCQUFrQixFQUFFLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyIvLyBDb3B5cmlnaHQgMjAyNiBQaXBlbGluZSBCdWlsZGVyIENvbnRyaWJ1dG9yc1xuLy8gU1BEWC1MaWNlbnNlLUlkZW50aWZpZXI6IEFwYWNoZS0yLjBcblxuLyoqXG4gKiBMaWdodHdlaWdodCBpbi1wcm9jZXNzIGV2ZW50IGVtaXR0ZXIgZm9yIGVudGl0eSBsaWZlY3ljbGUgZXZlbnRzLlxuICpcbiAqIFNlcnZpY2VzIGVtaXQgZXZlbnRzIGFmdGVyIG11dGF0aW9ucyAoY3JlYXRlL3VwZGF0ZS9kZWxldGUpIHZpYSBDcnVkU2VydmljZSBob29rcy5cbiAqIFN1YnNjcmliZXJzIHJlYWN0IGFzeW5jaHJvbm91c2x5IHRvIGVudGl0eSBjaGFuZ2VzLlxuICpcbiAqIEFjdGl2ZSBzdWJzY3JpYmVyczpcbiAqIC0gKipDb21wbGlhbmNlIGV2ZW50IHN1YnNjcmliZXIqKiAoYHJlZ2lzdGVyQ29tcGxpYW5jZUV2ZW50U3Vic2NyaWJlcigpYCkg4oCUIGZvcndhcmRzXG4gKiAgIGVudGl0eSBldmVudHMgdG8gdGhlIGNvbXBsaWFuY2Ugc2VydmljZSBmb3IgcG9zdC1tdXRhdGlvbiBydWxlIGV2YWx1YXRpb24uXG4gKiAgIFJlZ2lzdGVyZWQgYXQgc3RhcnR1cCBpbiBwbHVnaW4gYW5kIHBpcGVsaW5lIHNlcnZpY2UgaW5kZXgudHMuXG4gKlxuICogRGVzaWduOlxuICogLSBGaXJlLWFuZC1mb3JnZXQ6IGVtaXQoKSBuZXZlciB0aHJvd3MsIHN1YnNjcmliZXIgZXJyb3JzIGFyZSBsb2dnZWRcbiAqIC0gSW4tcHJvY2VzcyBvbmx5OiBubyBuZXR3b3JrLCBubyBSZWRpcywgbm8gaW5mcmFzdHJ1Y3R1cmVcbiAqIC0gU3Vic2NyaWJlcnMgcnVuIGFzeW5jOiBuZXZlciBibG9jayB0aGUgb3JpZ2luYWwgcmVxdWVzdFxuICovXG5cbmltcG9ydCB7IGNyZWF0ZUxvZ2dlciB9IGZyb20gJy4uL3V0aWxzL2xvZ2dlcic7XG5cbmNvbnN0IGxvZ2dlciA9IGNyZWF0ZUxvZ2dlcignZW50aXR5LWV2ZW50cycpO1xuXG5leHBvcnQgdHlwZSBFbnRpdHlFdmVudFR5cGUgPSAnY3JlYXRlZCcgfCAndXBkYXRlZCcgfCAnZGVsZXRlZCc7XG5leHBvcnQgdHlwZSBFbnRpdHlUYXJnZXQgPSAncGx1Z2luJyB8ICdwaXBlbGluZScgfCAnbWVzc2FnZScgfCAnb3JnYW5pemF0aW9uJyB8ICd1c2VyJztcblxuZXhwb3J0IGludGVyZmFjZSBFbnRpdHlFdmVudCB7XG4gIC8qKiBUaGUgdHlwZSBvZiBtdXRhdGlvbiB0aGF0IG9jY3VycmVkICovXG4gIGV2ZW50VHlwZTogRW50aXR5RXZlbnRUeXBlO1xuICAvKiogVGhlIGVudGl0eSB0eXBlIHRoYXQgd2FzIG11dGF0ZWQgKi9cbiAgdGFyZ2V0OiBFbnRpdHlUYXJnZXQ7XG4gIC8qKiBUaGUgZW50aXR5J3MgdW5pcXVlIElEICovXG4gIGVudGl0eUlkOiBzdHJpbmc7XG4gIC8qKiBUaGUgb3JnYW5pemF0aW9uIHRoYXQgb3ducyB0aGlzIGVudGl0eSAqL1xuICBvcmdJZDogc3RyaW5nO1xuICAvKiogVGhlIHVzZXIgd2hvIHBlcmZvcm1lZCB0aGUgbXV0YXRpb24gKi9cbiAgdXNlcklkOiBzdHJpbmc7XG4gIC8qKiBXaGVuIHRoZSBldmVudCBvY2N1cnJlZCAqL1xuICB0aW1lc3RhbXA6IERhdGU7XG4gIC8qKiBTbmFwc2hvdCBvZiBlbnRpdHkgYXR0cmlidXRlcyAoZm9yIGNvbXBsaWFuY2UgZXZhbHVhdGlvbikgKi9cbiAgYXR0cmlidXRlczogUmVjb3JkPHN0cmluZywgdW5rbm93bj47XG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgRW50aXR5RXZlbnRTdWJzY3JpYmVyIHtcbiAgb25FbnRpdHlFdmVudChldmVudDogRW50aXR5RXZlbnQpOiBQcm9taXNlPHZvaWQ+O1xufVxuXG5jbGFzcyBFbnRpdHlFdmVudEVtaXR0ZXIge1xuICBwcml2YXRlIHN1YnNjcmliZXJzOiBFbnRpdHlFdmVudFN1YnNjcmliZXJbXSA9IFtdO1xuXG4gIC8qKlxuICAgKiBSZWdpc3RlciBhIHN1YnNjcmliZXIgdG8gcmVjZWl2ZSBlbnRpdHkgZXZlbnRzLlxuICAgKi9cbiAgc3Vic2NyaWJlKHN1YnNjcmliZXI6IEVudGl0eUV2ZW50U3Vic2NyaWJlcik6IHZvaWQge1xuICAgIHRoaXMuc3Vic2NyaWJlcnMucHVzaChzdWJzY3JpYmVyKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBSZW1vdmUgYSBzdWJzY3JpYmVyLlxuICAgKi9cbiAgdW5zdWJzY3JpYmUoc3Vic2NyaWJlcjogRW50aXR5RXZlbnRTdWJzY3JpYmVyKTogdm9pZCB7XG4gICAgdGhpcy5zdWJzY3JpYmVycyA9IHRoaXMuc3Vic2NyaWJlcnMuZmlsdGVyKChzKSA9PiBzICE9PSBzdWJzY3JpYmVyKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBFbWl0IGFuIGVudGl0eSBldmVudCB0byBhbGwgc3Vic2NyaWJlcnMuXG4gICAqIEZpcmUtYW5kLWZvcmdldDogZXJyb3JzIGFyZSBjYXVnaHQgYW5kIGxvZ2dlZCwgbmV2ZXIgdGhyb3duLlxuICAgKi9cbiAgZW1pdChldmVudDogRW50aXR5RXZlbnQpOiB2b2lkIHtcbiAgICBmb3IgKGNvbnN0IHN1YnNjcmliZXIgb2YgdGhpcy5zdWJzY3JpYmVycykge1xuICAgICAgc3Vic2NyaWJlci5vbkVudGl0eUV2ZW50KGV2ZW50KS5jYXRjaCgoZXJyKSA9PiB7XG4gICAgICAgIGxvZ2dlci5kZWJ1ZygnRW50aXR5IGV2ZW50IHN1YnNjcmliZXIgZmFpbGVkJywge1xuICAgICAgICAgIHRhcmdldDogZXZlbnQudGFyZ2V0LFxuICAgICAgICAgIGV2ZW50VHlwZTogZXZlbnQuZXZlbnRUeXBlLFxuICAgICAgICAgIGVudGl0eUlkOiBldmVudC5lbnRpdHlJZCxcbiAgICAgICAgICBlcnJvcjogZXJyIGluc3RhbmNlb2YgRXJyb3IgPyBlcnIubWVzc2FnZSA6IFN0cmluZyhlcnIpLFxuICAgICAgICB9KTtcbiAgICAgIH0pO1xuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBHZXQgdGhlIGN1cnJlbnQgc3Vic2NyaWJlciBjb3VudCAoZm9yIHRlc3RpbmcvZGlhZ25vc3RpY3MpLlxuICAgKi9cbiAgZ2V0IHN1YnNjcmliZXJDb3VudCgpOiBudW1iZXIge1xuICAgIHJldHVybiB0aGlzLnN1YnNjcmliZXJzLmxlbmd0aDtcbiAgfVxufVxuXG4vKiogU2luZ2xldG9uIGVudGl0eSBldmVudCBlbWl0dGVyIOKAlCBzaGFyZWQgYWNyb3NzIHRoZSBwcm9jZXNzICovXG5leHBvcnQgY29uc3QgZW50aXR5RXZlbnRzID0gbmV3IEVudGl0eUV2ZW50RW1pdHRlcigpO1xuIl19
@@ -0,0 +1,108 @@
1
+ import * as http from 'http';
2
+ import { ServiceConfig } from '../types/common';
3
+ export { parseRetryAfter, addJitter } from './retry-strategy';
4
+ /**
5
+ * HTTP request options.
6
+ */
7
+ export interface RequestOptions {
8
+ /** Request headers */
9
+ headers?: Record<string, string>;
10
+ /** Request timeout in milliseconds */
11
+ timeout?: number;
12
+ /** Maximum retry attempts for transient failures (default: 2) */
13
+ maxRetries?: number;
14
+ /** Base delay between retries in ms — doubles each attempt (default: 200) */
15
+ retryDelayMs?: number;
16
+ /** Maximum retry attempts specifically for 429 rate limiting (default: 4) */
17
+ maxRateLimitRetries?: number;
18
+ /** Optional request ID for distributed tracing (added as X-Request-Id header) */
19
+ requestId?: string;
20
+ }
21
+ /**
22
+ * HTTP client response wrapper.
23
+ */
24
+ export interface HttpClientResponse<T = unknown> {
25
+ /** HTTP status code */
26
+ statusCode: number;
27
+ /** Response body (parsed JSON) */
28
+ body: T;
29
+ /** Response headers */
30
+ headers: http.IncomingHttpHeaders;
31
+ }
32
+ /**
33
+ * Internal HTTP client for service-to-service communication.
34
+ *
35
+ * @example
36
+ * ```typescript
37
+ * const client = new InternalHttpClient({
38
+ * host: 'quota',
39
+ * port: 3000,
40
+ * timeout: 5000,
41
+ * });
42
+ *
43
+ * const response = await client.get('/org123/apiCalls');
44
+ * const result = await client.post('/org123/increment', { quotaType: 'apiCalls' });
45
+ * ```
46
+ */
47
+ export declare class InternalHttpClient {
48
+ private config;
49
+ private agent;
50
+ /**
51
+ * Create a new HTTP client instance.
52
+ *
53
+ * @param config - Service configuration
54
+ */
55
+ constructor(config: ServiceConfig);
56
+ /**
57
+ * Make a GET request.
58
+ */
59
+ get<T = unknown>(path: string, options?: RequestOptions): Promise<HttpClientResponse<T>>;
60
+ /**
61
+ * Make a POST request.
62
+ */
63
+ post<T = unknown>(path: string, body?: unknown, options?: RequestOptions): Promise<HttpClientResponse<T>>;
64
+ /**
65
+ * Make a PUT request.
66
+ */
67
+ put<T = unknown>(path: string, body?: unknown, options?: RequestOptions): Promise<HttpClientResponse<T>>;
68
+ /**
69
+ * Make a DELETE request.
70
+ */
71
+ delete<T = unknown>(path: string, options?: RequestOptions): Promise<HttpClientResponse<T>>;
72
+ /**
73
+ * Request with retry logic for transient failures.
74
+ *
75
+ * - 429 (rate limit): respects `Retry-After` header, uses longer base delay (4x),
76
+ * retries up to `maxRateLimitRetries` times (default 4).
77
+ * - 502/503/504 (server errors): standard exponential backoff, up to `maxRetries` (default 2).
78
+ * - Connection errors / timeouts: retries up to `maxRetries`.
79
+ * - All delays include ±25% jitter to prevent thundering herd.
80
+ */
81
+ private requestWithRetry;
82
+ private sleep;
83
+ /**
84
+ * Internal request method.
85
+ */
86
+ private request;
87
+ }
88
+ /**
89
+ * Create an HTTP client with error handling that returns null on failure.
90
+ * Useful for fail-open scenarios.
91
+ *
92
+ * @param config - Service configuration
93
+ * @returns Client wrapper with safe methods
94
+ */
95
+ export declare function createSafeClient(config: ServiceConfig): {
96
+ /**
97
+ * Safe GET request - returns null on error.
98
+ */
99
+ get<T>(path: string, options?: RequestOptions): Promise<HttpClientResponse<T> | null>;
100
+ /**
101
+ * Safe POST request - returns null on error.
102
+ */
103
+ post<T>(path: string, body?: unknown, options?: RequestOptions): Promise<HttpClientResponse<T> | null>;
104
+ /**
105
+ * Safe PUT request - returns null on error.
106
+ */
107
+ put<T>(path: string, body?: unknown, options?: RequestOptions): Promise<HttpClientResponse<T> | null>;
108
+ };
@@ -0,0 +1,285 @@
1
+ "use strict";
2
+ // Copyright 2026 Pipeline Builder Contributors
3
+ // SPDX-License-Identifier: Apache-2.0
4
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
5
+ if (k2 === undefined) k2 = k;
6
+ var desc = Object.getOwnPropertyDescriptor(m, k);
7
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
8
+ desc = { enumerable: true, get: function() { return m[k]; } };
9
+ }
10
+ Object.defineProperty(o, k2, desc);
11
+ }) : (function(o, m, k, k2) {
12
+ if (k2 === undefined) k2 = k;
13
+ o[k2] = m[k];
14
+ }));
15
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
16
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
17
+ }) : function(o, v) {
18
+ o["default"] = v;
19
+ });
20
+ var __importStar = (this && this.__importStar) || (function () {
21
+ var ownKeys = function(o) {
22
+ ownKeys = Object.getOwnPropertyNames || function (o) {
23
+ var ar = [];
24
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
25
+ return ar;
26
+ };
27
+ return ownKeys(o);
28
+ };
29
+ return function (mod) {
30
+ if (mod && mod.__esModule) return mod;
31
+ var result = {};
32
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
33
+ __setModuleDefault(result, mod);
34
+ return result;
35
+ };
36
+ })();
37
+ Object.defineProperty(exports, "__esModule", { value: true });
38
+ exports.InternalHttpClient = exports.addJitter = exports.parseRetryAfter = void 0;
39
+ exports.createSafeClient = createSafeClient;
40
+ const http = __importStar(require("http"));
41
+ const retry_strategy_1 = require("./retry-strategy");
42
+ const http_status_1 = require("../constants/http-status");
43
+ const logger_1 = require("../utils/logger");
44
+ // Re-export retry utilities for backward compatibility
45
+ var retry_strategy_2 = require("./retry-strategy");
46
+ Object.defineProperty(exports, "parseRetryAfter", { enumerable: true, get: function () { return retry_strategy_2.parseRetryAfter; } });
47
+ Object.defineProperty(exports, "addJitter", { enumerable: true, get: function () { return retry_strategy_2.addJitter; } });
48
+ const logger = (0, logger_1.createLogger)('http-client');
49
+ /**
50
+ * Default request timeout in milliseconds (env: `HTTP_CLIENT_TIMEOUT`).
51
+ */
52
+ const DEFAULT_TIMEOUT = parseInt(process.env.HTTP_CLIENT_TIMEOUT || '5000', 10);
53
+ /**
54
+ * Internal HTTP client for service-to-service communication.
55
+ *
56
+ * @example
57
+ * ```typescript
58
+ * const client = new InternalHttpClient({
59
+ * host: 'quota',
60
+ * port: 3000,
61
+ * timeout: 5000,
62
+ * });
63
+ *
64
+ * const response = await client.get('/org123/apiCalls');
65
+ * const result = await client.post('/org123/increment', { quotaType: 'apiCalls' });
66
+ * ```
67
+ */
68
+ class InternalHttpClient {
69
+ config;
70
+ agent;
71
+ /**
72
+ * Create a new HTTP client instance.
73
+ *
74
+ * @param config - Service configuration
75
+ */
76
+ constructor(config) {
77
+ this.config = {
78
+ host: config.host,
79
+ port: config.port,
80
+ timeout: config.timeout ?? DEFAULT_TIMEOUT,
81
+ };
82
+ this.agent = new http.Agent({ keepAlive: true });
83
+ }
84
+ /**
85
+ * Make a GET request.
86
+ */
87
+ async get(path, options) {
88
+ return this.requestWithRetry('GET', path, undefined, options);
89
+ }
90
+ /**
91
+ * Make a POST request.
92
+ */
93
+ async post(path, body, options) {
94
+ return this.requestWithRetry('POST', path, body, options);
95
+ }
96
+ /**
97
+ * Make a PUT request.
98
+ */
99
+ async put(path, body, options) {
100
+ return this.requestWithRetry('PUT', path, body, options);
101
+ }
102
+ /**
103
+ * Make a DELETE request.
104
+ */
105
+ async delete(path, options) {
106
+ return this.requestWithRetry('DELETE', path, undefined, options);
107
+ }
108
+ /**
109
+ * Request with retry logic for transient failures.
110
+ *
111
+ * - 429 (rate limit): respects `Retry-After` header, uses longer base delay (4x),
112
+ * retries up to `maxRateLimitRetries` times (default 4).
113
+ * - 502/503/504 (server errors): standard exponential backoff, up to `maxRetries` (default 2).
114
+ * - Connection errors / timeouts: retries up to `maxRetries`.
115
+ * - All delays include ±25% jitter to prevent thundering herd.
116
+ */
117
+ async requestWithRetry(method, path, body, options) {
118
+ const retryConfig = {
119
+ maxRetries: options?.maxRetries ?? retry_strategy_1.DEFAULT_MAX_RETRIES,
120
+ maxRateLimitRetries: options?.maxRateLimitRetries ?? retry_strategy_1.DEFAULT_MAX_RATE_LIMIT_RETRIES,
121
+ retryDelayMs: options?.retryDelayMs ?? retry_strategy_1.DEFAULT_RETRY_DELAY_MS,
122
+ };
123
+ const totalMaxAttempts = Math.max(retryConfig.maxRetries, retryConfig.maxRateLimitRetries);
124
+ let lastError;
125
+ for (let attempt = 0; attempt <= totalMaxAttempts; attempt++) {
126
+ try {
127
+ const response = await this.request(method, path, body, options);
128
+ const decision = (0, retry_strategy_1.getRetryDecision)(response.statusCode, response.headers, attempt, retryConfig);
129
+ if (decision.shouldRetry) {
130
+ logger.debug(decision.reason + ', retrying', { method, path, attempt: attempt + 1, delayMs: decision.delayMs });
131
+ await this.sleep(decision.delayMs);
132
+ continue;
133
+ }
134
+ return response;
135
+ }
136
+ catch (error) {
137
+ lastError = error instanceof Error ? error : new Error(String(error));
138
+ const decision = (0, retry_strategy_1.getErrorRetryDecision)(attempt, retryConfig);
139
+ if (decision.shouldRetry) {
140
+ logger.debug('Retrying after error', { method, path, error: lastError.message, attempt: attempt + 1 });
141
+ await this.sleep(decision.delayMs);
142
+ continue;
143
+ }
144
+ }
145
+ }
146
+ throw lastError;
147
+ }
148
+ sleep(ms) {
149
+ return new Promise(resolve => setTimeout(resolve, ms));
150
+ }
151
+ /**
152
+ * Internal request method.
153
+ */
154
+ request(method, path, body, options) {
155
+ return new Promise((resolve, reject) => {
156
+ const bodyStr = body ? JSON.stringify(body) : undefined;
157
+ const headers = {
158
+ 'Content-Type': 'application/json',
159
+ ...options?.headers,
160
+ };
161
+ // Propagate request ID for distributed tracing
162
+ if (options?.requestId) {
163
+ headers['X-Request-Id'] = options.requestId;
164
+ }
165
+ if (bodyStr) {
166
+ headers['Content-Length'] = Buffer.byteLength(bodyStr);
167
+ }
168
+ // Validate path to prevent protocol injection / request smuggling
169
+ if (path.includes('://') || path.startsWith('//') || /[\r\n\0]/.test(path)) {
170
+ throw new Error(`Invalid request path: ${path}`);
171
+ }
172
+ const requestOptions = {
173
+ hostname: this.config.host,
174
+ port: this.config.port,
175
+ path: path.startsWith('/') ? path : `/${path}`,
176
+ method,
177
+ headers,
178
+ timeout: options?.timeout ?? this.config.timeout,
179
+ agent: this.agent,
180
+ };
181
+ const req = http.request(requestOptions, (res) => {
182
+ let data = '';
183
+ res.on('data', (chunk) => {
184
+ data += chunk;
185
+ });
186
+ res.on('end', () => {
187
+ try {
188
+ const parsedBody = data ? JSON.parse(data) : {};
189
+ resolve({
190
+ statusCode: res.statusCode || http_status_1.HttpStatus.INTERNAL_SERVER_ERROR,
191
+ body: parsedBody,
192
+ headers: res.headers,
193
+ });
194
+ }
195
+ catch (parseError) {
196
+ logger.warn('Failed to parse response body', {
197
+ host: this.config.host,
198
+ path,
199
+ error: parseError instanceof Error ? parseError.message : String(parseError),
200
+ });
201
+ resolve({
202
+ statusCode: res.statusCode || http_status_1.HttpStatus.INTERNAL_SERVER_ERROR,
203
+ body: {},
204
+ headers: res.headers,
205
+ });
206
+ }
207
+ });
208
+ });
209
+ req.on('error', (error) => {
210
+ logger.error('HTTP request failed', {
211
+ host: this.config.host,
212
+ port: this.config.port,
213
+ path,
214
+ method,
215
+ error: error.message,
216
+ });
217
+ reject(error);
218
+ });
219
+ req.on('timeout', () => {
220
+ req.destroy();
221
+ const error = new Error(`Request timeout after ${this.config.timeout}ms`);
222
+ logger.warn('HTTP request timeout', {
223
+ host: this.config.host,
224
+ path,
225
+ timeout: this.config.timeout,
226
+ });
227
+ reject(error);
228
+ });
229
+ if (bodyStr) {
230
+ req.write(bodyStr);
231
+ }
232
+ req.end();
233
+ });
234
+ }
235
+ }
236
+ exports.InternalHttpClient = InternalHttpClient;
237
+ /**
238
+ * Create an HTTP client with error handling that returns null on failure.
239
+ * Useful for fail-open scenarios.
240
+ *
241
+ * @param config - Service configuration
242
+ * @returns Client wrapper with safe methods
243
+ */
244
+ function createSafeClient(config) {
245
+ const client = new InternalHttpClient(config);
246
+ return {
247
+ /**
248
+ * Safe GET request - returns null on error.
249
+ */
250
+ async get(path, options) {
251
+ try {
252
+ return await client.get(path, options);
253
+ }
254
+ catch (err) {
255
+ logger.debug('Safe GET failed, returning null', { path, error: err instanceof Error ? err.message : String(err) });
256
+ return null;
257
+ }
258
+ },
259
+ /**
260
+ * Safe POST request - returns null on error.
261
+ */
262
+ async post(path, body, options) {
263
+ try {
264
+ return await client.post(path, body, options);
265
+ }
266
+ catch (err) {
267
+ logger.debug('Safe POST failed, returning null', { path, error: err instanceof Error ? err.message : String(err) });
268
+ return null;
269
+ }
270
+ },
271
+ /**
272
+ * Safe PUT request - returns null on error.
273
+ */
274
+ async put(path, body, options) {
275
+ try {
276
+ return await client.put(path, body, options);
277
+ }
278
+ catch (err) {
279
+ logger.debug('Safe PUT failed, returning null', { path, error: err instanceof Error ? err.message : String(err) });
280
+ return null;
281
+ }
282
+ },
283
+ };
284
+ }
285
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaHR0cC1jbGllbnQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvc2VydmljZXMvaHR0cC1jbGllbnQudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IjtBQUFBLCtDQUErQztBQUMvQyxzQ0FBc0M7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztBQWdTdEMsNENBZ0RDO0FBOVVELDJDQUE2QjtBQUM3QixxREFPMEI7QUFDMUIsMERBQXNEO0FBRXRELDRDQUErQztBQUUvQyx1REFBdUQ7QUFDdkQsbURBQThEO0FBQXJELGlIQUFBLGVBQWUsT0FBQTtBQUFFLDJHQUFBLFNBQVMsT0FBQTtBQUVuQyxNQUFNLE1BQU0sR0FBRyxJQUFBLHFCQUFZLEVBQUMsYUFBYSxDQUFDLENBQUM7QUFFM0M7O0dBRUc7QUFDSCxNQUFNLGVBQWUsR0FBRyxRQUFRLENBQUMsT0FBTyxDQUFDLEdBQUcsQ0FBQyxtQkFBbUIsSUFBSSxNQUFNLEVBQUUsRUFBRSxDQUFDLENBQUM7QUFnQ2hGOzs7Ozs7Ozs7Ozs7OztHQWNHO0FBQ0gsTUFBYSxrQkFBa0I7SUFDckIsTUFBTSxDQUEwQjtJQUNoQyxLQUFLLENBQWE7SUFFMUI7Ozs7T0FJRztJQUNILFlBQVksTUFBcUI7UUFDL0IsSUFBSSxDQUFDLE1BQU0sR0FBRztZQUNaLElBQUksRUFBRSxNQUFNLENBQUMsSUFBSTtZQUNqQixJQUFJLEVBQUUsTUFBTSxDQUFDLElBQUk7WUFDakIsT0FBTyxFQUFFLE1BQU0sQ0FBQyxPQUFPLElBQUksZUFBZTtTQUMzQyxDQUFDO1FBQ0YsSUFBSSxDQUFDLEtBQUssR0FBRyxJQUFJLElBQUksQ0FBQyxLQUFLLENBQUMsRUFBRSxTQUFTLEVBQUUsSUFBSSxFQUFFLENBQUMsQ0FBQztJQUNuRCxDQUFDO0lBRUQ7O09BRUc7SUFDSCxLQUFLLENBQUMsR0FBRyxDQUFjLElBQVksRUFBRSxPQUF3QjtRQUMzRCxPQUFPLElBQUksQ0FBQyxnQkFBZ0IsQ0FBSSxLQUFL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QUV4QixJQUFJLENBQUM7Z0JBQ0gsT0FBTyxNQUFNLE1BQU0sQ0FBQyxJQUFJLENBQUksSUFBSSxFQUFFLElBQUksRUFBRSxPQUFPLENBQUMsQ0FBQztZQUNuRCxDQUFDO1lBQUMsT0FBTyxHQUFHLEVBQUUsQ0FBQztnQkFDYixNQUFNLENBQUMsS0FBSyxDQUFDLGtDQUFrQyxFQUFFLEVBQUUsSUFBSSxFQUFFLEtBQUssRUFBRSxHQUFHLFlBQVksS0FBSyxDQUFDLENBQUMsQ0FBQyxHQUFHLENBQUMsT0FBTyxDQUFDLENBQUMsQ0FBQyxNQUFNLENBQUMsR0FBRyxDQUFDLEVBQUUsQ0FBQyxDQUFDO2dCQUNwSCxPQUFPLElBQUksQ0FBQztZQUNkLENBQUM7UUFDSCxDQUFDO1FBRUQ7O1dBRUc7UUFDSCxLQUFLLENBQUMsR0FBRyxDQUNQLElBQVksRUFDWixJQUFjLEVBQ2QsT0FBd0I7WUFFeEIsSUFBSSxDQUFDO2dCQUNILE9BQU8sTUFBTSxNQUFNLENBQUMsR0FBRyxDQUFJLElBQUksRUFBRSxJQUFJLEVBQUUsT0FBTyxDQUFDLENBQUM7WUFDbEQsQ0FBQztZQUFDLE9BQU8sR0FBRyxFQUFFLENBQUM7Z0JBQ2IsTUFBTSxDQUFDLEtBQUssQ0FBQyxpQ0FBaUMsRUFBRSxFQUFFLElBQUksRUFBRSxLQUFLLEVBQUUsR0FBRyxZQUFZLEtBQUssQ0FBQyxDQUFDLENBQUMsR0FBRyxDQUFDLE9BQU8sQ0FBQyxDQUFDLENBQUMsTUFBTSxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUMsQ0FBQztnQkFDbkgsT0FBTyxJQUFJLENBQUM7WUFDZCxDQUFDO1FBQ0gsQ0FBQztLQUNGLENBQUM7QUFDSixDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiLy8gQ29weXJpZ2h0IDIwMjYgUGlwZWxpbmUgQnVpbGRlciBDb250cmlidXRvcnNcbi8vIFNQRFgtTGljZW5zZS1JZGVudGlmaWVyOiBBcGFjaGUtMi4wXG5cbmltcG9ydCAqIGFzIGh0dHAgZnJvbSAnaHR0cCc7XG5pbXBvcnQge1xuICBERUZBVUxUX01BWF9SRVRSSUVTLFxuICBERUZBVUxUX1JFVFJZX0RFTEFZX01TLFxuICBERUZBVUxUX01BWF9SQVRFX0xJTUlUX1JFVFJJRVMsXG4gIGdldFJldHJ5RGVjaXNpb24sXG4gIGdldEVycm9yUmV0cnlEZWNpc2lvbixcbiAgUmV0cnlDb25maWcsXG59IGZyb20gJy4vcmV0cnktc3RyYXRlZ3knO1xuaW1wb3J0IHsgSHR0cFN0YXR1cyB9IGZyb20gJy4uL2NvbnN0YW50cy9odHRwLXN0YXR1cyc7XG5pbXBvcnQgeyBTZXJ2aWNlQ29uZmlnIH0gZnJvbSAnLi4vdHlwZXMvY29tbW9uJztcbmltcG9ydCB7IGNyZWF0ZUxvZ2dlciB9IGZyb20gJy4uL3V0aWxzL2xvZ2dlcic7XG5cbi8vIFJlLWV4cG9ydCByZXRyeSB1dGlsaXRpZXMgZm9yIGJhY2t3YXJkIGNvbXBhdGliaWxpdHlcbmV4cG9ydCB7IHBhcnNlUmV0cnlBZnRlciwgYWRkSml0dGVyIH0gZnJvbSAnLi9yZXRyeS1zdHJhdGVneSc7XG5cbmNvbnN0IGxvZ2dlciA9IGNyZWF0ZUxvZ2dlcignaHR0cC1jbGllbnQnKTtcblxuLyoqXG4gKiBEZWZhdWx0IHJlcXVlc3QgdGltZW91dCBpbiBtaWxsaXNlY29uZHMgKGVudjogYEhUVFBfQ0xJRU5UX1RJTUVPVVRgKS5cbiAqL1xuY29uc3QgREVGQVVMVF9USU1FT1VUID0gcGFyc2VJbnQocHJvY2Vzcy5lbnYuSFRUUF9DTElFTlRfVElNRU9VVCB8fCAnNTAwMCcsIDEwKTtcblxuLyoqXG4gKiBIVFRQIHJlcXVlc3Qgb3B0aW9ucy5cbiAqL1xuZXhwb3J0IGludGVyZmFjZSBSZXF1ZXN0T3B0aW9ucyB7XG4gIC8qKiBSZXF1ZXN0IGhlYWRlcnMgKi9cbiAgaGVhZGVycz86IFJlY29yZDxzdHJpbmcsIHN0cmluZz47XG4gIC8qKiBSZXF1ZXN0IHRpbWVvdXQgaW4gbWlsbGlzZWNvbmRzICovXG4gIHRpbWVvdXQ/OiBudW1iZXI7XG4gIC8qKiBNYXhpbXVtIHJldHJ5IGF0dGVtcHRzIGZvciB0cmFuc2llbnQgZmFpbHVyZXMgKGRlZmF1bHQ6IDIpICovXG4gIG1heFJldHJpZXM/OiBudW1iZXI7XG4gIC8qKiBCYXNlIGRlbGF5IGJldHdlZW4gcmV0cmllcyBpbiBtcyDigJQgZG91YmxlcyBlYWNoIGF0dGVtcHQgKGRlZmF1bHQ6IDIwMCkgKi9cbiAgcmV0cnlEZWxheU1zPzogbnVtYmVyO1xuICAvKiogTWF4aW11bSByZXRyeSBhdHRlbXB0cyBzcGVjaWZpY2FsbHkgZm9yIDQyOSByYXRlIGxpbWl0aW5nIChkZWZhdWx0OiA0KSAqL1xuICBtYXhSYXRlTGltaXRSZXRyaWVzPzogbnVtYmVyO1xuICAvKiogT3B0aW9uYWwgcmVxdWVzdCBJRCBmb3IgZGlzdHJpYnV0ZWQgdHJhY2luZyAoYWRkZWQgYXMgWC1SZXF1ZXN0LUlkIGhlYWRlcikgKi9cbiAgcmVxdWVzdElkPzogc3RyaW5nO1xufVxuXG4vKipcbiAqIEhUVFAgY2xpZW50IHJlc3BvbnNlIHdyYXBwZXIuXG4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgSHR0cENsaWVudFJlc3BvbnNlPFQgPSB1bmtub3duPiB7XG4gIC8qKiBIVFRQIHN0YXR1cyBjb2RlICovXG4gIHN0YXR1c0NvZGU6IG51bWJlcjtcbiAgLyoqIFJlc3BvbnNlIGJvZHkgKHBhcnNlZCBKU09OKSAqL1xuICBib2R5OiBUO1xuICAvKiogUmVzcG9uc2UgaGVhZGVycyAqL1xuICBoZWFkZXJzOiBodHRwLkluY29taW5nSHR0cEhlYWRlcnM7XG59XG5cbi8qKlxuICogSW50ZXJuYWwgSFRUUCBjbGllbnQgZm9yIHNlcnZpY2UtdG8tc2VydmljZSBjb21tdW5pY2F0aW9uLlxuICpcbiAqIEBleGFtcGxlXG4gKiBgYGB0eXBlc2NyaXB0XG4gKiBjb25zdCBjbGllbnQgPSBuZXcgSW50ZXJuYWxIdHRwQ2xpZW50KHtcbiAqICAgaG9zdDogJ3F1b3RhJyxcbiAqICAgcG9ydDogMzAwMCxcbiAqICAgdGltZW91dDogNTAwMCxcbiAqIH0pO1xuICpcbiAqIGNvbnN0IHJlc3BvbnNlID0gYXdhaXQgY2xpZW50LmdldCgnL29yZzEyMy9hcGlDYWxscycpO1xuICogY29uc3QgcmVzdWx0ID0gYXdhaXQgY2xpZW50LnBvc3QoJy9vcmcxMjMvaW5jcmVtZW50JywgeyBxdW90YVR5cGU6ICdhcGlDYWxscycgfSk7XG4gKiBgYGBcbiAqL1xuZXhwb3J0IGNsYXNzIEludGVybmFsSHR0cENsaWVudCB7XG4gIHByaXZhdGUgY29uZmlnOiBSZXF1aXJlZDxTZXJ2aWNlQ29uZmlnPjtcbiAgcHJpdmF0ZSBhZ2VudDogaHR0cC5BZ2VudDtcblxuICAvKipcbiAgICogQ3JlYXRlIGEgbmV3IEhUVFAgY2xpZW50IGluc3RhbmNlLlxuICAgKlxuICAgKiBAcGFyYW0gY29uZmlnIC0gU2VydmljZSBjb25maWd1cmF0aW9uXG4gICAqL1xuICBjb25zdHJ1Y3Rvcihjb25maWc6IFNlcnZpY2VDb25maWcpIHtcbiAgICB0aGlzLmNvbmZpZyA9IHtcbiAgICAgIGhvc3Q6IGNvbmZpZy5ob3N0LFxuICAgICAgcG9ydDogY29uZmlnLnBvcnQsXG4gICAgICB0aW1lb3V0OiBjb25maWcudGltZW91dCA/PyBERUZBVUxUX1RJTUVPVVQsXG4gICAgfTtcbiAgICB0aGlzLmFnZW50ID0gbmV3IGh0dHAuQWdlbnQoeyBrZWVwQWxpdmU6IHRydWUgfSk7XG4gIH1cblxuICAvKipcbiAgICogTWFrZSBhIEdFVCByZXF1ZXN0LlxuICAgKi9cbiAgYXN5bmMgZ2V0PFQgPSB1bmtub3duPihwYXRoOiBzdHJpbmcsIG9wdGlvbnM/OiBSZXF1ZXN0T3B0aW9ucyk6IFByb21pc2U8SHR0cENsaWVudFJlc3BvbnNlPFQ+PiB7XG4gICAgcmV0dXJuIHRoaXMucmVxdWVzdFdpdGhSZXRyeTxUPignR0VUJywgcGF0aCwgdW5kZWZpbmVkLCBvcHRpb25zKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBNYWtlIGEgUE9TVCByZXF1ZXN0LlxuICAgKi9cbiAgYXN5bmMgcG9zdDxUID0gdW5rbm93bj4oXG4gICAgcGF0aDogc3RyaW5nLFxuICAgIGJvZHk/OiB1bmtub3duLFxuICAgIG9wdGlvbnM/OiBSZXF1ZXN0T3B0aW9ucyxcbiAgKTogUHJvbWlzZTxIdHRwQ2xpZW50UmVzcG9uc2U8VD4+IHtcbiAgICByZXR1cm4gdGhpcy5yZXF1ZXN0V2l0aFJldHJ5PFQ+KCdQT1NUJywgcGF0aCwgYm9keSwgb3B0aW9ucyk7XG4gIH1cblxuICAvKipcbiAgICogTWFrZSBhIFBVVCByZXF1ZXN0LlxuICAgKi9cbiAgYXN5bmMgcHV0PFQgPSB1bmtub3duPihcbiAgICBwYXRoOiBzdHJpbmcsXG4gICAgYm9keT86IHVua25vd24sXG4gICAgb3B0aW9ucz86IFJlcXVlc3RPcHRpb25zLFxuICApOiBQcm9taXNlPEh0dHBDbGllbnRSZXNwb25zZTxUPj4ge1xuICAgIHJldHVybiB0aGlzLnJlcXVlc3RXaXRoUmV0cnk8VD4oJ1BVVCcsIHBhdGgsIGJvZHksIG9wdGlvbnMpO1xuICB9XG5cbiAgLyoqXG4gICAqIE1ha2UgYSBERUxFVEUgcmVxdWVzdC5cbiAgICovXG4gIGFzeW5jIGRlbGV0ZTxUID0gdW5rbm93bj4ocGF0aDogc3RyaW5nLCBvcHRpb25zPzogUmVxdWVzdE9wdGlvbnMpOiBQcm9taXNlPEh0dHBDbGllbnRSZXNwb25zZTxUPj4ge1xuICAgIHJldHVybiB0aGlzLnJlcXVlc3RXaXRoUmV0cnk8VD4oJ0RFTEVURScsIHBhdGgsIHVuZGVmaW5lZCwgb3B0aW9ucyk7XG4gIH1cblxuICAvKipcbiAgICogUmVxdWVzdCB3aXRoIHJldHJ5IGxvZ2ljIGZvciB0cmFuc2llbnQgZmFpbHVyZXMuXG4gICAqXG4gICAqIC0gNDI5IChyYXRlIGxpbWl0KTogcmVzcGVjdHMgYFJldHJ5LUFmdGVyYCBoZWFkZXIsIHVzZXMgbG9uZ2VyIGJhc2UgZGVsYXkgKDR4KSxcbiAgICogICByZXRyaWVzIHVwIHRvIGBtYXhSYXRlTGltaXRSZXRyaWVzYCB0aW1lcyAoZGVmYXVsdCA0KS5cbiAgICogLSA1MDIvNTAzLzUwNCAoc2VydmVyIGVycm9ycyk6IHN0YW5kYXJkIGV4cG9uZW50aWFsIGJhY2tvZmYsIHVwIHRvIGBtYXhSZXRyaWVzYCAoZGVmYXVsdCAyKS5cbiAgICogLSBDb25uZWN0aW9uIGVycm9ycyAvIHRpbWVvdXRzOiByZXRyaWVzIHVwIHRvIGBtYXhSZXRyaWVzYC5cbiAgICogLSBBbGwgZGVsYXlzIGluY2x1ZGUgwrEyNSUgaml0dGVyIHRvIHByZXZlbnQgdGh1bmRlcmluZyBoZXJkLlxuICAgKi9cbiAgcHJpdmF0ZSBhc3luYyByZXF1ZXN0V2l0aFJldHJ5PFQ+KFxuICAgIG1ldGhvZDogc3RyaW5nLFxuICAgIHBhdGg6IHN0cmluZyxcbiAgICBib2R5PzogdW5rbm93bixcbiAgICBvcHRpb25zPzogUmVxdWVzdE9wdGlvbnMsXG4gICk6IFByb21pc2U8SHR0cENsaWVudFJlc3BvbnNlPFQ+PiB7XG4gICAgY29uc3QgcmV0cnlDb25maWc6IFJldHJ5Q29uZmlnID0ge1xuICAgICAgbWF4UmV0cmllczogb3B0aW9ucz8ubWF4UmV0cmllcyA/PyBERUZBVUxUX01BWF9SRVRSSUVTLFxuICAgICAgbWF4UmF0ZUxpbWl0UmV0cmllczogb3B0aW9ucz8ubWF4UmF0ZUxpbWl0UmV0cmllcyA/PyBERUZBVUxUX01BWF9SQVRFX0xJTUlUX1JFVFJJRVMsXG4gICAgICByZXRyeURlbGF5TXM6IG9wdGlvbnM/LnJldHJ5RGVsYXlNcyA/PyBERUZBVUxUX1JFVFJZX0RFTEFZX01TLFxuICAgIH07XG4gICAgY29uc3QgdG90YWxNYXhBdHRlbXB0cyA9IE1hdGgubWF4KHJldHJ5Q29uZmlnLm1heFJldHJpZXMsIHJldHJ5Q29uZmlnLm1heFJhdGVMaW1pdFJldHJpZXMpO1xuXG4gICAgbGV0IGxhc3RFcnJvcjogRXJyb3IgfCB1bmRlZmluZWQ7XG5cbiAgICBmb3IgKGxldCBhdHRlbXB0ID0gMDsgYXR0ZW1wdCA8PSB0b3RhbE1heEF0dGVtcHRzOyBhdHRlbXB0KyspIHtcbiAgICAgIHRyeSB7XG4gICAgICAgIGNvbnN0IHJlc3BvbnNlID0gYXdhaXQgdGhpcy5yZXF1ZXN0PFQ+KG1ldGhvZCwgcGF0aCwgYm9keSwgb3B0aW9ucyk7XG5cbiAgICAgICAgY29uc3QgZGVjaXNpb24gPSBnZXRSZXRyeURlY2lzaW9uKHJlc3BvbnNlLnN0YXR1c0NvZGUsIHJlc3BvbnNlLmhlYWRlcnMsIGF0dGVtcHQsIHJldHJ5Q29uZmlnKTtcbiAgICAgICAgaWYgKGRlY2lzaW9uLnNob3VsZFJldHJ5KSB7XG4gICAgICAgICAgbG9nZ2VyLmRlYnVnKGRlY2lzaW9uLnJlYXNvbiArICcsIHJldHJ5aW5nJywgeyBtZXRob2QsIHBhdGgsIGF0dGVtcHQ6IGF0dGVtcHQgKyAxLCBkZWxheU1zOiBkZWNpc2lvbi5kZWxheU1zIH0pO1xuICAgICAgICAgIGF3YWl0IHRoaXMuc2xlZXAoZGVjaXNpb24uZGVsYXlNcyk7XG4gICAgICAgICAgY29udGludWU7XG4gICAgICAgIH1cblxuICAgICAgICByZXR1cm4gcmVzcG9uc2U7XG4gICAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgICBsYXN0RXJyb3IgPSBlcnJvciBpbnN0YW5jZW9mIEVycm9yID8gZXJyb3IgOiBuZXcgRXJyb3IoU3RyaW5nKGVycm9yKSk7XG5cbiAgICAgICAgY29uc3QgZGVjaXNpb24gPSBnZXRFcnJvclJldHJ5RGVjaXNpb24oYXR0ZW1wdCwgcmV0cnlDb25maWcpO1xuICAgICAgICBpZiAoZGVjaXNpb24uc2hvdWxkUmV0cnkpIHtcbiAgICAgICAgICBsb2dnZXIuZGVidWcoJ1JldHJ5aW5nIGFmdGVyIGVycm9yJywgeyBtZXRob2QsIHBhdGgsIGVycm9yOiBsYXN0RXJyb3IubWVzc2FnZSwgYXR0ZW1wdDogYXR0ZW1wdCArIDEgfSk7XG4gICAgICAgICAgYXdhaXQgdGhpcy5zbGVlcChkZWNpc2lvbi5kZWxheU1zKTtcbiAgICAgICAgICBjb250aW51ZTtcbiAgICAgICAgfVxuICAgICAgfVxuICAgIH1cblxuICAgIHRocm93IGxhc3RFcnJvciE7XG4gIH1cblxuICBwcml2YXRlIHNsZWVwKG1zOiBudW1iZXIpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICByZXR1cm4gbmV3IFByb21pc2UocmVzb2x2ZSA9PiBzZXRUaW1lb3V0KHJlc29sdmUsIG1zKSk7XG4gIH1cblxuICAvKipcbiAgICogSW50ZXJuYWwgcmVxdWVzdCBtZXRob2QuXG4gICAqL1xuICBwcml2YXRlIHJlcXVlc3Q8VD4oXG4gICAgbWV0aG9kOiBzdHJpbmcsXG4gICAgcGF0aDogc3RyaW5nLFxuICAgIGJvZHk/OiB1bmtub3duLFxuICAgIG9wdGlvbnM/OiBSZXF1ZXN0T3B0aW9ucyxcbiAgKTogUHJvbWlzZTxIdHRwQ2xpZW50UmVzcG9uc2U8VD4+IHtcbiAgICByZXR1cm4gbmV3IFByb21pc2UoKHJlc29sdmUsIHJlamVjdCkgPT4ge1xuICAgICAgY29uc3QgYm9keVN0ciA9IGJvZHkgPyBKU09OLnN0cmluZ2lmeShib2R5KSA6IHVuZGVmaW5lZDtcblxuICAgICAgY29uc3QgaGVhZGVyczogaHR0cC5PdXRnb2luZ0h0dHBIZWFkZXJzID0ge1xuICAgICAgICAnQ29udGVudC1UeXBlJzogJ2FwcGxpY2F0aW9uL2pzb24nLFxuICAgICAgICAuLi5vcHRpb25zPy5oZWFkZXJzLFxuICAgICAgfTtcblxuICAgICAgLy8gUHJvcGFnYXRlIHJlcXVlc3QgSUQgZm9yIGRpc3RyaWJ1dGVkIHRyYWNpbmdcbiAgICAgIGlmIChvcHRpb25zPy5yZXF1ZXN0SWQpIHtcbiAgICAgICAgaGVhZGVyc1snWC1SZXF1ZXN0LUlkJ10gPSBvcHRpb25zLnJlcXVlc3RJZDtcbiAgICAgIH1cblxuICAgICAgaWYgKGJvZHlTdHIpIHtcbiAgICAgICAgaGVhZGVyc1snQ29udGVudC1MZW5ndGgnXSA9IEJ1ZmZlci5ieXRlTGVuZ3RoKGJvZHlTdHIpO1xuICAgICAgfVxuXG4gICAgICAvLyBWYWxpZGF0ZSBwYXRoIHRvIHByZXZlbnQgcHJvdG9jb2wgaW5qZWN0aW9uIC8gcmVxdWVzdCBzbXVnZ2xpbmdcbiAgICAgIGlmIChwYXRoLmluY2x1ZGVzKCc6Ly8nKSB8fCBwYXRoLnN0YXJ0c1dpdGgoJy8vJykgfHwgL1tcXHJcXG5cXDBdLy50ZXN0KHBhdGgpKSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcihgSW52YWxpZCByZXF1ZXN0IHBhdGg6ICR7cGF0aH1gKTtcbiAgICAgIH1cblxuICAgICAgY29uc3QgcmVxdWVzdE9wdGlvbnM6IGh0dHAuUmVxdWVzdE9wdGlvbnMgPSB7XG4gICAgICAgIGhvc3RuYW1lOiB0aGlzLmNvbmZpZy5ob3N0LFxuICAgICAgICBwb3J0OiB0aGlzLmNvbmZpZy5wb3J0LFxuICAgICAgICBwYXRoOiBwYXRoLnN0YXJ0c1dpdGgoJy8nKSA/IHBhdGggOiBgLyR7cGF0aH1gLFxuICAgICAgICBtZXRob2QsXG4gICAgICAgIGhlYWRlcnMsXG4gICAgICAgIHRpbWVvdXQ6IG9wdGlvbnM/LnRpbWVvdXQgPz8gdGhpcy5jb25maWcudGltZW91dCxcbiAgICAgICAgYWdlbnQ6IHRoaXMuYWdlbnQsXG4gICAgICB9O1xuXG4gICAgICBjb25zdCByZXEgPSBodHRwLnJlcXVlc3QocmVxdWVzdE9wdGlvbnMsIChyZXMpID0+IHtcbiAgICAgICAgbGV0IGRhdGEgPSAnJztcblxuICAgICAgICByZXMub24oJ2RhdGEnLCAoY2h1bmspID0+IHtcbiAgICAgICAgICBkYXRhICs9IGNodW5rO1xuICAgICAgICB9KTtcblxuICAgICAgICByZXMub24oJ2VuZCcsICgpID0+IHtcbiAgICAgICAgICB0cnkge1xuICAgICAgICAgICAgY29uc3QgcGFyc2VkQm9keSA9IGRhdGEgPyBKU09OLnBhcnNlKGRhdGEpIDoge307XG4gICAgICAgICAgICByZXNvbHZlKHtcbiAgICAgICAgICAgICAgc3RhdHVzQ29kZTogcmVzLnN0YXR1c0NvZGUgfHwgSHR0cFN0YXR1cy5JTlRFUk5BTF9TRVJWRVJfRVJST1IsXG4gICAgICAgICAgICAgIGJvZHk6IHBhcnNlZEJvZHkgYXMgVCxcbiAgICAgICAgICAgICAgaGVhZGVyczogcmVzLmhlYWRlcnMsXG4gICAgICAgICAgICB9KTtcbiAgICAgICAgICB9IGNhdGNoIChwYXJzZUVycm9yKSB7XG4gICAgICAgICAgICBsb2dnZXIud2FybignRmFpbGVkIHRvIHBhcnNlIHJlc3BvbnNlIGJvZHknLCB7XG4gICAgICAgICAgICAgIGhvc3Q6IHRoaXMuY29uZmlnLmhvc3QsXG4gICAgICAgICAgICAgIHBhdGgsXG4gICAgICAgICAgICAgIGVycm9yOiBwYXJzZUVycm9yIGluc3RhbmNlb2YgRXJyb3IgPyBwYXJzZUVycm9yLm1lc3NhZ2UgOiBTdHJpbmcocGFyc2VFcnJvciksXG4gICAgICAgICAgICB9KTtcbiAgICAgICAgICAgIHJlc29sdmUoe1xuICAgICAgICAgICAgICBzdGF0dXNDb2RlOiByZXMuc3RhdHVzQ29kZSB8fCBIdHRwU3RhdHVzLklOVEVSTkFMX1NFUlZFUl9FUlJPUixcbiAgICAgICAgICAgICAgYm9keToge30gYXMgVCxcbiAgICAgICAgICAgICAgaGVhZGVyczogcmVzLmhlYWRlcnMsXG4gICAgICAgICAgICB9KTtcbiAgICAgICAgICB9XG4gICAgICAgIH0pO1xuICAgICAgfSk7XG5cbiAgICAgIHJlcS5vbignZXJyb3InLCAoZXJyb3IpID0+IHtcbiAgICAgICAgbG9nZ2VyLmVycm9yKCdIVFRQIHJlcXVlc3QgZmFpbGVkJywge1xuICAgICAgICAgIGhvc3Q6IHRoaXMuY29uZmlnLmhvc3QsXG4gICAgICAgICAgcG9ydDogdGhpcy5jb25maWcucG9ydCxcbiAgICAgICAgICBwYXRoLFxuICAgICAgICAgIG1ldGhvZCxcbiAgICAgICAgICBlcnJvcjogZXJyb3IubWVzc2FnZSxcbiAgICAgICAgfSk7XG4gICAgICAgIHJlamVjdChlcnJvcik7XG4gICAgICB9KTtcblxuICAgICAgcmVxLm9uKCd0aW1lb3V0JywgKCkgPT4ge1xuICAgICAgICByZXEuZGVzdHJveSgpO1xuICAgICAgICBjb25zdCBlcnJvciA9IG5ldyBFcnJvcihgUmVxdWVzdCB0aW1lb3V0IGFmdGVyICR7dGhpcy5jb25maWcudGltZW91dH1tc2ApO1xuICAgICAgICBsb2dnZXIud2FybignSFRUUCByZXF1ZXN0IHRpbWVvdXQnLCB7XG4gICAgICAgICAgaG9zdDogdGhpcy5jb25maWcuaG9zdCxcbiAgICAgICAgICBwYXRoLFxuICAgICAgICAgIHRpbWVvdXQ6IHRoaXMuY29uZmlnLnRpbWVvdXQsXG4gICAgICAgIH0pO1xuICAgICAgICByZWplY3QoZXJyb3IpO1xuICAgICAgfSk7XG5cbiAgICAgIGlmIChib2R5U3RyKSB7XG4gICAgICAgIHJlcS53cml0ZShib2R5U3RyKTtcbiAgICAgIH1cblxuICAgICAgcmVxLmVuZCgpO1xuICAgIH0pO1xuICB9XG59XG5cbi8qKlxuICogQ3JlYXRlIGFuIEhUVFAgY2xpZW50IHdpdGggZXJyb3IgaGFuZGxpbmcgdGhhdCByZXR1cm5zIG51bGwgb24gZmFpbHVyZS5cbiAqIFVzZWZ1bCBmb3IgZmFpbC1vcGVuIHNjZW5hcmlvcy5cbiAqXG4gKiBAcGFyYW0gY29uZmlnIC0gU2VydmljZSBjb25maWd1cmF0aW9uXG4gKiBAcmV0dXJucyBDbGllbnQgd3JhcHBlciB3aXRoIHNhZmUgbWV0aG9kc1xuICovXG5leHBvcnQgZnVuY3Rpb24gY3JlYXRlU2FmZUNsaWVudChjb25maWc6IFNlcnZpY2VDb25maWcpIHtcbiAgY29uc3QgY2xpZW50ID0gbmV3IEludGVybmFsSHR0cENsaWVudChjb25maWcpO1xuXG4gIHJldHVybiB7XG4gICAgLyoqXG4gICAgICogU2FmZSBHRVQgcmVxdWVzdCAtIHJldHVybnMgbnVsbCBvbiBlcnJvci5cbiAgICAgKi9cbiAgICBhc3luYyBnZXQ8VD4ocGF0aDogc3RyaW5nLCBvcHRpb25zPzogUmVxdWVzdE9wdGlvbnMpOiBQcm9taXNlPEh0dHBDbGllbnRSZXNwb25zZTxUPiB8IG51bGw+IHtcbiAgICAgIHRyeSB7XG4gICAgICAgIHJldHVybiBhd2FpdCBjbGllbnQuZ2V0PFQ+KHBhdGgsIG9wdGlvbnMpO1xuICAgICAgfSBjYXRjaCAoZXJyKSB7XG4gICAgICAgIGxvZ2dlci5kZWJ1ZygnU2FmZSBHRVQgZmFpbGVkLCByZXR1cm5pbmcgbnVsbCcsIHsgcGF0aCwgZXJyb3I6IGVyciBpbnN0YW5jZW9mIEVycm9yID8gZXJyLm1lc3NhZ2UgOiBTdHJpbmcoZXJyKSB9KTtcbiAgICAgICAgcmV0dXJuIG51bGw7XG4gICAgICB9XG4gICAgfSxcblxuICAgIC8qKlxuICAgICAqIFNhZmUgUE9TVCByZXF1ZXN0IC0gcmV0dXJucyBudWxsIG9uIGVycm9yLlxuICAgICAqL1xuICAgIGFzeW5jIHBvc3Q8VD4oXG4gICAgICBwYXRoOiBzdHJpbmcsXG4gICAgICBib2R5PzogdW5rbm93bixcbiAgICAgIG9wdGlvbnM/OiBSZXF1ZXN0T3B0aW9ucyxcbiAgICApOiBQcm9taXNlPEh0dHBDbGllbnRSZXNwb25zZTxUPiB8IG51bGw+IHtcbiAgICAgIHRyeSB7XG4gICAgICAgIHJldHVybiBhd2FpdCBjbGllbnQucG9zdDxUPihwYXRoLCBib2R5LCBvcHRpb25zKTtcbiAgICAgIH0gY2F0Y2ggKGVycikge1xuICAgICAgICBsb2dnZXIuZGVidWcoJ1NhZmUgUE9TVCBmYWlsZWQsIHJldHVybmluZyBudWxsJywgeyBwYXRoLCBlcnJvcjogZXJyIGluc3RhbmNlb2YgRXJyb3IgPyBlcnIubWVzc2FnZSA6IFN0cmluZyhlcnIpIH0pO1xuICAgICAgICByZXR1cm4gbnVsbDtcbiAgICAgIH1cbiAgICB9LFxuXG4gICAgLyoqXG4gICAgICogU2FmZSBQVVQgcmVxdWVzdCAtIHJldHVybnMgbnVsbCBvbiBlcnJvci5cbiAgICAgKi9cbiAgICBhc3luYyBwdXQ8VD4oXG4gICAgICBwYXRoOiBzdHJpbmcsXG4gICAgICBib2R5PzogdW5rbm93bixcbiAgICAgIG9wdGlvbnM/OiBSZXF1ZXN0T3B0aW9ucyxcbiAgICApOiBQcm9taXNlPEh0dHBDbGllbnRSZXNwb25zZTxUPiB8IG51bGw+IHtcbiAgICAgIHRyeSB7XG4gICAgICAgIHJldHVybiBhd2FpdCBjbGllbnQucHV0PFQ+KHBhdGgsIGJvZHksIG9wdGlvbnMpO1xuICAgICAgfSBjYXRjaCAoZXJyKSB7XG4gICAgICAgIGxvZ2dlci5kZWJ1ZygnU2FmZSBQVVQgZmFpbGVkLCByZXR1cm5pbmcgbnVsbCcsIHsgcGF0aCwgZXJyb3I6IGVyciBpbnN0YW5jZW9mIEVycm9yID8gZXJyLm1lc3NhZ2UgOiBTdHJpbmcoZXJyKSB9KTtcbiAgICAgICAgcmV0dXJuIG51bGw7XG4gICAgICB9XG4gICAgfSxcbiAgfTtcbn1cbiJdfQ==
@@ -0,0 +1,10 @@
1
+ export * from './cache-service';
2
+ export * from './compliance-client';
3
+ export * from './compliance-event-subscriber';
4
+ export * from './entity-events';
5
+ export * from './http-client';
6
+ export { DEFAULT_MAX_RETRIES, DEFAULT_RETRY_DELAY_MS, DEFAULT_MAX_RATE_LIMIT_RETRIES, calculateBackoff, isTransientStatusCode, isRateLimited, getRetryDecision, getErrorRetryDecision, } from './retry-strategy';
7
+ export type { RetryConfig, RetryDecision } from './retry-strategy';
8
+ export * from './quota';
9
+ export { logAdminAction, type AuditEntry } from './admin-audit';
10
+ export { enqueueComplianceEvent, registerComplianceQueueBackend, type ComplianceEvent } from './compliance-queue';
@@ -0,0 +1,40 @@
1
+ "use strict";
2
+ // Copyright 2026 Pipeline Builder Contributors
3
+ // SPDX-License-Identifier: Apache-2.0
4
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
5
+ if (k2 === undefined) k2 = k;
6
+ var desc = Object.getOwnPropertyDescriptor(m, k);
7
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
8
+ desc = { enumerable: true, get: function() { return m[k]; } };
9
+ }
10
+ Object.defineProperty(o, k2, desc);
11
+ }) : (function(o, m, k, k2) {
12
+ if (k2 === undefined) k2 = k;
13
+ o[k2] = m[k];
14
+ }));
15
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
16
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
17
+ };
18
+ Object.defineProperty(exports, "__esModule", { value: true });
19
+ exports.registerComplianceQueueBackend = exports.enqueueComplianceEvent = exports.logAdminAction = exports.getErrorRetryDecision = exports.getRetryDecision = exports.isRateLimited = exports.isTransientStatusCode = exports.calculateBackoff = exports.DEFAULT_MAX_RATE_LIMIT_RETRIES = exports.DEFAULT_RETRY_DELAY_MS = exports.DEFAULT_MAX_RETRIES = void 0;
20
+ __exportStar(require("./cache-service"), exports);
21
+ __exportStar(require("./compliance-client"), exports);
22
+ __exportStar(require("./compliance-event-subscriber"), exports);
23
+ __exportStar(require("./entity-events"), exports);
24
+ __exportStar(require("./http-client"), exports);
25
+ var retry_strategy_1 = require("./retry-strategy");
26
+ Object.defineProperty(exports, "DEFAULT_MAX_RETRIES", { enumerable: true, get: function () { return retry_strategy_1.DEFAULT_MAX_RETRIES; } });
27
+ Object.defineProperty(exports, "DEFAULT_RETRY_DELAY_MS", { enumerable: true, get: function () { return retry_strategy_1.DEFAULT_RETRY_DELAY_MS; } });
28
+ Object.defineProperty(exports, "DEFAULT_MAX_RATE_LIMIT_RETRIES", { enumerable: true, get: function () { return retry_strategy_1.DEFAULT_MAX_RATE_LIMIT_RETRIES; } });
29
+ Object.defineProperty(exports, "calculateBackoff", { enumerable: true, get: function () { return retry_strategy_1.calculateBackoff; } });
30
+ Object.defineProperty(exports, "isTransientStatusCode", { enumerable: true, get: function () { return retry_strategy_1.isTransientStatusCode; } });
31
+ Object.defineProperty(exports, "isRateLimited", { enumerable: true, get: function () { return retry_strategy_1.isRateLimited; } });
32
+ Object.defineProperty(exports, "getRetryDecision", { enumerable: true, get: function () { return retry_strategy_1.getRetryDecision; } });
33
+ Object.defineProperty(exports, "getErrorRetryDecision", { enumerable: true, get: function () { return retry_strategy_1.getErrorRetryDecision; } });
34
+ __exportStar(require("./quota"), exports);
35
+ var admin_audit_1 = require("./admin-audit");
36
+ Object.defineProperty(exports, "logAdminAction", { enumerable: true, get: function () { return admin_audit_1.logAdminAction; } });
37
+ var compliance_queue_1 = require("./compliance-queue");
38
+ Object.defineProperty(exports, "enqueueComplianceEvent", { enumerable: true, get: function () { return compliance_queue_1.enqueueComplianceEvent; } });
39
+ Object.defineProperty(exports, "registerComplianceQueueBackend", { enumerable: true, get: function () { return compliance_queue_1.registerComplianceQueueBackend; } });
40
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvc2VydmljZXMvaW5kZXgudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IjtBQUFBLCtDQUErQztBQUMvQyxzQ0FBc0M7Ozs7Ozs7Ozs7Ozs7Ozs7O0FBRXRDLGtEQUFnQztBQUNoQyxzREFBb0M7QUFDcEMsZ0VBQThDO0FBQzlDLGtEQUFnQztBQUNoQyxnREFBOEI7QUFDOUIsbURBUzBCO0FBUnhCLHFIQUFBLG1CQUFtQixPQUFBO0FBQ25CLHdIQUFBLHNCQUFzQixPQUFBO0FBQ3RCLGdJQUFBLDhCQUE4QixPQUFBO0FBQzlCLGtIQUFBLGdCQUFnQixPQUFBO0FBQ2hCLHVIQUFBLHFCQUFxQixPQUFBO0FBQ3JCLCtHQUFBLGFBQWEsT0FBQTtBQUNiLGtIQUFBLGdCQUFnQixPQUFBO0FBQ2hCLHVIQUFBLHFCQUFxQixPQUFBO0FBR3ZCLDBDQUF3QjtBQUN4Qiw2Q0FBZ0U7QUFBdkQsNkdBQUEsY0FBYyxPQUFBO0FBQ3ZCLHVEQUFrSDtBQUF6RywwSEFBQSxzQkFBc0IsT0FBQTtBQUFFLGtJQUFBLDhCQUE4QixPQUFBIiwic291cmNlc0NvbnRlbnQiOlsiLy8gQ29weXJpZ2h0IDIwMjYgUGlwZWxpbmUgQnVpbGRlciBDb250cmlidXRvcnNcbi8vIFNQRFgtTGljZW5zZS1JZGVudGlmaWVyOiBBcGFjaGUtMi4wXG5cbmV4cG9ydCAqIGZyb20gJy4vY2FjaGUtc2VydmljZSc7XG5leHBvcnQgKiBmcm9tICcuL2NvbXBsaWFuY2UtY2xpZW50JztcbmV4cG9ydCAqIGZyb20gJy4vY29tcGxpYW5jZS1ldmVudC1zdWJzY3JpYmVyJztcbmV4cG9ydCAqIGZyb20gJy4vZW50aXR5LWV2ZW50cyc7XG5leHBvcnQgKiBmcm9tICcuL2h0dHAtY2xpZW50JztcbmV4cG9ydCB7XG4gIERFRkFVTFRfTUFYX1JFVFJJRVMsXG4gIERFRkFVTFRfUkVUUllfREVMQVlfTVMsXG4gIERFRkFVTFRfTUFYX1JBVEVfTElNSVRfUkVUUklFUyxcbiAgY2FsY3VsYXRlQmFja29mZixcbiAgaXNUcmFuc2llbnRTdGF0dXNDb2RlLFxuICBpc1JhdGVMaW1pdGVkLFxuICBnZXRSZXRyeURlY2lzaW9uLFxuICBnZXRFcnJvclJldHJ5RGVjaXNpb24sXG59IGZyb20gJy4vcmV0cnktc3RyYXRlZ3knO1xuZXhwb3J0IHR5cGUgeyBSZXRyeUNvbmZpZywgUmV0cnlEZWNpc2lvbiB9IGZyb20gJy4vcmV0cnktc3RyYXRlZ3knO1xuZXhwb3J0ICogZnJvbSAnLi9xdW90YSc7XG5leHBvcnQgeyBsb2dBZG1pbkFjdGlvbiwgdHlwZSBBdWRpdEVudHJ5IH0gZnJvbSAnLi9hZG1pbi1hdWRpdCc7XG5leHBvcnQgeyBlbnF1ZXVlQ29tcGxpYW5jZUV2ZW50LCByZWdpc3RlckNvbXBsaWFuY2VRdWV1ZUJhY2tlbmQsIHR5cGUgQ29tcGxpYW5jZUV2ZW50IH0gZnJvbSAnLi9jb21wbGlhbmNlLXF1ZXVlJztcbiJdfQ==