@pipeline-builder/pipeline-data 0.0.1
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.
- package/LICENSE +202 -0
- package/README.md +61 -0
- package/drizzle.config.ts +17 -0
- package/lib/api/access-control-builder.d.ts +148 -0
- package/lib/api/access-control-builder.js +199 -0
- package/lib/api/crud-service.d.ts +343 -0
- package/lib/api/crud-service.js +849 -0
- package/lib/api/query-builders.d.ts +82 -0
- package/lib/api/query-builders.js +460 -0
- package/lib/api/reporting-service.d.ts +685 -0
- package/lib/api/reporting-service.js +1564 -0
- package/lib/api/soft-delete-sweep.d.ts +65 -0
- package/lib/api/soft-delete-sweep.js +124 -0
- package/lib/api/viewer-context.d.ts +29 -0
- package/lib/api/viewer-context.js +63 -0
- package/lib/core/query-filters.d.ts +263 -0
- package/lib/core/query-filters.js +4 -0
- package/lib/database/drizzle-schema.d.ts +7357 -0
- package/lib/database/drizzle-schema.js +66 -0
- package/lib/database/index.d.ts +5 -0
- package/lib/database/index.js +8 -0
- package/lib/database/migrator.d.ts +20 -0
- package/lib/database/migrator.js +80 -0
- package/lib/database/postgres-connection.d.ts +201 -0
- package/lib/database/postgres-connection.js +413 -0
- package/lib/database/retry-strategy.d.ts +68 -0
- package/lib/database/retry-strategy.js +122 -0
- package/lib/database/schema/alert.d.ts +588 -0
- package/lib/database/schema/alert.js +130 -0
- package/lib/database/schema/compliance.d.ts +3319 -0
- package/lib/database/schema/compliance.js +377 -0
- package/lib/database/schema/dashboard.d.ts +474 -0
- package/lib/database/schema/dashboard.js +129 -0
- package/lib/database/schema/message-attachment.d.ts +183 -0
- package/lib/database/schema/message-attachment.js +40 -0
- package/lib/database/schema/message.d.ts +411 -0
- package/lib/database/schema/message.js +114 -0
- package/lib/database/schema/pipeline-template.d.ts +466 -0
- package/lib/database/schema/pipeline-template.js +80 -0
- package/lib/database/schema/pipeline.d.ts +1613 -0
- package/lib/database/schema/pipeline.js +332 -0
- package/lib/database/schema/plugin.d.ts +749 -0
- package/lib/database/schema/plugin.js +166 -0
- package/lib/database/tenancy.d.ts +103 -0
- package/lib/database/tenancy.js +167 -0
- package/lib/index.d.ts +32 -0
- package/lib/index.js +38 -0
- package/package.json +161 -0
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared soft-delete retention purge.
|
|
3
|
+
*
|
|
4
|
+
* Every {@link CrudService} entity soft-deletes (sets `deletedAt` + a
|
|
5
|
+
* `purge_after` deadline). This orchestrator runs one purge pass across a set
|
|
6
|
+
* of such entities, hard-deleting tombstones whose deadline has passed. It is
|
|
7
|
+
* the `run` callback a service hands to `createScheduler` (leader-locked), so
|
|
8
|
+
* only one pod sweeps at a time.
|
|
9
|
+
*
|
|
10
|
+
* Runs in an explicit **sysadmin tenant scope** (`runWithTenantContext({
|
|
11
|
+
* isSuperAdmin: true })`) so the underlying `purgeExpired` spans every org and
|
|
12
|
+
* bypasses RLS on FORCE'd tables (plugins/pipelines/etc.). A bare no-tenant
|
|
13
|
+
* context would see zero rows on those tables — and in production (`strict`
|
|
14
|
+
* mode) `withTenantTx` throws outright — so the scope is established here rather
|
|
15
|
+
* than left to the caller. This is a cross-tenant housekeeping job, not a
|
|
16
|
+
* per-org operation.
|
|
17
|
+
*/
|
|
18
|
+
import { type Scheduler } from '@pipeline-builder/api-core';
|
|
19
|
+
/** The slice of a CrudService the sweep needs, plus a label for logs/metrics. */
|
|
20
|
+
export interface PurgeableEntity {
|
|
21
|
+
/** Table/entity label (e.g. 'pipeline') for per-table logging. */
|
|
22
|
+
name: string;
|
|
23
|
+
/** Hard-delete up to `limit` expired tombstones; returns rows purged. */
|
|
24
|
+
purgeExpired(now: Date, limit?: number): Promise<number>;
|
|
25
|
+
}
|
|
26
|
+
export interface SoftDeletePurgeOptions {
|
|
27
|
+
/** Rows per batch per table (default 500). */
|
|
28
|
+
batchSize?: number;
|
|
29
|
+
/** Max batches per table per tick (default 20 → ≤ 10k/table/tick); the rest
|
|
30
|
+
* is deferred to the next tick so a huge backlog can't blow the lock TTL. */
|
|
31
|
+
maxBatchesPerEntity?: number;
|
|
32
|
+
}
|
|
33
|
+
/** Kill-switch: `SOFT_DELETE_PURGE_ENABLED=false` disables all hard-purging
|
|
34
|
+
* (tombstones still accumulate + stay restorable; nothing is destroyed). */
|
|
35
|
+
export declare function isSoftDeletePurgeEnabled(): boolean;
|
|
36
|
+
/**
|
|
37
|
+
* Run one purge sweep across `entities`. Loops each entity's `purgeExpired` in
|
|
38
|
+
* batches until a batch returns `< batchSize` (drained) or the per-tick cap is
|
|
39
|
+
* hit (logged; continued next tick). Never throws — a failing entity is logged
|
|
40
|
+
* and the sweep moves on. Returns per-entity purged counts (also logged).
|
|
41
|
+
*/
|
|
42
|
+
export declare function runSoftDeletePurge(entities: PurgeableEntity[], opts?: SoftDeletePurgeOptions): Promise<Record<string, number>>;
|
|
43
|
+
export interface SoftDeletePurgeSchedulerOptions extends SoftDeletePurgeOptions {
|
|
44
|
+
/** Service label for logs + the leader-lock key (e.g. 'pipeline', 'plugin'). */
|
|
45
|
+
service: string;
|
|
46
|
+
/** Entities to sweep — usually the service's own CrudService singletons. */
|
|
47
|
+
entities: PurgeableEntity[];
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Build (but do NOT start) a leader-locked scheduler that runs the soft-delete
|
|
51
|
+
* purge sweep for `entities` on a cadence. The caller `.start()`s it and wires
|
|
52
|
+
* `stop()` to SIGTERM. Returns null when purging is disabled.
|
|
53
|
+
*
|
|
54
|
+
* Env config:
|
|
55
|
+
* SOFT_DELETE_PURGE_ENABLED (default true; false ⇒ null, no sweep)
|
|
56
|
+
* SOFT_DELETE_PURGE_INTERVAL_HOURS (default 6)
|
|
57
|
+
* SOFT_DELETE_PURGE_STARTUP_DELAY_MS (default 120000 — 2 min settle)
|
|
58
|
+
* SOFT_DELETE_PURGE_LOCK_TTL_MS (default 900000 — 15 min; outlasts a
|
|
59
|
+
* sweep, stays under the interval)
|
|
60
|
+
*
|
|
61
|
+
* A cross-pod leader lock (when Redis is configured) means only one replica
|
|
62
|
+
* sweeps per window; without Redis it runs on every pod — still safe, since the
|
|
63
|
+
* purge is a batched idempotent DELETE, just redundant.
|
|
64
|
+
*/
|
|
65
|
+
export declare function createSoftDeletePurgeScheduler(opts: SoftDeletePurgeSchedulerOptions): Scheduler | null;
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
// Copyright 2026 Pipeline Builder Contributors
|
|
2
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
3
|
+
/**
|
|
4
|
+
* Shared soft-delete retention purge.
|
|
5
|
+
*
|
|
6
|
+
* Every {@link CrudService} entity soft-deletes (sets `deletedAt` + a
|
|
7
|
+
* `purge_after` deadline). This orchestrator runs one purge pass across a set
|
|
8
|
+
* of such entities, hard-deleting tombstones whose deadline has passed. It is
|
|
9
|
+
* the `run` callback a service hands to `createScheduler` (leader-locked), so
|
|
10
|
+
* only one pod sweeps at a time.
|
|
11
|
+
*
|
|
12
|
+
* Runs in an explicit **sysadmin tenant scope** (`runWithTenantContext({
|
|
13
|
+
* isSuperAdmin: true })`) so the underlying `purgeExpired` spans every org and
|
|
14
|
+
* bypasses RLS on FORCE'd tables (plugins/pipelines/etc.). A bare no-tenant
|
|
15
|
+
* context would see zero rows on those tables — and in production (`strict`
|
|
16
|
+
* mode) `withTenantTx` throws outright — so the scope is established here rather
|
|
17
|
+
* than left to the caller. This is a cross-tenant housekeeping job, not a
|
|
18
|
+
* per-org operation.
|
|
19
|
+
*/
|
|
20
|
+
import { createLogger, createScheduler, createEnvRedisLock, closeLeaderLock } from '@pipeline-builder/api-core';
|
|
21
|
+
import { runWithTenantContext } from '../database/tenancy.js';
|
|
22
|
+
const logger = createLogger('soft-delete-sweep');
|
|
23
|
+
/** Kill-switch: `SOFT_DELETE_PURGE_ENABLED=false` disables all hard-purging
|
|
24
|
+
* (tombstones still accumulate + stay restorable; nothing is destroyed). */
|
|
25
|
+
export function isSoftDeletePurgeEnabled() {
|
|
26
|
+
return (process.env.SOFT_DELETE_PURGE_ENABLED ?? 'true').toLowerCase() !== 'false';
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Run one purge sweep across `entities`. Loops each entity's `purgeExpired` in
|
|
30
|
+
* batches until a batch returns `< batchSize` (drained) or the per-tick cap is
|
|
31
|
+
* hit (logged; continued next tick). Never throws — a failing entity is logged
|
|
32
|
+
* and the sweep moves on. Returns per-entity purged counts (also logged).
|
|
33
|
+
*/
|
|
34
|
+
export async function runSoftDeletePurge(entities, opts = {}) {
|
|
35
|
+
const counts = {};
|
|
36
|
+
if (!isSoftDeletePurgeEnabled()) {
|
|
37
|
+
logger.debug('Soft-delete purge disabled (SOFT_DELETE_PURGE_ENABLED=false)');
|
|
38
|
+
return counts;
|
|
39
|
+
}
|
|
40
|
+
const batchSize = opts.batchSize ?? 500;
|
|
41
|
+
const maxBatches = opts.maxBatchesPerEntity ?? 20;
|
|
42
|
+
// One `now` for the whole tick — rows that expire mid-sweep wait for the next.
|
|
43
|
+
const now = new Date();
|
|
44
|
+
// Establish a sysadmin scope so every `purgeExpired` (which routes through
|
|
45
|
+
// `withTenantTx`) bypasses RLS and spans all orgs. Without this, FORCE'd
|
|
46
|
+
// tables return zero rows and production `strict` mode throws.
|
|
47
|
+
return runWithTenantContext({ isSuperAdmin: true }, async () => {
|
|
48
|
+
for (const entity of entities) {
|
|
49
|
+
let total = 0;
|
|
50
|
+
for (let i = 0; i < maxBatches; i++) {
|
|
51
|
+
let purged;
|
|
52
|
+
try {
|
|
53
|
+
purged = await entity.purgeExpired(now, batchSize);
|
|
54
|
+
}
|
|
55
|
+
catch (err) {
|
|
56
|
+
logger.error('Purge batch failed', { entity: entity.name, error: String(err) });
|
|
57
|
+
break;
|
|
58
|
+
}
|
|
59
|
+
total += purged;
|
|
60
|
+
if (purged < batchSize)
|
|
61
|
+
break; // drained
|
|
62
|
+
if (i === maxBatches - 1) {
|
|
63
|
+
logger.warn('Purge hit per-tick cap; remaining tombstones deferred to next tick', {
|
|
64
|
+
entity: entity.name, purgedThisTick: total,
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
if (total > 0)
|
|
69
|
+
logger.info('Purged expired soft-deleted rows', { entity: entity.name, count: total });
|
|
70
|
+
counts[entity.name] = total;
|
|
71
|
+
}
|
|
72
|
+
return counts;
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Build (but do NOT start) a leader-locked scheduler that runs the soft-delete
|
|
77
|
+
* purge sweep for `entities` on a cadence. The caller `.start()`s it and wires
|
|
78
|
+
* `stop()` to SIGTERM. Returns null when purging is disabled.
|
|
79
|
+
*
|
|
80
|
+
* Env config:
|
|
81
|
+
* SOFT_DELETE_PURGE_ENABLED (default true; false ⇒ null, no sweep)
|
|
82
|
+
* SOFT_DELETE_PURGE_INTERVAL_HOURS (default 6)
|
|
83
|
+
* SOFT_DELETE_PURGE_STARTUP_DELAY_MS (default 120000 — 2 min settle)
|
|
84
|
+
* SOFT_DELETE_PURGE_LOCK_TTL_MS (default 900000 — 15 min; outlasts a
|
|
85
|
+
* sweep, stays under the interval)
|
|
86
|
+
*
|
|
87
|
+
* A cross-pod leader lock (when Redis is configured) means only one replica
|
|
88
|
+
* sweeps per window; without Redis it runs on every pod — still safe, since the
|
|
89
|
+
* purge is a batched idempotent DELETE, just redundant.
|
|
90
|
+
*/
|
|
91
|
+
export function createSoftDeletePurgeScheduler(opts) {
|
|
92
|
+
if (!isSoftDeletePurgeEnabled()) {
|
|
93
|
+
logger.info('Soft-delete purge scheduler disabled (SOFT_DELETE_PURGE_ENABLED=false)', { service: opts.service });
|
|
94
|
+
return null;
|
|
95
|
+
}
|
|
96
|
+
const intervalMs = Math.max(1, Number.parseInt(process.env.SOFT_DELETE_PURGE_INTERVAL_HOURS ?? '6', 10) || 6) * 60 * 60 * 1000;
|
|
97
|
+
const startupDelayMs = Math.max(0, Number.parseInt(process.env.SOFT_DELETE_PURGE_STARTUP_DELAY_MS ?? '120000', 10) || 0);
|
|
98
|
+
const lockTtlMs = Math.max(1000, Number.parseInt(process.env.SOFT_DELETE_PURGE_LOCK_TTL_MS ?? '900000', 10) || 900000);
|
|
99
|
+
const lock = createEnvRedisLock();
|
|
100
|
+
logger.info('Soft-delete purge scheduler starting', {
|
|
101
|
+
service: opts.service,
|
|
102
|
+
entities: opts.entities.map((e) => e.name),
|
|
103
|
+
intervalHours: intervalMs / 3_600_000,
|
|
104
|
+
locked: !!lock,
|
|
105
|
+
});
|
|
106
|
+
const scheduler = createScheduler({
|
|
107
|
+
name: `soft-delete-purge:${opts.service}`,
|
|
108
|
+
intervalMs,
|
|
109
|
+
startupDelayMs,
|
|
110
|
+
run: async () => { await runSoftDeletePurge(opts.entities, opts); },
|
|
111
|
+
...(lock ? { lock: { redis: () => lock, key: `soft-delete-purge:${opts.service}:leader`, ttlMs: lockTtlMs } } : {}),
|
|
112
|
+
});
|
|
113
|
+
if (!lock)
|
|
114
|
+
return scheduler;
|
|
115
|
+
// Own the leader-lock Redis client's lifecycle: `stop()` (wired to the
|
|
116
|
+
// service's runServer onShutdown) also closes the connection so it can't keep
|
|
117
|
+
// the process from exiting cleanly. Per-cycle lock acquire/release is handled
|
|
118
|
+
// by withLeaderLock; this is just connection teardown.
|
|
119
|
+
return {
|
|
120
|
+
start: () => scheduler.start(),
|
|
121
|
+
stop: () => { scheduler.stop(); void closeLeaderLock(lock); },
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic29mdC1kZWxldGUtc3dlZXAuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvYXBpL3NvZnQtZGVsZXRlLXN3ZWVwLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLCtDQUErQztBQUMvQyxzQ0FBc0M7QUFFdEM7Ozs7Ozs7Ozs7Ozs7Ozs7R0FnQkc7QUFFSCxPQUFPLEVBQUUsWUFBWSxFQUFFLGVBQWUsRUFBRSxrQkFBa0IsRUFBRSxlQUFlLEVBQWtCLE1BQU0sNEJBQTRCLENBQUM7QUFDaEksT0FBTyxFQUFFLG9CQUFvQixFQUFFLE1BQU0sd0JBQXdCLENBQUM7QUFFOUQsTUFBTSxNQUFNLEdBQUcsWUFBWSxDQUFDLG1CQUFtQixDQUFDLENBQUM7QUFrQmpEOzZFQUM2RTtBQUM3RSxNQUFNLFVBQVUsd0JBQXdCO0lBQ3RDLE9BQU8sQ0FBQyxPQUFPLENBQUMsR0FBRyxDQUFDLHlCQUF5QixJQUFJLE1BQU0sQ0FBQyxDQUFDLFdBQVcsRUFBRSxLQUFLLE9BQU8sQ0FBQztBQUNyRixDQUFDO0FBRUQ7Ozs7O0dBS0c7QUFDSCxNQUFNLENBQUMsS0FBSyxVQUFVLGtCQUFrQixDQUN0QyxRQUEyQixFQUMzQixJQUFJLEdBQTJCLEVBQUU7SUFFakMsTUFBTSxNQUFNLEdBQTJCLEVBQUUsQ0FBQztJQUMxQyxJQUFJLENBQUMsd0JBQXdCLEVBQUUsRUFBRSxDQUFDO1FBQ2hDLE1BQU0sQ0FBQyxLQUFLLENBQUMsOERBQThELENBQUMsQ0FBQztRQUM3RSxPQUFPLE1BQU0sQ0FBQztJQUNoQixDQUFDO0lBRUQsTUFBTSxTQUFTLEdBQUcsSUFBSSxDQUFDLFNBQVMsSUFBSSxHQUFHLENBQUM7SUFDeEMsTUFBTSxVQUFVLEdBQUcsSUFBSSxDQUFDLG1CQUFtQixJQUFJLEVBQUUsQ0FBQztJQUNsRCwrRUFBK0U7SUFDL0UsTUFBTSxHQUFHLEdBQUcsSUFBSSxJQUFJLEVBQUUsQ0FBQztJQUV2QiwyRUFBMkU7SUFDM0UseUVBQXlFO0lBQ3pFLCtEQUErRDtJQUMvRCxPQUFPLG9CQUFvQixDQUFDLEVBQUUsWUFBWSxFQUFFLElBQUksRUFBRSxFQUFFLEtBQUssSUFBSSxFQUFFO1FBQzdELEtBQUssTUFBTSxNQUFNLElBQUksUUFBUSxFQUFFLENBQUM7WUFDOUIsSUFBSSxLQUFLLEdBQUcsQ0FBQyxDQUFDO1lBQ2QsS0FBSyxJQUFJLENBQUMsR0FBRyxDQUFDLEVBQUUsQ0FBQyxHQUFHLFVBQVUsRUFBRSxDQUFDLEVBQUUsRUFBRSxDQUFDO2dCQUNwQyxJQUFJLE1BQWMsQ0FBQztnQkFDbkIsSUFBSSxDQUFDO29CQUNILE1BQU0sR0FBRyxNQUFNLE1BQU0sQ0FBQyxZQUFZLENBQUMsR0FBRyxFQUFFLFNBQVMsQ0FBQyxDQUFDO2dCQUNyRCxDQUFDO2dCQUFDLE9BQU8sR0FBRyxFQUFFLENBQUM7b0JBQ2IsTUFBTSxDQUFDLEtBQUssQ0FBQyxvQkFBb0IsRUFBRSxFQUFFLE1BQU0sRUFBRSxNQUFNLENBQUMsSUFBSSxFQUFFLEtBQUssRUFBRSxNQUFNLENBQUMsR0FBRyxDQUFDLEVBQUUsQ0FBQyxDQUFDO29CQUNoRixNQUFNO2dCQUNSLENBQUM7Z0JBQ0QsS0FBSyxJQUFJLE1BQU0sQ0FBQztnQkFDaEIsSUFBSSxNQUFNLEdBQUcsU0FBUztvQkFBRSxNQUFNLENBQUMsVUFBVTtnQkFDekMsSUFBSSxDQUFDLEtBQUssVUFBVSxHQUFHLENBQUMsRUFBRSxDQUFDO29CQUN6QixNQUFNLENBQUMsSUFBSSxDQUFDLG9FQUFvRSxFQUFFO3dCQUNoRixNQUFNLEVBQUUsTUFBTSxDQUFDLElBQUksRUFBRSxjQUFjLEVBQUUsS0FBSztxQkFDM0MsQ0FBQyxDQUFDO2dCQUNMLENBQUM7WUFDSCxDQUFDO1lBQ0QsSUFBSSxLQUFLLEdBQUcsQ0FBQztnQkFBRSxNQUFNLENBQUMsSUFBSSxDQUFDLGtDQUFrQyxFQUFFLEVBQUUsTUFBTSxFQUFFLE1BQU0sQ0FBQyxJQUFJLEVBQUUsS0FBSyxFQUFFLEtBQUssRUFBRSxDQUFDLENBQUM7WUFDdEcsTUFBTSxDQUFDLE1BQU0sQ0FBQyxJQUFJLENBQUMsR0FBRyxLQUFLLENBQUM7UUFDOUIsQ0FBQztRQUVELE9BQU8sTUFBTSxDQUFDO0lBQ2hCLENBQUMsQ0FBQyxDQUFDO0FBQ0wsQ0FBQztBQVdEOzs7Ozs7Ozs7Ozs7Ozs7R0FlRztBQUNILE1BQU0sVUFBVSw4QkFBOEIsQ0FBQyxJQUFxQztJQUNsRixJQUFJLENBQUMsd0JBQXdCLEVBQUUsRUFBRSxDQUFDO1FBQ2hDLE1BQU0sQ0FBQyxJQUFJLENBQUMsd0VBQXdFLEVBQUUsRUFBRSxPQUFPLEVBQUUsSUFBSSxDQUFDLE9BQU8sRUFBRSxDQUFDLENBQUM7UUFDakgsT0FBTyxJQUFJLENBQUM7SUFDZCxDQUFDO0lBRUQsTUFBTSxVQUFVLEdBQUcsSUFBSSxDQUFDLEdBQUcsQ0FBQyxDQUFDLEVBQUUsTUFBTSxDQUFDLFFBQVEsQ0FBQyxPQUFPLENBQUMsR0FBRyxDQUFDLGdDQUFnQyxJQUFJLEdBQUcsRUFBRSxFQUFFLENBQUMsSUFBSSxDQUFDLENBQUMsR0FBRyxFQUFFLEdBQUcsRUFBRSxHQUFHLElBQUksQ0FBQztJQUMvSCxNQUFNLGNBQWMsR0FBRyxJQUFJLENBQUMsR0FBRyxDQUFDLENBQUMsRUFBRSxNQUFNLENBQUMsUUFBUSxDQUFDLE9BQU8sQ0FBQyxHQUFHLENBQUMsa0NBQWtDLElBQUksUUFBUSxFQUFFLEVBQUUsQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDO0lBQ3pILE1BQU0sU0FBUyxHQUFHLElBQUksQ0FBQyxHQUFHLENBQUMsSUFBSSxFQUFFLE1BQU0sQ0FBQyxRQUFRLENBQUMsT0FBTyxDQUFDLEdBQUcsQ0FBQyw2QkFBNkIsSUFBSSxRQUFRLEVBQUUsRUFBRSxDQUFDLElBQUksTUFBTSxDQUFDLENBQUM7SUFDdkgsTUFBTSxJQUFJLEdBQUcsa0JBQWtCLEVBQUUsQ0FBQztJQUVsQyxNQUFNLENBQUMsSUFBSSxDQUFDLHNDQUFzQyxFQUFFO1FBQ2xELE9BQU8sRUFBRSxJQUFJLENBQUMsT0FBTztRQUNyQixRQUFRLEVBQUUsSUFBSSxDQUFDLFFBQVEsQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLEVBQUUsRUFBRSxDQUFDLENBQUMsQ0FBQyxJQUFJLENBQUM7UUFDMUMsYUFBYSxFQUFFLFVBQVUsR0FBRyxTQUFTO1FBQ3JDLE1BQU0sRUFBRSxDQUFDLENBQUMsSUFBSTtLQUNmLENBQUMsQ0FBQztJQUVILE1BQU0sU0FBUyxHQUFHLGVBQWUsQ0FBQztRQUNoQyxJQUFJLEVBQUUscUJBQXFCLElBQUksQ0FBQyxPQUFPLEVBQUU7UUFDekMsVUFBVTtRQUNWLGNBQWM7UUFDZCxHQUFHLEVBQUUsS0FBSyxJQUFJLEVBQUUsR0FBRyxNQUFNLGtCQUFrQixDQUFDLElBQUksQ0FBQyxRQUFRLEVBQUUsSUFBSSxDQUFDLENBQUMsQ0FBQyxDQUFDO1FBQ25FLEdBQUcsQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLEVBQUUsSUFBSSxFQUFFLEVBQUUsS0FBSyxFQUFFLEdBQUcsRUFBRSxDQUFDLElBQUksRUFBRSxHQUFHLEVBQUUscUJBQXFCLElBQUksQ0FBQyxPQUFPLFNBQVMsRUFBRSxLQUFLLEVBQUUsU0FBUyxFQUFFLEVBQUUsQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDO0tBQ3BILENBQUMsQ0FBQztJQUNILElBQUksQ0FBQyxJQUFJO1FBQUUsT0FBTyxTQUFTLENBQUM7SUFFNUIsdUVBQXVFO0lBQ3ZFLDhFQUE4RTtJQUM5RSw4RUFBOEU7SUFDOUUsdURBQXVEO0lBQ3ZELE9BQU87UUFDTCxLQUFLLEVBQUUsR0FBRyxFQUFFLENBQUMsU0FBUyxDQUFDLEtBQUssRUFBRTtRQUM5QixJQUFJLEVBQUUsR0FBRyxFQUFFLEdBQUcsU0FBUyxDQUFDLElBQUksRUFBRSxDQUFDLENBQUMsS0FBSyxlQUFlLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxDQUFDO0tBQzlELENBQUM7QUFDSixDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiLy8gQ29weXJpZ2h0IDIwMjYgUGlwZWxpbmUgQnVpbGRlciBDb250cmlidXRvcnNcbi8vIFNQRFgtTGljZW5zZS1JZGVudGlmaWVyOiBBcGFjaGUtMi4wXG5cbi8qKlxuICogU2hhcmVkIHNvZnQtZGVsZXRlIHJldGVudGlvbiBwdXJnZS5cbiAqXG4gKiBFdmVyeSB7QGxpbmsgQ3J1ZFNlcnZpY2V9IGVudGl0eSBzb2Z0LWRlbGV0ZXMgKHNldHMgYGRlbGV0ZWRBdGAgKyBhXG4gKiBgcHVyZ2VfYWZ0ZXJgIGRlYWRsaW5lKS4gVGhpcyBvcmNoZXN0cmF0b3IgcnVucyBvbmUgcHVyZ2UgcGFzcyBhY3Jvc3MgYSBzZXRcbiAqIG9mIHN1Y2ggZW50aXRpZXMsIGhhcmQtZGVsZXRpbmcgdG9tYnN0b25lcyB3aG9zZSBkZWFkbGluZSBoYXMgcGFzc2VkLiBJdCBpc1xuICogdGhlIGBydW5gIGNhbGxiYWNrIGEgc2VydmljZSBoYW5kcyB0byBgY3JlYXRlU2NoZWR1bGVyYCAobGVhZGVyLWxvY2tlZCksIHNvXG4gKiBvbmx5IG9uZSBwb2Qgc3dlZXBzIGF0IGEgdGltZS5cbiAqXG4gKiBSdW5zIGluIGFuIGV4cGxpY2l0ICoqc3lzYWRtaW4gdGVuYW50IHNjb3BlKiogKGBydW5XaXRoVGVuYW50Q29udGV4dCh7XG4gKiBpc1N1cGVyQWRtaW46IHRydWUgfSlgKSBzbyB0aGUgdW5kZXJseWluZyBgcHVyZ2VFeHBpcmVkYCBzcGFucyBldmVyeSBvcmcgYW5kXG4gKiBieXBhc3NlcyBSTFMgb24gRk9SQ0UnZCB0YWJsZXMgKHBsdWdpbnMvcGlwZWxpbmVzL2V0Yy4pLiBBIGJhcmUgbm8tdGVuYW50XG4gKiBjb250ZXh0IHdvdWxkIHNlZSB6ZXJvIHJvd3Mgb24gdGhvc2UgdGFibGVzIOKAlCBhbmQgaW4gcHJvZHVjdGlvbiAoYHN0cmljdGBcbiAqIG1vZGUpIGB3aXRoVGVuYW50VHhgIHRocm93cyBvdXRyaWdodCDigJQgc28gdGhlIHNjb3BlIGlzIGVzdGFibGlzaGVkIGhlcmUgcmF0aGVyXG4gKiB0aGFuIGxlZnQgdG8gdGhlIGNhbGxlci4gVGhpcyBpcyBhIGNyb3NzLXRlbmFudCBob3VzZWtlZXBpbmcgam9iLCBub3QgYVxuICogcGVyLW9yZyBvcGVyYXRpb24uXG4gKi9cblxuaW1wb3J0IHsgY3JlYXRlTG9nZ2VyLCBjcmVhdGVTY2hlZHVsZXIsIGNyZWF0ZUVudlJlZGlzTG9jaywgY2xvc2VMZWFkZXJMb2NrLCB0eXBlIFNjaGVkdWxlciB9IGZyb20gJ0BwaXBlbGluZS1idWlsZGVyL2FwaS1jb3JlJztcbmltcG9ydCB7IHJ1bldpdGhUZW5hbnRDb250ZXh0IH0gZnJvbSAnLi4vZGF0YWJhc2UvdGVuYW5jeS5qcyc7XG5cbmNvbnN0IGxvZ2dlciA9IGNyZWF0ZUxvZ2dlcignc29mdC1kZWxldGUtc3dlZXAnKTtcblxuLyoqIFRoZSBzbGljZSBvZiBhIENydWRTZXJ2aWNlIHRoZSBzd2VlcCBuZWVkcywgcGx1cyBhIGxhYmVsIGZvciBsb2dzL21ldHJpY3MuICovXG5leHBvcnQgaW50ZXJmYWNlIFB1cmdlYWJsZUVudGl0eSB7XG4gIC8qKiBUYWJsZS9lbnRpdHkgbGFiZWwgKGUuZy4gJ3BpcGVsaW5lJykgZm9yIHBlci10YWJsZSBsb2dnaW5nLiAqL1xuICBuYW1lOiBzdHJpbmc7XG4gIC8qKiBIYXJkLWRlbGV0ZSB1cCB0byBgbGltaXRgIGV4cGlyZWQgdG9tYnN0b25lczsgcmV0dXJucyByb3dzIHB1cmdlZC4gKi9cbiAgcHVyZ2VFeHBpcmVkKG5vdzogRGF0ZSwgbGltaXQ/OiBudW1iZXIpOiBQcm9taXNlPG51bWJlcj47XG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgU29mdERlbGV0ZVB1cmdlT3B0aW9ucyB7XG4gIC8qKiBSb3dzIHBlciBiYXRjaCBwZXIgdGFibGUgKGRlZmF1bHQgNTAwKS4gKi9cbiAgYmF0Y2hTaXplPzogbnVtYmVyO1xuICAvKiogTWF4IGJhdGNoZXMgcGVyIHRhYmxlIHBlciB0aWNrIChkZWZhdWx0IDIwIOKGkiDiiaQgMTBrL3RhYmxlL3RpY2spOyB0aGUgcmVzdFxuICAgKiAgaXMgZGVmZXJyZWQgdG8gdGhlIG5leHQgdGljayBzbyBhIGh1Z2UgYmFja2xvZyBjYW4ndCBibG93IHRoZSBsb2NrIFRUTC4gKi9cbiAgbWF4QmF0Y2hlc1BlckVudGl0eT86IG51bWJlcjtcbn1cblxuLyoqIEtpbGwtc3dpdGNoOiBgU09GVF9ERUxFVEVfUFVSR0VfRU5BQkxFRD1mYWxzZWAgZGlzYWJsZXMgYWxsIGhhcmQtcHVyZ2luZ1xuICogICh0b21ic3RvbmVzIHN0aWxsIGFjY3VtdWxhdGUgKyBzdGF5IHJlc3RvcmFibGU7IG5vdGhpbmcgaXMgZGVzdHJveWVkKS4gKi9cbmV4cG9ydCBmdW5jdGlvbiBpc1NvZnREZWxldGVQdXJnZUVuYWJsZWQoKTogYm9vbGVhbiB7XG4gIHJldHVybiAocHJvY2Vzcy5lbnYuU09GVF9ERUxFVEVfUFVSR0VfRU5BQkxFRCA/PyAndHJ1ZScpLnRvTG93ZXJDYXNlKCkgIT09ICdmYWxzZSc7XG59XG5cbi8qKlxuICogUnVuIG9uZSBwdXJnZSBzd2VlcCBhY3Jvc3MgYGVudGl0aWVzYC4gTG9vcHMgZWFjaCBlbnRpdHkncyBgcHVyZ2VFeHBpcmVkYCBpblxuICogYmF0Y2hlcyB1bnRpbCBhIGJhdGNoIHJldHVybnMgYDwgYmF0Y2hTaXplYCAoZHJhaW5lZCkgb3IgdGhlIHBlci10aWNrIGNhcCBpc1xuICogaGl0IChsb2dnZWQ7IGNvbnRpbnVlZCBuZXh0IHRpY2spLiBOZXZlciB0aHJvd3Mg4oCUIGEgZmFpbGluZyBlbnRpdHkgaXMgbG9nZ2VkXG4gKiBhbmQgdGhlIHN3ZWVwIG1vdmVzIG9uLiBSZXR1cm5zIHBlci1lbnRpdHkgcHVyZ2VkIGNvdW50cyAoYWxzbyBsb2dnZWQpLlxuICovXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gcnVuU29mdERlbGV0ZVB1cmdlKFxuICBlbnRpdGllczogUHVyZ2VhYmxlRW50aXR5W10sXG4gIG9wdHM6IFNvZnREZWxldGVQdXJnZU9wdGlvbnMgPSB7fSxcbik6IFByb21pc2U8UmVjb3JkPHN0cmluZywgbnVtYmVyPj4ge1xuICBjb25zdCBjb3VudHM6IFJlY29yZDxzdHJpbmcsIG51bWJlcj4gPSB7fTtcbiAgaWYgKCFpc1NvZnREZWxldGVQdXJnZUVuYWJsZWQoKSkge1xuICAgIGxvZ2dlci5kZWJ1ZygnU29mdC1kZWxldGUgcHVyZ2UgZGlzYWJsZWQgKFNPRlRfREVMRVRFX1BVUkdFX0VOQUJMRUQ9ZmFsc2UpJyk7XG4gICAgcmV0dXJuIGNvdW50cztcbiAgfVxuXG4gIGNvbnN0IGJhdGNoU2l6ZSA9IG9wdHMuYmF0Y2hTaXplID8/IDUwMDtcbiAgY29uc3QgbWF4QmF0Y2hlcyA9IG9wdHMubWF4QmF0Y2hlc1BlckVudGl0eSA/PyAyMDtcbiAgLy8gT25lIGBub3dgIGZvciB0aGUgd2hvbGUgdGljayDigJQgcm93cyB0aGF0IGV4cGlyZSBtaWQtc3dlZXAgd2FpdCBmb3IgdGhlIG5leHQuXG4gIGNvbnN0IG5vdyA9IG5ldyBEYXRlKCk7XG5cbiAgLy8gRXN0YWJsaXNoIGEgc3lzYWRtaW4gc2NvcGUgc28gZXZlcnkgYHB1cmdlRXhwaXJlZGAgKHdoaWNoIHJvdXRlcyB0aHJvdWdoXG4gIC8vIGB3aXRoVGVuYW50VHhgKSBieXBhc3NlcyBSTFMgYW5kIHNwYW5zIGFsbCBvcmdzLiBXaXRob3V0IHRoaXMsIEZPUkNFJ2RcbiAgLy8gdGFibGVzIHJldHVybiB6ZXJvIHJvd3MgYW5kIHByb2R1Y3Rpb24gYHN0cmljdGAgbW9kZSB0aHJvd3MuXG4gIHJldHVybiBydW5XaXRoVGVuYW50Q29udGV4dCh7IGlzU3VwZXJBZG1pbjogdHJ1ZSB9LCBhc3luYyAoKSA9PiB7XG4gICAgZm9yIChjb25zdCBlbnRpdHkgb2YgZW50aXRpZXMpIHtcbiAgICAgIGxldCB0b3RhbCA9IDA7XG4gICAgICBmb3IgKGxldCBpID0gMDsgaSA8IG1heEJhdGNoZXM7IGkrKykge1xuICAgICAgICBsZXQgcHVyZ2VkOiBudW1iZXI7XG4gICAgICAgIHRyeSB7XG4gICAgICAgICAgcHVyZ2VkID0gYXdhaXQgZW50aXR5LnB1cmdlRXhwaXJlZChub3csIGJhdGNoU2l6ZSk7XG4gICAgICAgIH0gY2F0Y2ggKGVycikge1xuICAgICAgICAgIGxvZ2dlci5lcnJvcignUHVyZ2UgYmF0Y2ggZmFpbGVkJywgeyBlbnRpdHk6IGVudGl0eS5uYW1lLCBlcnJvcjogU3RyaW5nKGVycikgfSk7XG4gICAgICAgICAgYnJlYWs7XG4gICAgICAgIH1cbiAgICAgICAgdG90YWwgKz0gcHVyZ2VkO1xuICAgICAgICBpZiAocHVyZ2VkIDwgYmF0Y2hTaXplKSBicmVhazsgLy8gZHJhaW5lZFxuICAgICAgICBpZiAoaSA9PT0gbWF4QmF0Y2hlcyAtIDEpIHtcbiAgICAgICAgICBsb2dnZXIud2FybignUHVyZ2UgaGl0IHBlci10aWNrIGNhcDsgcmVtYWluaW5nIHRvbWJzdG9uZXMgZGVmZXJyZWQgdG8gbmV4dCB0aWNrJywge1xuICAgICAgICAgICAgZW50aXR5OiBlbnRpdHkubmFtZSwgcHVyZ2VkVGhpc1RpY2s6IHRvdGFsLFxuICAgICAgICAgIH0pO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgICBpZiAodG90YWwgPiAwKSBsb2dnZXIuaW5mbygnUHVyZ2VkIGV4cGlyZWQgc29mdC1kZWxldGVkIHJvd3MnLCB7IGVudGl0eTogZW50aXR5Lm5hbWUsIGNvdW50OiB0b3RhbCB9KTtcbiAgICAgIGNvdW50c1tlbnRpdHkubmFtZV0gPSB0b3RhbDtcbiAgICB9XG5cbiAgICByZXR1cm4gY291bnRzO1xuICB9KTtcbn1cblxuLy8gLS0gU2NoZWR1bGVyIGZhY3RvcnkgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cblxuZXhwb3J0IGludGVyZmFjZSBTb2Z0RGVsZXRlUHVyZ2VTY2hlZHVsZXJPcHRpb25zIGV4dGVuZHMgU29mdERlbGV0ZVB1cmdlT3B0aW9ucyB7XG4gIC8qKiBTZXJ2aWNlIGxhYmVsIGZvciBsb2dzICsgdGhlIGxlYWRlci1sb2NrIGtleSAoZS5nLiAncGlwZWxpbmUnLCAncGx1Z2luJykuICovXG4gIHNlcnZpY2U6IHN0cmluZztcbiAgLyoqIEVudGl0aWVzIHRvIHN3ZWVwIOKAlCB1c3VhbGx5IHRoZSBzZXJ2aWNlJ3Mgb3duIENydWRTZXJ2aWNlIHNpbmdsZXRvbnMuICovXG4gIGVudGl0aWVzOiBQdXJnZWFibGVFbnRpdHlbXTtcbn1cblxuLyoqXG4gKiBCdWlsZCAoYnV0IGRvIE5PVCBzdGFydCkgYSBsZWFkZXItbG9ja2VkIHNjaGVkdWxlciB0aGF0IHJ1bnMgdGhlIHNvZnQtZGVsZXRlXG4gKiBwdXJnZSBzd2VlcCBmb3IgYGVudGl0aWVzYCBvbiBhIGNhZGVuY2UuIFRoZSBjYWxsZXIgYC5zdGFydCgpYHMgaXQgYW5kIHdpcmVzXG4gKiBgc3RvcCgpYCB0byBTSUdURVJNLiBSZXR1cm5zIG51bGwgd2hlbiBwdXJnaW5nIGlzIGRpc2FibGVkLlxuICpcbiAqIEVudiBjb25maWc6XG4gKiAgIFNPRlRfREVMRVRFX1BVUkdFX0VOQUJMRUQgICAgICAgICAgIChkZWZhdWx0IHRydWU7IGZhbHNlIOKHkiBudWxsLCBubyBzd2VlcClcbiAqICAgU09GVF9ERUxFVEVfUFVSR0VfSU5URVJWQUxfSE9VUlMgICAgKGRlZmF1bHQgNilcbiAqICAgU09GVF9ERUxFVEVfUFVSR0VfU1RBUlRVUF9ERUxBWV9NUyAgKGRlZmF1bHQgMTIwMDAwIOKAlCAyIG1pbiBzZXR0bGUpXG4gKiAgIFNPRlRfREVMRVRFX1BVUkdFX0xPQ0tfVFRMX01TICAgICAgIChkZWZhdWx0IDkwMDAwMCDigJQgMTUgbWluOyBvdXRsYXN0cyBhXG4gKiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzd2VlcCwgc3RheXMgdW5kZXIgdGhlIGludGVydmFsKVxuICpcbiAqIEEgY3Jvc3MtcG9kIGxlYWRlciBsb2NrICh3aGVuIFJlZGlzIGlzIGNvbmZpZ3VyZWQpIG1lYW5zIG9ubHkgb25lIHJlcGxpY2FcbiAqIHN3ZWVwcyBwZXIgd2luZG93OyB3aXRob3V0IFJlZGlzIGl0IHJ1bnMgb24gZXZlcnkgcG9kIOKAlCBzdGlsbCBzYWZlLCBzaW5jZSB0aGVcbiAqIHB1cmdlIGlzIGEgYmF0Y2hlZCBpZGVtcG90ZW50IERFTEVURSwganVzdCByZWR1bmRhbnQuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBjcmVhdGVTb2Z0RGVsZXRlUHVyZ2VTY2hlZHVsZXIob3B0czogU29mdERlbGV0ZVB1cmdlU2NoZWR1bGVyT3B0aW9ucyk6IFNjaGVkdWxlciB8IG51bGwge1xuICBpZiAoIWlzU29mdERlbGV0ZVB1cmdlRW5hYmxlZCgpKSB7XG4gICAgbG9nZ2VyLmluZm8oJ1NvZnQtZGVsZXRlIHB1cmdlIHNjaGVkdWxlciBkaXNhYmxlZCAoU09GVF9ERUxFVEVfUFVSR0VfRU5BQkxFRD1mYWxzZSknLCB7IHNlcnZpY2U6IG9wdHMuc2VydmljZSB9KTtcbiAgICByZXR1cm4gbnVsbDtcbiAgfVxuXG4gIGNvbnN0IGludGVydmFsTXMgPSBNYXRoLm1heCgxLCBOdW1iZXIucGFyc2VJbnQocHJvY2Vzcy5lbnYuU09GVF9ERUxFVEVfUFVSR0VfSU5URVJWQUxfSE9VUlMgPz8gJzYnLCAxMCkgfHwgNikgKiA2MCAqIDYwICogMTAwMDtcbiAgY29uc3Qgc3RhcnR1cERlbGF5TXMgPSBNYXRoLm1heCgwLCBOdW1iZXIucGFyc2VJbnQocHJvY2Vzcy5lbnYuU09GVF9ERUxFVEVfUFVSR0VfU1RBUlRVUF9ERUxBWV9NUyA/PyAnMTIwMDAwJywgMTApIHx8IDApO1xuICBjb25zdCBsb2NrVHRsTXMgPSBNYXRoLm1heCgxMDAwLCBOdW1iZXIucGFyc2VJbnQocHJvY2Vzcy5lbnYuU09GVF9ERUxFVEVfUFVSR0VfTE9DS19UVExfTVMgPz8gJzkwMDAwMCcsIDEwKSB8fCA5MDAwMDApO1xuICBjb25zdCBsb2NrID0gY3JlYXRlRW52UmVkaXNMb2NrKCk7XG5cbiAgbG9nZ2VyLmluZm8oJ1NvZnQtZGVsZXRlIHB1cmdlIHNjaGVkdWxlciBzdGFydGluZycsIHtcbiAgICBzZXJ2aWNlOiBvcHRzLnNlcnZpY2UsXG4gICAgZW50aXRpZXM6IG9wdHMuZW50aXRpZXMubWFwKChlKSA9PiBlLm5hbWUpLFxuICAgIGludGVydmFsSG91cnM6IGludGVydmFsTXMgLyAzXzYwMF8wMDAsXG4gICAgbG9ja2VkOiAhIWxvY2ssXG4gIH0pO1xuXG4gIGNvbnN0IHNjaGVkdWxlciA9IGNyZWF0ZVNjaGVkdWxlcih7XG4gICAgbmFtZTogYHNvZnQtZGVsZXRlLXB1cmdlOiR7b3B0cy5zZXJ2aWNlfWAsXG4gICAgaW50ZXJ2YWxNcyxcbiAgICBzdGFydHVwRGVsYXlNcyxcbiAgICBydW46IGFzeW5jICgpID0+IHsgYXdhaXQgcnVuU29mdERlbGV0ZVB1cmdlKG9wdHMuZW50aXRpZXMsIG9wdHMpOyB9LFxuICAgIC4uLihsb2NrID8geyBsb2NrOiB7IHJlZGlzOiAoKSA9PiBsb2NrLCBrZXk6IGBzb2Z0LWRlbGV0ZS1wdXJnZToke29wdHMuc2VydmljZX06bGVhZGVyYCwgdHRsTXM6IGxvY2tUdGxNcyB9IH0gOiB7fSksXG4gIH0pO1xuICBpZiAoIWxvY2spIHJldHVybiBzY2hlZHVsZXI7XG5cbiAgLy8gT3duIHRoZSBsZWFkZXItbG9jayBSZWRpcyBjbGllbnQncyBsaWZlY3ljbGU6IGBzdG9wKClgICh3aXJlZCB0byB0aGVcbiAgLy8gc2VydmljZSdzIHJ1blNlcnZlciBvblNodXRkb3duKSBhbHNvIGNsb3NlcyB0aGUgY29ubmVjdGlvbiBzbyBpdCBjYW4ndCBrZWVwXG4gIC8vIHRoZSBwcm9jZXNzIGZyb20gZXhpdGluZyBjbGVhbmx5LiBQZXItY3ljbGUgbG9jayBhY3F1aXJlL3JlbGVhc2UgaXMgaGFuZGxlZFxuICAvLyBieSB3aXRoTGVhZGVyTG9jazsgdGhpcyBpcyBqdXN0IGNvbm5lY3Rpb24gdGVhcmRvd24uXG4gIHJldHVybiB7XG4gICAgc3RhcnQ6ICgpID0+IHNjaGVkdWxlci5zdGFydCgpLFxuICAgIHN0b3A6ICgpID0+IHsgc2NoZWR1bGVyLnN0b3AoKTsgdm9pZCBjbG9zZUxlYWRlckxvY2sobG9jayk7IH0sXG4gIH07XG59XG4iXX0=
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/** The viewer fields a per-user predicate reads off a filter. */
|
|
2
|
+
export interface ViewerScopedFilter {
|
|
3
|
+
/** Caller's user id. Compared against the row's per-user column. */
|
|
4
|
+
readonly viewerUserId?: string;
|
|
5
|
+
/** Whether the caller is a platform super-admin (sees every rung). */
|
|
6
|
+
readonly viewerIsSuperAdmin?: boolean;
|
|
7
|
+
}
|
|
8
|
+
/** The current request's user id, or `undefined` outside a tenant scope. */
|
|
9
|
+
export declare function currentViewerUserId(): string | undefined;
|
|
10
|
+
/**
|
|
11
|
+
* Stamp the request's viewer identity onto a filter.
|
|
12
|
+
*
|
|
13
|
+
* An EXPLICIT value on the filter always wins, so a caller that deliberately
|
|
14
|
+
* scopes to a specific user (or a test that fixes the viewer) stays expressible;
|
|
15
|
+
* the context only fills what the caller left blank.
|
|
16
|
+
*
|
|
17
|
+
* Safe against `CrudService.runRead`'s sysadmin widening (the parent-org read
|
|
18
|
+
* path, which re-enters the context with `isSuperAdmin: true`): conditions are
|
|
19
|
+
* always built BEFORE that scope is entered, so the stamp reflects the real
|
|
20
|
+
* caller, never the widened one.
|
|
21
|
+
*
|
|
22
|
+
* @example
|
|
23
|
+
* ```typescript
|
|
24
|
+
* protected buildConditions(filter, orgId, parentOrgId) {
|
|
25
|
+
* return buildXConditions(withViewerContext(filter), orgId, parentOrgId);
|
|
26
|
+
* }
|
|
27
|
+
* ```
|
|
28
|
+
*/
|
|
29
|
+
export declare function withViewerContext<F extends ViewerScopedFilter>(filter: Partial<F>): Partial<F>;
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
// Copyright 2026 Pipeline Builder Contributors
|
|
2
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
3
|
+
/**
|
|
4
|
+
* Viewer identity for app-layer predicates that carry a PER-USER rung.
|
|
5
|
+
*
|
|
6
|
+
* Most visibility predicates are org-grained, which RLS and the shared
|
|
7
|
+
* access-control builder already express. Two entities need finer grain:
|
|
8
|
+
*
|
|
9
|
+
* - **pipeline templates** — the `private` rung is author-only (`created_by`)
|
|
10
|
+
* - **messages** — a per-user targeted row (`recipient_user_id`) is visible
|
|
11
|
+
* only to its target, not to everyone in the recipient org
|
|
12
|
+
*
|
|
13
|
+
* Both need to know WHO is asking, and neither can get it from `CrudService`'s
|
|
14
|
+
* signatures: `writeConditions` (update/delete) builds the read clause from a
|
|
15
|
+
* bare `{ id }` filter and has nowhere to pass a viewer. Hand-threading the
|
|
16
|
+
* viewer through every call site is the alternative, and it fails in practice —
|
|
17
|
+
* it produces parallel `find*Visible*` methods and silently drops the viewer at
|
|
18
|
+
* whichever call site forgets it (an org member then reads a row addressed to
|
|
19
|
+
* someone else).
|
|
20
|
+
*
|
|
21
|
+
* So the viewer travels the same trusted, request-scoped channel as the org
|
|
22
|
+
* stamp: `TenantContext`, set once at the request boundary from the validated
|
|
23
|
+
* JWT. A service opts in by stamping it in ONE place — its `buildConditions`
|
|
24
|
+
* override, which every read and write funnels through, including direct
|
|
25
|
+
* `this.buildConditions(...)` calls.
|
|
26
|
+
*
|
|
27
|
+
* Fails CLOSED everywhere: no tenant scope (background jobs, migrations, the
|
|
28
|
+
* retention sweep) means no viewer, and a viewer-less predicate must match
|
|
29
|
+
* nothing on the per-user rung rather than matching everything.
|
|
30
|
+
*/
|
|
31
|
+
import { getTenantContext } from '../database/tenancy.js';
|
|
32
|
+
/** The current request's user id, or `undefined` outside a tenant scope. */
|
|
33
|
+
export function currentViewerUserId() {
|
|
34
|
+
return getTenantContext()?.userId;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Stamp the request's viewer identity onto a filter.
|
|
38
|
+
*
|
|
39
|
+
* An EXPLICIT value on the filter always wins, so a caller that deliberately
|
|
40
|
+
* scopes to a specific user (or a test that fixes the viewer) stays expressible;
|
|
41
|
+
* the context only fills what the caller left blank.
|
|
42
|
+
*
|
|
43
|
+
* Safe against `CrudService.runRead`'s sysadmin widening (the parent-org read
|
|
44
|
+
* path, which re-enters the context with `isSuperAdmin: true`): conditions are
|
|
45
|
+
* always built BEFORE that scope is entered, so the stamp reflects the real
|
|
46
|
+
* caller, never the widened one.
|
|
47
|
+
*
|
|
48
|
+
* @example
|
|
49
|
+
* ```typescript
|
|
50
|
+
* protected buildConditions(filter, orgId, parentOrgId) {
|
|
51
|
+
* return buildXConditions(withViewerContext(filter), orgId, parentOrgId);
|
|
52
|
+
* }
|
|
53
|
+
* ```
|
|
54
|
+
*/
|
|
55
|
+
export function withViewerContext(filter) {
|
|
56
|
+
const ctx = getTenantContext();
|
|
57
|
+
return {
|
|
58
|
+
...filter,
|
|
59
|
+
viewerUserId: filter.viewerUserId ?? ctx?.userId,
|
|
60
|
+
viewerIsSuperAdmin: filter.viewerIsSuperAdmin ?? ctx?.isSuperAdmin ?? false,
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidmlld2VyLWNvbnRleHQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvYXBpL3ZpZXdlci1jb250ZXh0LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLCtDQUErQztBQUMvQyxzQ0FBc0M7QUFFdEM7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztHQTJCRztBQUVILE9BQU8sRUFBRSxnQkFBZ0IsRUFBRSxNQUFNLHdCQUF3QixDQUFDO0FBVTFELDRFQUE0RTtBQUM1RSxNQUFNLFVBQVUsbUJBQW1CO0lBQ2pDLE9BQU8sZ0JBQWdCLEVBQUUsRUFBRSxNQUFNLENBQUM7QUFDcEMsQ0FBQztBQUVEOzs7Ozs7Ozs7Ozs7Ozs7Ozs7R0FrQkc7QUFDSCxNQUFNLFVBQVUsaUJBQWlCLENBQStCLE1BQWtCO0lBQ2hGLE1BQU0sR0FBRyxHQUFHLGdCQUFnQixFQUFFLENBQUM7SUFDL0IsT0FBTztRQUNMLEdBQUcsTUFBTTtRQUNULFlBQVksRUFBRSxNQUFNLENBQUMsWUFBWSxJQUFJLEdBQUcsRUFBRSxNQUFNO1FBQ2hELGtCQUFrQixFQUFFLE1BQU0sQ0FBQyxrQkFBa0IsSUFBSSxHQUFHLEVBQUUsWUFBWSxJQUFJLEtBQUs7S0FDNUUsQ0FBQztBQUNKLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyIvLyBDb3B5cmlnaHQgMjAyNiBQaXBlbGluZSBCdWlsZGVyIENvbnRyaWJ1dG9yc1xuLy8gU1BEWC1MaWNlbnNlLUlkZW50aWZpZXI6IEFwYWNoZS0yLjBcblxuLyoqXG4gKiBWaWV3ZXIgaWRlbnRpdHkgZm9yIGFwcC1sYXllciBwcmVkaWNhdGVzIHRoYXQgY2FycnkgYSBQRVItVVNFUiBydW5nLlxuICpcbiAqIE1vc3QgdmlzaWJpbGl0eSBwcmVkaWNhdGVzIGFyZSBvcmctZ3JhaW5lZCwgd2hpY2ggUkxTIGFuZCB0aGUgc2hhcmVkXG4gKiBhY2Nlc3MtY29udHJvbCBidWlsZGVyIGFscmVhZHkgZXhwcmVzcy4gVHdvIGVudGl0aWVzIG5lZWQgZmluZXIgZ3JhaW46XG4gKlxuICogIC0gKipwaXBlbGluZSB0ZW1wbGF0ZXMqKiDigJQgdGhlIGBwcml2YXRlYCBydW5nIGlzIGF1dGhvci1vbmx5IChgY3JlYXRlZF9ieWApXG4gKiAgLSAqKm1lc3NhZ2VzKiog4oCUIGEgcGVyLXVzZXIgdGFyZ2V0ZWQgcm93IChgcmVjaXBpZW50X3VzZXJfaWRgKSBpcyB2aXNpYmxlXG4gKiAgICBvbmx5IHRvIGl0cyB0YXJnZXQsIG5vdCB0byBldmVyeW9uZSBpbiB0aGUgcmVjaXBpZW50IG9yZ1xuICpcbiAqIEJvdGggbmVlZCB0byBrbm93IFdITyBpcyBhc2tpbmcsIGFuZCBuZWl0aGVyIGNhbiBnZXQgaXQgZnJvbSBgQ3J1ZFNlcnZpY2VgJ3NcbiAqIHNpZ25hdHVyZXM6IGB3cml0ZUNvbmRpdGlvbnNgICh1cGRhdGUvZGVsZXRlKSBidWlsZHMgdGhlIHJlYWQgY2xhdXNlIGZyb20gYVxuICogYmFyZSBgeyBpZCB9YCBmaWx0ZXIgYW5kIGhhcyBub3doZXJlIHRvIHBhc3MgYSB2aWV3ZXIuIEhhbmQtdGhyZWFkaW5nIHRoZVxuICogdmlld2VyIHRocm91Z2ggZXZlcnkgY2FsbCBzaXRlIGlzIHRoZSBhbHRlcm5hdGl2ZSwgYW5kIGl0IGZhaWxzIGluIHByYWN0aWNlIOKAlFxuICogaXQgcHJvZHVjZXMgcGFyYWxsZWwgYGZpbmQqVmlzaWJsZSpgIG1ldGhvZHMgYW5kIHNpbGVudGx5IGRyb3BzIHRoZSB2aWV3ZXIgYXRcbiAqIHdoaWNoZXZlciBjYWxsIHNpdGUgZm9yZ2V0cyBpdCAoYW4gb3JnIG1lbWJlciB0aGVuIHJlYWRzIGEgcm93IGFkZHJlc3NlZCB0b1xuICogc29tZW9uZSBlbHNlKS5cbiAqXG4gKiBTbyB0aGUgdmlld2VyIHRyYXZlbHMgdGhlIHNhbWUgdHJ1c3RlZCwgcmVxdWVzdC1zY29wZWQgY2hhbm5lbCBhcyB0aGUgb3JnXG4gKiBzdGFtcDogYFRlbmFudENvbnRleHRgLCBzZXQgb25jZSBhdCB0aGUgcmVxdWVzdCBib3VuZGFyeSBmcm9tIHRoZSB2YWxpZGF0ZWRcbiAqIEpXVC4gQSBzZXJ2aWNlIG9wdHMgaW4gYnkgc3RhbXBpbmcgaXQgaW4gT05FIHBsYWNlIOKAlCBpdHMgYGJ1aWxkQ29uZGl0aW9uc2BcbiAqIG92ZXJyaWRlLCB3aGljaCBldmVyeSByZWFkIGFuZCB3cml0ZSBmdW5uZWxzIHRocm91Z2gsIGluY2x1ZGluZyBkaXJlY3RcbiAqIGB0aGlzLmJ1aWxkQ29uZGl0aW9ucyguLi4pYCBjYWxscy5cbiAqXG4gKiBGYWlscyBDTE9TRUQgZXZlcnl3aGVyZTogbm8gdGVuYW50IHNjb3BlIChiYWNrZ3JvdW5kIGpvYnMsIG1pZ3JhdGlvbnMsIHRoZVxuICogcmV0ZW50aW9uIHN3ZWVwKSBtZWFucyBubyB2aWV3ZXIsIGFuZCBhIHZpZXdlci1sZXNzIHByZWRpY2F0ZSBtdXN0IG1hdGNoXG4gKiBub3RoaW5nIG9uIHRoZSBwZXItdXNlciBydW5nIHJhdGhlciB0aGFuIG1hdGNoaW5nIGV2ZXJ5dGhpbmcuXG4gKi9cblxuaW1wb3J0IHsgZ2V0VGVuYW50Q29udGV4dCB9IGZyb20gJy4uL2RhdGFiYXNlL3RlbmFuY3kuanMnO1xuXG4vKiogVGhlIHZpZXdlciBmaWVsZHMgYSBwZXItdXNlciBwcmVkaWNhdGUgcmVhZHMgb2ZmIGEgZmlsdGVyLiAqL1xuZXhwb3J0IGludGVyZmFjZSBWaWV3ZXJTY29wZWRGaWx0ZXIge1xuICAvKiogQ2FsbGVyJ3MgdXNlciBpZC4gQ29tcGFyZWQgYWdhaW5zdCB0aGUgcm93J3MgcGVyLXVzZXIgY29sdW1uLiAqL1xuICByZWFkb25seSB2aWV3ZXJVc2VySWQ/OiBzdHJpbmc7XG4gIC8qKiBXaGV0aGVyIHRoZSBjYWxsZXIgaXMgYSBwbGF0Zm9ybSBzdXBlci1hZG1pbiAoc2VlcyBldmVyeSBydW5nKS4gKi9cbiAgcmVhZG9ubHkgdmlld2VySXNTdXBlckFkbWluPzogYm9vbGVhbjtcbn1cblxuLyoqIFRoZSBjdXJyZW50IHJlcXVlc3QncyB1c2VyIGlkLCBvciBgdW5kZWZpbmVkYCBvdXRzaWRlIGEgdGVuYW50IHNjb3BlLiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGN1cnJlbnRWaWV3ZXJVc2VySWQoKTogc3RyaW5nIHwgdW5kZWZpbmVkIHtcbiAgcmV0dXJuIGdldFRlbmFudENvbnRleHQoKT8udXNlcklkO1xufVxuXG4vKipcbiAqIFN0YW1wIHRoZSByZXF1ZXN0J3Mgdmlld2VyIGlkZW50aXR5IG9udG8gYSBmaWx0ZXIuXG4gKlxuICogQW4gRVhQTElDSVQgdmFsdWUgb24gdGhlIGZpbHRlciBhbHdheXMgd2lucywgc28gYSBjYWxsZXIgdGhhdCBkZWxpYmVyYXRlbHlcbiAqIHNjb3BlcyB0byBhIHNwZWNpZmljIHVzZXIgKG9yIGEgdGVzdCB0aGF0IGZpeGVzIHRoZSB2aWV3ZXIpIHN0YXlzIGV4cHJlc3NpYmxlO1xuICogdGhlIGNvbnRleHQgb25seSBmaWxscyB3aGF0IHRoZSBjYWxsZXIgbGVmdCBibGFuay5cbiAqXG4gKiBTYWZlIGFnYWluc3QgYENydWRTZXJ2aWNlLnJ1blJlYWRgJ3Mgc3lzYWRtaW4gd2lkZW5pbmcgKHRoZSBwYXJlbnQtb3JnIHJlYWRcbiAqIHBhdGgsIHdoaWNoIHJlLWVudGVycyB0aGUgY29udGV4dCB3aXRoIGBpc1N1cGVyQWRtaW46IHRydWVgKTogY29uZGl0aW9ucyBhcmVcbiAqIGFsd2F5cyBidWlsdCBCRUZPUkUgdGhhdCBzY29wZSBpcyBlbnRlcmVkLCBzbyB0aGUgc3RhbXAgcmVmbGVjdHMgdGhlIHJlYWxcbiAqIGNhbGxlciwgbmV2ZXIgdGhlIHdpZGVuZWQgb25lLlxuICpcbiAqIEBleGFtcGxlXG4gKiBgYGB0eXBlc2NyaXB0XG4gKiBwcm90ZWN0ZWQgYnVpbGRDb25kaXRpb25zKGZpbHRlciwgb3JnSWQsIHBhcmVudE9yZ0lkKSB7XG4gKiAgIHJldHVybiBidWlsZFhDb25kaXRpb25zKHdpdGhWaWV3ZXJDb250ZXh0KGZpbHRlciksIG9yZ0lkLCBwYXJlbnRPcmdJZCk7XG4gKiB9XG4gKiBgYGBcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHdpdGhWaWV3ZXJDb250ZXh0PEYgZXh0ZW5kcyBWaWV3ZXJTY29wZWRGaWx0ZXI+KGZpbHRlcjogUGFydGlhbDxGPik6IFBhcnRpYWw8Rj4ge1xuICBjb25zdCBjdHggPSBnZXRUZW5hbnRDb250ZXh0KCk7XG4gIHJldHVybiB7XG4gICAgLi4uZmlsdGVyLFxuICAgIHZpZXdlclVzZXJJZDogZmlsdGVyLnZpZXdlclVzZXJJZCA/PyBjdHg/LnVzZXJJZCxcbiAgICB2aWV3ZXJJc1N1cGVyQWRtaW46IGZpbHRlci52aWV3ZXJJc1N1cGVyQWRtaW4gPz8gY3R4Py5pc1N1cGVyQWRtaW4gPz8gZmFsc2UsXG4gIH07XG59XG4iXX0=
|
|
@@ -0,0 +1,263 @@
|
|
|
1
|
+
import type { Visibility } 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
|
+
* visibility: '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
|
+
/** Caller's user id, matched against the entity's per-user column. */
|
|
23
|
+
readonly viewerUserId?: string;
|
|
24
|
+
/** Whether the caller is a platform super-admin (sees every rung). */
|
|
25
|
+
readonly viewerIsSuperAdmin?: boolean;
|
|
26
|
+
/**
|
|
27
|
+
* Organization identifier to filter entities by organization
|
|
28
|
+
* Can be a single org ID or array for multi-org filtering
|
|
29
|
+
*/
|
|
30
|
+
readonly orgId?: string | string[];
|
|
31
|
+
/**
|
|
32
|
+
* Narrow to one rung of the shared three-rung sharing ladder. Applied WITHIN
|
|
33
|
+
* what the caller can already see — never widens it.
|
|
34
|
+
* @see Visibility
|
|
35
|
+
*/
|
|
36
|
+
readonly visibility?: Visibility | string;
|
|
37
|
+
/**
|
|
38
|
+
* Filter by default status
|
|
39
|
+
* - true: Only default entities
|
|
40
|
+
* - false: Only non-default entities
|
|
41
|
+
* - undefined: All entities
|
|
42
|
+
*/
|
|
43
|
+
readonly isDefault?: boolean;
|
|
44
|
+
/**
|
|
45
|
+
* Filter by active/inactive status
|
|
46
|
+
* - true: Only active entities
|
|
47
|
+
* - false: Only inactive entities
|
|
48
|
+
* - undefined: All entities
|
|
49
|
+
*/
|
|
50
|
+
readonly isActive?: boolean;
|
|
51
|
+
/**
|
|
52
|
+
* Number of results to return
|
|
53
|
+
* @minimum 1
|
|
54
|
+
* @maximum 1000
|
|
55
|
+
*/
|
|
56
|
+
readonly limit?: number;
|
|
57
|
+
/**
|
|
58
|
+
* Number of results to skip (for pagination)
|
|
59
|
+
* @minimum 0
|
|
60
|
+
*/
|
|
61
|
+
readonly offset?: number;
|
|
62
|
+
/**
|
|
63
|
+
* Sort field and direction
|
|
64
|
+
* @example "name:asc", "createdAt:desc"
|
|
65
|
+
*/
|
|
66
|
+
readonly sort?: string;
|
|
67
|
+
/**
|
|
68
|
+
* Filter by catalog owner (developer-portal "my services" view).
|
|
69
|
+
* Matches the entity's `ownerId` exactly (a user id or team id).
|
|
70
|
+
* Only applied by builders for entities that carry an owner column
|
|
71
|
+
* (pipelines, plugins); ignored elsewhere.
|
|
72
|
+
*/
|
|
73
|
+
readonly ownerId?: string;
|
|
74
|
+
/**
|
|
75
|
+
* Filter by lifecycle stage (experimental | production | deprecated).
|
|
76
|
+
* Only applied by builders for entities that carry a lifecycle column.
|
|
77
|
+
*/
|
|
78
|
+
readonly lifecycle?: string;
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Filter interface for plugin-specific properties.
|
|
82
|
+
* Extends CommonFilter to include plugin-related filter options.
|
|
83
|
+
*
|
|
84
|
+
* @example
|
|
85
|
+
* ```typescript
|
|
86
|
+
* const filter: PluginFilter = {
|
|
87
|
+
* name: 'nodejs-build',
|
|
88
|
+
* version: '1.0.0',
|
|
89
|
+
* isActive: true
|
|
90
|
+
* };
|
|
91
|
+
* ```
|
|
92
|
+
*/
|
|
93
|
+
export interface PluginFilter extends CommonFilter {
|
|
94
|
+
/**
|
|
95
|
+
* Plugin name to filter by
|
|
96
|
+
*/
|
|
97
|
+
readonly name?: string;
|
|
98
|
+
/**
|
|
99
|
+
* Plugin version to filter by
|
|
100
|
+
* Supports semantic versioning
|
|
101
|
+
* @example "1.0.0", "^2.0.0", "~1.2.3"
|
|
102
|
+
*/
|
|
103
|
+
readonly version?: string;
|
|
104
|
+
/**
|
|
105
|
+
* Keyword to search within the keywords JSONB array (case-insensitive contains)
|
|
106
|
+
*/
|
|
107
|
+
readonly keyword?: string;
|
|
108
|
+
/**
|
|
109
|
+
* Plugin category to filter by
|
|
110
|
+
* @example "language", "security", "testing"
|
|
111
|
+
*/
|
|
112
|
+
readonly category?: string;
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* Filter interface for pipeline-specific properties.
|
|
116
|
+
* Extends CommonFilter to include pipeline-related filter options.
|
|
117
|
+
*
|
|
118
|
+
* @example
|
|
119
|
+
* ```typescript
|
|
120
|
+
* const filter: PipelineFilter = {
|
|
121
|
+
* project: 'my-app',
|
|
122
|
+
* organization: 'my-org',
|
|
123
|
+
* pipelineName: 'my-pipeline',
|
|
124
|
+
* isActive: true
|
|
125
|
+
* };
|
|
126
|
+
* ```
|
|
127
|
+
*/
|
|
128
|
+
export interface PipelineFilter extends CommonFilter {
|
|
129
|
+
/**
|
|
130
|
+
* Project name associated with the pipeline
|
|
131
|
+
*/
|
|
132
|
+
readonly project?: string;
|
|
133
|
+
/**
|
|
134
|
+
* Organization name associated with the pipeline
|
|
135
|
+
*/
|
|
136
|
+
readonly organization?: string;
|
|
137
|
+
/**
|
|
138
|
+
* Pipeline name to filter by
|
|
139
|
+
*/
|
|
140
|
+
readonly pipelineName?: string;
|
|
141
|
+
/**
|
|
142
|
+
* Keyword to search within the keywords JSONB array (case-insensitive contains)
|
|
143
|
+
*/
|
|
144
|
+
readonly keyword?: string;
|
|
145
|
+
}
|
|
146
|
+
/** Filter interface for pipeline-template queries (golden-path catalog). */
|
|
147
|
+
export interface PipelineTemplateFilter extends CommonFilter {
|
|
148
|
+
/** Template name (case-insensitive contains). */
|
|
149
|
+
readonly name?: string;
|
|
150
|
+
/** Category to filter by (e.g. 'language', 'general'). */
|
|
151
|
+
readonly category?: string;
|
|
152
|
+
/** Keyword search within the keywords JSONB array. */
|
|
153
|
+
readonly keyword?: string;
|
|
154
|
+
}
|
|
155
|
+
/**
|
|
156
|
+
* Filter interface for message-specific properties.
|
|
157
|
+
* Extends CommonFilter to include message-related filter options.
|
|
158
|
+
*/
|
|
159
|
+
export interface MessageFilter extends CommonFilter {
|
|
160
|
+
/**
|
|
161
|
+
* Thread ID to filter by (for fetching thread replies).
|
|
162
|
+
* Pass `null` to filter for root messages only (threadId IS NULL).
|
|
163
|
+
*/
|
|
164
|
+
readonly threadId?: string | null;
|
|
165
|
+
/**
|
|
166
|
+
* Recipient organization ID to filter by
|
|
167
|
+
* Use '*' for broadcast announcements
|
|
168
|
+
*/
|
|
169
|
+
readonly recipientOrgId?: string;
|
|
170
|
+
/**
|
|
171
|
+
* Recipient user ID to filter by (per-user targeting within the recipient
|
|
172
|
+
* org). Pass `null` to match org-wide messages only (recipient_user_id IS
|
|
173
|
+
* NULL). Rarely set directly by callers — see `viewerUserId` for the
|
|
174
|
+
* visibility-scoping variant.
|
|
175
|
+
*/
|
|
176
|
+
readonly recipientUserId?: string | null;
|
|
177
|
+
/**
|
|
178
|
+
* Message type filter
|
|
179
|
+
*/
|
|
180
|
+
readonly messageType?: 'announcement' | 'conversation';
|
|
181
|
+
/**
|
|
182
|
+
* Filter by priority level
|
|
183
|
+
*/
|
|
184
|
+
readonly priority?: 'normal' | 'high' | 'urgent';
|
|
185
|
+
/**
|
|
186
|
+
* Channel/inbox-bucket filter (e.g. 'support', 'help'). Matches rows
|
|
187
|
+
* exactly; pass null to match channel IS NULL (org-to-org messages).
|
|
188
|
+
*/
|
|
189
|
+
readonly channel?: string | null;
|
|
190
|
+
/**
|
|
191
|
+
* Filter by read state for the requesting org.
|
|
192
|
+
* Implemented as a JSONB key-existence check against `messages.read_by`
|
|
193
|
+
* (a `{ [orgId]: isoTimestamp }` map), using the orgId passed to
|
|
194
|
+
* `buildMessageConditions`.
|
|
195
|
+
* - true → only messages the org has read (orgId key exists in read_by)
|
|
196
|
+
* - false → only messages the org has NOT read
|
|
197
|
+
* - undefined → no read-state filter
|
|
198
|
+
*/
|
|
199
|
+
readonly isRead?: boolean;
|
|
200
|
+
/**
|
|
201
|
+
* Free-text inbox search. Case-insensitive substring match against the
|
|
202
|
+
* message `subject` OR `content` (LIKE wildcards in the term are escaped, so a
|
|
203
|
+
* literal `%`/`_` matches itself). Applied on top of the visibility scope, so
|
|
204
|
+
* it never widens what the caller can see.
|
|
205
|
+
*/
|
|
206
|
+
readonly search?: string;
|
|
207
|
+
}
|
|
208
|
+
/**
|
|
209
|
+
* Filter for compliance policies.
|
|
210
|
+
*/
|
|
211
|
+
export interface CompliancePolicyFilter extends CommonFilter {
|
|
212
|
+
readonly name?: string;
|
|
213
|
+
readonly isTemplate?: boolean;
|
|
214
|
+
}
|
|
215
|
+
/**
|
|
216
|
+
* Filter for compliance rules.
|
|
217
|
+
*/
|
|
218
|
+
export interface ComplianceRuleFilter extends CommonFilter {
|
|
219
|
+
readonly name?: string;
|
|
220
|
+
readonly policyId?: string;
|
|
221
|
+
readonly target?: 'plugin' | 'pipeline';
|
|
222
|
+
readonly field?: string;
|
|
223
|
+
readonly severity?: 'warning' | 'error' | 'critical';
|
|
224
|
+
readonly scope?: 'org' | 'published';
|
|
225
|
+
readonly tag?: string;
|
|
226
|
+
}
|
|
227
|
+
/**
|
|
228
|
+
* Filter for compliance exemptions.
|
|
229
|
+
*/
|
|
230
|
+
export interface ComplianceExemptionFilter {
|
|
231
|
+
readonly orgId?: string;
|
|
232
|
+
readonly ruleId?: string;
|
|
233
|
+
readonly entityType?: 'plugin' | 'pipeline';
|
|
234
|
+
readonly entityId?: string;
|
|
235
|
+
readonly status?: 'pending' | 'approved' | 'rejected' | 'expired';
|
|
236
|
+
readonly limit?: number;
|
|
237
|
+
readonly offset?: number;
|
|
238
|
+
}
|
|
239
|
+
/**
|
|
240
|
+
* Filter for compliance audit log entries.
|
|
241
|
+
*/
|
|
242
|
+
export interface ComplianceAuditFilter {
|
|
243
|
+
readonly orgId?: string;
|
|
244
|
+
readonly target?: 'plugin' | 'pipeline';
|
|
245
|
+
readonly action?: string;
|
|
246
|
+
readonly result?: 'pass' | 'warn' | 'block';
|
|
247
|
+
readonly scanId?: string;
|
|
248
|
+
readonly dateFrom?: string;
|
|
249
|
+
readonly dateTo?: string;
|
|
250
|
+
readonly limit?: number;
|
|
251
|
+
readonly offset?: number;
|
|
252
|
+
}
|
|
253
|
+
/**
|
|
254
|
+
* Filter for compliance scans.
|
|
255
|
+
*/
|
|
256
|
+
export interface ComplianceScanFilter {
|
|
257
|
+
readonly orgId?: string;
|
|
258
|
+
readonly target?: 'plugin' | 'pipeline' | 'all';
|
|
259
|
+
readonly status?: 'pending' | 'running' | 'completed' | 'failed' | 'cancelled';
|
|
260
|
+
readonly triggeredBy?: 'manual' | 'scheduled' | 'rule-change' | 'rule-dry-run';
|
|
261
|
+
readonly limit?: number;
|
|
262
|
+
readonly offset?: number;
|
|
263
|
+
}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
// Copyright 2026 Pipeline Builder Contributors
|
|
2
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
3
|
+
export {};
|
|
4
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicXVlcnktZmlsdGVycy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9jb3JlL3F1ZXJ5LWZpbHRlcnMudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsK0NBQStDO0FBQy9DLHNDQUFzQyIsInNvdXJjZXNDb250ZW50IjpbIi8vIENvcHlyaWdodCAyMDI2IFBpcGVsaW5lIEJ1aWxkZXIgQ29udHJpYnV0b3JzXG4vLyBTUERYLUxpY2Vuc2UtSWRlbnRpZmllcjogQXBhY2hlLTIuMFxuXG5pbXBvcnQgdHlwZSB7IFZpc2liaWxpdHkgfSBmcm9tICdAcGlwZWxpbmUtYnVpbGRlci9hcGktY29yZSc7XG5cbi8qKlxuICogQmFzZSBmaWx0ZXIgaW50ZXJmYWNlIGNvbnRhaW5pbmcgY29tbW9uIGZpbHRlciBwcm9wZXJ0aWVzIHNoYXJlZCBhY3Jvc3MgYWxsIGVudGl0eSB0eXBlcy5cbiAqXG4gKiBAZXhhbXBsZVxuICogYGBgdHlwZXNjcmlwdFxuICogY29uc3QgZmlsdGVyOiBDb21tb25GaWx0ZXIgPSB7XG4gKiAgIGlkOiAnMTIzJyxcbiAqICAgb3JnSWQ6ICdteS1vcmcnLFxuICogICB2aXNpYmlsaXR5OiAncHVibGljJyxcbiAqICAgaXNEZWZhdWx0OiB0cnVlLFxuICogICBpc0FjdGl2ZTogdHJ1ZVxuICogfTtcbiAqIGBgYFxuICovXG5leHBvcnQgaW50ZXJmYWNlIENvbW1vbkZpbHRlciB7XG4gIC8qKlxuICAgKiBVbmlxdWUgaWRlbnRpZmllciBmb3IgdGhlIGVudGl0eVxuICAgKiBDYW4gYmUgYSBzaW5nbGUgSUQgb3IgYXJyYXkgb2YgSURzIGZvciBiYXRjaCBmaWx0ZXJpbmdcbiAgICovXG4gIHJlYWRvbmx5IGlkPzogc3RyaW5nIHwgc3RyaW5nW107XG5cbiAgLy8gLS0tIFZpZXdlciBjb250ZXh0IChzZXJ2ZXItc2V0LCBORVZFUiBjbGllbnQtc3VwcGxpZWQpIC0tLS0tLS0tLS0tLS0tLS0tLS0tLVxuICAvLyBPbmx5IGVudGl0aWVzIHdob3NlIHZpc2liaWxpdHkgcHJlZGljYXRlIGhhcyBhIFBFUi1VU0VSIHJ1bmcgcmVhZCB0aGVzZSDigJRcbiAgLy8gcGlwZWxpbmUgdGVtcGxhdGVzIChgcHJpdmF0ZWAgaXMgYXV0aG9yLW9ubHkpIGFuZCBtZXNzYWdlcyAoYSBwZXItdXNlclxuICAvLyB0YXJnZXRlZCByb3cgaXMgdmlzaWJsZSBvbmx5IHRvIGl0cyB0YXJnZXQpLiBUaGVpciBzZXJ2aWNlcyBzdGFtcCB0aGVtIGZyb21cbiAgLy8gdGhlIHJlcXVlc3QncyBgVGVuYW50Q29udGV4dGAgdmlhIGB3aXRoVmlld2VyQ29udGV4dGAsIHNvIG5vIHJvdXRlIG9yIHF1ZXJ5XG4gIC8vIHN0cmluZyBjYW4gaW5qZWN0IHRoZW0uIEV2ZXJ5dGhpbmcgZWxzZSBpZ25vcmVzIHRoZW0uXG4gIC8vXG4gIC8vIEJvdGggZmFpbCBDTE9TRUQgd2hlbiBhYnNlbnQ6IG5vIHZpZXdlciBtZWFucyB0aGUgcGVyLXVzZXIgcnVuZyBtYXRjaGVzXG4gIC8vIE5PVEhJTkcsIG5ldmVyIGV2ZXJ5dGhpbmcuXG5cbiAgLyoqIENhbGxlcidzIHVzZXIgaWQsIG1hdGNoZWQgYWdhaW5zdCB0aGUgZW50aXR5J3MgcGVyLXVzZXIgY29sdW1uLiAqL1xuICByZWFkb25seSB2aWV3ZXJVc2VySWQ/OiBzdHJpbmc7XG4gIC8qKiBXaGV0aGVyIHRoZSBjYWxsZXIgaXMgYSBwbGF0Zm9ybSBzdXBlci1hZG1pbiAoc2VlcyBldmVyeSBydW5nKS4gKi9cbiAgcmVhZG9ubHkgdmlld2VySXNTdXBlckFkbWluPzogYm9vbGVhbjtcblxuICAvKipcbiAgICogT3JnYW5pemF0aW9uIGlkZW50aWZpZXIgdG8gZmlsdGVyIGVudGl0aWVzIGJ5IG9yZ2FuaXphdGlvblxuICAgKiBDYW4gYmUgYSBzaW5nbGUgb3JnIElEIG9yIGFycmF5IGZvciBtdWx0aS1vcmcgZmlsdGVyaW5nXG4gICAqL1xuICByZWFkb25seSBvcmdJZD86IHN0cmluZyB8IHN0cmluZ1tdO1xuXG4gIC8qKlxuICAgKiBOYXJyb3cgdG8gb25lIHJ1bmcgb2YgdGhlIHNoYXJlZCB0aHJlZS1ydW5nIHNoYXJpbmcgbGFkZGVyLiBBcHBsaWVkIFdJVEhJTlxuICAgKiB3aGF0IHRoZSBjYWxsZXIgY2FuIGFscmVhZHkgc2VlIOKAlCBuZXZlciB3aWRlbnMgaXQuXG4gICAqIEBzZWUgVmlzaWJpbGl0eVxuICAgKi9cbiAgcmVhZG9ubHkgdmlzaWJpbGl0eT86IFZpc2liaWxpdHkgfCBzdHJpbmc7XG5cbiAgLyoqXG4gICAqIEZpbHRlciBieSBkZWZhdWx0IHN0YXR1c1xuICAgKiAtIHRydWU6IE9ubHkgZGVmYXVsdCBlbnRpdGllc1xuICAgKiAtIGZhbHNlOiBPbmx5IG5vbi1kZWZhdWx0IGVudGl0aWVzXG4gICAqIC0gdW5kZWZpbmVkOiBBbGwgZW50aXRpZXNcbiAgICovXG4gIHJlYWRvbmx5IGlzRGVmYXVsdD86IGJvb2xlYW47XG5cbiAgLyoqXG4gICAqIEZpbHRlciBieSBhY3RpdmUvaW5hY3RpdmUgc3RhdHVzXG4gICAqIC0gdHJ1ZTogT25seSBhY3RpdmUgZW50aXRpZXNcbiAgICogLSBmYWxzZTogT25seSBpbmFjdGl2ZSBlbnRpdGllc1xuICAgKiAtIHVuZGVmaW5lZDogQWxsIGVudGl0aWVzXG4gICAqL1xuICByZWFkb25seSBpc0FjdGl2ZT86IGJvb2xlYW47XG5cbiAgLyoqXG4gICAqIE51bWJlciBvZiByZXN1bHRzIHRvIHJldHVyblxuICAgKiBAbWluaW11bSAxXG4gICAqIEBtYXhpbXVtIDEwMDBcbiAgICovXG4gIHJlYWRvbmx5IGxpbWl0PzogbnVtYmVyO1xuXG4gIC8qKlxuICAgKiBOdW1iZXIgb2YgcmVzdWx0cyB0byBza2lwIChmb3IgcGFnaW5hdGlvbilcbiAgICogQG1pbmltdW0gMFxuICAgKi9cbiAgcmVhZG9ubHkgb2Zmc2V0PzogbnVtYmVyO1xuXG4gIC8qKlxuICAgKiBTb3J0IGZpZWxkIGFuZCBkaXJlY3Rpb25cbiAgICogQGV4YW1wbGUgXCJuYW1lOmFzY1wiLCBcImNyZWF0ZWRBdDpkZXNjXCJcbiAgICovXG4gIHJlYWRvbmx5IHNvcnQ/OiBzdHJpbmc7XG5cbiAgLyoqXG4gICAqIEZpbHRlciBieSBjYXRhbG9nIG93bmVyIChkZXZlbG9wZXItcG9ydGFsIFwibXkgc2VydmljZXNcIiB2aWV3KS5cbiAgICogTWF0Y2hlcyB0aGUgZW50aXR5J3MgYG93bmVySWRgIGV4YWN0bHkgKGEgdXNlciBpZCBvciB0ZWFtIGlkKS5cbiAgICogT25seSBhcHBsaWVkIGJ5IGJ1aWxkZXJzIGZvciBlbnRpdGllcyB0aGF0IGNhcnJ5IGFuIG93bmVyIGNvbHVtblxuICAgKiAocGlwZWxpbmVzLCBwbHVnaW5zKTsgaWdub3JlZCBlbHNld2hlcmUuXG4gICAqL1xuICByZWFkb25seSBvd25lcklkPzogc3RyaW5nO1xuXG4gIC8qKlxuICAgKiBGaWx0ZXIgYnkgbGlmZWN5Y2xlIHN0YWdlIChleHBlcmltZW50YWwgfCBwcm9kdWN0aW9uIHwgZGVwcmVjYXRlZCkuXG4gICAqIE9ubHkgYXBwbGllZCBieSBidWlsZGVycyBmb3IgZW50aXRpZXMgdGhhdCBjYXJyeSBhIGxpZmVjeWNsZSBjb2x1bW4uXG4gICAqL1xuICByZWFkb25seSBsaWZlY3ljbGU/OiBzdHJpbmc7XG59XG5cbi8qKlxuICogRmlsdGVyIGludGVyZmFjZSBmb3IgcGx1Z2luLXNwZWNpZmljIHByb3BlcnRpZXMuXG4gKiBFeHRlbmRzIENvbW1vbkZpbHRlciB0byBpbmNsdWRlIHBsdWdpbi1yZWxhdGVkIGZpbHRlciBvcHRpb25zLlxuICpcbiAqIEBleGFtcGxlXG4gKiBgYGB0eXBlc2NyaXB0XG4gKiBjb25zdCBmaWx0ZXI6IFBsdWdpbkZpbHRlciA9IHtcbiAqICAgbmFtZTogJ25vZGVqcy1idWlsZCcsXG4gKiAgIHZlcnNpb246ICcxLjAuMCcsXG4gKiAgIGlzQWN0aXZlOiB0cnVlXG4gKiB9O1xuICogYGBgXG4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgUGx1Z2luRmlsdGVyIGV4dGVuZHMgQ29tbW9uRmlsdGVyIHtcbiAgLyoqXG4gICAqIFBsdWdpbiBuYW1lIHRvIGZpbHRlciBieVxuICAgKi9cbiAgcmVhZG9ubHkgbmFtZT86IHN0cmluZztcblxuICAvKipcbiAgICogUGx1Z2luIHZlcnNpb24gdG8gZmlsdGVyIGJ5XG4gICAqIFN1cHBvcnRzIHNlbWFudGljIHZlcnNpb25pbmdcbiAgICogQGV4YW1wbGUgXCIxLjAuMFwiLCBcIl4yLjAuMFwiLCBcIn4xLjIuM1wiXG4gICAqL1xuICByZWFkb25seSB2ZXJzaW9uPzogc3RyaW5nO1xuXG4gIC8qKlxuICAgKiBLZXl3b3JkIHRvIHNlYXJjaCB3aXRoaW4gdGhlIGtleXdvcmRzIEpTT05CIGFycmF5IChjYXNlLWluc2Vuc2l0aXZlIGNvbnRhaW5zKVxuICAgKi9cbiAgcmVhZG9ubHkga2V5d29yZD86IHN0cmluZztcblxuICAvKipcbiAgICogUGx1Z2luIGNhdGVnb3J5IHRvIGZpbHRlciBieVxuICAgKiBAZXhhbXBsZSBcImxhbmd1YWdlXCIsIFwic2VjdXJpdHlcIiwgXCJ0ZXN0aW5nXCJcbiAgICovXG4gIHJlYWRvbmx5IGNhdGVnb3J5Pzogc3RyaW5nO1xufVxuXG4vKipcbiAqIEZpbHRlciBpbnRlcmZhY2UgZm9yIHBpcGVsaW5lLXNwZWNpZmljIHByb3BlcnRpZXMuXG4gKiBFeHRlbmRzIENvbW1vbkZpbHRlciB0byBpbmNsdWRlIHBpcGVsaW5lLXJlbGF0ZWQgZmlsdGVyIG9wdGlvbnMuXG4gKlxuICogQGV4YW1wbGVcbiAqIGBgYHR5cGVzY3JpcHRcbiAqIGNvbnN0IGZpbHRlcjogUGlwZWxpbmVGaWx0ZXIgPSB7XG4gKiAgIHByb2plY3Q6ICdteS1hcHAnLFxuICogICBvcmdhbml6YXRpb246ICdteS1vcmcnLFxuICogICBwaXBlbGluZU5hbWU6ICdteS1waXBlbGluZScsXG4gKiAgIGlzQWN0aXZlOiB0cnVlXG4gKiB9O1xuICogYGBgXG4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgUGlwZWxpbmVGaWx0ZXIgZXh0ZW5kcyBDb21tb25GaWx0ZXIge1xuICAvKipcbiAgICogUHJvamVjdCBuYW1lIGFzc29jaWF0ZWQgd2l0aCB0aGUgcGlwZWxpbmVcbiAgICovXG4gIHJlYWRvbmx5IHByb2plY3Q/OiBzdHJpbmc7XG5cbiAgLyoqXG4gICAqIE9yZ2FuaXphdGlvbiBuYW1lIGFzc29jaWF0ZWQgd2l0aCB0aGUgcGlwZWxpbmVcbiAgICovXG4gIHJlYWRvbmx5IG9yZ2FuaXphdGlvbj86IHN0cmluZztcblxuICAvKipcbiAgICogUGlwZWxpbmUgbmFtZSB0byBmaWx0ZXIgYnlcbiAgICovXG4gIHJlYWRvbmx5IHBpcGVsaW5lTmFtZT86IHN0cmluZztcblxuICAvKipcbiAgICogS2V5d29yZCB0byBzZWFyY2ggd2l0aGluIHRoZSBrZXl3b3JkcyBKU09OQiBhcnJheSAoY2FzZS1pbnNlbnNpdGl2ZSBjb250YWlucylcbiAgICovXG4gIHJlYWRvbmx5IGtleXdvcmQ/OiBzdHJpbmc7XG59XG5cbi8qKiBGaWx0ZXIgaW50ZXJmYWNlIGZvciBwaXBlbGluZS10ZW1wbGF0ZSBxdWVyaWVzIChnb2xkZW4tcGF0aCBjYXRhbG9nKS4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgUGlwZWxpbmVUZW1wbGF0ZUZpbHRlciBleHRlbmRzIENvbW1vbkZpbHRlciB7XG4gIC8qKiBUZW1wbGF0ZSBuYW1lIChjYXNlLWluc2Vuc2l0aXZlIGNvbnRhaW5zKS4gKi9cbiAgcmVhZG9ubHkgbmFtZT86IHN0cmluZztcbiAgLyoqIENhdGVnb3J5IHRvIGZpbHRlciBieSAoZS5nLiAnbGFuZ3VhZ2UnLCAnZ2VuZXJhbCcpLiAqL1xuICByZWFkb25seSBjYXRlZ29yeT86IHN0cmluZztcbiAgLyoqIEtleXdvcmQgc2VhcmNoIHdpdGhpbiB0aGUga2V5d29yZHMgSlNPTkIgYXJyYXkuICovXG4gIHJlYWRvbmx5IGtleXdvcmQ/OiBzdHJpbmc7XG4gIC8vIFNoYXJpbmcgcnVuZyArIHZpZXdlciBjb250ZXh0IGFyZSBpbmhlcml0ZWQgZnJvbSBDb21tb25GaWx0ZXIuXG59XG5cbi8qKlxuICogRmlsdGVyIGludGVyZmFjZSBmb3IgbWVzc2FnZS1zcGVjaWZpYyBwcm9wZXJ0aWVzLlxuICogRXh0ZW5kcyBDb21tb25GaWx0ZXIgdG8gaW5jbHVkZSBtZXNzYWdlLXJlbGF0ZWQgZmlsdGVyIG9wdGlvbnMuXG4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgTWVzc2FnZUZpbHRlciBleHRlbmRzIENvbW1vbkZpbHRlciB7XG4gIC8qKlxuICAgKiBUaHJlYWQgSUQgdG8gZmlsdGVyIGJ5IChmb3IgZmV0Y2hpbmcgdGhyZWFkIHJlcGxpZXMpLlxuICAgKiBQYXNzIGBudWxsYCB0byBmaWx0ZXIgZm9yIHJvb3QgbWVzc2FnZXMgb25seSAodGhyZWFkSWQgSVMgTlVMTCkuXG4gICAqL1xuICByZWFkb25seSB0aHJlYWRJZD86IHN0cmluZyB8IG51bGw7XG5cbiAgLyoqXG4gICAqIFJlY2lwaWVudCBvcmdhbml6YXRpb24gSUQgdG8gZmlsdGVyIGJ5XG4gICAqIFVzZSAnKicgZm9yIGJyb2FkY2FzdCBhbm5vdW5jZW1lbnRzXG4gICAqL1xuICByZWFkb25seSByZWNpcGllbnRPcmdJZD86IHN0cmluZztcblxuICAvKipcbiAgICogUmVjaXBpZW50IHVzZXIgSUQgdG8gZmlsdGVyIGJ5IChwZXItdXNlciB0YXJnZXRpbmcgd2l0aGluIHRoZSByZWNpcGllbnRcbiAgICogb3JnKS4gUGFzcyBgbnVsbGAgdG8gbWF0Y2ggb3JnLXdpZGUgbWVzc2FnZXMgb25seSAocmVjaXBpZW50X3VzZXJfaWQgSVNcbiAgICogTlVMTCkuIFJhcmVseSBzZXQgZGlyZWN0bHkgYnkgY2FsbGVycyDigJQgc2VlIGB2aWV3ZXJVc2VySWRgIGZvciB0aGVcbiAgICogdmlzaWJpbGl0eS1zY29waW5nIHZhcmlhbnQuXG4gICAqL1xuICByZWFkb25seSByZWNpcGllbnRVc2VySWQ/OiBzdHJpbmcgfCBudWxsO1xuXG4gIC8vIE5PVEU6IHRoZSBWSUVXRVIncyB1c2VyIGlkIChgdmlld2VyVXNlcklkYCkgaXMgaW5oZXJpdGVkIGZyb20gQ29tbW9uRmlsdGVyLlxuICAvLyBGb3IgbWVzc2FnZXMgaXQgaXMgTk9UIGEgY29sdW1uIGZpbHRlcjogd2hlbiBwcmVzZW50LCB0aGUgcmVjaXBpZW50LXNpZGVcbiAgLy8gYnJhbmNoIGluIGBidWlsZE1lc3NhZ2VDb25kaXRpb25zYCB3aWRlbnMgdG8gaW5jbHVkZSByb3dzIHRhcmdldGVkIGF0IHRoaXNcbiAgLy8gdXNlciAocmVjaXBpZW50X3VzZXJfaWQgPSB2aWV3ZXJVc2VySWQpIEFMT05HU0lERSBvcmctd2lkZSBvbmVzXG4gIC8vIChyZWNpcGllbnRfdXNlcl9pZCBJUyBOVUxMKS4gV2hlbiBhYnNlbnQsIG9ubHkgb3JnLXdpZGUgcmVjaXBpZW50IHJvd3MgYXJlXG4gIC8vIHZpc2libGUsIHNvIGEgdXNlci10YXJnZXRlZCBtZXNzYWdlIHN0YXlzIHByaXZhdGUgdG8gaXRzIHRhcmdldCwgdGhlIHNlbmRlcixcbiAgLy8gYW5kIHRoZSBzeXN0ZW0gb3JnLiBNZXNzYWdlU2VydmljZSBzdGFtcHMgaXQgZnJvbSB0aGUgdGVuYW50IGNvbnRleHQuXG5cbiAgLyoqXG4gICAqIE1lc3NhZ2UgdHlwZSBmaWx0ZXJcbiAgICovXG4gIHJlYWRvbmx5IG1lc3NhZ2VUeXBlPzogJ2Fubm91bmNlbWVudCcgfCAnY29udmVyc2F0aW9uJztcblxuICAvKipcbiAgICogRmlsdGVyIGJ5IHByaW9yaXR5IGxldmVsXG4gICAqL1xuICByZWFkb25seSBwcmlvcml0eT86ICdub3JtYWwnIHwgJ2hpZ2gnIHwgJ3VyZ2VudCc7XG5cbiAgLyoqXG4gICAqIENoYW5uZWwvaW5ib3gtYnVja2V0IGZpbHRlciAoZS5nLiAnc3VwcG9ydCcsICdoZWxwJykuIE1hdGNoZXMgcm93c1xuICAgKiBleGFjdGx5OyBwYXNzIG51bGwgdG8gbWF0Y2ggY2hhbm5lbCBJUyBOVUxMIChvcmctdG8tb3JnIG1lc3NhZ2VzKS5cbiAgICovXG4gIHJlYWRvbmx5IGNoYW5uZWw/OiBzdHJpbmcgfCBudWxsO1xuXG4gIC8qKlxuICAgKiBGaWx0ZXIgYnkgcmVhZCBzdGF0ZSBmb3IgdGhlIHJlcXVlc3Rpbmcgb3JnLlxuICAgKiBJbXBsZW1lbnRlZCBhcyBhIEpTT05CIGtleS1leGlzdGVuY2UgY2hlY2sgYWdhaW5zdCBgbWVzc2FnZXMucmVhZF9ieWBcbiAgICogKGEgYHsgW29yZ0lkXTogaXNvVGltZXN0YW1wIH1gIG1hcCksIHVzaW5nIHRoZSBvcmdJZCBwYXNzZWQgdG9cbiAgICogYGJ1aWxkTWVzc2FnZUNvbmRpdGlvbnNgLlxuICAgKiAtIHRydWUgIOKGkiBvbmx5IG1lc3NhZ2VzIHRoZSBvcmcgaGFzIHJlYWQgKG9yZ0lkIGtleSBleGlzdHMgaW4gcmVhZF9ieSlcbiAgICogLSBmYWxzZSDihpIgb25seSBtZXNzYWdlcyB0aGUgb3JnIGhhcyBOT1QgcmVhZFxuICAgKiAtIHVuZGVmaW5lZCDihpIgbm8gcmVhZC1zdGF0ZSBmaWx0ZXJcbiAgICovXG4gIHJlYWRvbmx5IGlzUmVhZD86IGJvb2xlYW47XG5cbiAgLyoqXG4gICAqIEZyZWUtdGV4dCBpbmJveCBzZWFyY2guIENhc2UtaW5zZW5zaXRpdmUgc3Vic3RyaW5nIG1hdGNoIGFnYWluc3QgdGhlXG4gICAqIG1lc3NhZ2UgYHN1YmplY3RgIE9SIGBjb250ZW50YCAoTElLRSB3aWxkY2FyZHMgaW4gdGhlIHRlcm0gYXJlIGVzY2FwZWQsIHNvIGFcbiAgICogbGl0ZXJhbCBgJWAvYF9gIG1hdGNoZXMgaXRzZWxmKS4gQXBwbGllZCBvbiB0b3Agb2YgdGhlIHZpc2liaWxpdHkgc2NvcGUsIHNvXG4gICAqIGl0IG5ldmVyIHdpZGVucyB3aGF0IHRoZSBjYWxsZXIgY2FuIHNlZS5cbiAgICovXG4gIHJlYWRvbmx5IHNlYXJjaD86IHN0cmluZztcbn1cblxuLy8gPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PVxuLy8gQ29tcGxpYW5jZSBGaWx0ZXJzXG4vLyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09XG5cbi8qKlxuICogRmlsdGVyIGZvciBjb21wbGlhbmNlIHBvbGljaWVzLlxuICovXG5leHBvcnQgaW50ZXJmYWNlIENvbXBsaWFuY2VQb2xpY3lGaWx0ZXIgZXh0ZW5kcyBDb21tb25GaWx0ZXIge1xuICByZWFkb25seSBuYW1lPzogc3RyaW5nO1xuICByZWFkb25seSBpc1RlbXBsYXRlPzogYm9vbGVhbjtcbn1cblxuLyoqXG4gKiBGaWx0ZXIgZm9yIGNvbXBsaWFuY2UgcnVsZXMuXG4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgQ29tcGxpYW5jZVJ1bGVGaWx0ZXIgZXh0ZW5kcyBDb21tb25GaWx0ZXIge1xuICByZWFkb25seSBuYW1lPzogc3RyaW5nO1xuICByZWFkb25seSBwb2xpY3lJZD86IHN0cmluZztcbiAgcmVhZG9ubHkgdGFyZ2V0PzogJ3BsdWdpbicgfCAncGlwZWxpbmUnO1xuICByZWFkb25seSBmaWVsZD86IHN0cmluZztcbiAgcmVhZG9ubHkgc2V2ZXJpdHk/OiAnd2FybmluZycgfCAnZXJyb3InIHwgJ2NyaXRpY2FsJztcbiAgcmVhZG9ubHkgc2NvcGU/OiAnb3JnJyB8ICdwdWJsaXNoZWQnO1xuICByZWFkb25seSB0YWc/OiBzdHJpbmc7XG59XG5cbi8qKlxuICogRmlsdGVyIGZvciBjb21wbGlhbmNlIGV4ZW1wdGlvbnMuXG4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgQ29tcGxpYW5jZUV4ZW1wdGlvbkZpbHRlciB7XG4gIHJlYWRvbmx5IG9yZ0lkPzogc3RyaW5nO1xuICByZWFkb25seSBydWxlSWQ/OiBzdHJpbmc7XG4gIHJlYWRvbmx5IGVudGl0eVR5cGU/OiAncGx1Z2luJyB8ICdwaXBlbGluZSc7XG4gIHJlYWRvbmx5IGVudGl0eUlkPzogc3RyaW5nO1xuICByZWFkb25seSBzdGF0dXM/OiAncGVuZGluZycgfCAnYXBwcm92ZWQnIHwgJ3JlamVjdGVkJyB8ICdleHBpcmVkJztcbiAgcmVhZG9ubHkgbGltaXQ/OiBudW1iZXI7XG4gIHJlYWRvbmx5IG9mZnNldD86IG51bWJlcjtcbn1cblxuLyoqXG4gKiBGaWx0ZXIgZm9yIGNvbXBsaWFuY2UgYXVkaXQgbG9nIGVudHJpZXMuXG4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgQ29tcGxpYW5jZUF1ZGl0RmlsdGVyIHtcbiAgcmVhZG9ubHkgb3JnSWQ/OiBzdHJpbmc7XG4gIHJlYWRvbmx5IHRhcmdldD86ICdwbHVnaW4nIHwgJ3BpcGVsaW5lJztcbiAgcmVhZG9ubHkgYWN0aW9uPzogc3RyaW5nO1xuICByZWFkb25seSByZXN1bHQ/OiAncGFzcycgfCAnd2FybicgfCAnYmxvY2snO1xuICByZWFkb25seSBzY2FuSWQ/OiBzdHJpbmc7XG4gIHJlYWRvbmx5IGRhdGVGcm9tPzogc3RyaW5nO1xuICByZWFkb25seSBkYXRlVG8/OiBzdHJpbmc7XG4gIHJlYWRvbmx5IGxpbWl0PzogbnVtYmVyO1xuICByZWFkb25seSBvZmZzZXQ/OiBudW1iZXI7XG59XG5cbi8qKlxuICogRmlsdGVyIGZvciBjb21wbGlhbmNlIHNjYW5zLlxuICovXG5leHBvcnQgaW50ZXJmYWNlIENvbXBsaWFuY2VTY2FuRmlsdGVyIHtcbiAgcmVhZG9ubHkgb3JnSWQ/OiBzdHJpbmc7XG4gIHJlYWRvbmx5IHRhcmdldD86ICdwbHVnaW4nIHwgJ3BpcGVsaW5lJyB8ICdhbGwnO1xuICByZWFkb25seSBzdGF0dXM/OiAncGVuZGluZycgfCAncnVubmluZycgfCAnY29tcGxldGVkJyB8ICdmYWlsZWQnIHwgJ2NhbmNlbGxlZCc7XG4gIHJlYWRvbmx5IHRyaWdnZXJlZEJ5PzogJ21hbnVhbCcgfCAnc2NoZWR1bGVkJyB8ICdydWxlLWNoYW5nZScgfCAncnVsZS1kcnktcnVuJztcbiAgcmVhZG9ubHkgbGltaXQ/OiBudW1iZXI7XG4gIHJlYWRvbmx5IG9mZnNldD86IG51bWJlcjtcbn1cbiJdfQ==
|