@pipeline-builder/pipeline-data 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.
@@ -0,0 +1,248 @@
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.reportingService = exports.ReportingService = void 0;
6
+ const api_core_1 = require("@pipeline-builder/api-core");
7
+ const drizzle_orm_1 = require("drizzle-orm");
8
+ const crud_service_1 = require("./crud-service");
9
+ const drizzle_schema_1 = require("../database/drizzle-schema");
10
+ const postgres_connection_1 = require("../database/postgres-connection");
11
+ /** Cast raw SQL result rows to a typed array. Alias for drizzleRows. */
12
+ const sqlRows = (result) => (0, crud_service_1.drizzleRows)(result.rows);
13
+ /**
14
+ * Cache for reporting aggregations. Two tiers:
15
+ * - Inventory queries (plugin summary/distribution/versions): 5 min TTL — changes on plugin CRUD
16
+ * - Execution/build queries with date ranges: 2 min TTL — new events arrive continuously
17
+ */
18
+ const inventoryCache = (0, api_core_1.createCacheService)('report:inv:', parseInt(process.env.CACHE_TTL_REPORT_INVENTORY || '300', 10));
19
+ const timeseriesCache = (0, api_core_1.createCacheService)('report:ts:', parseInt(process.env.CACHE_TTL_REPORT_TIMESERIES || '120', 10));
20
+ // ─── Service ────────────────────────────────────────────
21
+ /**
22
+ * Read-only reporting service for pipeline execution and plugin inventory aggregations.
23
+ * Does not extend CrudService — reports are aggregate queries, not entity CRUD.
24
+ *
25
+ * All queries are cached in-memory to avoid repeated expensive SQL aggregations:
26
+ * - Inventory queries (plugin summary/distribution/versions): 5 min TTL
27
+ * - Timeseries queries (execution/build metrics with date ranges): 2 min TTL
28
+ */
29
+ class ReportingService {
30
+ /** Invalidate all cached reports for an org (call after event ingest). */
31
+ async invalidateOrg(orgId) {
32
+ await Promise.all([
33
+ inventoryCache.invalidatePattern(`${orgId}:*`),
34
+ timeseriesCache.invalidatePattern(`${orgId}:*`),
35
+ ]);
36
+ }
37
+ // ── Category 1: Pipeline Execution & Performance ──
38
+ /** 1.1 Execution count per pipeline with status breakdown. */
39
+ async getExecutionCount(orgId) {
40
+ return timeseriesCache.getOrSet(`${orgId}:exec-count`, () => postgres_connection_1.db.execute((0, drizzle_orm_1.sql) `
41
+ SELECT
42
+ p.id, p.project, p.organization, p.pipeline_name,
43
+ COUNT(*)::int AS total,
44
+ COUNT(*) FILTER (WHERE e.status = 'SUCCEEDED')::int AS succeeded,
45
+ COUNT(*) FILTER (WHERE e.status = 'FAILED')::int AS failed,
46
+ COUNT(*) FILTER (WHERE e.status = 'CANCELED')::int AS canceled,
47
+ MIN(e.started_at)::text AS first_execution,
48
+ MAX(e.started_at)::text AS last_execution
49
+ FROM ${drizzle_schema_1.schema.pipeline} p
50
+ JOIN ${drizzle_schema_1.schema.pipelineEvent} e ON e.pipeline_id = p.id
51
+ AND e.event_type = 'PIPELINE' AND e.status != 'STARTED'
52
+ WHERE p.org_id = ${orgId} AND p.is_active = true
53
+ GROUP BY p.id
54
+ ORDER BY total DESC
55
+ `).then(r => sqlRows(r)));
56
+ }
57
+ /** 1.2 Success rate over time for an org. */
58
+ async getSuccessRate(orgId, interval, from, to) {
59
+ return timeseriesCache.getOrSet(`${orgId}:success-rate:${interval}:${from}:${to}`, () => postgres_connection_1.db.execute((0, drizzle_orm_1.sql) `
60
+ SELECT
61
+ DATE_TRUNC(${interval}, e.started_at)::text AS period,
62
+ COUNT(*) FILTER (WHERE e.status = 'SUCCEEDED')::int AS succeeded,
63
+ COUNT(*) FILTER (WHERE e.status = 'FAILED')::int AS failed,
64
+ COUNT(*) FILTER (WHERE e.status = 'CANCELED')::int AS canceled,
65
+ ROUND(COUNT(*) FILTER (WHERE e.status = 'SUCCEEDED')::numeric
66
+ / NULLIF(COUNT(*), 0) * 100, 1)::float AS success_pct
67
+ FROM ${drizzle_schema_1.schema.pipelineEvent} e
68
+ JOIN ${drizzle_schema_1.schema.pipeline} p ON p.id = e.pipeline_id
69
+ WHERE p.org_id = ${orgId} AND e.event_type = 'PIPELINE'
70
+ AND e.status IN ('SUCCEEDED', 'FAILED', 'CANCELED')
71
+ AND e.started_at >= ${from}::timestamptz AND e.started_at <= ${to}::timestamptz
72
+ GROUP BY period ORDER BY period
73
+ `).then(r => sqlRows(r)));
74
+ }
75
+ /** 1.3 Average duration per pipeline. */
76
+ async getAverageDuration(orgId, from, to) {
77
+ return timeseriesCache.getOrSet(`${orgId}:avg-duration:${from}:${to}`, () => postgres_connection_1.db.execute((0, drizzle_orm_1.sql) `
78
+ SELECT
79
+ p.id, p.project, p.pipeline_name,
80
+ AVG(e.duration_ms)::int AS avg_ms,
81
+ MIN(e.duration_ms)::int AS min_ms,
82
+ MAX(e.duration_ms)::int AS max_ms,
83
+ PERCENTILE_CONT(0.95) WITHIN GROUP (ORDER BY e.duration_ms)::int AS p95_ms,
84
+ COUNT(*)::int AS executions
85
+ FROM ${drizzle_schema_1.schema.pipelineEvent} e
86
+ JOIN ${drizzle_schema_1.schema.pipeline} p ON p.id = e.pipeline_id
87
+ WHERE p.org_id = ${orgId} AND e.event_type = 'PIPELINE' AND e.duration_ms IS NOT NULL
88
+ AND e.started_at >= ${from}::timestamptz AND e.started_at <= ${to}::timestamptz
89
+ GROUP BY p.id ORDER BY avg_ms DESC
90
+ `).then(r => sqlRows(r)));
91
+ }
92
+ /** 1.5 Stage failure heatmap — which stages fail most. */
93
+ async getStageFailures(orgId, from, to) {
94
+ return timeseriesCache.getOrSet(`${orgId}:stage-failures:${from}:${to}`, () => postgres_connection_1.db.execute((0, drizzle_orm_1.sql) `
95
+ SELECT
96
+ e.stage_name,
97
+ COUNT(*) FILTER (WHERE e.status = 'FAILED')::int AS failures,
98
+ COUNT(*)::int AS total,
99
+ ROUND(COUNT(*) FILTER (WHERE e.status = 'FAILED')::numeric
100
+ / NULLIF(COUNT(*), 0) * 100, 1)::float AS failure_pct
101
+ FROM ${drizzle_schema_1.schema.pipelineEvent} e
102
+ JOIN ${drizzle_schema_1.schema.pipeline} p ON p.id = e.pipeline_id
103
+ WHERE p.org_id = ${orgId} AND e.event_type = 'STAGE' AND e.stage_name IS NOT NULL
104
+ AND e.started_at >= ${from}::timestamptz AND e.started_at <= ${to}::timestamptz
105
+ GROUP BY e.stage_name ORDER BY failures DESC
106
+ `).then(r => sqlRows(r)));
107
+ }
108
+ /** 1.6 Stage bottlenecks — slowest stages per pipeline. */
109
+ async getStageBottlenecks(orgId, from, to) {
110
+ return timeseriesCache.getOrSet(`${orgId}:stage-bottlenecks:${from}:${to}`, () => postgres_connection_1.db.execute((0, drizzle_orm_1.sql) `
111
+ SELECT
112
+ p.id, p.pipeline_name, e.stage_name,
113
+ AVG(e.duration_ms)::int AS avg_ms,
114
+ MAX(e.duration_ms)::int AS max_ms
115
+ FROM ${drizzle_schema_1.schema.pipelineEvent} e
116
+ JOIN ${drizzle_schema_1.schema.pipeline} p ON p.id = e.pipeline_id
117
+ WHERE p.org_id = ${orgId} AND e.event_type = 'STAGE' AND e.duration_ms IS NOT NULL
118
+ AND e.started_at >= ${from}::timestamptz AND e.started_at <= ${to}::timestamptz
119
+ GROUP BY p.id, e.stage_name ORDER BY avg_ms DESC
120
+ `).then(r => sqlRows(r)));
121
+ }
122
+ /** 1.7 Action failure rate — which plugin steps fail most. */
123
+ async getActionFailures(orgId, from, to) {
124
+ return timeseriesCache.getOrSet(`${orgId}:action-failures:${from}:${to}`, () => postgres_connection_1.db.execute((0, drizzle_orm_1.sql) `
125
+ SELECT
126
+ e.action_name,
127
+ COUNT(*) FILTER (WHERE e.status = 'FAILED')::int AS failures,
128
+ COUNT(*)::int AS total,
129
+ ROUND(COUNT(*) FILTER (WHERE e.status = 'FAILED')::numeric
130
+ / NULLIF(COUNT(*), 0) * 100, 1)::float AS failure_pct
131
+ FROM ${drizzle_schema_1.schema.pipelineEvent} e
132
+ JOIN ${drizzle_schema_1.schema.pipeline} p ON p.id = e.pipeline_id
133
+ WHERE p.org_id = ${orgId} AND e.event_type = 'ACTION' AND e.action_name IS NOT NULL
134
+ AND e.started_at >= ${from}::timestamptz AND e.started_at <= ${to}::timestamptz
135
+ GROUP BY e.action_name ORDER BY failures DESC
136
+ `).then(r => sqlRows(r)));
137
+ }
138
+ /** 1.8 Error categorization — group failure messages. */
139
+ async getErrors(orgId, from, to, limit = 20) {
140
+ return timeseriesCache.getOrSet(`${orgId}:errors:${from}:${to}:${limit}`, () => postgres_connection_1.db.execute((0, drizzle_orm_1.sql) `
141
+ SELECT
142
+ SUBSTRING(e.error_message FROM 1 FOR 200) AS error_pattern,
143
+ COUNT(*)::int AS occurrences,
144
+ COUNT(DISTINCT e.pipeline_id)::int AS affected_pipelines,
145
+ MAX(e.started_at)::text AS last_seen
146
+ FROM ${drizzle_schema_1.schema.pipelineEvent} e
147
+ JOIN ${drizzle_schema_1.schema.pipeline} p ON p.id = e.pipeline_id
148
+ WHERE p.org_id = ${orgId} AND e.status = 'FAILED' AND e.error_message IS NOT NULL
149
+ AND e.started_at >= ${from}::timestamptz AND e.started_at <= ${to}::timestamptz
150
+ GROUP BY error_pattern ORDER BY occurrences DESC
151
+ LIMIT ${limit}
152
+ `).then(r => sqlRows(r)));
153
+ }
154
+ // ── Category 2: Plugin Inventory & Builds ──
155
+ /** 2.1 Plugin summary — counts and breakdowns. */
156
+ async getPluginSummary(orgId) {
157
+ return inventoryCache.getOrSet(`${orgId}:plugin-summary`, async () => {
158
+ const rows = await postgres_connection_1.db.execute((0, drizzle_orm_1.sql) `
159
+ SELECT
160
+ COUNT(*)::int AS total,
161
+ COUNT(*) FILTER (WHERE ${drizzle_schema_1.schema.plugin.isActive})::int AS active,
162
+ COUNT(*) FILTER (WHERE NOT ${drizzle_schema_1.schema.plugin.isActive})::int AS inactive,
163
+ COUNT(*) FILTER (WHERE ${drizzle_schema_1.schema.plugin.accessModifier} = 'public')::int AS public,
164
+ COUNT(*) FILTER (WHERE ${drizzle_schema_1.schema.plugin.accessModifier} = 'private')::int AS private,
165
+ COUNT(DISTINCT ${drizzle_schema_1.schema.plugin.name})::int AS unique_names
166
+ FROM ${drizzle_schema_1.schema.plugin}
167
+ WHERE ${drizzle_schema_1.schema.plugin.orgId} = ${orgId}
168
+ `);
169
+ return (sqlRows(rows)[0] || { total: 0, active: 0, inactive: 0, public: 0, private: 0, uniqueNames: 0 });
170
+ });
171
+ }
172
+ /** 2.2 Type & compute distribution. */
173
+ async getPluginDistribution(orgId) {
174
+ return inventoryCache.getOrSet(`${orgId}:plugin-distribution`, () => postgres_connection_1.db.execute((0, drizzle_orm_1.sql) `
175
+ SELECT
176
+ ${drizzle_schema_1.schema.plugin.pluginType} AS plugin_type,
177
+ ${drizzle_schema_1.schema.plugin.computeType} AS compute_type,
178
+ COUNT(*)::int AS count
179
+ FROM ${drizzle_schema_1.schema.plugin}
180
+ WHERE ${drizzle_schema_1.schema.plugin.orgId} = ${orgId} AND ${drizzle_schema_1.schema.plugin.isActive} = true
181
+ GROUP BY ${drizzle_schema_1.schema.plugin.pluginType}, ${drizzle_schema_1.schema.plugin.computeType}
182
+ ORDER BY count DESC
183
+ `).then(r => sqlRows(r)));
184
+ }
185
+ /** 2.3 Version counts per plugin name. */
186
+ async getPluginVersions(orgId) {
187
+ return inventoryCache.getOrSet(`${orgId}:plugin-versions`, () => postgres_connection_1.db.execute((0, drizzle_orm_1.sql) `
188
+ SELECT
189
+ ${drizzle_schema_1.schema.plugin.name},
190
+ COUNT(*)::int AS version_count,
191
+ MAX(${drizzle_schema_1.schema.plugin.version}) AS latest_version,
192
+ bool_or(${drizzle_schema_1.schema.plugin.isDefault}) AS has_default
193
+ FROM ${drizzle_schema_1.schema.plugin}
194
+ WHERE ${drizzle_schema_1.schema.plugin.orgId} = ${orgId} AND ${drizzle_schema_1.schema.plugin.isActive} = true
195
+ GROUP BY ${drizzle_schema_1.schema.plugin.name}
196
+ ORDER BY version_count DESC
197
+ `).then(r => sqlRows(r)));
198
+ }
199
+ /** 2.4 Build success rate over time. */
200
+ async getBuildSuccessRate(orgId, interval, from, to) {
201
+ return timeseriesCache.getOrSet(`${orgId}:build-success:${interval}:${from}:${to}`, () => postgres_connection_1.db.execute((0, drizzle_orm_1.sql) `
202
+ SELECT
203
+ DATE_TRUNC(${interval}, e.started_at)::text AS period,
204
+ COUNT(*) FILTER (WHERE e.status = 'completed')::int AS succeeded,
205
+ COUNT(*) FILTER (WHERE e.status = 'failed')::int AS failed,
206
+ ROUND(COUNT(*) FILTER (WHERE e.status = 'completed')::numeric
207
+ / NULLIF(COUNT(*), 0) * 100, 1)::float AS success_pct
208
+ FROM ${drizzle_schema_1.schema.pipelineEvent} e
209
+ WHERE e.org_id = ${orgId} AND e.event_source = 'plugin-build'
210
+ AND e.status IN ('completed', 'failed')
211
+ AND e.started_at >= ${from}::timestamptz AND e.started_at <= ${to}::timestamptz
212
+ GROUP BY period ORDER BY period
213
+ `).then(r => sqlRows(r)));
214
+ }
215
+ /** 2.5 Build duration per plugin. */
216
+ async getBuildDuration(orgId, from, to) {
217
+ return timeseriesCache.getOrSet(`${orgId}:build-duration:${from}:${to}`, () => postgres_connection_1.db.execute((0, drizzle_orm_1.sql) `
218
+ SELECT
219
+ e.detail->>'pluginName' AS plugin_name,
220
+ AVG(e.duration_ms)::int AS avg_ms,
221
+ MAX(e.duration_ms)::int AS max_ms,
222
+ COUNT(*)::int AS builds
223
+ FROM ${drizzle_schema_1.schema.pipelineEvent} e
224
+ WHERE e.org_id = ${orgId} AND e.event_source = 'plugin-build' AND e.duration_ms IS NOT NULL
225
+ AND e.started_at >= ${from}::timestamptz AND e.started_at <= ${to}::timestamptz
226
+ GROUP BY plugin_name ORDER BY avg_ms DESC
227
+ `).then(r => sqlRows(r)));
228
+ }
229
+ /** 2.6 Build failures — top error messages. */
230
+ async getBuildFailures(orgId, from, to, limit = 20) {
231
+ return timeseriesCache.getOrSet(`${orgId}:build-failures:${from}:${to}:${limit}`, () => postgres_connection_1.db.execute((0, drizzle_orm_1.sql) `
232
+ SELECT
233
+ e.detail->>'pluginName' AS plugin_name,
234
+ e.error_message,
235
+ COUNT(*)::int AS occurrences,
236
+ MAX(e.started_at)::text AS last_seen
237
+ FROM ${drizzle_schema_1.schema.pipelineEvent} e
238
+ WHERE e.org_id = ${orgId} AND e.event_source = 'plugin-build' AND e.status = 'failed'
239
+ AND e.started_at >= ${from}::timestamptz AND e.started_at <= ${to}::timestamptz
240
+ GROUP BY plugin_name, e.error_message
241
+ ORDER BY occurrences DESC
242
+ LIMIT ${limit}
243
+ `).then(r => sqlRows(r)));
244
+ }
245
+ }
246
+ exports.ReportingService = ReportingService;
247
+ exports.reportingService = new ReportingService();
248
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicmVwb3J0aW5nLXNlcnZpY2UuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvYXBpL3JlcG9ydGluZy1zZXJ2aWNlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7QUFBQSwrQ0FBK0M7QUFDL0Msc0NBQXNDOzs7QUFFdEMseURBQWdFO0FBQ2hFLDZDQUFrQztBQUNsQyxpREFBNkM7QUFDN0MsK0RBQW9EO0FBQ3BELHlFQUFxRDtBQUVyRCx3RUFBd0U7QUFDeEUsTUFBTSxPQUFPLEdBQUcsQ0FBSSxNQUEyQixFQUFPLEVBQUUsQ0FBQyxJQUFBLDBCQUFXLEVBQUksTUFBTSxDQUFDLElBQUksQ0FBQyxDQUFDO0FBRXJGOzs7O0dBSUc7QUFDSCxNQUFNLGNBQWMsR0FBRyxJQUFBLDZCQUFrQixFQUFDLGFBQWEsRUFBRSxRQUFRLENBQUMsT0FBTyxDQUFDLEdBQUcsQ0FBQywwQkFBMEIsSUFBSSxLQUFLLEVBQUUsRUFBRSxDQUFDLENBQUMsQ0FBQztBQUN4SCxNQUFNLGVBQWUsR0FBRyxJQUFBLDZCQUFrQixFQUFDLFlBQVksRUFBRSxRQUFRLENBQUMsT0FBTyxDQUFDLEdBQUcsQ0FBQywyQkFBMkIsSUFBSSxLQUFLLEVBQUUsRUFBRSxDQUFDLENBQUMsQ0FBQztBQTRHekgsMkRBQTJEO0FBRTNEOzs7Ozs7O0dBT0c7QUFDSCxNQUFhLGdCQUFnQjtJQUUzQiwwRUFBMEU7SUFDMUUsS0FBSyxDQUFDLGFBQWEsQ0FBQyxLQUFhO1FBQy9CLE1BQU0sT0FBTyxDQUFDLEdBQUcsQ0FBQztZQUNoQixjQUFjLENBQUMsaUJBQWlCLENBQUMsR0FBRyxLQUFLLElBQUksQ0FBQztZQUM5QyxlQUFlLENBQUMsaUJBQWlCLENBQUMsR0FBRyxLQUFLLElBQUksQ0FBQztTQUNoRCxDQUFDLENBQUM7SUFDTCxDQUFDO0lBRUQscURBQXFEO0lBRXJELDhEQUE4RDtJQUM5RCxLQUFLLENBQUMsaUJBQWlCLENBQUMsS0FBYTtRQUNuQyxPQUFPLGVBQWUsQ0FB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Q3JDLEtBQUssQ0FBQyxnQkFBZ0IsQ0FBQyxLQUFhLEVBQUUsSUFBWSxFQUFFLEVBQVU7UUFDNUQsT0FBTyxlQUFlLENBQUMsUUFBUSxDQUFDLEdBQUcsS0FBSyxtQkFBbUIsSUFBSSxJQUFJLEVBQUUsRUFBRSxFQUFFLEdBQUcsRUFBRSxDQUM1RSx3QkFBRSxDQUFDLE9BQU8sQ0FBQyxJQUFBLGlCQUFHLEVBQUE7Ozs7OztlQU1MLHVCQUFNLENBQUMsYUFBYTsyQkFDUixLQUFLO2dDQUNBLElBQUkscUNBQXFDLEVBQUU7O09BRXBFLENBQUMsQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxPQUFPLENBQWdCLENBQUMsQ0FBQyxDQUFDLENBQ3hDLENBQUM7SUFDSixDQUFDO0lBRUQsK0NBQStDO0lBQy9DLEtBQUssQ0FBQyxnQkFBZ0IsQ0FBQyxLQUFhLEVBQUUsSUFBWSxFQUFFLEVBQVUsRUFBRSxRQUFnQixFQUFFO1FBQ2hGLE9BQU8sZUFBZSxDQUFDLFFBQVEsQ0FBQyxHQUFHLEtBQUssbUJBQW1CLElBQUksSUFBSSxFQUFFLElBQUksS0FBSyxFQUFFLEVBQUUsR0FBRyxFQUFFLENBQ3JGLHdCQUFFLENBQUMsT0FBTyxDQUFDLElBQUEsaUJBQUcsRUFBQTs7Ozs7O2VBTUwsdUJBQU0sQ0FBQyxhQUFhOzJCQUNSLEtBQUs7Z0NBQ0EsSUFBSSxxQ0FBcUMsRUFBRTs7O2dCQUczRCxLQUFLO09BQ2QsQ0FBQyxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDLE9BQU8sQ0FBZSxDQUFDLENBQUMsQ0FBQyxDQUN2QyxDQUFDO0lBQ0osQ0FBQztDQUNGO0FBaFFELDRDQWdRQztBQUVZLFFBQUEsZ0JBQWdCLEdBQUcsSUFBSSxnQkFBZ0IsRUFBRSxDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiLy8gQ29weXJpZ2h0IDIwMjYgUGlwZWxpbmUgQnVpbGRlciBDb250cmlidXRvcnNcbi8vIFNQRFgtTGljZW5zZS1JZGVudGlmaWVyOiBBcGFjaGUtMi4wXG5cbmltcG9ydCB7IGNyZWF0ZUNhY2hlU2VydmljZSB9IGZyb20gJ0BwaXBlbGluZS1idWlsZGVyL2FwaS1jb3JlJztcbmltcG9ydCB7IHNxbCB9IGZyb20gJ2RyaXp6bGUtb3JtJztcbmltcG9ydCB7IGRyaXp6bGVSb3dzIH0gZnJvbSAnLi9jcnVkLXNlcnZpY2UnO1xuaW1wb3J0IHsgc2NoZW1hIH0gZnJvbSAnLi4vZGF0YWJhc2UvZHJpenpsZS1zY2hlbWEnO1xuaW1wb3J0IHsgZGIgfSBmcm9tICcuLi9kYXRhYmFzZS9wb3N0Z3Jlcy1jb25uZWN0aW9uJztcblxuLyoqIENhc3QgcmF3IFNRTCByZXN1bHQgcm93cyB0byBhIHR5cGVkIGFycmF5LiBBbGlhcyBmb3IgZHJpenpsZVJvd3MuICovXG5jb25zdCBzcWxSb3dzID0gPFQ+KHJlc3VsdDogeyByb3dzOiB1bmtub3duW10gfSk6IFRbXSA9PiBkcml6emxlUm93czxUPihyZXN1bHQucm93cyk7XG5cbi8qKlxuICogQ2FjaGUgZm9yIHJlcG9ydGluZyBhZ2dyZWdhdGlvbnMuIFR3byB0aWVyczpcbiAqIC0gSW52ZW50b3J5IHF1ZXJpZXMgKHBsdWdpbiBzdW1tYXJ5L2Rpc3RyaWJ1dGlvbi92ZXJzaW9ucyk6IDUgbWluIFRUTCDigJQgY2hhbmdlcyBvbiBwbHVnaW4gQ1JVRFxuICogLSBFeGVjdXRpb24vYnVpbGQgcXVlcmllcyB3aXRoIGRhdGUgcmFuZ2VzOiAyIG1pbiBUVEwg4oCUIG5ldyBldmVudHMgYXJyaXZlIGNvbnRpbnVvdXNseVxuICovXG5jb25zdCBpbnZlbnRvcnlDYWNoZSA9IGNyZWF0ZUNhY2hlU2VydmljZSgncmVwb3J0OmludjonLCBwYXJzZUludChwcm9jZXNzLmVudi5DQUNIRV9UVExfUkVQT1JUX0lOVkVOVE9SWSB8fCAnMzAwJywgMTApKTtcbmNvbnN0IHRpbWVzZXJpZXNDYWNoZSA9IGNyZWF0ZUNhY2hlU2VydmljZSgncmVwb3J0OnRzOicsIHBhcnNlSW50KHByb2Nlc3MuZW52LkNBQ0hFX1RUTF9SRVBPUlRfVElNRVNFUklFUyB8fCAnMTIwJywgMTApKTtcblxuLy8g4pSA4pSA4pSAIFR5cGVzIOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgFxuXG5pbnRlcmZhY2UgRXhlY3V0aW9uQ291bnQge1xuICBpZDogc3RyaW5nO1xuICBwcm9qZWN0OiBzdHJpbmc7XG4gIG9yZ2FuaXphdGlvbjogc3RyaW5nO1xuICBwaXBlbGluZU5hbWU6IHN0cmluZyB8IG51bGw7XG4gIHRvdGFsOiBudW1iZXI7XG4gIHN1Y2NlZWRlZDogbnVtYmVyO1xuICBmYWlsZWQ6IG51bWJlcjtcbiAgY2FuY2VsZWQ6IG51bWJlcjtcbiAgZmlyc3RFeGVjdXRpb246IHN0cmluZyB8IG51bGw7XG4gIGxhc3RFeGVjdXRpb246IHN0cmluZyB8IG51bGw7XG59XG5cbmludGVyZmFjZSBUaW1lU2VyaWVzRW50cnkge1xuICBwZXJpb2Q6IHN0cmluZztcbiAgc3VjY2VlZGVkOiBudW1iZXI7XG4gIGZhaWxlZDogbnVtYmVyO1xuICBjYW5jZWxlZDogbnVtYmVyO1xuICBzdWNjZXNzUGN0OiBudW1iZXI7XG59XG5cbmludGVyZmFjZSBEdXJhdGlvblN0YXRzIHtcbiAgaWQ6IHN0cmluZztcbiAgcHJvamVjdDogc3RyaW5nO1xuICBwaXBlbGluZU5hbWU6IHN0cmluZyB8IG51bGw7XG4gIGF2Z01zOiBudW1iZXI7XG4gIG1pbk1zOiBudW1iZXI7XG4gIG1heE1zOiBudW1iZXI7XG4gIHA5NU1zOiBudW1iZXI7XG4gIGV4ZWN1dGlvbnM6IG51bWJlcjtcbn1cblxuaW50ZXJmYWNlIFN0YWdlRmFpbHVyZSB7XG4gIHN0YWdlTmFtZTogc3RyaW5nO1xuICBmYWlsdXJlczogbnVtYmVyO1xuICB0b3RhbDogbnVtYmVyO1xuICBmYWlsdXJlUGN0OiBudW1iZXI7XG59XG5cbmludGVyZmFjZSBTdGFnZUJvdHRsZW5lY2sge1xuICBpZDogc3RyaW5nO1xuICBwaXBlbGluZU5hbWU6IHN0cmluZyB8IG51bGw7XG4gIHN0YWdlTmFtZTogc3RyaW5nO1xuICBhdmdNczogbnVtYmVyO1xuICBtYXhNczogbnVtYmVyO1xufVxuXG5pbnRlcmZhY2UgQWN0aW9uRmFpbHVyZSB7XG4gIGFjdGlvbk5hbWU6IHN0cmluZztcbiAgZmFpbHVyZXM6IG51bWJlcjtcbiAgdG90YWw6IG51bWJlcjtcbiAgZmFpbHVyZVBjdDogbnVtYmVyO1xufVxuXG5pbnRlcmZhY2UgRXJyb3JFbnRyeSB7XG4gIGVycm9yUGF0dGVybjogc3RyaW5nO1xuICBvY2N1cnJlbmNlczogbnVtYmVyO1xuICBhZmZlY3RlZFBpcGVsaW5lczogbnVtYmVyO1xuICBsYXN0U2Vlbjogc3RyaW5nO1xufVxuXG5pbnRlcmZhY2UgUGx1Z2luU3VtbWFyeSB7XG4gIHRvdGFsOiBudW1iZXI7XG4gIGFjdGl2ZTogbnVtYmVyO1xuICBpbmFjdGl2ZTogbnVtYmVyO1xuICBwdWJsaWM6IG51bWJlcjtcbiAgcHJpdmF0ZTogbnVtYmVyO1xuICB1bmlxdWVOYW1lczogbnVtYmVyO1xufVxuXG5pbnRlcmZhY2UgVHlwZUNvbXB1dGVEaXN0cmlidXRpb24ge1xuICBwbHVnaW5UeXBlOiBzdHJpbmc7XG4gIGNvbXB1dGVUeXBlOiBzdHJpbmc7XG4gIGNvdW50OiBudW1iZXI7XG59XG5cbmludGVyZmFjZSBWZXJzaW9uQ291bnQge1xuICBuYW1lOiBzdHJpbmc7XG4gIHZlcnNpb25Db3VudDogbnVtYmVyO1xuICBsYXRlc3RWZXJzaW9uOiBzdHJpbmc7XG4gIGhhc0RlZmF1bHQ6IGJvb2xlYW47XG59XG5cbmludGVyZmFjZSBCdWlsZFRpbWVTZXJpZXNFbnRyeSB7XG4gIHBlcmlvZDogc3RyaW5nO1xuICBzdWNjZWVkZWQ6IG51bWJlcjtcbiAgZmFpbGVkOiBudW1iZXI7XG4gIHN1Y2Nlc3NQY3Q6IG51bWJlcjtcbn1cblxuaW50ZXJmYWNlIEJ1aWxkRHVyYXRpb24ge1xuICBwbHVnaW5OYW1lOiBzdHJpbmc7XG4gIGF2Z01zOiBudW1iZXI7XG4gIG1heE1zOiBudW1iZXI7XG4gIGJ1aWxkczogbnVtYmVyO1xufVxuXG5pbnRlcmZhY2UgQnVpbGRGYWlsdXJlIHtcbiAgcGx1Z2luTmFtZTogc3RyaW5nO1xuICBlcnJvck1lc3NhZ2U6IHN0cmluZztcbiAgb2NjdXJyZW5jZXM6IG51bWJlcjtcbiAgbGFzdFNlZW46IHN0cmluZztcbn1cblxuLy8g4pSA4pSA4pSAIFNlcnZpY2Ug4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSAXG5cbi8qKlxuICogUmVhZC1vbmx5IHJlcG9ydGluZyBzZXJ2aWNlIGZvciBwaXBlbGluZSBleGVjdXRpb24gYW5kIHBsdWdpbiBpbnZlbnRvcnkgYWdncmVnYXRpb25zLlxuICogRG9lcyBub3QgZXh0ZW5kIENydWRTZXJ2aWNlIOKAlCByZXBvcnRzIGFyZSBhZ2dyZWdhdGUgcXVlcmllcywgbm90IGVudGl0eSBDUlVELlxuICpcbiAqIEFsbCBxdWVyaWVzIGFyZSBjYWNoZWQgaW4tbWVtb3J5IHRvIGF2b2lkIHJlcGVhdGVkIGV4cGVuc2l2ZSBTUUwgYWdncmVnYXRpb25zOlxuICogLSBJbnZlbnRvcnkgcXVlcmllcyAocGx1Z2luIHN1bW1hcnkvZGlzdHJpYnV0aW9uL3ZlcnNpb25zKTogNSBtaW4gVFRMXG4gKiAtIFRpbWVzZXJpZXMgcXVlcmllcyAoZXhlY3V0aW9uL2J1aWxkIG1ldHJpY3Mgd2l0aCBkYXRlIHJhbmdlcyk6IDIgbWluIFRUTFxuICovXG5leHBvcnQgY2xhc3MgUmVwb3J0aW5nU2VydmljZSB7XG5cbiAgLyoqIEludmFsaWRhdGUgYWxsIGNhY2hlZCByZXBvcnRzIGZvciBhbiBvcmcgKGNhbGwgYWZ0ZXIgZXZlbnQgaW5nZXN0KS4gKi9cbiAgYXN5bmMgaW52YWxpZGF0ZU9yZyhvcmdJZDogc3RyaW5nKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgYXdhaXQgUHJvbWlzZS5hbGwoW1xuICAgICAgaW52ZW50b3J5Q2FjaGUuaW52YWxpZGF0ZVBhdHRlcm4oYCR7b3JnSWR9OipgKSxcbiAgICAgIHRpbWVzZXJpZXNDYWNoZS5pbnZhbGlkYXRlUGF0dGVybihgJHtvcmdJZH06KmApLFxuICAgIF0pO1xuICB9XG5cbiAgLy8g4pSA4pSAIENhdGVnb3J5IDE6IFBpcGVsaW5lIEV4ZWN1dGlvbiAmIFBlcmZvcm1hbmNlIOKUgOKUgFxuXG4gIC8qKiAxLjEgRXhlY3V0aW9uIGNvdW50IHBlciBwaXBlbGluZSB3aXRoIHN0YXR1cyBicmVha2Rvd24uICovXG4gIGFzeW5jIGdldEV4ZWN1dGlvbkNvdW50KG9yZ0lkOiBzdHJpbmcpOiBQcm9taXNlPEV4ZWN1dGlvbkNvdW50W10+IHtcbiAgICByZXR1cm4gdGltZXNlcmllc0NhY2hlLmdldE9yU2V0KGAke29yZ0lkfTpleGVjLWNvdW50YCwgKCkgPT5cbiAgICAgIGRiLmV4ZWN1dGUoc3FsYFxuICAgICAgICBTRUxFQ1RcbiAgICAgICAgICBwLmlkLCBwLnByb2plY3QsIHAub3JnYW5pemF0aW9uLCBwLnBpcGVsaW5lX25hbWUsXG4gICAgICAgICAgQ09VTlQoKik6OmludCBBUyB0b3RhbCxcbiAgICAgICAgICBDT1VOVCgqKSBGSUxURVIgKFdIRVJFIGUuc3RhdHVzID0gJ1NVQ0NFRURFRCcpOjppbnQgQVMgc3VjY2VlZGVkLFxuICAgICAgICAgIENPVU5UKCopIEZJTFRFUiAoV0hFUkUgZS5zdGF0dXMgPSAnRkFJTEVEJyk6OmludCBBUyBmYWlsZWQsXG4gICAgICAgICAgQ09VTlQoKikgRklMVEVSIChXSEVSRSBlLnN0YXR1cyA9ICdDQU5DRUxFRCcpOjppbnQgQVMgY2FuY2VsZWQsXG4gICAgICAgICAgTUlOKGUuc3RhcnRlZF9hdCk6OnRleHQgQVMgZmlyc3RfZXhlY3V0aW9uLFxuICAgICAgICAgIE1BWChlLnN0YXJ0ZWRfYXQpOjp0ZXh0IEFTIGxhc3RfZXhlY3V0aW9uXG4gICAgICAgIEZST00gJHtzY2hlbWEucGlwZWxpbmV9IHBcbiAgICAgICAgSk9JTiAke3NjaGVtYS5waXBlbGluZUV2ZW50fSBlIE9OIGUucGlwZWxpbmVfaWQgPSBwLmlkXG4gICAgICAgICAgQU5EIGUuZXZlbnRfdHlwZSA9ICdQSVBFTElORScgQU5EIGUuc3RhdHVzICE9ICdTVEFSVEVEJ1xuICAgICAgICBXSEVSRSBwLm9yZ19pZCA9ICR7b3JnSWR9IEFORCBwLmlzX2FjdGl2ZSA9IHRydWVcbiAgICAgICAgR1JPVVAgQlkgcC5pZFxuICAgICAgICBPUkRFUiBCWSB0b3RhbCBERVNDXG4gICAgICBgKS50aGVuKHIgPT4gc3FsUm93czxFeGVjdXRpb25Db3VudD4ocikpLFxuICAgICk7XG4gIH1cblxuICAvKiogMS4yIFN1Y2Nlc3MgcmF0ZSBvdmVyIHRpbWUgZm9yIGFuIG9yZy4gKi9cbiAgYXN5bmMgZ2V0U3VjY2Vzc1JhdGUob3JnSWQ6IHN0cmluZywgaW50ZXJ2YWw6IHN0cmluZywgZnJvbTogc3RyaW5nLCB0bzogc3RyaW5nKTogUHJvbWlzZTxUaW1lU2VyaWVzRW50cnlbXT4ge1xuICAgIHJldHVybiB0aW1lc2VyaWVzQ2FjaGUuZ2V0T3JTZXQoYCR7b3JnSWR9OnN1Y2Nlc3MtcmF0ZToke2ludGVydmFsfToke2Zyb219OiR7dG99YCwgKCkgPT5cbiAgICAgIGRiLmV4ZWN1dGUoc3FsYFxuICAgICAgICBTRUxFQ1RcbiAgICAgICAgICBEQVRFX1RSVU5DKCR7aW50ZXJ2YWx9LCBlLnN0YXJ0ZWRfYXQpOjp0ZXh0IEFTIHBlcmlvZCxcbiAgICAgICAgICBDT1VOVCgqKSBGSUxURVIgKFdIRVJFIGUuc3RhdHVzID0gJ1NVQ0NFRURFRCcpOjppbnQgQVMgc3VjY2VlZGVkLFxuICAgICAgICAgIENPVU5UKCopIEZJTFRFUiAoV0hFUkUgZS5zdGF0dXMgPSAnRkFJTEVEJyk6OmludCBBUyBmYWlsZWQsXG4gICAgICAgICAgQ09VTlQoKikgRklMVEVSIChXSEVSRSBlLnN0YXR1cyA9ICdDQU5DRUxFRCcpOjppbnQgQVMgY2FuY2VsZWQsXG4gICAgICAgICAgUk9VTkQoQ09VTlQoKikgRklMVEVSIChXSEVSRSBlLnN0YXR1cyA9ICdTVUNDRUVERUQnKTo6bnVtZXJpY1xuICAgICAgICAgICAgLyBOVUxMSUYoQ09VTlQoKiksIDApICogMTAwLCAxKTo6ZmxvYXQgQVMgc3VjY2Vzc19wY3RcbiAgICAgICAgRlJPTSAke3NjaGVtYS5waXBlbGluZUV2ZW50fSBlXG4gICAgICAgIEpPSU4gJHtzY2hlbWEucGlwZWxpbmV9IHAgT04gcC5pZCA9IGUucGlwZWxpbmVfaWRcbiAgICAgICAgV0hFUkUgcC5vcmdfaWQgPSAke29yZ0lkfSBBTkQgZS5ldmVudF90eXBlID0gJ1BJUEVMSU5FJ1xuICAgICAgICAgIEFORCBlLnN0YXR1cyBJTiAoJ1NVQ0NFRURFRCcsICdGQUlMRUQnLCAnQ0FOQ0VMRUQnKVxuICAgICAgICAgIEFORCBlLnN0YXJ0ZWRfYXQgPj0gJHtmcm9tfTo6dGltZXN0YW1wdHogQU5EIGUuc3RhcnRlZF9hdCA8PSAke3RvfTo6dGltZXN0YW1wdHpcbiAgICAgICAgR1JPVVAgQlkgcGVyaW9kIE9SREVSIEJZIHBlcmlvZFxuICAgICAgYCkudGhlbihyID0+IHNxbFJvd3M8VGltZVNlcmllc0VudHJ5PihyKSksXG4gICAgKTtcbiAgfVxuXG4gIC8qKiAxLjMgQXZlcmFnZSBkdXJhdGlvbiBwZXIgcGlwZWxpbmUuICovXG4gIGFzeW5jIGdldEF2ZXJhZ2VEdXJhdGlvbihvcmdJZDogc3RyaW5nLCBmcm9tOiBzdHJpbmcsIHRvOiBzdHJpbmcpOiBQcm9taXNlPER1cmF0aW9uU3RhdHNbXT4ge1xuICAgIHJldHVybiB0aW1lc2VyaWVzQ2FjaGUuZ2V0T3JTZXQoYCR7b3JnSWR9OmF2Zy1kdXJhdGlvbjoke2Zyb219OiR7dG99YCwgKCkgPT5cbiAgICAgIGRiLmV4ZWN1dGUoc3FsYFxuICAgICAgICBTRUxFQ1RcbiAgICAgICAgICBwLmlkLCBwLnByb2plY3QsIHAucGlwZWxpbmVfbmFtZSxcbiAgICAgICAgICBBVkcoZS5kdXJhdGlvbl9tcyk6OmludCBBUyBhdmdfbXMsXG4gICAgICAgICAgTUlOKGUuZHVyYXRpb25fbXMpOjppbnQgQVMgbWluX21zLFxuICAgICAgICAgIE1BWChlLmR1cmF0aW9uX21zKTo6aW50IEFTIG1heF9tcyxcbiAgICAgICAgICBQRVJDRU5USUxFX0NPTlQoMC45NSkgV0lUSElOIEdST1VQIChPUkRFUiBCWSBlLmR1cmF0aW9uX21zKTo6aW50IEFTIHA5NV9tcyxcbiAgICAgICAgICBDT1VOVCgqKTo6aW50IEFTIGV4ZWN1dGlvbnNcbiAgICAgICAgRlJPTSAke3NjaGVtYS5waXBlbGluZUV2ZW50fSBlXG4gICAgICAgIEpPSU4gJHtzY2hlbWEucGlwZWxpbmV9IHAgT04gcC5pZCA9IGUucGlwZWxpbmVfaWRcbiAgICAgICAgV0hFUkUgcC5vcmdfaWQgPSAke29yZ0lkfSBBTkQgZS5ldmVudF90eXBlID0gJ1BJUEVMSU5FJyBBTkQgZS5kdXJhdGlvbl9tcyBJUyBOT1QgTlVMTFxuICAgICAgICAgIEFORCBlLnN0YXJ0ZWRfYXQgPj0gJHtmcm9tfTo6dGltZXN0YW1wdHogQU5EIGUuc3RhcnRlZF9hdCA8PSAke3RvfTo6dGltZXN0YW1wdHpcbiAgICAgICAgR1JPVVAgQlkgcC5pZCBPUkRFUiBCWSBhdmdfbXMgREVTQ1xuICAgICAgYCkudGhlbihyID0+IHNxbFJvd3M8RHVyYXRpb25TdGF0cz4ocikpLFxuICAgICk7XG4gIH1cblxuICAvKiogMS41IFN0YWdlIGZhaWx1cmUgaGVhdG1hcCDigJQgd2hpY2ggc3RhZ2VzIGZhaWwgbW9zdC4gKi9cbiAgYXN5bmMgZ2V0U3RhZ2VGYWlsdXJlcyhvcmdJZDogc3RyaW5nLCBmcm9tOiBzdHJpbmcsIHRvOiBzdHJpbmcpOiBQcm9taXNlPFN0YWdlRmFpbHVyZVtdPiB7XG4gICAgcmV0dXJuIHRpbWVzZXJpZXNDYWNoZS5nZXRPclNldChgJHtvcmdJZH06c3RhZ2UtZmFpbHVyZXM6JHtmcm9tfToke3RvfWAsICgpID0+XG4gICAgICBkYi5leGVjdXRlKHNxbGBcbiAgICAgICAgU0VMRUNUXG4gICAgICAgICAgZS5zdGFnZV9uYW1lLFxuICAgICAgICAgIENPVU5UKCopIEZJTFRFUiAoV0hFUkUgZS5zdGF0dXMgPSAnRkFJTEVEJyk6OmludCBBUyBmYWlsdXJlcyxcbiAgICAgICAgICBDT1VOVCgqKTo6aW50IEFTIHRvdGFsLFxuICAgICAgICAgIFJPVU5EKENPVU5UKCopIEZJTFRFUiAoV0hFUkUgZS5zdGF0dXMgPSAnRkFJTEVEJyk6Om51bWVyaWNcbiAgICAgICAgICAgIC8gTlVMTElGKENPVU5UKCopLCAwKSAqIDEwMCwgMSk6OmZsb2F0IEFTIGZhaWx1cmVfcGN0XG4gICAgICAgIEZST00gJHtzY2hlbWEucGlwZWxpbmVFdmVudH0gZVxuICAgICAgICBKT0lOICR7c2NoZW1hLnBpcGVsaW5lfSBwIE9OIHAuaWQgPSBlLnBpcGVsaW5lX2lkXG4gICAgICAgIFdIRVJFIHAub3JnX2lkID0gJHtvcmdJZH0gQU5EIGUuZXZlbnRfdHlwZSA9ICdTVEFHRScgQU5EIGUuc3RhZ2VfbmFtZSBJUyBOT1QgTlVMTFxuICAgICAgICAgIEFORCBlLnN0YXJ0ZWRfYXQgPj0gJHtmcm9tfTo6dGltZXN0YW1wdHogQU5EIGUuc3RhcnRlZF9hdCA8PSAke3RvfTo6dGltZXN0YW1wdHpcbiAgICAgICAgR1JPVVAgQlkgZS5zdGFnZV9uYW1lIE9SREVSIEJZIGZhaWx1cmVzIERFU0NcbiAgICAgIGApLnRoZW4ociA9PiBzcWxSb3dzPFN0YWdlRmFpbHVyZT4ocikpLFxuICAgICk7XG4gIH1cblxuICAvKiogMS42IFN0YWdlIGJvdHRsZW5lY2tzIOKAlCBzbG93ZXN0IHN0YWdlcyBwZXIgcGlwZWxpbmUuICovXG4gIGFzeW5jIGdldFN0YWdlQm90dGxlbmVja3Mob3JnSWQ6IHN0cmluZywgZnJvbTogc3RyaW5nLCB0bzogc3RyaW5nKTogUHJvbWlzZTxTdGFnZUJvdHRsZW5lY2tbXT4ge1xuICAgIHJldHVybiB0aW1lc2VyaWVzQ2FjaGUuZ2V0T3JTZXQoYCR7b3JnSWR9OnN0YWdlLWJvdHRsZW5lY2tzOiR7ZnJvbX06JHt0b31gLCAoKSA9PlxuICAgICAgZGIuZXhlY3V0ZShzcWxgXG4gICAgICAgIFNFTEVDVFxuICAgICAgICAgIHAuaWQsIHAucGlwZWxpbmVfbmFtZSwgZS5zdGFnZV9uYW1lLFxuICAgICAgICAgIEFWRyhlLmR1cmF0aW9uX21zKTo6aW50IEFTIGF2Z19tcyxcbiAgICAgICAgICBNQVgoZS5kdXJhdGlvbl9tcyk6OmludCBBUyBtYXhfbXNcbiAgICAgICAgRlJPTSAke3NjaGVtYS5waXBlbGluZUV2ZW50fSBlXG4gICAgICAgIEpPSU4gJHtzY2hlbWEucGlwZWxpbmV9IHAgT04gcC5pZCA9IGUucGlwZWxpbmVfaWRcbiAgICAgICAgV0hFUkUgcC5vcmdfaWQgPSAke29yZ0lkfSBBTkQgZS5ldmVudF90eXBlID0gJ1NUQUdFJyBBTkQgZS5kdXJhdGlvbl9tcyBJUyBOT1QgTlVMTFxuICAgICAgICAgIEFORCBlLnN0YXJ0ZWRfYXQgPj0gJHtmcm9tfTo6dGltZXN0YW1wdHogQU5EIGUuc3RhcnRlZF9hdCA8PSAke3RvfTo6dGltZXN0YW1wdHpcbiAgICAgICAgR1JPVVAgQlkgcC5pZCwgZS5zdGFnZV9uYW1lIE9SREVSIEJZIGF2Z19tcyBERVNDXG4gICAgICBgKS50aGVuKHIgPT4gc3FsUm93czxTdGFnZUJvdHRsZW5lY2s+KHIpKSxcbiAgICApO1xuICB9XG5cbiAgLyoqIDEuNyBBY3Rpb24gZmFpbHVyZSByYXRlIOKAlCB3aGljaCBwbHVnaW4gc3RlcHMgZmFpbCBtb3N0LiAqL1xuICBhc3luYyBnZXRBY3Rpb25GYWlsdXJlcyhvcmdJZDogc3RyaW5nLCBmcm9tOiBzdHJpbmcsIHRvOiBzdHJpbmcpOiBQcm9taXNlPEFjdGlvbkZhaWx1cmVbXT4ge1xuICAgIHJldHVybiB0aW1lc2VyaWVzQ2FjaGUuZ2V0T3JTZXQoYCR7b3JnSWR9OmFjdGlvbi1mYWlsdXJlczoke2Zyb219OiR7dG99YCwgKCkgPT5cbiAgICAgIGRiLmV4ZWN1dGUoc3FsYFxuICAgICAgICBTRUxFQ1RcbiAgICAgICAgICBlLmFjdGlvbl9uYW1lLFxuICAgICAgICAgIENPVU5UKCopIEZJTFRFUiAoV0hFUkUgZS5zdGF0dXMgPSAnRkFJTEVEJyk6OmludCBBUyBmYWlsdXJlcyxcbiAgICAgICAgICBDT1VOVCgqKTo6aW50IEFTIHRvdGFsLFxuICAgICAgICAgIFJPVU5EKENPVU5UKCopIEZJTFRFUiAoV0hFUkUgZS5zdGF0dXMgPSAnRkFJTEVEJyk6Om51bWVyaWNcbiAgICAgICAgICAgIC8gTlVMTElGKENPVU5UKCopLCAwKSAqIDEwMCwgMSk6OmZsb2F0IEFTIGZhaWx1cmVfcGN0XG4gICAgICAgIEZST00gJHtzY2hlbWEucGlwZWxpbmVFdmVudH0gZVxuICAgICAgICBKT0lOICR7c2NoZW1hLnBpcGVsaW5lfSBwIE9OIHAuaWQgPSBlLnBpcGVsaW5lX2lkXG4gICAgICAgIFdIRVJFIHAub3JnX2lkID0gJHtvcmdJZH0gQU5EIGUuZXZlbnRfdHlwZSA9ICdBQ1RJT04nIEFORCBlLmFjdGlvbl9uYW1lIElTIE5PVCBOVUxMXG4gICAgICAgICAgQU5EIGUuc3RhcnRlZF9hdCA+PSAke2Zyb219Ojp0aW1lc3RhbXB0eiBBTkQgZS5zdGFydGVkX2F0IDw9ICR7dG99Ojp0aW1lc3RhbXB0elxuICAgICAgICBHUk9VUCBCWSBlLmFjdGlvbl9uYW1lIE9SREVSIEJZIGZhaWx1cmVzIERFU0NcbiAgICAgIGApLnRoZW4ociA9PiBzcWxSb3dzPEFjdGlvbkZhaWx1cmU+KHIpKSxcbiAgICApO1xuICB9XG5cbiAgLyoqIDEuOCBFcnJvciBjYXRlZ29yaXphdGlvbiDigJQgZ3JvdXAgZmFpbHVyZSBtZXNzYWdlcy4gKi9cbiAgYXN5bmMgZ2V0RXJyb3JzKG9yZ0lkOiBzdHJpbmcsIGZyb206IHN0cmluZywgdG86IHN0cmluZywgbGltaXQ6IG51bWJlciA9IDIwKTogUHJvbWlzZTxFcnJvckVudHJ5W10+IHtcbiAgICByZXR1cm4gdGltZXNlcmllc0NhY2hlLmdldE9yU2V0KGAke29yZ0lkfTplcnJvcnM6JHtmcm9tfToke3RvfToke2xpbWl0fWAsICgpID0+XG4gICAgICBkYi5leGVjdXRlKHNxbGBcbiAgICAgICAgU0VMRUNUXG4gICAgICAgICAgU1VCU1RSSU5HKGUuZXJyb3JfbWVzc2FnZSBGUk9NIDEgRk9SIDIwMCkgQVMgZXJyb3JfcGF0dGVybixcbiAgICAgICAgICBDT1VOVCgqKTo6aW50IEFTIG9jY3VycmVuY2VzLFxuICAgICAgICAgIENPVU5UKERJU1RJTkNUIGUucGlwZWxpbmVfaWQpOjppbnQgQVMgYWZmZWN0ZWRfcGlwZWxpbmVzLFxuICAgICAgICAgIE1BWChlLnN0YXJ0ZWRfYXQpOjp0ZXh0IEFTIGxhc3Rfc2VlblxuICAgICAgICBGUk9NICR7c2NoZW1hLnBpcGVsaW5lRXZlbnR9IGVcbiAgICAgICAgSk9JTiAke3NjaGVtYS5waXBlbGluZX0gcCBPTiBwLmlkID0gZS5waXBlbGluZV9pZFxuICAgICAgICBXSEVSRSBwLm9yZ19pZCA9ICR7b3JnSWR9IEFORCBlLnN0YXR1cyA9ICdGQUlMRUQnIEFORCBlLmVycm9yX21lc3NhZ2UgSVMgTk9UIE5VTExcbiAgICAgICAgICBBTkQgZS5zdGFydGVkX2F0ID49ICR7ZnJvbX06OnRpbWVzdGFtcHR6IEFORCBlLnN0YXJ0ZWRfYXQgPD0gJHt0b306OnRpbWVzdGFtcHR6XG4gICAgICAgIEdST1VQIEJZIGVycm9yX3BhdHRlcm4gT1JERVIgQlkgb2NjdXJyZW5jZXMgREVTQ1xuICAgICAgICBMSU1JVCAke2xpbWl0fVxuICAgICAgYCkudGhlbihyID0+IHNxbFJvd3M8RXJyb3JFbnRyeT4ocikpLFxuICAgICk7XG4gIH1cblxuICAvLyDilIDilIAgQ2F0ZWdvcnkgMjogUGx1Z2luIEludmVudG9yeSAmIEJ1aWxkcyDilIDilIBcblxuICAvKiogMi4xIFBsdWdpbiBzdW1tYXJ5IOKAlCBjb3VudHMgYW5kIGJyZWFrZG93bnMuICovXG4gIGFzeW5jIGdldFBsdWdpblN1bW1hcnkob3JnSWQ6IHN0cmluZyk6IFByb21pc2U8UGx1Z2luU3VtbWFyeT4ge1xuICAgIHJldHVybiBpbnZlbnRvcnlDYWNoZS5nZXRPclNldChgJHtvcmdJZH06cGx1Z2luLXN1bW1hcnlgLCBhc3luYyAoKSA9PiB7XG4gICAgICBjb25zdCByb3dzID0gYXdhaXQgZGIuZXhlY3V0ZShzcWxgXG4gICAgICAgIFNFTEVDVFxuICAgICAgICAgIENPVU5UKCopOjppbnQgQVMgdG90YWwsXG4gICAgICAgICAgQ09VTlQoKikgRklMVEVSIChXSEVSRSAke3NjaGVtYS5wbHVnaW4uaXNBY3RpdmV9KTo6aW50IEFTIGFjdGl2ZSxcbiAgICAgICAgICBDT1VOVCgqKSBGSUxURVIgKFdIRVJFIE5PVCAke3NjaGVtYS5wbHVnaW4uaXNBY3RpdmV9KTo6aW50IEFTIGluYWN0aXZlLFxuICAgICAgICAgIENPVU5UKCopIEZJTFRFUiAoV0hFUkUgJHtzY2hlbWEucGx1Z2luLmFjY2Vzc01vZGlmaWVyfSA9ICdwdWJsaWMnKTo6aW50IEFTIHB1YmxpYyxcbiAgICAgICAgICBDT1VOVCgqKSBGSUxURVIgKFdIRVJFICR7c2NoZW1hLnBsdWdpbi5hY2Nlc3NNb2RpZmllcn0gPSAncHJpdmF0ZScpOjppbnQgQVMgcHJpdmF0ZSxcbiAgICAgICAgICBDT1VOVChESVNUSU5DVCAke3NjaGVtYS5wbHVnaW4ubmFtZX0pOjppbnQgQVMgdW5pcXVlX25hbWVzXG4gICAgICAgIEZST00gJHtzY2hlbWEucGx1Z2lufVxuICAgICAgICBXSEVSRSAke3NjaGVtYS5wbHVnaW4ub3JnSWR9ID0gJHtvcmdJZH1cbiAgICAgIGApO1xuICAgICAgcmV0dXJuIChzcWxSb3dzPFBsdWdpblN1bW1hcnk+KHJvd3MpWzBdIHx8IHsgdG90YWw6IDAsIGFjdGl2ZTogMCwgaW5hY3RpdmU6IDAsIHB1YmxpYzogMCwgcHJpdmF0ZTogMCwgdW5pcXVlTmFtZXM6IDAgfSk7XG4gICAgfSk7XG4gIH1cblxuICAvKiogMi4yIFR5cGUgJiBjb21wdXRlIGRpc3RyaWJ1dGlvbi4gKi9cbiAgYXN5bmMgZ2V0UGx1Z2luRGlzdHJpYnV0aW9uKG9yZ0lkOiBzdHJpbmcpOiBQcm9taXNlPFR5cGVDb21wdXRlRGlzdHJpYnV0aW9uW10+IHtcbiAgICByZXR1cm4gaW52ZW50b3J5Q2FjaGUuZ2V0T3JTZXQoYCR7b3JnSWR9OnBsdWdpbi1kaXN0cmlidXRpb25gLCAoKSA9PlxuICAgICAgZGIuZXhlY3V0ZShzcWxgXG4gICAgICAgIFNFTEVDVFxuICAgICAgICAgICR7c2NoZW1hLnBsdWdpbi5wbHVnaW5UeXBlfSBBUyBwbHVnaW5fdHlwZSxcbiAgICAgICAgICAke3NjaGVtYS5wbHVnaW4uY29tcHV0ZVR5cGV9IEFTIGNvbXB1dGVfdHlwZSxcbiAgICAgICAgICBDT1VOVCgqKTo6aW50IEFTIGNvdW50XG4gICAgICAgIEZST00gJHtzY2hlbWEucGx1Z2lufVxuICAgICAgICBXSEVSRSAke3NjaGVtYS5wbHVnaW4ub3JnSWR9ID0gJHtvcmdJZH0gQU5EICR7c2NoZW1hLnBsdWdpbi5pc0FjdGl2ZX0gPSB0cnVlXG4gICAgICAgIEdST1VQIEJZICR7c2NoZW1hLnBsdWdpbi5wbHVnaW5UeXBlfSwgJHtzY2hlbWEucGx1Z2luLmNvbXB1dGVUeXBlfVxuICAgICAgICBPUkRFUiBCWSBjb3VudCBERVNDXG4gICAgICBgKS50aGVuKHIgPT4gc3FsUm93czxUeXBlQ29tcHV0ZURpc3RyaWJ1dGlvbj4ocikpLFxuICAgICk7XG4gIH1cblxuICAvKiogMi4zIFZlcnNpb24gY291bnRzIHBlciBwbHVnaW4gbmFtZS4gKi9cbiAgYXN5bmMgZ2V0UGx1Z2luVmVyc2lvbnMob3JnSWQ6IHN0cmluZyk6IFByb21pc2U8VmVyc2lvbkNvdW50W10+IHtcbiAgICByZXR1cm4gaW52ZW50b3J5Q2FjaGUuZ2V0T3JTZXQoYCR7b3JnSWR9OnBsdWdpbi12ZXJzaW9uc2AsICgpID0+XG4gICAgICBkYi5leGVjdXRlKHNxbGBcbiAgICAgICAgU0VMRUNUXG4gICAgICAgICAgJHtzY2hlbWEucGx1Z2luLm5hbWV9LFxuICAgICAgICAgIENPVU5UKCopOjppbnQgQVMgdmVyc2lvbl9jb3VudCxcbiAgICAgICAgICBNQVgoJHtzY2hlbWEucGx1Z2luLnZlcnNpb259KSBBUyBsYXRlc3RfdmVyc2lvbixcbiAgICAgICAgICBib29sX29yKCR7c2NoZW1hLnBsdWdpbi5pc0RlZmF1bHR9KSBBUyBoYXNfZGVmYXVsdFxuICAgICAgICBGUk9NICR7c2NoZW1hLnBsdWdpbn1cbiAgICAgICAgV0hFUkUgJHtzY2hlbWEucGx1Z2luLm9yZ0lkfSA9ICR7b3JnSWR9IEFORCAke3NjaGVtYS5wbHVnaW4uaXNBY3RpdmV9ID0gdHJ1ZVxuICAgICAgICBHUk9VUCBCWSAke3NjaGVtYS5wbHVnaW4ubmFtZX1cbiAgICAgICAgT1JERVIgQlkgdmVyc2lvbl9jb3VudCBERVNDXG4gICAgICBgKS50aGVuKHIgPT4gc3FsUm93czxWZXJzaW9uQ291bnQ+KHIpKSxcbiAgICApO1xuICB9XG5cbiAgLyoqIDIuNCBCdWlsZCBzdWNjZXNzIHJhdGUgb3ZlciB0aW1lLiAqL1xuICBhc3luYyBnZXRCdWlsZFN1Y2Nlc3NSYXRlKG9yZ0lkOiBzdHJpbmcsIGludGVydmFsOiBzdHJpbmcsIGZyb206IHN0cmluZywgdG86IHN0cmluZyk6IFByb21pc2U8QnVpbGRUaW1lU2VyaWVzRW50cnlbXT4ge1xuICAgIHJldHVybiB0aW1lc2VyaWVzQ2FjaGUuZ2V0T3JTZXQoYCR7b3JnSWR9OmJ1aWxkLXN1Y2Nlc3M6JHtpbnRlcnZhbH06JHtmcm9tfToke3RvfWAsICgpID0+XG4gICAgICBkYi5leGVjdXRlKHNxbGBcbiAgICAgICAgU0VMRUNUXG4gICAgICAgICAgREFURV9UUlVOQygke2ludGVydmFsfSwgZS5zdGFydGVkX2F0KTo6dGV4dCBBUyBwZXJpb2QsXG4gICAgICAgICAgQ09VTlQoKikgRklMVEVSIChXSEVSRSBlLnN0YXR1cyA9ICdjb21wbGV0ZWQnKTo6aW50IEFTIHN1Y2NlZWRlZCxcbiAgICAgICAgICBDT1VOVCgqKSBGSUxURVIgKFdIRVJFIGUuc3RhdHVzID0gJ2ZhaWxlZCcpOjppbnQgQVMgZmFpbGVkLFxuICAgICAgICAgIFJPVU5EKENPVU5UKCopIEZJTFRFUiAoV0hFUkUgZS5zdGF0dXMgPSAnY29tcGxldGVkJyk6Om51bWVyaWNcbiAgICAgICAgICAgIC8gTlVMTElGKENPVU5UKCopLCAwKSAqIDEwMCwgMSk6OmZsb2F0IEFTIHN1Y2Nlc3NfcGN0XG4gICAgICAgIEZST00gJHtzY2hlbWEucGlwZWxpbmVFdmVudH0gZVxuICAgICAgICBXSEVSRSBlLm9yZ19pZCA9ICR7b3JnSWR9IEFORCBlLmV2ZW50X3NvdXJjZSA9ICdwbHVnaW4tYnVpbGQnXG4gICAgICAgICAgQU5EIGUuc3RhdHVzIElOICgnY29tcGxldGVkJywgJ2ZhaWxlZCcpXG4gICAgICAgICAgQU5EIGUuc3RhcnRlZF9hdCA+PSAke2Zyb219Ojp0aW1lc3RhbXB0eiBBTkQgZS5zdGFydGVkX2F0IDw9ICR7dG99Ojp0aW1lc3RhbXB0elxuICAgICAgICBHUk9VUCBCWSBwZXJpb2QgT1JERVIgQlkgcGVyaW9kXG4gICAgICBgKS50aGVuKHIgPT4gc3FsUm93czxCdWlsZFRpbWVTZXJpZXNFbnRyeT4ocikpLFxuICAgICk7XG4gIH1cblxuICAvKiogMi41IEJ1aWxkIGR1cmF0aW9uIHBlciBwbHVnaW4uICovXG4gIGFzeW5jIGdldEJ1aWxkRHVyYXRpb24ob3JnSWQ6IHN0cmluZywgZnJvbTogc3RyaW5nLCB0bzogc3RyaW5nKTogUHJvbWlzZTxCdWlsZER1cmF0aW9uW10+IHtcbiAgICByZXR1cm4gdGltZXNlcmllc0NhY2hlLmdldE9yU2V0KGAke29yZ0lkfTpidWlsZC1kdXJhdGlvbjoke2Zyb219OiR7dG99YCwgKCkgPT5cbiAgICAgIGRiLmV4ZWN1dGUoc3FsYFxuICAgICAgICBTRUxFQ1RcbiAgICAgICAgICBlLmRldGFpbC0+PidwbHVnaW5OYW1lJyBBUyBwbHVnaW5fbmFtZSxcbiAgICAgICAgICBBVkcoZS5kdXJhdGlvbl9tcyk6OmludCBBUyBhdmdfbXMsXG4gICAgICAgICAgTUFYKGUuZHVyYXRpb25fbXMpOjppbnQgQVMgbWF4X21zLFxuICAgICAgICAgIENPVU5UKCopOjppbnQgQVMgYnVpbGRzXG4gICAgICAgIEZST00gJHtzY2hlbWEucGlwZWxpbmVFdmVudH0gZVxuICAgICAgICBXSEVSRSBlLm9yZ19pZCA9ICR7b3JnSWR9IEFORCBlLmV2ZW50X3NvdXJjZSA9ICdwbHVnaW4tYnVpbGQnIEFORCBlLmR1cmF0aW9uX21zIElTIE5PVCBOVUxMXG4gICAgICAgICAgQU5EIGUuc3RhcnRlZF9hdCA+PSAke2Zyb219Ojp0aW1lc3RhbXB0eiBBTkQgZS5zdGFydGVkX2F0IDw9ICR7dG99Ojp0aW1lc3RhbXB0elxuICAgICAgICBHUk9VUCBCWSBwbHVnaW5fbmFtZSBPUkRFUiBCWSBhdmdfbXMgREVTQ1xuICAgICAgYCkudGhlbihyID0+IHNxbFJvd3M8QnVpbGREdXJhdGlvbj4ocikpLFxuICAgICk7XG4gIH1cblxuICAvKiogMi42IEJ1aWxkIGZhaWx1cmVzIOKAlCB0b3AgZXJyb3IgbWVzc2FnZXMuICovXG4gIGFzeW5jIGdldEJ1aWxkRmFpbHVyZXMob3JnSWQ6IHN0cmluZywgZnJvbTogc3RyaW5nLCB0bzogc3RyaW5nLCBsaW1pdDogbnVtYmVyID0gMjApOiBQcm9taXNlPEJ1aWxkRmFpbHVyZVtdPiB7XG4gICAgcmV0dXJuIHRpbWVzZXJpZXNDYWNoZS5nZXRPclNldChgJHtvcmdJZH06YnVpbGQtZmFpbHVyZXM6JHtmcm9tfToke3RvfToke2xpbWl0fWAsICgpID0+XG4gICAgICBkYi5leGVjdXRlKHNxbGBcbiAgICAgICAgU0VMRUNUXG4gICAgICAgICAgZS5kZXRhaWwtPj4ncGx1Z2luTmFtZScgQVMgcGx1Z2luX25hbWUsXG4gICAgICAgICAgZS5lcnJvcl9tZXNzYWdlLFxuICAgICAgICAgIENPVU5UKCopOjppbnQgQVMgb2NjdXJyZW5jZXMsXG4gICAgICAgICAgTUFYKGUuc3RhcnRlZF9hdCk6OnRleHQgQVMgbGFzdF9zZWVuXG4gICAgICAgIEZST00gJHtzY2hlbWEucGlwZWxpbmVFdmVudH0gZVxuICAgICAgICBXSEVSRSBlLm9yZ19pZCA9ICR7b3JnSWR9IEFORCBlLmV2ZW50X3NvdXJjZSA9ICdwbHVnaW4tYnVpbGQnIEFORCBlLnN0YXR1cyA9ICdmYWlsZWQnXG4gICAgICAgICAgQU5EIGUuc3RhcnRlZF9hdCA+PSAke2Zyb219Ojp0aW1lc3RhbXB0eiBBTkQgZS5zdGFydGVkX2F0IDw9ICR7dG99Ojp0aW1lc3RhbXB0elxuICAgICAgICBHUk9VUCBCWSBwbHVnaW5fbmFtZSwgZS5lcnJvcl9tZXNzYWdlXG4gICAgICAgIE9SREVSIEJZIG9jY3VycmVuY2VzIERFU0NcbiAgICAgICAgTElNSVQgJHtsaW1pdH1cbiAgICAgIGApLnRoZW4ociA9PiBzcWxSb3dzPEJ1aWxkRmFpbHVyZT4ocikpLFxuICAgICk7XG4gIH1cbn1cblxuZXhwb3J0IGNvbnN0IHJlcG9ydGluZ1NlcnZpY2UgPSBuZXcgUmVwb3J0aW5nU2VydmljZSgpO1xuIl19
@@ -0,0 +1,235 @@
1
+ import { AccessModifier } from '@pipeline-builder/api-core';
2
+ /**
3
+ * Base filter interface containing common filter properties shared across all entity types.
4
+ *
5
+ * @example
6
+ * ```typescript
7
+ * const filter: CommonFilter = {
8
+ * id: '123',
9
+ * orgId: 'my-org',
10
+ * accessModifier: AccessModifier.PUBLIC,
11
+ * isDefault: true,
12
+ * isActive: true
13
+ * };
14
+ * ```
15
+ */
16
+ export interface CommonFilter {
17
+ /**
18
+ * Unique identifier for the entity
19
+ * Can be a single ID or array of IDs for batch filtering
20
+ */
21
+ readonly id?: string | string[];
22
+ /**
23
+ * Organization identifier to filter entities by organization
24
+ * Can be a single org ID or array for multi-org filtering
25
+ */
26
+ readonly orgId?: string | string[];
27
+ /**
28
+ * Access modifier to filter by visibility/permissions
29
+ * Use AccessModifier enum for type safety
30
+ * @see AccessModifier
31
+ */
32
+ readonly accessModifier?: AccessModifier | string;
33
+ /**
34
+ * Filter by default status
35
+ * - true: Only default entities
36
+ * - false: Only non-default entities
37
+ * - undefined: All entities
38
+ */
39
+ readonly isDefault?: boolean;
40
+ /**
41
+ * Filter by active/inactive status
42
+ * - true: Only active entities
43
+ * - false: Only inactive entities
44
+ * - undefined: All entities
45
+ */
46
+ readonly isActive?: boolean;
47
+ /**
48
+ * Number of results to return
49
+ * @minimum 1
50
+ * @maximum 1000
51
+ */
52
+ readonly limit?: number;
53
+ /**
54
+ * Number of results to skip (for pagination)
55
+ * @minimum 0
56
+ */
57
+ readonly offset?: number;
58
+ /**
59
+ * Sort field and direction
60
+ * @example "name:asc", "createdAt:desc"
61
+ */
62
+ readonly sort?: string;
63
+ }
64
+ /**
65
+ * Filter interface for plugin-specific properties.
66
+ * Extends CommonFilter to include plugin-related filter options.
67
+ *
68
+ * @example
69
+ * ```typescript
70
+ * const filter: PluginFilter = {
71
+ * name: 'nodejs-build',
72
+ * version: '1.0.0',
73
+ * isActive: true
74
+ * };
75
+ * ```
76
+ */
77
+ export interface PluginFilter extends CommonFilter {
78
+ /**
79
+ * Plugin name to filter by
80
+ */
81
+ readonly name?: string;
82
+ /**
83
+ * Plugin version to filter by
84
+ * Supports semantic versioning
85
+ * @example "1.0.0", "^2.0.0", "~1.2.3"
86
+ */
87
+ readonly version?: string;
88
+ /**
89
+ * Docker image tag associated with the plugin
90
+ */
91
+ readonly imageTag?: string;
92
+ /**
93
+ * Keyword to search within the keywords JSONB array (case-insensitive contains)
94
+ */
95
+ readonly keyword?: string;
96
+ /**
97
+ * Plugin category to filter by
98
+ * @example "language", "security", "testing"
99
+ */
100
+ readonly category?: string;
101
+ }
102
+ /**
103
+ * Filter interface for pipeline-specific properties.
104
+ * Extends CommonFilter to include pipeline-related filter options.
105
+ *
106
+ * @example
107
+ * ```typescript
108
+ * const filter: PipelineFilter = {
109
+ * project: 'my-app',
110
+ * organization: 'my-org',
111
+ * pipelineName: 'my-pipeline',
112
+ * isActive: true
113
+ * };
114
+ * ```
115
+ */
116
+ export interface PipelineFilter extends CommonFilter {
117
+ /**
118
+ * Project name associated with the pipeline
119
+ */
120
+ readonly project?: string;
121
+ /**
122
+ * Organization name associated with the pipeline
123
+ */
124
+ readonly organization?: string;
125
+ /**
126
+ * Pipeline name to filter by
127
+ */
128
+ readonly pipelineName?: string;
129
+ /**
130
+ * Keyword to search within the keywords JSONB array (case-insensitive contains)
131
+ */
132
+ readonly keyword?: string;
133
+ }
134
+ /**
135
+ * Filter interface for message-specific properties.
136
+ * Extends CommonFilter to include message-related filter options.
137
+ */
138
+ export interface MessageFilter extends CommonFilter {
139
+ /**
140
+ * Thread ID to filter by (for fetching thread replies).
141
+ * Pass `null` to filter for root messages only (threadId IS NULL).
142
+ */
143
+ readonly threadId?: string | null;
144
+ /**
145
+ * Recipient organization ID to filter by
146
+ * Use '*' for broadcast announcements
147
+ */
148
+ readonly recipientOrgId?: string;
149
+ /**
150
+ * Message type filter
151
+ */
152
+ readonly messageType?: 'announcement' | 'conversation';
153
+ /**
154
+ * Filter by read status
155
+ */
156
+ readonly isRead?: boolean;
157
+ /**
158
+ * Filter by priority level
159
+ */
160
+ readonly priority?: 'normal' | 'high' | 'urgent';
161
+ }
162
+ /**
163
+ * Filter for compliance policies.
164
+ */
165
+ export interface CompliancePolicyFilter extends CommonFilter {
166
+ readonly name?: string;
167
+ readonly isTemplate?: boolean;
168
+ }
169
+ /**
170
+ * Filter for compliance rules.
171
+ */
172
+ export interface ComplianceRuleFilter extends CommonFilter {
173
+ readonly name?: string;
174
+ readonly policyId?: string;
175
+ readonly target?: 'plugin' | 'pipeline';
176
+ readonly field?: string;
177
+ readonly severity?: 'warning' | 'error' | 'critical';
178
+ readonly scope?: 'org' | 'published';
179
+ readonly tag?: string;
180
+ }
181
+ /**
182
+ * Filter for compliance rule subscriptions.
183
+ */
184
+ export interface ComplianceRuleSubscriptionFilter {
185
+ readonly orgId?: string;
186
+ readonly ruleId?: string;
187
+ readonly isActive?: boolean;
188
+ readonly limit?: number;
189
+ readonly offset?: number;
190
+ }
191
+ /**
192
+ * Filter for compliance exemptions.
193
+ */
194
+ export interface ComplianceExemptionFilter {
195
+ readonly orgId?: string;
196
+ readonly ruleId?: string;
197
+ readonly entityType?: 'plugin' | 'pipeline';
198
+ readonly entityId?: string;
199
+ readonly status?: 'pending' | 'approved' | 'rejected' | 'expired';
200
+ readonly limit?: number;
201
+ readonly offset?: number;
202
+ }
203
+ /**
204
+ * Filter for compliance audit log entries.
205
+ */
206
+ export interface ComplianceAuditFilter {
207
+ readonly orgId?: string;
208
+ readonly target?: 'plugin' | 'pipeline';
209
+ readonly action?: string;
210
+ readonly result?: 'pass' | 'warn' | 'block';
211
+ readonly scanId?: string;
212
+ readonly dateFrom?: string;
213
+ readonly dateTo?: string;
214
+ readonly limit?: number;
215
+ readonly offset?: number;
216
+ }
217
+ /**
218
+ * Filter for compliance scans.
219
+ */
220
+ export interface ComplianceScanFilter {
221
+ readonly orgId?: string;
222
+ readonly target?: 'plugin' | 'pipeline' | 'all';
223
+ readonly status?: 'pending' | 'running' | 'completed' | 'failed' | 'cancelled';
224
+ readonly triggeredBy?: 'manual' | 'scheduled' | 'rule-change' | 'rule-dry-run';
225
+ readonly limit?: number;
226
+ readonly offset?: number;
227
+ }
228
+ /**
229
+ * Validates message filter properties.
230
+ * Returns a result object with `valid` flag and `errors` array.
231
+ */
232
+ export declare function validateMessageFilter(filter: Partial<MessageFilter>): {
233
+ valid: boolean;
234
+ errors: string[];
235
+ };
@@ -0,0 +1,23 @@
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.validateMessageFilter = validateMessageFilter;
6
+ /**
7
+ * Validates message filter properties.
8
+ * Returns a result object with `valid` flag and `errors` array.
9
+ */
10
+ function validateMessageFilter(filter) {
11
+ const errors = [];
12
+ if (filter.messageType && !['announcement', 'conversation'].includes(filter.messageType)) {
13
+ errors.push(`Invalid messageType: "${filter.messageType}". Must be "announcement" or "conversation"`);
14
+ }
15
+ if (filter.priority && !['normal', 'high', 'urgent'].includes(filter.priority)) {
16
+ errors.push(`Invalid priority: "${filter.priority}". Must be "normal", "high", or "urgent"`);
17
+ }
18
+ if (filter.threadId !== undefined && filter.threadId !== null && typeof filter.threadId !== 'string') {
19
+ errors.push('threadId must be a string UUID or null');
20
+ }
21
+ return { valid: errors.length === 0, errors };
22
+ }
23
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicXVlcnktZmlsdGVycy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9jb3JlL3F1ZXJ5LWZpbHRlcnMudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IjtBQUFBLCtDQUErQztBQUMvQyxzQ0FBc0M7O0FBMFF0QyxzREFpQkM7QUFyQkQ7OztHQUdHO0FBQ0gsU0FBZ0IscUJBQXFCLENBQUMsTUFBOEI7SUFJbEUsTUFBTSxNQUFNLEdBQWEsRUFBRSxDQUFDO0lBRTVCLElBQUksTUFBTSxDQUFDLFdBQVcsSUFBSSxDQUFDLENBQUMsY0FBYyxFQUFFLGNBQWMsQ0FBQyxDQUFDLFFBQVEsQ0FBQyxNQUFNLENBQUMsV0FBVyxDQUFDLEVBQUUsQ0FBQztRQUN6RixNQUFNLENBQUMsSUFBSSxDQUFDLHlCQUF5QixNQUFNLENBQUMsV0FBVyw2Q0FBNkMsQ0FBQyxDQUFDO0lBQ3hHLENBQUM7SUFDRCxJQUFJLE1BQU0sQ0FBQyxRQUFRLElBQUksQ0FBQyxDQUFDLFFBQVEsRUFBRSxNQUFNLEVBQUUsUUFBUSxDQUFDLENBQUMsUUFBUSxDQUFDLE1BQU0sQ0FBQyxRQUFRLENBQUMsRUFBRSxDQUFDO1FBQy9FLE1BQU0sQ0FBQyxJQUFJLENBQUMsc0JBQXNCLE1BQU0sQ0FBQyxRQUFRLDBDQUEwQyxDQUFDLENBQUM7SUFDL0YsQ0FBQztJQUNELElBQUksTUFBTSxDQUFDLFFBQVEsS0FBSyxTQUFTLElBQUksTUFBTSxDQUFDLFFBQVEsS0FBSyxJQUFJLElBQUksT0FBTyxNQUFNLENBQUMsUUFBUSxLQUFLLFFBQVEsRUFBRSxDQUFDO1FBQ3JHLE1BQU0sQ0FBQyxJQUFJLENBQUMsd0NBQXdDLENBQUMsQ0FBQztJQUN4RCxDQUFDO0lBRUQsT0FBTyxFQUFFLEtBQUssRUFBRSxNQUFNLENBQUMsTUFBTSxLQUFLLENBQUMsRUFBRSxNQUFNLEVBQUUsQ0FBQztBQUNoRCxDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiLy8gQ29weXJpZ2h0IDIwMjYgUGlwZWxpbmUgQnVpbGRlciBDb250cmlidXRvcnNcbi8vIFNQRFgtTGljZW5zZS1JZGVudGlmaWVyOiBBcGFjaGUtMi4wXG5cbmltcG9ydCB7IEFjY2Vzc01vZGlmaWVyIH0gZnJvbSAnQHBpcGVsaW5lLWJ1aWxkZXIvYXBpLWNvcmUnO1xuXG4vKipcbiAqIEJhc2UgZmlsdGVyIGludGVyZmFjZSBjb250YWluaW5nIGNvbW1vbiBmaWx0ZXIgcHJvcGVydGllcyBzaGFyZWQgYWNyb3NzIGFsbCBlbnRpdHkgdHlwZXMuXG4gKlxuICogQGV4YW1wbGVcbiAqIGBgYHR5cGVzY3JpcHRcbiAqIGNvbnN0IGZpbHRlcjogQ29tbW9uRmlsdGVyID0ge1xuICogICBpZDogJzEyMycsXG4gKiAgIG9yZ0lkOiAnbXktb3JnJyxcbiAqICAgYWNjZXNzTW9kaWZpZXI6IEFjY2Vzc01vZGlmaWVyLlBVQkxJQyxcbiAqICAgaXNEZWZhdWx0OiB0cnVlLFxuICogICBpc0FjdGl2ZTogdHJ1ZVxuICogfTtcbiAqIGBgYFxuICovXG5leHBvcnQgaW50ZXJmYWNlIENvbW1vbkZpbHRlciB7XG4gIC8qKlxuICAgKiBVbmlxdWUgaWRlbnRpZmllciBmb3IgdGhlIGVudGl0eVxuICAgKiBDYW4gYmUgYSBzaW5nbGUgSUQgb3IgYXJyYXkgb2YgSURzIGZvciBiYXRjaCBmaWx0ZXJpbmdcbiAgICovXG4gIHJlYWRvbmx5IGlkPzogc3RyaW5nIHwgc3RyaW5nW107XG5cbiAgLyoqXG4gICAqIE9yZ2FuaXphdGlvbiBpZGVudGlmaWVyIHRvIGZpbHRlciBlbnRpdGllcyBieSBvcmdhbml6YXRpb25cbiAgICogQ2FuIGJlIGEgc2luZ2xlIG9yZyBJRCBvciBhcnJheSBmb3IgbXVsdGktb3JnIGZpbHRlcmluZ1xuICAgKi9cbiAgcmVhZG9ubHkgb3JnSWQ/OiBzdHJpbmcgfCBzdHJpbmdbXTtcblxuICAvKipcbiAgICogQWNjZXNzIG1vZGlmaWVyIHRvIGZpbHRlciBieSB2aXNpYmlsaXR5L3Blcm1pc3Npb25zXG4gICAqIFVzZSBBY2Nlc3NNb2RpZmllciBlbnVtIGZvciB0eXBlIHNhZmV0eVxuICAgKiBAc2VlIEFjY2Vzc01vZGlmaWVyXG4gICAqL1xuICByZWFkb25seSBhY2Nlc3NNb2RpZmllcj86IEFjY2Vzc01vZGlmaWVyIHwgc3RyaW5nO1xuXG4gIC8qKlxuICAgKiBGaWx0ZXIgYnkgZGVmYXVsdCBzdGF0dXNcbiAgICogLSB0cnVlOiBPbmx5IGRlZmF1bHQgZW50aXRpZXNcbiAgICogLSBmYWxzZTogT25seSBub24tZGVmYXVsdCBlbnRpdGllc1xuICAgKiAtIHVuZGVmaW5lZDogQWxsIGVudGl0aWVzXG4gICAqL1xuICByZWFkb25seSBpc0RlZmF1bHQ/OiBib29sZWFuO1xuXG4gIC8qKlxuICAgKiBGaWx0ZXIgYnkgYWN0aXZlL2luYWN0aXZlIHN0YXR1c1xuICAgKiAtIHRydWU6IE9ubHkgYWN0aXZlIGVudGl0aWVzXG4gICAqIC0gZmFsc2U6IE9ubHkgaW5hY3RpdmUgZW50aXRpZXNcbiAgICogLSB1bmRlZmluZWQ6IEFsbCBlbnRpdGllc1xuICAgKi9cbiAgcmVhZG9ubHkgaXNBY3RpdmU/OiBib29sZWFuO1xuXG4gIC8qKlxuICAgKiBOdW1iZXIgb2YgcmVzdWx0cyB0byByZXR1cm5cbiAgICogQG1pbmltdW0gMVxuICAgKiBAbWF4aW11bSAxMDAwXG4gICAqL1xuICByZWFkb25seSBsaW1pdD86IG51bWJlcjtcblxuICAvKipcbiAgICogTnVtYmVyIG9mIHJlc3VsdHMgdG8gc2tpcCAoZm9yIHBhZ2luYXRpb24pXG4gICAqIEBtaW5pbXVtIDBcbiAgICovXG4gIHJlYWRvbmx5IG9mZnNldD86IG51bWJlcjtcblxuICAvKipcbiAgICogU29ydCBmaWVsZCBhbmQgZGlyZWN0aW9uXG4gICAqIEBleGFtcGxlIFwibmFtZTphc2NcIiwgXCJjcmVhdGVkQXQ6ZGVzY1wiXG4gICAqL1xuICByZWFkb25seSBzb3J0Pzogc3RyaW5nO1xufVxuXG4vKipcbiAqIEZpbHRlciBpbnRlcmZhY2UgZm9yIHBsdWdpbi1zcGVjaWZpYyBwcm9wZXJ0aWVzLlxuICogRXh0ZW5kcyBDb21tb25GaWx0ZXIgdG8gaW5jbHVkZSBwbHVnaW4tcmVsYXRlZCBmaWx0ZXIgb3B0aW9ucy5cbiAqXG4gKiBAZXhhbXBsZVxuICogYGBgdHlwZXNjcmlwdFxuICogY29uc3QgZmlsdGVyOiBQbHVnaW5GaWx0ZXIgPSB7XG4gKiAgIG5hbWU6ICdub2RlanMtYnVpbGQnLFxuICogICB2ZXJzaW9uOiAnMS4wLjAnLFxuICogICBpc0FjdGl2ZTogdHJ1ZVxuICogfTtcbiAqIGBgYFxuICovXG5leHBvcnQgaW50ZXJmYWNlIFBsdWdpbkZpbHRlciBleHRlbmRzIENvbW1vbkZpbHRlciB7XG4gIC8qKlxuICAgKiBQbHVnaW4gbmFtZSB0byBmaWx0ZXIgYnlcbiAgICovXG4gIHJlYWRvbmx5IG5hbWU/OiBzdHJpbmc7XG5cbiAgLyoqXG4gICAqIFBsdWdpbiB2ZXJzaW9uIHRvIGZpbHRlciBieVxuICAgKiBTdXBwb3J0cyBzZW1hbnRpYyB2ZXJzaW9uaW5nXG4gICAqIEBleGFtcGxlIFwiMS4wLjBcIiwgXCJeMi4wLjBcIiwgXCJ+MS4yLjNcIlxuICAgKi9cbiAgcmVhZG9ubHkgdmVyc2lvbj86IHN0cmluZztcblxuICAvKipcbiAgICogRG9ja2VyIGltYWdlIHRhZyBhc3NvY2lhdGVkIHdpdGggdGhlIHBsdWdpblxuICAgKi9cbiAgcmVhZG9ubHkgaW1hZ2VUYWc/OiBzdHJpbmc7XG5cbiAgLyoqXG4gICAqIEtleXdvcmQgdG8gc2VhcmNoIHdpdGhpbiB0aGUga2V5d29yZHMgSlNPTkIgYXJyYXkgKGNhc2UtaW5zZW5zaXRpdmUgY29udGFpbnMpXG4gICAqL1xuICByZWFkb25seSBrZXl3b3JkPzogc3RyaW5nO1xuXG4gIC8qKlxuICAgKiBQbHVnaW4gY2F0ZWdvcnkgdG8gZmlsdGVyIGJ5XG4gICAqIEBleGFtcGxlIFwibGFuZ3VhZ2VcIiwgXCJzZWN1cml0eVwiLCBcInRlc3RpbmdcIlxuICAgKi9cbiAgcmVhZG9ubHkgY2F0ZWdvcnk/OiBzdHJpbmc7XG59XG5cbi8qKlxuICogRmlsdGVyIGludGVyZmFjZSBmb3IgcGlwZWxpbmUtc3BlY2lmaWMgcHJvcGVydGllcy5cbiAqIEV4dGVuZHMgQ29tbW9uRmlsdGVyIHRvIGluY2x1ZGUgcGlwZWxpbmUtcmVsYXRlZCBmaWx0ZXIgb3B0aW9ucy5cbiAqXG4gKiBAZXhhbXBsZVxuICogYGBgdHlwZXNjcmlwdFxuICogY29uc3QgZmlsdGVyOiBQaXBlbGluZUZpbHRlciA9IHtcbiAqICAgcHJvamVjdDogJ215LWFwcCcsXG4gKiAgIG9yZ2FuaXphdGlvbjogJ215LW9yZycsXG4gKiAgIHBpcGVsaW5lTmFtZTogJ215LXBpcGVsaW5lJyxcbiAqICAgaXNBY3RpdmU6IHRydWVcbiAqIH07XG4gKiBgYGBcbiAqL1xuZXhwb3J0IGludGVyZmFjZSBQaXBlbGluZUZpbHRlciBleHRlbmRzIENvbW1vbkZpbHRlciB7XG4gIC8qKlxuICAgKiBQcm9qZWN0IG5hbWUgYXNzb2NpYXRlZCB3aXRoIHRoZSBwaXBlbGluZVxuICAgKi9cbiAgcmVhZG9ubHkgcHJvamVjdD86IHN0cmluZztcblxuICAvKipcbiAgICogT3JnYW5pemF0aW9uIG5hbWUgYXNzb2NpYXRlZCB3aXRoIHRoZSBwaXBlbGluZVxuICAgKi9cbiAgcmVhZG9ubHkgb3JnYW5pemF0aW9uPzogc3RyaW5nO1xuXG4gIC8qKlxuICAgKiBQaXBlbGluZSBuYW1lIHRvIGZpbHRlciBieVxuICAgKi9cbiAgcmVhZG9ubHkgcGlwZWxpbmVOYW1lPzogc3RyaW5nO1xuXG4gIC8qKlxuICAgKiBLZXl3b3JkIHRvIHNlYXJjaCB3aXRoaW4gdGhlIGtleXdvcmRzIEpTT05CIGFycmF5IChjYXNlLWluc2Vuc2l0aXZlIGNvbnRhaW5zKVxuICAgKi9cbiAgcmVhZG9ubHkga2V5d29yZD86IHN0cmluZztcbn1cblxuLyoqXG4gKiBGaWx0ZXIgaW50ZXJmYWNlIGZvciBtZXNzYWdlLXNwZWNpZmljIHByb3BlcnRpZXMuXG4gKiBFeHRlbmRzIENvbW1vbkZpbHRlciB0byBpbmNsdWRlIG1lc3NhZ2UtcmVsYXRlZCBmaWx0ZXIgb3B0aW9ucy5cbiAqL1xuZXhwb3J0IGludGVyZmFjZSBNZXNzYWdlRmlsdGVyIGV4dGVuZHMgQ29tbW9uRmlsdGVyIHtcbiAgLyoqXG4gICAqIFRocmVhZCBJRCB0byBmaWx0ZXIgYnkgKGZvciBmZXRjaGluZyB0aHJlYWQgcmVwbGllcykuXG4gICAqIFBhc3MgYG51bGxgIHRvIGZpbHRlciBmb3Igcm9vdCBtZXNzYWdlcyBvbmx5ICh0aHJlYWRJZCBJUyBOVUxMKS5cbiAgICovXG4gIHJlYWRvbmx5IHRocmVhZElkPzogc3RyaW5nIHwgbnVsbDtcblxuICAvKipcbiAgICogUmVjaXBpZW50IG9yZ2FuaXphdGlvbiBJRCB0byBmaWx0ZXIgYnlcbiAgICogVXNlICcqJyBmb3IgYnJvYWRjYXN0IGFubm91bmNlbWVudHNcbiAgICovXG4gIHJlYWRvbmx5IHJlY2lwaWVudE9yZ0lkPzogc3RyaW5nO1xuXG4gIC8qKlxuICAgKiBNZXNzYWdlIHR5cGUgZmlsdGVyXG4gICAqL1xuICByZWFkb25seSBtZXNzYWdlVHlwZT86ICdhbm5vdW5jZW1lbnQnIHwgJ2NvbnZlcnNhdGlvbic7XG5cbiAgLyoqXG4gICAqIEZpbHRlciBieSByZWFkIHN0YXR1c1xuICAgKi9cbiAgcmVhZG9ubHkgaXNSZWFkPzogYm9vbGVhbjtcblxuICAvKipcbiAgICogRmlsdGVyIGJ5IHByaW9yaXR5IGxldmVsXG4gICAqL1xuICByZWFkb25seSBwcmlvcml0eT86ICdub3JtYWwnIHwgJ2hpZ2gnIHwgJ3VyZ2VudCc7XG59XG5cbi8vID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT1cbi8vIENvbXBsaWFuY2UgRmlsdGVyc1xuLy8gPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PVxuXG4vKipcbiAqIEZpbHRlciBmb3IgY29tcGxpYW5jZSBwb2xpY2llcy5cbiAqL1xuZXhwb3J0IGludGVyZmFjZSBDb21wbGlhbmNlUG9saWN5RmlsdGVyIGV4dGVuZHMgQ29tbW9uRmlsdGVyIHtcbiAgcmVhZG9ubHkgbmFtZT86IHN0cmluZztcbiAgcmVhZG9ubHkgaXNUZW1wbGF0ZT86IGJvb2xlYW47XG59XG5cbi8qKlxuICogRmlsdGVyIGZvciBjb21wbGlhbmNlIHJ1bGVzLlxuICovXG5leHBvcnQgaW50ZXJmYWNlIENvbXBsaWFuY2VSdWxlRmlsdGVyIGV4dGVuZHMgQ29tbW9uRmlsdGVyIHtcbiAgcmVhZG9ubHkgbmFtZT86IHN0cmluZztcbiAgcmVhZG9ubHkgcG9saWN5SWQ/OiBzdHJpbmc7XG4gIHJlYWRvbmx5IHRhcmdldD86ICdwbHVnaW4nIHwgJ3BpcGVsaW5lJztcbiAgcmVhZG9ubHkgZmllbGQ/OiBzdHJpbmc7XG4gIHJlYWRvbmx5IHNldmVyaXR5PzogJ3dhcm5pbmcnIHwgJ2Vycm9yJyB8ICdjcml0aWNhbCc7XG4gIHJlYWRvbmx5IHNjb3BlPzogJ29yZycgfCAncHVibGlzaGVkJztcbiAgcmVhZG9ubHkgdGFnPzogc3RyaW5nO1xufVxuXG4vKipcbiAqIEZpbHRlciBmb3IgY29tcGxpYW5jZSBydWxlIHN1YnNjcmlwdGlvbnMuXG4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgQ29tcGxpYW5jZVJ1bGVTdWJzY3JpcHRpb25GaWx0ZXIge1xuICByZWFkb25seSBvcmdJZD86IHN0cmluZztcbiAgcmVhZG9ubHkgcnVsZUlkPzogc3RyaW5nO1xuICByZWFkb25seSBpc0FjdGl2ZT86IGJvb2xlYW47XG4gIHJlYWRvbmx5IGxpbWl0PzogbnVtYmVyO1xuICByZWFkb25seSBvZmZzZXQ/OiBudW1iZXI7XG59XG5cbi8qKlxuICogRmlsdGVyIGZvciBjb21wbGlhbmNlIGV4ZW1wdGlvbnMuXG4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgQ29tcGxpYW5jZUV4ZW1wdGlvbkZpbHRlciB7XG4gIHJlYWRvbmx5IG9yZ0lkPzogc3RyaW5nO1xuICByZWFkb25seSBydWxlSWQ/OiBzdHJpbmc7XG4gIHJlYWRvbmx5IGVudGl0eVR5cGU/OiAncGx1Z2luJyB8ICdwaXBlbGluZSc7XG4gIHJlYWRvbmx5IGVudGl0eUlkPzogc3RyaW5nO1xuICByZWFkb25seSBzdGF0dXM/OiAncGVuZGluZycgfCAnYXBwcm92ZWQnIHwgJ3JlamVjdGVkJyB8ICdleHBpcmVkJztcbiAgcmVhZG9ubHkgbGltaXQ/OiBudW1iZXI7XG4gIHJlYWRvbmx5IG9mZnNldD86IG51bWJlcjtcbn1cblxuLyoqXG4gKiBGaWx0ZXIgZm9yIGNvbXBsaWFuY2UgYXVkaXQgbG9nIGVudHJpZXMuXG4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgQ29tcGxpYW5jZUF1ZGl0RmlsdGVyIHtcbiAgcmVhZG9ubHkgb3JnSWQ/OiBzdHJpbmc7XG4gIHJlYWRvbmx5IHRhcmdldD86ICdwbHVnaW4nIHwgJ3BpcGVsaW5lJztcbiAgcmVhZG9ubHkgYWN0aW9uPzogc3RyaW5nO1xuICByZWFkb25seSByZXN1bHQ/OiAncGFzcycgfCAnd2FybicgfCAnYmxvY2snO1xuICByZWFkb25seSBzY2FuSWQ/OiBzdHJpbmc7XG4gIHJlYWRvbmx5IGRhdGVGcm9tPzogc3RyaW5nO1xuICByZWFkb25seSBkYXRlVG8/OiBzdHJpbmc7XG4gIHJlYWRvbmx5IGxpbWl0PzogbnVtYmVyO1xuICByZWFkb25seSBvZmZzZXQ/OiBudW1iZXI7XG59XG5cbi8qKlxuICogRmlsdGVyIGZvciBjb21wbGlhbmNlIHNjYW5zLlxuICovXG5leHBvcnQgaW50ZXJmYWNlIENvbXBsaWFuY2VTY2FuRmlsdGVyIHtcbiAgcmVhZG9ubHkgb3JnSWQ/OiBzdHJpbmc7XG4gIHJlYWRvbmx5IHRhcmdldD86ICdwbHVnaW4nIHwgJ3BpcGVsaW5lJyB8ICdhbGwnO1xuICByZWFkb25seSBzdGF0dXM/OiAncGVuZGluZycgfCAncnVubmluZycgfCAnY29tcGxldGVkJyB8ICdmYWlsZWQnIHwgJ2NhbmNlbGxlZCc7XG4gIHJlYWRvbmx5IHRyaWdnZXJlZEJ5PzogJ21hbnVhbCcgfCAnc2NoZWR1bGVkJyB8ICdydWxlLWNoYW5nZScgfCAncnVsZS1kcnktcnVuJztcbiAgcmVhZG9ubHkgbGltaXQ/OiBudW1iZXI7XG4gIHJlYWRvbmx5IG9mZnNldD86IG51bWJlcjtcbn1cblxuLyoqXG4gKiBWYWxpZGF0ZXMgbWVzc2FnZSBmaWx0ZXIgcHJvcGVydGllcy5cbiAqIFJldHVybnMgYSByZXN1bHQgb2JqZWN0IHdpdGggYHZhbGlkYCBmbGFnIGFuZCBgZXJyb3JzYCBhcnJheS5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHZhbGlkYXRlTWVzc2FnZUZpbHRlcihmaWx0ZXI6IFBhcnRpYWw8TWVzc2FnZUZpbHRlcj4pOiB7XG4gIHZhbGlkOiBib29sZWFuO1xuICBlcnJvcnM6IHN0cmluZ1tdO1xufSB7XG4gIGNvbnN0IGVycm9yczogc3RyaW5nW10gPSBbXTtcblxuICBpZiAoZmlsdGVyLm1lc3NhZ2VUeXBlICYmICFbJ2Fubm91bmNlbWVudCcsICdjb252ZXJzYXRpb24nXS5pbmNsdWRlcyhmaWx0ZXIubWVzc2FnZVR5cGUpKSB7XG4gICAgZXJyb3JzLnB1c2goYEludmFsaWQgbWVzc2FnZVR5cGU6IFwiJHtmaWx0ZXIubWVzc2FnZVR5cGV9XCIuIE11c3QgYmUgXCJhbm5vdW5jZW1lbnRcIiBvciBcImNvbnZlcnNhdGlvblwiYCk7XG4gIH1cbiAgaWYgKGZpbHRlci5wcmlvcml0eSAmJiAhWydub3JtYWwnLCAnaGlnaCcsICd1cmdlbnQnXS5pbmNsdWRlcyhmaWx0ZXIucHJpb3JpdHkpKSB7XG4gICAgZXJyb3JzLnB1c2goYEludmFsaWQgcHJpb3JpdHk6IFwiJHtmaWx0ZXIucHJpb3JpdHl9XCIuIE11c3QgYmUgXCJub3JtYWxcIiwgXCJoaWdoXCIsIG9yIFwidXJnZW50XCJgKTtcbiAgfVxuICBpZiAoZmlsdGVyLnRocmVhZElkICE9PSB1bmRlZmluZWQgJiYgZmlsdGVyLnRocmVhZElkICE9PSBudWxsICYmIHR5cGVvZiBmaWx0ZXIudGhyZWFkSWQgIT09ICdzdHJpbmcnKSB7XG4gICAgZXJyb3JzLnB1c2goJ3RocmVhZElkIG11c3QgYmUgYSBzdHJpbmcgVVVJRCBvciBudWxsJyk7XG4gIH1cblxuICByZXR1cm4geyB2YWxpZDogZXJyb3JzLmxlbmd0aCA9PT0gMCwgZXJyb3JzIH07XG59XG4iXX0=