@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,148 @@
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.getParam = getParam;
6
+ exports.getOrgId = getOrgId;
7
+ exports.getAuthHeader = getAuthHeader;
8
+ exports.parseQueryBoolean = parseQueryBoolean;
9
+ exports.parseQueryInt = parseQueryInt;
10
+ exports.parseQueryString = parseQueryString;
11
+ exports.parsePositiveInt = parsePositiveInt;
12
+ const headers_1 = require("./headers");
13
+ /**
14
+ * Extract a single string parameter from Express 5 route params.
15
+ *
16
+ * @param params - Request params object
17
+ * @param key - Parameter key
18
+ * @returns The parameter value as a string, or undefined if not present
19
+ *
20
+ * @example
21
+ * ```typescript
22
+ * // Route: GET /plugins/:id
23
+ * const id = getParam(req.params, 'id');
24
+ * if (!id) {
25
+ * return sendError(res, 400, 'Missing id parameter');
26
+ * }
27
+ * ```
28
+ */
29
+ function getParam(params, key) {
30
+ const value = params[key];
31
+ if (value === undefined) {
32
+ return undefined;
33
+ }
34
+ return Array.isArray(value) ? value[0] : value;
35
+ }
36
+ /**
37
+ * Extract the organization ID from request.
38
+ * Checks params, headers, and user object.
39
+ *
40
+ * @param req - Express request object
41
+ * @returns Organization ID or undefined
42
+ *
43
+ * @example
44
+ * ```typescript
45
+ * const orgId = getOrgId(req);
46
+ * if (!orgId) {
47
+ * return sendError(res, 400, 'Organization ID required');
48
+ * }
49
+ * ```
50
+ */
51
+ function getOrgId(req) {
52
+ // Check route params first
53
+ const paramOrgId = getParam(req.params, 'orgId');
54
+ if (paramOrgId) {
55
+ return paramOrgId;
56
+ }
57
+ // Check x-org-id header
58
+ const headerOrgId = (0, headers_1.getHeaderString)(req.headers['x-org-id'])?.trim();
59
+ if (headerOrgId) {
60
+ return headerOrgId;
61
+ }
62
+ // Check authenticated user
63
+ const userOrgId = req.user?.organizationId?.trim();
64
+ if (userOrgId) {
65
+ return userOrgId;
66
+ }
67
+ return undefined;
68
+ }
69
+ /**
70
+ * Get the authorization header from request.
71
+ *
72
+ * @param req - Express request object
73
+ * @returns Authorization header value or empty string
74
+ */
75
+ function getAuthHeader(req) {
76
+ return (0, headers_1.getHeaderString)(req.headers.authorization) ?? '';
77
+ }
78
+ /**
79
+ * Parse a query parameter as a boolean.
80
+ *
81
+ * @param value - Query parameter value
82
+ * @returns Parsed boolean or undefined
83
+ *
84
+ * @example
85
+ * ```typescript
86
+ * const isActive = parseQueryBoolean(req.query.isActive);
87
+ * ```
88
+ */
89
+ function parseQueryBoolean(value) {
90
+ if (value === undefined || value === null || value === '')
91
+ return undefined;
92
+ if (typeof value === 'boolean')
93
+ return value;
94
+ if (typeof value === 'string') {
95
+ const lower = value.toLowerCase();
96
+ if (lower === 'true' || lower === '1')
97
+ return true;
98
+ if (lower === 'false' || lower === '0')
99
+ return false;
100
+ }
101
+ return undefined;
102
+ }
103
+ /**
104
+ * Parse a query parameter as an integer.
105
+ *
106
+ * @param value - Query parameter value
107
+ * @param defaultValue - Default value if parsing fails
108
+ * @returns Parsed integer
109
+ *
110
+ * @example
111
+ * ```typescript
112
+ * const limit = parseQueryInt(req.query.limit, 10);
113
+ * const offset = parseQueryInt(req.query.offset, 0);
114
+ * ```
115
+ */
116
+ function parseQueryInt(value, defaultValue) {
117
+ if (value === undefined || value === null || value === '')
118
+ return defaultValue;
119
+ const parsed = parseInt(String(value), 10);
120
+ return isNaN(parsed) ? defaultValue : parsed;
121
+ }
122
+ /**
123
+ * Parse a query parameter as a string.
124
+ *
125
+ * @param value - Query parameter value
126
+ * @returns String value or undefined
127
+ *
128
+ * @example
129
+ * ```typescript
130
+ * const search = parseQueryString(req.query.search);
131
+ * ```
132
+ */
133
+ function parseQueryString(value) {
134
+ if (value === undefined || value === null || value === '')
135
+ return undefined;
136
+ return String(value);
137
+ }
138
+ /**
139
+ * Parse a string to a positive integer, returning a fallback if invalid.
140
+ * Useful for parsing environment variables with numeric defaults.
141
+ */
142
+ function parsePositiveInt(value, fallback) {
143
+ if (!value)
144
+ return fallback;
145
+ const parsed = parseInt(value, 10);
146
+ return Number.isFinite(parsed) && parsed > 0 ? parsed : fallback;
147
+ }
148
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicGFyYW1zLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL3V0aWxzL3BhcmFtcy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiO0FBQUEsK0NBQStDO0FBQy9DLHNDQUFzQzs7QUEwQnRDLDRCQVNDO0FBaUJELDRCQW9CQztBQVFELHNDQUVDO0FBYUQsOENBU0M7QUFlRCxzQ0FJQztBQWFELDRDQUdDO0FBTUQsNENBSUM7QUFsSkQsdUNBQTRDO0FBTzVDOzs7Ozs7Ozs7Ozs7Ozs7R0FlRztBQUNILFNBQWdCLFFBQVEsQ0FDdEIsTUFBa0MsRUFDbEMsR0FBVztJQUVYLE1BQU0sS0FBSyxHQUFHLE1BQU0sQ0FBQyxHQUFHLENBQUMsQ0FBQztJQUMxQixJQUFJLEtBQUssS0FBSyxTQUFTLEVBQUUsQ0FBQztRQUN4QixPQUFPLFNBQVMsQ0FBQztJQUNuQixDQUFDO0lBQ0QsT0FBTyxLQUFLLENBQUMsT0FBTyxDQUFDLEtBQUssQ0FBQyxDQUFDLENBQUMsQ0FBQyxLQUFLLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLEtBQUssQ0FBQztBQUNqRCxDQUFDO0FBRUQ7Ozs7Ozs7Ozs7Ozs7O0dBY0c7QUFDSCxTQUFnQixRQUFRLENBQUMsR0FBWTtJQUNuQywyQkFBMkI7SUFDM0IsTUFBTSxVQUFVLEdBQUcsUUFBUSxDQUFDLEdBQUcsQ0FBQyxNQUFNLEVBQUUsT0FBTyxDQUFDLENBQUM7SUFDakQsSUFBSSxVQUFVLEVBQUUsQ0FBQztRQUNmLE9BQU8sVUFBVSxDQUFDO0lBQ3BCLENBQUM7SUFFRCx3QkFBd0I7SUFDeEIsTUFBTSxXQUFXLEdBQUcsSUFBQSx5QkFBZSxFQUFDLEdBQUcsQ0FBQyxPQUFPLENBQUMsVUFBVSxDQUFDLENBQUMsRUFBRSxJQUFJLEVBQUUsQ0FBQztJQUNyRSxJQUFJLFdBQVcsRUFBRSxDQUFDO1FBQ2hCLE9BQU8sV0FBVyxDQUFDO0lBQ3JCLENBQUM7SUFFRCwyQkFBMkI7SUFDM0IsTUFBTSxTQUFTLEdBQUcsR0FBRyxDQUFDLElBQUksRUFBRSxjQUFjLEVBQUUsSUFBSSxFQUFFLENBQUM7SUFDbkQsSUFBSSxTQUFTLEVBQUUsQ0FBQztRQUNkLE9BQU8sU0FBUyxDQUFDO0lBQ25CLENBQUM7SUFFRCxPQUFPLFNBQVMsQ0FBQztBQUNuQixDQUFDO0FBRUQ7Ozs7O0dBS0c7QUFDSCxTQUFnQixhQUFhLENBQUMsR0FBWTtJQUN4QyxPQUFPLElBQUEseUJBQWUsRUFBQyxHQUFHLENBQUMsT0FBTyxDQUFDLGFBQWEsQ0FBQyxJQUFJLEVBQUUsQ0FBQztBQUMxRCxDQUFDO0FBRUQ7Ozs7Ozs7Ozs7R0FVRztBQUNILFNBQWdCLGlCQUFpQixDQUFDLEtBQWM7SUFDOUMsSUFBSSxLQUFLLEtBQUssU0FBUyxJQUFJLEtBQUssS0FBSyxJQUFJLElBQUksS0FBSyxLQUFLLEVBQUU7UUFBRSxPQUFPLFNBQVMsQ0FBQztJQUM1RSxJQUFJLE9BQU8sS0FBSyxLQUFLLFNBQVM7UUFBRSxPQUFPLEtBQUssQ0FBQztJQUM3QyxJQUFJLE9BQU8sS0FBSyxLQUFLLFFBQVEsRUFBRSxDQUFDO1FBQzlCLE1BQU0sS0FBSyxHQUFHLEtBQUssQ0FBQyxXQUFXLEVBQUUsQ0FBQztRQUNsQyxJQUFJLEtBQUssS0FBSyxNQUFNLElBQUksS0FBSyxLQUFLLEdBQUc7WUFBRSxPQUFPLElBQUksQ0FBQztRQUNuRCxJQUFJLEtBQUssS0FBSyxPQUFPLElBQUksS0FBSyxLQUFLLEdBQUc7WUFBRSxPQUFPLEtBQUssQ0FBQztJQUN2RCxDQUFDO0lBQ0QsT0FBTyxTQUFTLENBQUM7QUFDbkIsQ0FBQztBQUVEOzs7Ozs7Ozs7Ozs7R0FZRztBQUNILFNBQWdCLGFBQWEsQ0FBQyxLQUFjLEVBQUUsWUFBb0I7SUFDaEUsSUFBSSxLQUFLLEtBQUssU0FBUyxJQUFJLEtBQUssS0FBSyxJQUFJLElBQUksS0FBSyxLQUFLLEVBQUU7UUFBRSxPQUFPLFlBQVksQ0FBQztJQUMvRSxNQUFNLE1BQU0sR0FBRyxRQUFRLENBQUMsTUFBTSxDQUFDLEtBQUssQ0FBQyxFQUFFLEVBQUUsQ0FBQyxDQUFDO0lBQzNDLE9BQU8sS0FBSyxDQUFDLE1BQU0sQ0FBQyxDQUFDLENBQUMsQ0FBQyxZQUFZLENBQUMsQ0FBQyxDQUFDLE1BQU0sQ0FBQztBQUMvQyxDQUFDO0FBRUQ7Ozs7Ozs7Ozs7R0FVRztBQUNILFNBQWdCLGdCQUFnQixDQUFDLEtBQWM7SUFDN0MsSUFBSSxLQUFLLEtBQUssU0FBUyxJQUFJLEtBQUssS0FBSyxJQUFJLElBQUksS0FBSyxLQUFLLEVBQUU7UUFBRSxPQUFPLFNBQVMsQ0FBQztJQUM1RSxPQUFPLE1BQU0sQ0FBQyxLQUFLLENBQUMsQ0FBQztBQUN2QixDQUFDO0FBRUQ7OztHQUdHO0FBQ0gsU0FBZ0IsZ0JBQWdCLENBQUMsS0FBeUIsRUFBRSxRQUFnQjtJQUMxRSxJQUFJLENBQUMsS0FBSztRQUFFLE9BQU8sUUFBUSxDQUFDO0lBQzVCLE1BQU0sTUFBTSxHQUFHLFFBQVEsQ0FBQyxLQUFLLEVBQUUsRUFBRSxDQUFDLENBQUM7SUFDbkMsT0FBTyxNQUFNLENBQUMsUUFBUSxDQUFDLE1BQU0sQ0FBQyxJQUFJLE1BQU0sR0FBRyxDQUFDLENBQUMsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxDQUFDLENBQUMsUUFBUSxDQUFDO0FBQ25FLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyIvLyBDb3B5cmlnaHQgMjAyNiBQaXBlbGluZSBCdWlsZGVyIENvbnRyaWJ1dG9yc1xuLy8gU1BEWC1MaWNlbnNlLUlkZW50aWZpZXI6IEFwYWNoZS0yLjBcblxuaW1wb3J0IHsgUmVxdWVzdCB9IGZyb20gJ2V4cHJlc3MnO1xuaW1wb3J0IHsgZ2V0SGVhZGVyU3RyaW5nIH0gZnJvbSAnLi9oZWFkZXJzJztcblxuLyoqXG4gKiBFeHByZXNzIDUgcGFyYW1ldGVyIHR5cGUuXG4gKi9cbnR5cGUgUGFyYW1WYWx1ZSA9IHN0cmluZyB8IHN0cmluZ1tdIHwgdW5kZWZpbmVkO1xuXG4vKipcbiAqIEV4dHJhY3QgYSBzaW5nbGUgc3RyaW5nIHBhcmFtZXRlciBmcm9tIEV4cHJlc3MgNSByb3V0ZSBwYXJhbXMuXG4gKlxuICogQHBhcmFtIHBhcmFtcyAtIFJlcXVlc3QgcGFyYW1zIG9iamVjdFxuICogQHBhcmFtIGtleSAtIFBhcmFtZXRlciBrZXlcbiAqIEByZXR1cm5zIFRoZSBwYXJhbWV0ZXIgdmFsdWUgYXMgYSBzdHJpbmcsIG9yIHVuZGVmaW5lZCBpZiBub3QgcHJlc2VudFxuICpcbiAqIEBleGFtcGxlXG4gKiBgYGB0eXBlc2NyaXB0XG4gKiAvLyBSb3V0ZTogR0VUIC9wbHVnaW5zLzppZFxuICogY29uc3QgaWQgPSBnZXRQYXJhbShyZXEucGFyYW1zLCAnaWQnKTtcbiAqIGlmICghaWQpIHtcbiAqICAgcmV0dXJuIHNlbmRFcnJvcihyZXMsIDQwMCwgJ01pc3NpbmcgaWQgcGFyYW1ldGVyJyk7XG4gKiB9XG4gKiBgYGBcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGdldFBhcmFtKFxuICBwYXJhbXM6IFJlY29yZDxzdHJpbmcsIFBhcmFtVmFsdWU+LFxuICBrZXk6IHN0cmluZyxcbik6IHN0cmluZyB8IHVuZGVmaW5lZCB7XG4gIGNvbnN0IHZhbHVlID0gcGFyYW1zW2tleV07XG4gIGlmICh2YWx1ZSA9PT0gdW5kZWZpbmVkKSB7XG4gICAgcmV0dXJuIHVuZGVmaW5lZDtcbiAgfVxuICByZXR1cm4gQXJyYXkuaXNBcnJheSh2YWx1ZSkgPyB2YWx1ZVswXSA6IHZhbHVlO1xufVxuXG4vKipcbiAqIEV4dHJhY3QgdGhlIG9yZ2FuaXphdGlvbiBJRCBmcm9tIHJlcXVlc3QuXG4gKiBDaGVja3MgcGFyYW1zLCBoZWFkZXJzLCBhbmQgdXNlciBvYmplY3QuXG4gKlxuICogQHBhcmFtIHJlcSAtIEV4cHJlc3MgcmVxdWVzdCBvYmplY3RcbiAqIEByZXR1cm5zIE9yZ2FuaXphdGlvbiBJRCBvciB1bmRlZmluZWRcbiAqXG4gKiBAZXhhbXBsZVxuICogYGBgdHlwZXNjcmlwdFxuICogY29uc3Qgb3JnSWQgPSBnZXRPcmdJZChyZXEpO1xuICogaWYgKCFvcmdJZCkge1xuICogICByZXR1cm4gc2VuZEVycm9yKHJlcywgNDAwLCAnT3JnYW5pemF0aW9uIElEIHJlcXVpcmVkJyk7XG4gKiB9XG4gKiBgYGBcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGdldE9yZ0lkKHJlcTogUmVxdWVzdCk6IHN0cmluZyB8IHVuZGVmaW5lZCB7XG4gIC8vIENoZWNrIHJvdXRlIHBhcmFtcyBmaXJzdFxuICBjb25zdCBwYXJhbU9yZ0lkID0gZ2V0UGFyYW0ocmVxLnBhcmFtcywgJ29yZ0lkJyk7XG4gIGlmIChwYXJhbU9yZ0lkKSB7XG4gICAgcmV0dXJuIHBhcmFtT3JnSWQ7XG4gIH1cblxuICAvLyBDaGVjayB4LW9yZy1pZCBoZWFkZXJcbiAgY29uc3QgaGVhZGVyT3JnSWQgPSBnZXRIZWFkZXJTdHJpbmcocmVxLmhlYWRlcnNbJ3gtb3JnLWlkJ10pPy50cmltKCk7XG4gIGlmIChoZWFkZXJPcmdJZCkge1xuICAgIHJldHVybiBoZWFkZXJPcmdJZDtcbiAgfVxuXG4gIC8vIENoZWNrIGF1dGhlbnRpY2F0ZWQgdXNlclxuICBjb25zdCB1c2VyT3JnSWQgPSByZXEudXNlcj8ub3JnYW5pemF0aW9uSWQ/LnRyaW0oKTtcbiAgaWYgKHVzZXJPcmdJZCkge1xuICAgIHJldHVybiB1c2VyT3JnSWQ7XG4gIH1cblxuICByZXR1cm4gdW5kZWZpbmVkO1xufVxuXG4vKipcbiAqIEdldCB0aGUgYXV0aG9yaXphdGlvbiBoZWFkZXIgZnJvbSByZXF1ZXN0LlxuICpcbiAqIEBwYXJhbSByZXEgLSBFeHByZXNzIHJlcXVlc3Qgb2JqZWN0XG4gKiBAcmV0dXJucyBBdXRob3JpemF0aW9uIGhlYWRlciB2YWx1ZSBvciBlbXB0eSBzdHJpbmdcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGdldEF1dGhIZWFkZXIocmVxOiBSZXF1ZXN0KTogc3RyaW5nIHtcbiAgcmV0dXJuIGdldEhlYWRlclN0cmluZyhyZXEuaGVhZGVycy5hdXRob3JpemF0aW9uKSA/PyAnJztcbn1cblxuLyoqXG4gKiBQYXJzZSBhIHF1ZXJ5IHBhcmFtZXRlciBhcyBhIGJvb2xlYW4uXG4gKlxuICogQHBhcmFtIHZhbHVlIC0gUXVlcnkgcGFyYW1ldGVyIHZhbHVlXG4gKiBAcmV0dXJucyBQYXJzZWQgYm9vbGVhbiBvciB1bmRlZmluZWRcbiAqXG4gKiBAZXhhbXBsZVxuICogYGBgdHlwZXNjcmlwdFxuICogY29uc3QgaXNBY3RpdmUgPSBwYXJzZVF1ZXJ5Qm9vbGVhbihyZXEucXVlcnkuaXNBY3RpdmUpO1xuICogYGBgXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBwYXJzZVF1ZXJ5Qm9vbGVhbih2YWx1ZTogdW5rbm93bik6IGJvb2xlYW4gfCB1bmRlZmluZWQge1xuICBpZiAodmFsdWUgPT09IHVuZGVmaW5lZCB8fCB2YWx1ZSA9PT0gbnVsbCB8fCB2YWx1ZSA9PT0gJycpIHJldHVybiB1bmRlZmluZWQ7XG4gIGlmICh0eXBlb2YgdmFsdWUgPT09ICdib29sZWFuJykgcmV0dXJuIHZhbHVlO1xuICBpZiAodHlwZW9mIHZhbHVlID09PSAnc3RyaW5nJykge1xuICAgIGNvbnN0IGxvd2VyID0gdmFsdWUudG9Mb3dlckNhc2UoKTtcbiAgICBpZiAobG93ZXIgPT09ICd0cnVlJyB8fCBsb3dlciA9PT0gJzEnKSByZXR1cm4gdHJ1ZTtcbiAgICBpZiAobG93ZXIgPT09ICdmYWxzZScgfHwgbG93ZXIgPT09ICcwJykgcmV0dXJuIGZhbHNlO1xuICB9XG4gIHJldHVybiB1bmRlZmluZWQ7XG59XG5cbi8qKlxuICogUGFyc2UgYSBxdWVyeSBwYXJhbWV0ZXIgYXMgYW4gaW50ZWdlci5cbiAqXG4gKiBAcGFyYW0gdmFsdWUgLSBRdWVyeSBwYXJhbWV0ZXIgdmFsdWVcbiAqIEBwYXJhbSBkZWZhdWx0VmFsdWUgLSBEZWZhdWx0IHZhbHVlIGlmIHBhcnNpbmcgZmFpbHNcbiAqIEByZXR1cm5zIFBhcnNlZCBpbnRlZ2VyXG4gKlxuICogQGV4YW1wbGVcbiAqIGBgYHR5cGVzY3JpcHRcbiAqIGNvbnN0IGxpbWl0ID0gcGFyc2VRdWVyeUludChyZXEucXVlcnkubGltaXQsIDEwKTtcbiAqIGNvbnN0IG9mZnNldCA9IHBhcnNlUXVlcnlJbnQocmVxLnF1ZXJ5Lm9mZnNldCwgMCk7XG4gKiBgYGBcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHBhcnNlUXVlcnlJbnQodmFsdWU6IHVua25vd24sIGRlZmF1bHRWYWx1ZTogbnVtYmVyKTogbnVtYmVyIHtcbiAgaWYgKHZhbHVlID09PSB1bmRlZmluZWQgfHwgdmFsdWUgPT09IG51bGwgfHwgdmFsdWUgPT09ICcnKSByZXR1cm4gZGVmYXVsdFZhbHVlO1xuICBjb25zdCBwYXJzZWQgPSBwYXJzZUludChTdHJpbmcodmFsdWUpLCAxMCk7XG4gIHJldHVybiBpc05hTihwYXJzZWQpID8gZGVmYXVsdFZhbHVlIDogcGFyc2VkO1xufVxuXG4vKipcbiAqIFBhcnNlIGEgcXVlcnkgcGFyYW1ldGVyIGFzIGEgc3RyaW5nLlxuICpcbiAqIEBwYXJhbSB2YWx1ZSAtIFF1ZXJ5IHBhcmFtZXRlciB2YWx1ZVxuICogQHJldHVybnMgU3RyaW5nIHZhbHVlIG9yIHVuZGVmaW5lZFxuICpcbiAqIEBleGFtcGxlXG4gKiBgYGB0eXBlc2NyaXB0XG4gKiBjb25zdCBzZWFyY2ggPSBwYXJzZVF1ZXJ5U3RyaW5nKHJlcS5xdWVyeS5zZWFyY2gpO1xuICogYGBgXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBwYXJzZVF1ZXJ5U3RyaW5nKHZhbHVlOiB1bmtub3duKTogc3RyaW5nIHwgdW5kZWZpbmVkIHtcbiAgaWYgKHZhbHVlID09PSB1bmRlZmluZWQgfHwgdmFsdWUgPT09IG51bGwgfHwgdmFsdWUgPT09ICcnKSByZXR1cm4gdW5kZWZpbmVkO1xuICByZXR1cm4gU3RyaW5nKHZhbHVlKTtcbn1cblxuLyoqXG4gKiBQYXJzZSBhIHN0cmluZyB0byBhIHBvc2l0aXZlIGludGVnZXIsIHJldHVybmluZyBhIGZhbGxiYWNrIGlmIGludmFsaWQuXG4gKiBVc2VmdWwgZm9yIHBhcnNpbmcgZW52aXJvbm1lbnQgdmFyaWFibGVzIHdpdGggbnVtZXJpYyBkZWZhdWx0cy5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHBhcnNlUG9zaXRpdmVJbnQodmFsdWU6IHN0cmluZyB8IHVuZGVmaW5lZCwgZmFsbGJhY2s6IG51bWJlcik6IG51bWJlciB7XG4gIGlmICghdmFsdWUpIHJldHVybiBmYWxsYmFjaztcbiAgY29uc3QgcGFyc2VkID0gcGFyc2VJbnQodmFsdWUsIDEwKTtcbiAgcmV0dXJuIE51bWJlci5pc0Zpbml0ZShwYXJzZWQpICYmIHBhcnNlZCA+IDAgPyBwYXJzZWQgOiBmYWxsYmFjaztcbn1cbiJdfQ==
@@ -0,0 +1,142 @@
1
+ import { Response } from 'express';
2
+ import { QuotaInfo } from '../types/common';
3
+ import { ErrorCode } from '../types/error-codes';
4
+ /**
5
+ * Send a standardized success response.
6
+ *
7
+ * @param res - Express response object
8
+ * @param statusCode - HTTP status code (default: 200)
9
+ * @param data - Response data
10
+ * @param message - Optional success message
11
+ *
12
+ * @example
13
+ * ```typescript
14
+ * sendSuccess(res, 200, { plugin: pluginData });
15
+ * sendSuccess(res, 201, { id: newId }, 'Resource created');
16
+ * ```
17
+ */
18
+ export declare function sendSuccess<T>(res: Response, statusCode?: number, data?: T, message?: string): void;
19
+ /**
20
+ * Send a standardized error response.
21
+ *
22
+ * @param res - Express response object
23
+ * @param statusCode - HTTP status code
24
+ * @param message - Error message
25
+ * @param code - Error code from ErrorCode enum
26
+ * @param details - Optional additional details
27
+ *
28
+ * @example
29
+ * ```typescript
30
+ * sendError(res, 404, 'Plugin not found', ErrorCode.NOT_FOUND);
31
+ * sendError(res, 400, 'Invalid input', ErrorCode.VALIDATION_ERROR, { field: 'name' });
32
+ * ```
33
+ */
34
+ export declare function sendError(res: Response, statusCode: number, message: string, code?: ErrorCode | string, details?: unknown): void;
35
+ /**
36
+ * Send a quota exceeded error response.
37
+ *
38
+ * @param res - Express response object
39
+ * @param quotaType - Type of quota exceeded
40
+ * @param quota - Current quota information
41
+ * @param resetAt - ISO timestamp when quota resets
42
+ *
43
+ * @example
44
+ * ```typescript
45
+ * sendQuotaExceeded(res, 'apiCalls', { type: 'apiCalls', limit: 10000, used: 10000, remaining: 0 }, resetAt);
46
+ * ```
47
+ */
48
+ export declare function sendQuotaExceeded(res: Response, quotaType: string, quota: QuotaInfo, resetAt?: string): void;
49
+ /**
50
+ * Paginated response interface.
51
+ */
52
+ export interface PaginatedResponse<T> {
53
+ success: true;
54
+ statusCode: number;
55
+ message?: string;
56
+ data: T[];
57
+ count: number;
58
+ limit: number;
59
+ offset: number;
60
+ total?: number;
61
+ }
62
+ /**
63
+ * Send a paginated list response.
64
+ *
65
+ * @param res - Express response object
66
+ * @param data - Array of items to return
67
+ * @param options - Pagination options
68
+ *
69
+ * @example
70
+ * ```typescript
71
+ * const plugins = await db.query.plugins.findMany({ limit, offset });
72
+ * sendPaginated(res, plugins, {
73
+ * limit: 10,
74
+ * offset: 0,
75
+ * total: 50,
76
+ * message: 'Plugins retrieved successfully',
77
+ * });
78
+ * ```
79
+ */
80
+ export declare function sendPaginated<T>(res: Response, data: T[], options: {
81
+ limit: number;
82
+ offset: number;
83
+ total?: number;
84
+ message?: string;
85
+ statusCode?: number;
86
+ }): void;
87
+ /**
88
+ * Send a paginated list response with the items nested under a named key.
89
+ * Use when the API contract is `{ <key>: [...], pagination: {...} }`
90
+ * (the dominant shape across api/* services).
91
+ *
92
+ * @example
93
+ * ```typescript
94
+ * sendPaginatedNested(res, 'pipelines', items, {
95
+ * total: 50, limit: 25, offset: 0, hasMore: true,
96
+ * });
97
+ * // → { pipelines: [...], pagination: { total: 50, limit: 25, offset: 0, hasMore: true } }
98
+ * ```
99
+ */
100
+ export declare function sendPaginatedNested<T>(res: Response, dataKey: string, data: T[], options: {
101
+ total?: number;
102
+ limit: number;
103
+ offset: number;
104
+ hasMore: boolean;
105
+ nextCursor?: string;
106
+ statusCode?: number;
107
+ }): void;
108
+ /**
109
+ * Extract database error details for logging/response.
110
+ *
111
+ * Extracts PostgreSQL error codes, details, hints, and constraint names
112
+ * from database errors for better error messages.
113
+ *
114
+ * @param error - Error object from database operation
115
+ * @returns Object with extracted error details
116
+ *
117
+ * @example
118
+ * ```typescript
119
+ * try {
120
+ * await db.insert(plugins).values(newPlugin);
121
+ * } catch (error) {
122
+ * const dbDetails = extractDbError(error);
123
+ * return sendError(res, 500, 'Database error', ErrorCode.DATABASE_ERROR, dbDetails);
124
+ * }
125
+ * ```
126
+ */
127
+ export declare function extractDbError(error: unknown): Record<string, unknown>;
128
+ /** Extract a message string from an unknown catch value. */
129
+ export declare function errorMessage(error: unknown): string;
130
+ /** Send a 400 bad-request response. */
131
+ export declare function sendBadRequest(res: Response, message: string, code?: ErrorCode | string): void;
132
+ /** Send a 500 internal error response. */
133
+ export declare function sendInternalError(res: Response, message: string, details?: Record<string, unknown>): void;
134
+ /** Common pagination + sorting parameters. */
135
+ export interface PaginationParams {
136
+ limit: number;
137
+ offset: number;
138
+ sortBy: string;
139
+ sortOrder: 'asc' | 'desc';
140
+ }
141
+ /** Parse pagination/sort params from query string, clamping to safe defaults. */
142
+ export declare function parsePaginationParams(query: Record<string, unknown>): PaginationParams;
@@ -0,0 +1,237 @@
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.sendSuccess = sendSuccess;
6
+ exports.sendError = sendError;
7
+ exports.sendQuotaExceeded = sendQuotaExceeded;
8
+ exports.sendPaginated = sendPaginated;
9
+ exports.sendPaginatedNested = sendPaginatedNested;
10
+ exports.extractDbError = extractDbError;
11
+ exports.errorMessage = errorMessage;
12
+ exports.sendBadRequest = sendBadRequest;
13
+ exports.sendInternalError = sendInternalError;
14
+ exports.parsePaginationParams = parsePaginationParams;
15
+ const logger_1 = require("./logger");
16
+ const error_codes_1 = require("../types/error-codes");
17
+ const common_schemas_1 = require("../validation/common-schemas");
18
+ const logger = (0, logger_1.createLogger)('response');
19
+ /**
20
+ * Send a standardized success response.
21
+ *
22
+ * @param res - Express response object
23
+ * @param statusCode - HTTP status code (default: 200)
24
+ * @param data - Response data
25
+ * @param message - Optional success message
26
+ *
27
+ * @example
28
+ * ```typescript
29
+ * sendSuccess(res, 200, { plugin: pluginData });
30
+ * sendSuccess(res, 201, { id: newId }, 'Resource created');
31
+ * ```
32
+ */
33
+ function sendSuccess(res, statusCode = 200, data, message) {
34
+ if (res.headersSent) {
35
+ logger.warn('Attempted to send success after headers already sent', { statusCode });
36
+ return;
37
+ }
38
+ const response = {
39
+ success: true,
40
+ statusCode,
41
+ };
42
+ if (data !== undefined) {
43
+ response.data = data;
44
+ }
45
+ if (message) {
46
+ response.message = message;
47
+ }
48
+ res.status(statusCode).json(response);
49
+ }
50
+ /**
51
+ * Send a standardized error response.
52
+ *
53
+ * @param res - Express response object
54
+ * @param statusCode - HTTP status code
55
+ * @param message - Error message
56
+ * @param code - Error code from ErrorCode enum
57
+ * @param details - Optional additional details
58
+ *
59
+ * @example
60
+ * ```typescript
61
+ * sendError(res, 404, 'Plugin not found', ErrorCode.NOT_FOUND);
62
+ * sendError(res, 400, 'Invalid input', ErrorCode.VALIDATION_ERROR, { field: 'name' });
63
+ * ```
64
+ */
65
+ function sendError(res, statusCode, message, code, details) {
66
+ if (res.headersSent) {
67
+ logger.warn('Attempted to send error after headers already sent', { statusCode, message });
68
+ return;
69
+ }
70
+ const response = {
71
+ success: false,
72
+ statusCode,
73
+ message,
74
+ };
75
+ if (code) {
76
+ response.code = code;
77
+ }
78
+ if (details !== undefined) {
79
+ response.details = details;
80
+ }
81
+ res.status(statusCode).json(response);
82
+ }
83
+ /**
84
+ * Send a quota exceeded error response.
85
+ *
86
+ * @param res - Express response object
87
+ * @param quotaType - Type of quota exceeded
88
+ * @param quota - Current quota information
89
+ * @param resetAt - ISO timestamp when quota resets
90
+ *
91
+ * @example
92
+ * ```typescript
93
+ * sendQuotaExceeded(res, 'apiCalls', { type: 'apiCalls', limit: 10000, used: 10000, remaining: 0 }, resetAt);
94
+ * ```
95
+ */
96
+ function sendQuotaExceeded(res, quotaType, quota, resetAt) {
97
+ const resetDate = resetAt ? new Date(resetAt) : new Date();
98
+ const resetIn = Math.max(0, Math.ceil((resetDate.getTime() - Date.now()) / 1000));
99
+ res.setHeader('Retry-After', resetIn);
100
+ res.setHeader('X-Quota-Limit', quota.limit);
101
+ res.setHeader('X-Quota-Used', quota.used);
102
+ res.setHeader('X-Quota-Remaining', Math.max(0, quota.remaining));
103
+ if (resetAt) {
104
+ res.setHeader('X-Quota-Reset', resetAt);
105
+ }
106
+ sendError(res, 429, `${quotaType} quota exceeded (${quota.used}/${quota.limit}). Please try again later.`, error_codes_1.ErrorCode.QUOTA_EXCEEDED, { quota });
107
+ }
108
+ /**
109
+ * Send a paginated list response.
110
+ *
111
+ * @param res - Express response object
112
+ * @param data - Array of items to return
113
+ * @param options - Pagination options
114
+ *
115
+ * @example
116
+ * ```typescript
117
+ * const plugins = await db.query.plugins.findMany({ limit, offset });
118
+ * sendPaginated(res, plugins, {
119
+ * limit: 10,
120
+ * offset: 0,
121
+ * total: 50,
122
+ * message: 'Plugins retrieved successfully',
123
+ * });
124
+ * ```
125
+ */
126
+ function sendPaginated(res, data, options) {
127
+ if (res.headersSent) {
128
+ logger.warn('Attempted to send paginated response after headers already sent');
129
+ return;
130
+ }
131
+ const { limit, offset, total, message, statusCode = 200 } = options;
132
+ const response = {
133
+ success: true,
134
+ statusCode,
135
+ data,
136
+ count: data.length,
137
+ limit,
138
+ offset,
139
+ };
140
+ if (message) {
141
+ response.message = message;
142
+ }
143
+ if (total !== undefined) {
144
+ response.total = total;
145
+ }
146
+ res.status(statusCode).json(response);
147
+ }
148
+ /**
149
+ * Send a paginated list response with the items nested under a named key.
150
+ * Use when the API contract is `{ <key>: [...], pagination: {...} }`
151
+ * (the dominant shape across api/* services).
152
+ *
153
+ * @example
154
+ * ```typescript
155
+ * sendPaginatedNested(res, 'pipelines', items, {
156
+ * total: 50, limit: 25, offset: 0, hasMore: true,
157
+ * });
158
+ * // → { pipelines: [...], pagination: { total: 50, limit: 25, offset: 0, hasMore: true } }
159
+ * ```
160
+ */
161
+ function sendPaginatedNested(res, dataKey, data, options) {
162
+ if (res.headersSent) {
163
+ logger.warn('Attempted to send paginated response after headers already sent');
164
+ return;
165
+ }
166
+ const { statusCode = 200, total, limit, offset, hasMore, nextCursor } = options;
167
+ const pagination = { limit, offset, hasMore };
168
+ if (total !== undefined)
169
+ pagination.total = total;
170
+ if (nextCursor)
171
+ pagination.nextCursor = nextCursor;
172
+ res.status(statusCode).json({ [dataKey]: data, pagination });
173
+ }
174
+ /**
175
+ * Extract database error details for logging/response.
176
+ *
177
+ * Extracts PostgreSQL error codes, details, hints, and constraint names
178
+ * from database errors for better error messages.
179
+ *
180
+ * @param error - Error object from database operation
181
+ * @returns Object with extracted error details
182
+ *
183
+ * @example
184
+ * ```typescript
185
+ * try {
186
+ * await db.insert(plugins).values(newPlugin);
187
+ * } catch (error) {
188
+ * const dbDetails = extractDbError(error);
189
+ * return sendError(res, 500, 'Database error', ErrorCode.DATABASE_ERROR, dbDetails);
190
+ * }
191
+ * ```
192
+ */
193
+ function extractDbError(error) {
194
+ if (!error || typeof error !== 'object') {
195
+ return {};
196
+ }
197
+ // Drizzle ORM wraps the original pg error in error.cause —
198
+ // check the cause first, then fall back to the error itself.
199
+ const err = error;
200
+ const source = (err.cause && typeof err.cause === 'object' ? err.cause : err);
201
+ const details = {};
202
+ if (source.code)
203
+ details.dbCode = source.code;
204
+ if (source.detail)
205
+ details.dbDetail = source.detail;
206
+ if (source.hint)
207
+ details.dbHint = source.hint;
208
+ if (source.constraint)
209
+ details.constraint = source.constraint;
210
+ if (source.table)
211
+ details.table = source.table;
212
+ if (source.column)
213
+ details.column = source.column;
214
+ return details;
215
+ }
216
+ // Convenience helpers (shared across plugin, pipeline, quota services)
217
+ /** Extract a message string from an unknown catch value. */
218
+ function errorMessage(error) {
219
+ return error instanceof Error ? error.message : String(error);
220
+ }
221
+ /** Send a 400 bad-request response. */
222
+ function sendBadRequest(res, message, code = error_codes_1.ErrorCode.VALIDATION_ERROR) {
223
+ sendError(res, 400, message, code);
224
+ }
225
+ /** Send a 500 internal error response. */
226
+ function sendInternalError(res, message, details) {
227
+ sendError(res, 500, message, error_codes_1.ErrorCode.INTERNAL_ERROR, details);
228
+ }
229
+ /** Parse pagination/sort params from query string, clamping to safe defaults. */
230
+ function parsePaginationParams(query) {
231
+ const limit = Math.min(Math.max(parseInt(String(query.limit), 10) || 10, 1), common_schemas_1.MAX_PAGE_LIMIT);
232
+ const offset = Math.max(parseInt(String(query.offset), 10) || 0, 0);
233
+ const sortBy = String(query.sortBy || 'createdAt');
234
+ const sortOrder = String(query.sortOrder || 'desc').toLowerCase() === 'asc' ? 'asc' : 'desc';
235
+ return { limit, offset, sortBy, sortOrder };
236
+ }
237
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicmVzcG9uc2UuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvdXRpbHMvcmVzcG9uc2UudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IjtBQUFBLCtDQUErQztBQUMvQyxzQ0FBc0M7O0FBd0J0QyxrQ0E4QkM7QUFpQkQsOEJBaUNDO0FBZUQsOENBeUJDO0FBa0NELHNDQW9DQztBQWVELGtEQXNCQztBQXFCRCx3Q0FtQkM7QUFLRCxvQ0FFQztBQUdELHdDQU1DO0FBR0QsOENBTUM7QUFhRCxzREFRQztBQTlVRCxxQ0FBd0M7QUFFeEMsc0RBQWlEO0FBQ2pELGlFQUE4RDtBQUU5RCxNQUFNLE1BQU0sR0FBRyxJQUFBLHFCQUFZLEVBQUMsVUFBVSxDQUFDLENBQUM7QUFFeEM7Ozs7Ozs7Ozs7Ozs7R0FhRztBQUNILFNBQWdCLFdBQVcsQ0FDekIsR0FBYSxFQUNiLGFBQXFCLEdBQUcsRUFDeEIsSUFBUSxFQUNSLE9BQWdCO0lBRWhCLElBQUksR0FBRyxDQUFDLFdBQVcsRUFBRSxDQUFDO1FBQ3BCLE1BQU0sQ0FBQyxJQUFJLENBQUMsc0RBQXNELEVBQUUsRUFBRSxVQUFVLEVBQUUsQ0FBQyxDQUFDO1FBQ3BGLE9BQU87SUFDVCxDQUFDO0lBRUQsTUFBTSxRQUFRLEdBS1Y7UUFDRixPQUFPLEVBQUUsSUFBSTtRQUNiLFVBQVU7S0FDWCxDQUFDO0lBRUYsSUFBSSxJQUFJLEtBQUssU0FBUyxFQUFFLENBQUM7UUFDdkIsUUFBUSxDQUFDLElBQUksR0FBRyxJQUFJLENBQUM7SUFDdkIsQ0FBQztJQUVELElBQUksT0FBTyxFQUFFLENBQUM7UUFDWixRQUFRLENBQUMsT0FBTyxHQUFHLE9BQU8sQ0FBQztJQUM3QixDQUFDO0lBRUQsR0FBRyxDQUFDLE1BQU0sQ0FBQyxVQUFVLENBQUMsQ0FBQyxJQUFJLENBQUMsUUFBUSxDQUFDLENBQUM7QUFDeEMsQ0FBQztBQUVEOzs7Ozs7Ozs7Ozs7OztHQWNHO0FBQ0gsU0FBZ0IsU0FBUyxDQUN2QixHQUFh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QUUsR0FBRyxFQUFFLE9BQU8sRUFBRSxJQUFJLENBQUMsQ0FBQztBQUNyQyxDQUFDO0FBRUQsMENBQTBDO0FBQzFDLFNBQWdCLGlCQUFpQixDQUMvQixHQUFhLEVBQ2IsT0FBZSxFQUNmLE9BQWlDO0lBRWpDLFNBQVMsQ0FBQyxHQUFHLEVBQUUsR0FBRyxFQUFFLE9BQU8sRUFBRSx1QkFBUyxDQUFDLGNBQWMsRUFBRSxPQUFPLENBQUMsQ0FBQztBQUNsRSxDQUFDO0FBWUQsaUZBQWlGO0FBQ2pGLFNBQWdCLHFCQUFxQixDQUFDLEtBQThCO0lBQ2xFLE1BQU0sS0FBSyxHQUFHLElBQUksQ0FBQyxHQUFHLENBQUMsSUFBSSxDQUFDLEdBQUcsQ0FBQyxRQUFRLENBQUMsTUFBTSxDQUFDLEtBQUssQ0FBQyxLQUFLLENBQUMsRUFBRSxFQUFFLENBQUMsSUFBSSxFQUFFLEVBQUUsQ0FBQyxDQUFDLEVBQUUsK0JBQWMsQ0FBQyxDQUFDO0lBQzdGLE1BQU0sTUFBTSxHQUFHLElBQUksQ0FBQyxHQUFHLENBQUMsUUFBUSxDQUFDLE1BQU0sQ0FBQyxLQUFLLENBQUMsTUFBTSxDQUFDLEVBQUUsRUFBRSxDQUFDLElBQUksQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDO0lBQ3BFLE1BQU0sTUFBTSxHQUFHLE1BQU0sQ0FBQyxLQUFLLENBQUMsTUFBTSxJQUFJLFdBQVcsQ0FBQyxDQUFDO0lBQ25ELE1BQU0sU0FBUyxHQUNiLE1BQU0sQ0FBQyxLQUFLLENBQUMsU0FBUyxJQUFJLE1BQU0sQ0FBQyxDQUFDLFdBQVcsRUFBRSxLQUFLLEtBQUssQ0FBQyxDQUFDLENBQUMsS0FBSyxDQUFDLENBQUMsQ0FBQyxNQUFNLENBQUM7SUFFN0UsT0FBTyxFQUFFLEtBQUssRUFBRSxNQUFNLEVBQUUsTUFBTSxFQUFFLFNBQVMsRUFBRSxDQUFDO0FBQzlDLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyIvLyBDb3B5cmlnaHQgMjAyNiBQaXBlbGluZSBCdWlsZGVyIENvbnRyaWJ1dG9yc1xuLy8gU1BEWC1MaWNlbnNlLUlkZW50aWZpZXI6IEFwYWNoZS0yLjBcblxuaW1wb3J0IHsgUmVzcG9uc2UgfSBmcm9tICdleHByZXNzJztcbmltcG9ydCB7IGNyZWF0ZUxvZ2dlciB9IGZyb20gJy4vbG9nZ2VyJztcbmltcG9ydCB7IFF1b3RhSW5mbyB9IGZyb20gJy4uL3R5cGVzL2NvbW1vbic7XG5pbXBvcnQgeyBFcnJvckNvZGUgfSBmcm9tICcuLi90eXBlcy9lcnJvci1jb2Rlcyc7XG5pbXBvcnQgeyBNQVhfUEFHRV9MSU1JVCB9IGZyb20gJy4uL3ZhbGlkYXRpb24vY29tbW9uLXNjaGVtYXMnO1xuXG5jb25zdCBsb2dnZXIgPSBjcmVhdGVMb2dnZXIoJ3Jlc3BvbnNlJyk7XG5cbi8qKlxuICogU2VuZCBhIHN0YW5kYXJkaXplZCBzdWNjZXNzIHJlc3BvbnNlLlxuICpcbiAqIEBwYXJhbSByZXMgLSBFeHByZXNzIHJlc3BvbnNlIG9iamVjdFxuICogQHBhcmFtIHN0YXR1c0NvZGUgLSBIVFRQIHN0YXR1cyBjb2RlIChkZWZhdWx0OiAyMDApXG4gKiBAcGFyYW0gZGF0YSAtIFJlc3BvbnNlIGRhdGFcbiAqIEBwYXJhbSBtZXNzYWdlIC0gT3B0aW9uYWwgc3VjY2VzcyBtZXNzYWdlXG4gKlxuICogQGV4YW1wbGVcbiAqIGBgYHR5cGVzY3JpcHRcbiAqIHNlbmRTdWNjZXNzKHJlcywgMjAwLCB7IHBsdWdpbjogcGx1Z2luRGF0YSB9KTtcbiAqIHNlbmRTdWNjZXNzKHJlcywgMjAxLCB7IGlkOiBuZXdJZCB9LCAnUmVzb3VyY2UgY3JlYXRlZCcpO1xuICogYGBgXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBzZW5kU3VjY2VzczxUPihcbiAgcmVzOiBSZXNwb25zZSxcbiAgc3RhdHVzQ29kZTogbnVtYmVyID0gMjAwLFxuICBkYXRhPzogVCxcbiAgbWVzc2FnZT86IHN0cmluZyxcbik6IHZvaWQge1xuICBpZiAocmVzLmhlYWRlcnNTZW50KSB7XG4gICAgbG9nZ2VyLndhcm4oJ0F0dGVtcHRlZCB0byBzZW5kIHN1Y2Nlc3MgYWZ0ZXIgaGVhZGVycyBhbHJlYWR5IHNlbnQnLCB7IHN0YXR1c0NvZGUgfSk7XG4gICAgcmV0dXJuO1xuICB9XG5cbiAgY29uc3QgcmVzcG9uc2U6IHtcbiAgICBzdWNjZXNzOiB0cnVlO1xuICAgIHN0YXR1c0NvZGU6IG51bWJlcjtcbiAgICBkYXRhPzogVDtcbiAgICBtZXNzYWdlPzogc3RyaW5nO1xuICB9ID0ge1xuICAgIHN1Y2Nlc3M6IHRydWUsXG4gICAgc3RhdHVzQ29kZSxcbiAgfTtcblxuICBpZiAoZGF0YSAhPT0gdW5kZWZpbmVkKSB7XG4gICAgcmVzcG9uc2UuZGF0YSA9IGRhdGE7XG4gIH1cblxuICBpZiAobWVzc2FnZSkge1xuICAgIHJlc3BvbnNlLm1lc3NhZ2UgPSBtZXNzYWdlO1xuICB9XG5cbiAgcmVzLnN0YXR1cyhzdGF0dXNDb2RlKS5qc29uKHJlc3BvbnNlKTtcbn1cblxuLyoqXG4gKiBTZW5kIGEgc3RhbmRhcmRpemVkIGVycm9yIHJlc3BvbnNlLlxuICpcbiAqIEBwYXJhbSByZXMgLSBFeHByZXNzIHJlc3BvbnNlIG9iamVjdFxuICogQHBhcmFtIHN0YXR1c0NvZGUgLSBIVFRQIHN0YXR1cyBjb2RlXG4gKiBAcGFyYW0gbWVzc2FnZSAtIEVycm9yIG1lc3NhZ2VcbiAqIEBwYXJhbSBjb2RlIC0gRXJyb3IgY29kZSBmcm9tIEVycm9yQ29kZSBlbnVtXG4gKiBAcGFyYW0gZGV0YWlscyAtIE9wdGlvbmFsIGFkZGl0aW9uYWwgZGV0YWlsc1xuICpcbiAqIEBleGFtcGxlXG4gKiBgYGB0eXBlc2NyaXB0XG4gKiBzZW5kRXJyb3IocmVzLCA0MDQsICdQbHVnaW4gbm90IGZvdW5kJywgRXJyb3JDb2RlLk5PVF9GT1VORCk7XG4gKiBzZW5kRXJyb3IocmVzLCA0MDAsICdJbnZhbGlkIGlucHV0JywgRXJyb3JDb2RlLlZBTElEQVRJT05fRVJST1IsIHsgZmllbGQ6ICduYW1lJyB9KTtcbiAqIGBgYFxuICovXG5leHBvcnQgZnVuY3Rpb24gc2VuZEVycm9yKFxuICByZXM6IFJlc3BvbnNlLFxuICBzdGF0dXNDb2RlOiBudW1iZXIsXG4gIG1lc3NhZ2U6IHN0cmluZyxcbiAgY29kZT86IEVycm9yQ29kZSB8IHN0cmluZyxcbiAgZGV0YWlscz86IHVua25vd24sXG4pOiB2b2lkIHtcbiAgaWYgKHJlcy5oZWFkZXJzU2VudCkge1xuICAgIGxvZ2dlci53YXJuKCdBdHRlbXB0ZWQgdG8gc2VuZCBlcnJvciBhZnRlciBoZWFkZXJzIGFscmVhZHkgc2VudCcsIHsgc3RhdHVzQ29kZSwgbWVzc2FnZSB9KTtcbiAgICByZXR1cm47XG4gIH1cblxuICBjb25zdCByZXNwb25zZToge1xuICAgIHN1Y2Nlc3M6IGZhbHNlO1xuICAgIHN0YXR1c0NvZGU6IG51bWJlcjtcbiAgICBtZXNzYWdlOiBzdHJpbmc7XG4gICAgY29kZT86IHN0cmluZztcbiAgICBkZXRhaWxzPzogdW5rbm93bjtcbiAgfSA9IHtcbiAgICBzdWNjZXNzOiBmYWxzZSxcbiAgICBzdGF0dXNDb2RlLFxuICAgIG1lc3NhZ2UsXG4gIH07XG5cbiAgaWYgKGNvZGUpIHtcbiAgICByZXNwb25zZS5jb2RlID0gY29kZTtcbiAgfVxuXG4gIGlmIChkZXRhaWxzICE9PSB1bmRlZmluZWQpIHtcbiAgICByZXNwb25zZS5kZXRhaWxzID0gZGV0YWlscztcbiAgfVxuXG4gIHJlcy5zdGF0dXMoc3RhdHVzQ29kZSkuanNvbihyZXNwb25zZSk7XG59XG5cbi8qKlxuICogU2VuZCBhIHF1b3RhIGV4Y2VlZGVkIGVycm9yIHJlc3BvbnNlLlxuICpcbiAqIEBwYXJhbSByZXMgLSBFeHByZXNzIHJlc3BvbnNlIG9iamVjdFxuICogQHBhcmFtIHF1b3RhVHlwZSAtIFR5cGUgb2YgcXVvdGEgZXhjZWVkZWRcbiAqIEBwYXJhbSBxdW90YSAtIEN1cnJlbnQgcXVvdGEgaW5mb3JtYXRpb25cbiAqIEBwYXJhbSByZXNldEF0IC0gSVNPIHRpbWVzdGFtcCB3aGVuIHF1b3RhIHJlc2V0c1xuICpcbiAqIEBleGFtcGxlXG4gKiBgYGB0eXBlc2NyaXB0XG4gKiBzZW5kUXVvdGFFeGNlZWRlZChyZXMsICdhcGlDYWxscycsIHsgdHlwZTogJ2FwaUNhbGxzJywgbGltaXQ6IDEwMDAwLCB1c2VkOiAxMDAwMCwgcmVtYWluaW5nOiAwIH0sIHJlc2V0QXQpO1xuICogYGBgXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBzZW5kUXVvdGFFeGNlZWRlZChcbiAgcmVzOiBSZXNwb25zZSxcbiAgcXVvdGFUeXBlOiBzdHJpbmcsXG4gIHF1b3RhOiBRdW90YUluZm8sXG4gIHJlc2V0QXQ/OiBzdHJpbmcsXG4pOiB2b2lkIHtcbiAgY29uc3QgcmVzZXREYXRlID0gcmVzZXRBdCA/IG5ldyBEYXRlKHJlc2V0QXQpIDogbmV3IERhdGUoKTtcbiAgY29uc3QgcmVzZXRJbiA9IE1hdGgubWF4KDAsIE1hdGguY2VpbCgocmVzZXREYXRlLmdldFRpbWUoKSAtIERhdGUubm93KCkpIC8gMTAwMCkpO1xuXG4gIHJlcy5zZXRIZWFkZXIoJ1JldHJ5LUFmdGVyJywgcmVzZXRJbik7XG4gIHJlcy5zZXRIZWFkZXIoJ1gtUXVvdGEtTGltaXQnLCBxdW90YS5saW1pdCk7XG4gIHJlcy5zZXRIZWFkZXIoJ1gtUXVvdGEtVXNlZCcsIHF1b3RhLnVzZWQpO1xuICByZXMuc2V0SGVhZGVyKCdYLVF1b3RhLVJlbWFpbmluZycsIE1hdGgubWF4KDAsIHF1b3RhLnJlbWFpbmluZykpO1xuXG4gIGlmIChyZXNldEF0KSB7XG4gICAgcmVzLnNldEhlYWRlcignWC1RdW90YS1SZXNldCcsIHJlc2V0QXQpO1xuICB9XG5cbiAgc2VuZEVycm9yKFxuICAgIHJlcyxcbiAgICA0MjksXG4gICAgYCR7cXVvdGFUeXBlfSBxdW90YSBleGNlZWRlZCAoJHtxdW90YS51c2VkfS8ke3F1b3RhLmxpbWl0fSkuIFBsZWFzZSB0cnkgYWdhaW4gbGF0ZXIuYCxcbiAgICBFcnJvckNvZGUuUVVPVEFfRVhDRUVERUQsXG4gICAgeyBxdW90YSB9LFxuICApO1xufVxuXG4vKipcbiAqIFBhZ2luYXRlZCByZXNwb25zZSBpbnRlcmZhY2UuXG4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgUGFnaW5hdGVkUmVzcG9uc2U8VD4ge1xuICBzdWNjZXNzOiB0cnVlO1xuICBzdGF0dXNDb2RlOiBudW1iZXI7XG4gIG1lc3NhZ2U/OiBzdHJpbmc7XG4gIGRhdGE6IFRbXTtcbiAgY291bnQ6IG51bWJlcjtcbiAgbGltaXQ6IG51bWJlcjtcbiAgb2Zmc2V0OiBudW1iZXI7XG4gIHRvdGFsPzogbnVtYmVyO1xufVxuXG4vKipcbiAqIFNlbmQgYSBwYWdpbmF0ZWQgbGlzdCByZXNwb25zZS5cbiAqXG4gKiBAcGFyYW0gcmVzIC0gRXhwcmVzcyByZXNwb25zZSBvYmplY3RcbiAqIEBwYXJhbSBkYXRhIC0gQXJyYXkgb2YgaXRlbXMgdG8gcmV0dXJuXG4gKiBAcGFyYW0gb3B0aW9ucyAtIFBhZ2luYXRpb24gb3B0aW9uc1xuICpcbiAqIEBleGFtcGxlXG4gKiBgYGB0eXBlc2NyaXB0XG4gKiBjb25zdCBwbHVnaW5zID0gYXdhaXQgZGIucXVlcnkucGx1Z2lucy5maW5kTWFueSh7IGxpbWl0LCBvZmZzZXQgfSk7XG4gKiBzZW5kUGFnaW5hdGVkKHJlcywgcGx1Z2lucywge1xuICogICBsaW1pdDogMTAsXG4gKiAgIG9mZnNldDogMCxcbiAqICAgdG90YWw6IDUwLFxuICogICBtZXNzYWdlOiAnUGx1Z2lucyByZXRyaWV2ZWQgc3VjY2Vzc2Z1bGx5JyxcbiAqIH0pO1xuICogYGBgXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBzZW5kUGFnaW5hdGVkPFQ+KFxuICByZXM6IFJlc3BvbnNlLFxuICBkYXRhOiBUW10sXG4gIG9wdGlvbnM6IHtcbiAgICBsaW1pdDogbnVtYmVyO1xuICAgIG9mZnNldDogbnVtYmVyO1xuICAgIHRvdGFsPzogbnVtYmVyO1xuICAgIG1lc3NhZ2U/OiBzdHJpbmc7XG4gICAgc3RhdHVzQ29kZT86IG51bWJlcjtcbiAgfSxcbik6IHZvaWQge1xuICBpZiAocmVzLmhlYWRlcnNTZW50KSB7XG4gICAgbG9nZ2VyLndhcm4oJ0F0dGVtcHRlZCB0byBzZW5kIHBhZ2luYXRlZCByZXNwb25zZSBhZnRlciBoZWFkZXJzIGFscmVhZHkgc2VudCcpO1xuICAgIHJldHVybjtcbiAgfVxuXG4gIGNvbnN0IHsgbGltaXQsIG9mZnNldCwgdG90YWwsIG1lc3NhZ2UsIHN0YXR1c0NvZGUgPSAyMDAgfSA9IG9wdGlvbnM7XG5cbiAgY29uc3QgcmVzcG9uc2U6IFBhZ2luYXRlZFJlc3BvbnNlPFQ+ID0ge1xuICAgIHN1Y2Nlc3M6IHRydWUsXG4gICAgc3RhdHVzQ29kZSxcbiAgICBkYXRhLFxuICAgIGNvdW50OiBkYXRhLmxlbmd0aCxcbiAgICBsaW1pdCxcbiAgICBvZmZzZXQsXG4gIH07XG5cbiAgaWYgKG1lc3NhZ2UpIHtcbiAgICByZXNwb25zZS5tZXNzYWdlID0gbWVzc2FnZTtcbiAgfVxuXG4gIGlmICh0b3RhbCAhPT0gdW5kZWZpbmVkKSB7XG4gICAgcmVzcG9uc2UudG90YWwgPSB0b3RhbDtcbiAgfVxuXG4gIHJlcy5zdGF0dXMoc3RhdHVzQ29kZSkuanNvbihyZXNwb25zZSk7XG59XG5cbi8qKlxuICogU2VuZCBhIHBhZ2luYXRlZCBsaXN0IHJlc3BvbnNlIHdpdGggdGhlIGl0ZW1zIG5lc3RlZCB1bmRlciBhIG5hbWVkIGtleS5cbiAqIFVzZSB3aGVuIHRoZSBBUEkgY29udHJhY3QgaXMgYHsgPGtleT46IFsuLi5dLCBwYWdpbmF0aW9uOiB7Li4ufSB9YFxuICogKHRoZSBkb21pbmFudCBzaGFwZSBhY3Jvc3MgYXBpLyogc2VydmljZXMpLlxuICpcbiAqIEBleGFtcGxlXG4gKiBgYGB0eXBlc2NyaXB0XG4gKiBzZW5kUGFnaW5hdGVkTmVzdGVkKHJlcywgJ3BpcGVsaW5lcycsIGl0ZW1zLCB7XG4gKiAgIHRvdGFsOiA1MCwgbGltaXQ6IDI1LCBvZmZzZXQ6IDAsIGhhc01vcmU6IHRydWUsXG4gKiB9KTtcbiAqIC8vIOKGkiB7IHBpcGVsaW5lczogWy4uLl0sIHBhZ2luYXRpb246IHsgdG90YWw6IDUwLCBsaW1pdDogMjUsIG9mZnNldDogMCwgaGFzTW9yZTogdHJ1ZSB9IH1cbiAqIGBgYFxuICovXG5leHBvcnQgZnVuY3Rpb24gc2VuZFBhZ2luYXRlZE5lc3RlZDxUPihcbiAgcmVzOiBSZXNwb25zZSxcbiAgZGF0YUtleTogc3RyaW5nLFxuICBkYXRhOiBUW10sXG4gIG9wdGlvbnM6IHtcbiAgICB0b3RhbD86IG51bWJlcjtcbiAgICBsaW1pdDogbnVtYmVyO1xuICAgIG9mZnNldDogbnVtYmVyO1xuICAgIGhhc01vcmU6IGJvb2xlYW47XG4gICAgbmV4dEN1cnNvcj86IHN0cmluZztcbiAgICBzdGF0dXNDb2RlPzogbnVtYmVyO1xuICB9LFxuKTogdm9pZCB7XG4gIGlmIChyZXMuaGVhZGVyc1NlbnQpIHtcbiAgICBsb2dnZXIud2FybignQXR0ZW1wdGVkIHRvIHNlbmQgcGFnaW5hdGVkIHJlc3BvbnNlIGFmdGVyIGhlYWRlcnMgYWxyZWFkeSBzZW50Jyk7XG4gICAgcmV0dXJuO1xuICB9XG4gIGNvbnN0IHsgc3RhdHVzQ29kZSA9IDIwMCwgdG90YWwsIGxpbWl0LCBvZmZzZXQsIGhhc01vcmUsIG5leHRDdXJzb3IgfSA9IG9wdGlvbnM7XG4gIGNvbnN0IHBhZ2luYXRpb246IFJlY29yZDxzdHJpbmcsIHVua25vd24+ID0geyBsaW1pdCwgb2Zmc2V0LCBoYXNNb3JlIH07XG4gIGlmICh0b3RhbCAhPT0gdW5kZWZpbmVkKSBwYWdpbmF0aW9uLnRvdGFsID0gdG90YWw7XG4gIGlmIChuZXh0Q3Vyc29yKSBwYWdpbmF0aW9uLm5leHRDdXJzb3IgPSBuZXh0Q3Vyc29yO1xuICByZXMuc3RhdHVzKHN0YXR1c0NvZGUpLmpzb24oeyBbZGF0YUtleV06IGRhdGEsIHBhZ2luYXRpb24gfSk7XG59XG5cbi8qKlxuICogRXh0cmFjdCBkYXRhYmFzZSBlcnJvciBkZXRhaWxzIGZvciBsb2dnaW5nL3Jlc3BvbnNlLlxuICpcbiAqIEV4dHJhY3RzIFBvc3RncmVTUUwgZXJyb3IgY29kZXMsIGRldGFpbHMsIGhpbnRzLCBhbmQgY29uc3RyYWludCBuYW1lc1xuICogZnJvbSBkYXRhYmFzZSBlcnJvcnMgZm9yIGJldHRlciBlcnJvciBtZXNzYWdlcy5cbiAqXG4gKiBAcGFyYW0gZXJyb3IgLSBFcnJvciBvYmplY3QgZnJvbSBkYXRhYmFzZSBvcGVyYXRpb25cbiAqIEByZXR1cm5zIE9iamVjdCB3aXRoIGV4dHJhY3RlZCBlcnJvciBkZXRhaWxzXG4gKlxuICogQGV4YW1wbGVcbiAqIGBgYHR5cGVzY3JpcHRcbiAqIHRyeSB7XG4gKiAgIGF3YWl0IGRiLmluc2VydChwbHVnaW5zKS52YWx1ZXMobmV3UGx1Z2luKTtcbiAqIH0gY2F0Y2ggKGVycm9yKSB7XG4gKiAgIGNvbnN0IGRiRGV0YWlscyA9IGV4dHJhY3REYkVycm9yKGVycm9yKTtcbiAqICAgcmV0dXJuIHNlbmRFcnJvcihyZXMsIDUwMCwgJ0RhdGFiYXNlIGVycm9yJywgRXJyb3JDb2RlLkRBVEFCQVNFX0VSUk9SLCBkYkRldGFpbHMpO1xuICogfVxuICogYGBgXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBleHRyYWN0RGJFcnJvcihlcnJvcjogdW5rbm93bik6IFJlY29yZDxzdHJpbmcsIHVua25vd24+IHtcbiAgaWYgKCFlcnJvciB8fCB0eXBlb2YgZXJyb3IgIT09ICdvYmplY3QnKSB7XG4gICAgcmV0dXJuIHt9O1xuICB9XG5cbiAgLy8gRHJpenpsZSBPUk0gd3JhcHMgdGhlIG9yaWdpbmFsIHBnIGVycm9yIGluIGVycm9yLmNhdXNlIOKAlFxuICAvLyBjaGVjayB0aGUgY2F1c2UgZmlyc3QsIHRoZW4gZmFsbCBiYWNrIHRvIHRoZSBlcnJvciBpdHNlbGYuXG4gIGNvbnN0IGVyciA9IGVycm9yIGFzIFJlY29yZDxzdHJpbmcsIHVua25vd24+O1xuICBjb25zdCBzb3VyY2UgPSAoZXJyLmNhdXNlICYmIHR5cGVvZiBlcnIuY2F1c2UgPT09ICdvYmplY3QnID8gZXJyLmNhdXNlIDogZXJyKSBhcyBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPjtcbiAgY29uc3QgZGV0YWlsczogUmVjb3JkPHN0cmluZywgdW5rbm93bj4gPSB7fTtcblxuICBpZiAoc291cmNlLmNvZGUpIGRldGFpbHMuZGJDb2RlID0gc291cmNlLmNvZGU7XG4gIGlmIChzb3VyY2UuZGV0YWlsKSBkZXRhaWxzLmRiRGV0YWlsID0gc291cmNlLmRldGFpbDtcbiAgaWYgKHNvdXJjZS5oaW50KSBkZXRhaWxzLmRiSGludCA9IHNvdXJjZS5oaW50O1xuICBpZiAoc291cmNlLmNvbnN0cmFpbnQpIGRldGFpbHMuY29uc3RyYWludCA9IHNvdXJjZS5jb25zdHJhaW50O1xuICBpZiAoc291cmNlLnRhYmxlKSBkZXRhaWxzLnRhYmxlID0gc291cmNlLnRhYmxlO1xuICBpZiAoc291cmNlLmNvbHVtbikgZGV0YWlscy5jb2x1bW4gPSBzb3VyY2UuY29sdW1uO1xuXG4gIHJldHVybiBkZXRhaWxzO1xufVxuXG4vLyBDb252ZW5pZW5jZSBoZWxwZXJzIChzaGFyZWQgYWNyb3NzIHBsdWdpbiwgcGlwZWxpbmUsIHF1b3RhIHNlcnZpY2VzKVxuXG4vKiogRXh0cmFjdCBhIG1lc3NhZ2Ugc3RyaW5nIGZyb20gYW4gdW5rbm93biBjYXRjaCB2YWx1ZS4gKi9cbmV4cG9ydCBmdW5jdGlvbiBlcnJvck1lc3NhZ2UoZXJyb3I6IHVua25vd24pOiBzdHJpbmcge1xuICByZXR1cm4gZXJyb3IgaW5zdGFuY2VvZiBFcnJvciA/IGVycm9yLm1lc3NhZ2UgOiBTdHJpbmcoZXJyb3IpO1xufVxuXG4vKiogU2VuZCBhIDQwMCBiYWQtcmVxdWVzdCByZXNwb25zZS4gKi9cbmV4cG9ydCBmdW5jdGlvbiBzZW5kQmFkUmVxdWVzdChcbiAgcmVzOiBSZXNwb25zZSxcbiAgbWVzc2FnZTogc3RyaW5nLFxuICBjb2RlOiBFcnJvckNvZGUgfCBzdHJpbmcgPSBFcnJvckNvZGUuVkFMSURBVElPTl9FUlJPUixcbik6IHZvaWQge1xuICBzZW5kRXJyb3IocmVzLCA0MDAsIG1lc3NhZ2UsIGNvZGUpO1xufVxuXG4vKiogU2VuZCBhIDUwMCBpbnRlcm5hbCBlcnJvciByZXNwb25zZS4gKi9cbmV4cG9ydCBmdW5jdGlvbiBzZW5kSW50ZXJuYWxFcnJvcihcbiAgcmVzOiBSZXNwb25zZSxcbiAgbWVzc2FnZTogc3RyaW5nLFxuICBkZXRhaWxzPzogUmVjb3JkPHN0cmluZywgdW5rbm93bj4sXG4pOiB2b2lkIHtcbiAgc2VuZEVycm9yKHJlcywgNTAwLCBtZXNzYWdlLCBFcnJvckNvZGUuSU5URVJOQUxfRVJST1IsIGRldGFpbHMpO1xufVxuXG4vLyBQYWdpbmF0aW9uXG5cbi8qKiBDb21tb24gcGFnaW5hdGlvbiArIHNvcnRpbmcgcGFyYW1ldGVycy4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgUGFnaW5hdGlvblBhcmFtcyB7XG4gIGxpbWl0OiBudW1iZXI7XG4gIG9mZnNldDogbnVtYmVyO1xuICBzb3J0Qnk6IHN0cmluZztcbiAgc29ydE9yZGVyOiAnYXNjJyB8ICdkZXNjJztcbn1cblxuLyoqIFBhcnNlIHBhZ2luYXRpb24vc29ydCBwYXJhbXMgZnJvbSBxdWVyeSBzdHJpbmcsIGNsYW1waW5nIHRvIHNhZmUgZGVmYXVsdHMuICovXG5leHBvcnQgZnVuY3Rpb24gcGFyc2VQYWdpbmF0aW9uUGFyYW1zKHF1ZXJ5OiBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPik6IFBhZ2luYXRpb25QYXJhbXMge1xuICBjb25zdCBsaW1pdCA9IE1hdGgubWluKE1hdGgubWF4KHBhcnNlSW50KFN0cmluZyhxdWVyeS5saW1pdCksIDEwKSB8fCAxMCwgMSksIE1BWF9QQUdFX0xJTUlUKTtcbiAgY29uc3Qgb2Zmc2V0ID0gTWF0aC5tYXgocGFyc2VJbnQoU3RyaW5nKHF1ZXJ5Lm9mZnNldCksIDEwKSB8fCAwLCAwKTtcbiAgY29uc3Qgc29ydEJ5ID0gU3RyaW5nKHF1ZXJ5LnNvcnRCeSB8fCAnY3JlYXRlZEF0Jyk7XG4gIGNvbnN0IHNvcnRPcmRlcjogJ2FzYycgfCAnZGVzYycgPVxuICAgIFN0cmluZyhxdWVyeS5zb3J0T3JkZXIgfHwgJ2Rlc2MnKS50b0xvd2VyQ2FzZSgpID09PSAnYXNjJyA/ICdhc2MnIDogJ2Rlc2MnO1xuXG4gIHJldHVybiB7IGxpbWl0LCBvZmZzZXQsIHNvcnRCeSwgc29ydE9yZGVyIH07XG59XG4iXX0=
@@ -0,0 +1,61 @@
1
+ import { z } from 'zod';
2
+ /**
3
+ * Schema for AI generation request body.
4
+ * Used by both POST /pipelines/generate and POST /plugins/generate.
5
+ */
6
+ export declare const AIGenerateBodySchema: z.ZodObject<{
7
+ prompt: z.ZodString;
8
+ provider: z.ZodString;
9
+ model: z.ZodString;
10
+ apiKey: z.ZodOptional<z.ZodString>;
11
+ previousConfig: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
12
+ fallbackProviders: z.ZodOptional<z.ZodArray<z.ZodString>>;
13
+ }, z.core.$strip>;
14
+ /** Validated type for AI generation request body. */
15
+ export type ValidatedAIGenerateBody = z.infer<typeof AIGenerateBodySchema>;
16
+ /**
17
+ * Schema for POST /plugins/deploy-generated request body.
18
+ * Validates the AI-generated plugin configuration before Docker build.
19
+ */
20
+ export declare const PluginDeployGeneratedSchema: z.ZodObject<{
21
+ name: z.ZodString;
22
+ description: z.ZodOptional<z.ZodString>;
23
+ version: z.ZodString;
24
+ pluginType: z.ZodDefault<z.ZodEnum<{
25
+ CodeBuildStep: "CodeBuildStep";
26
+ ShellStep: "ShellStep";
27
+ ManualApprovalStep: "ManualApprovalStep";
28
+ }>>;
29
+ computeType: z.ZodDefault<z.ZodEnum<{
30
+ SMALL: "SMALL";
31
+ MEDIUM: "MEDIUM";
32
+ LARGE: "LARGE";
33
+ X2_LARGE: "X2_LARGE";
34
+ }>>;
35
+ keywords: z.ZodDefault<z.ZodOptional<z.ZodArray<z.ZodString>>>;
36
+ primaryOutputDirectory: z.ZodOptional<z.ZodNullable<z.ZodString>>;
37
+ installCommands: z.ZodDefault<z.ZodOptional<z.ZodArray<z.ZodString>>>;
38
+ commands: z.ZodArray<z.ZodString>;
39
+ env: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
40
+ buildArgs: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
41
+ dockerfile: z.ZodString;
42
+ accessModifier: z.ZodDefault<z.ZodEnum<{
43
+ public: "public";
44
+ private: "private";
45
+ }>>;
46
+ }, z.core.$strip>;
47
+ /** Validated type for plugin deploy-generated request body. */
48
+ export type ValidatedPluginDeployGenerated = z.infer<typeof PluginDeployGeneratedSchema>;
49
+ /**
50
+ * Schema for POST /pipelines/generate/from-url/stream request body.
51
+ * Validates Git URL + AI provider configuration for repo-based pipeline generation.
52
+ */
53
+ export declare const AIGenerateFromUrlBodySchema: z.ZodObject<{
54
+ gitUrl: z.ZodString;
55
+ provider: z.ZodString;
56
+ model: z.ZodString;
57
+ apiKey: z.ZodOptional<z.ZodString>;
58
+ repoToken: z.ZodOptional<z.ZodString>;
59
+ }, z.core.$strip>;
60
+ /** Validated type for AI generate-from-URL request body. */
61
+ export type ValidatedAIGenerateFromUrlBody = z.infer<typeof AIGenerateFromUrlBodySchema>;