@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.
Files changed (48) hide show
  1. package/LICENSE +202 -0
  2. package/README.md +61 -0
  3. package/drizzle.config.ts +17 -0
  4. package/lib/api/access-control-builder.d.ts +148 -0
  5. package/lib/api/access-control-builder.js +199 -0
  6. package/lib/api/crud-service.d.ts +343 -0
  7. package/lib/api/crud-service.js +849 -0
  8. package/lib/api/query-builders.d.ts +82 -0
  9. package/lib/api/query-builders.js +460 -0
  10. package/lib/api/reporting-service.d.ts +685 -0
  11. package/lib/api/reporting-service.js +1564 -0
  12. package/lib/api/soft-delete-sweep.d.ts +65 -0
  13. package/lib/api/soft-delete-sweep.js +124 -0
  14. package/lib/api/viewer-context.d.ts +29 -0
  15. package/lib/api/viewer-context.js +63 -0
  16. package/lib/core/query-filters.d.ts +263 -0
  17. package/lib/core/query-filters.js +4 -0
  18. package/lib/database/drizzle-schema.d.ts +7357 -0
  19. package/lib/database/drizzle-schema.js +66 -0
  20. package/lib/database/index.d.ts +5 -0
  21. package/lib/database/index.js +8 -0
  22. package/lib/database/migrator.d.ts +20 -0
  23. package/lib/database/migrator.js +80 -0
  24. package/lib/database/postgres-connection.d.ts +201 -0
  25. package/lib/database/postgres-connection.js +413 -0
  26. package/lib/database/retry-strategy.d.ts +68 -0
  27. package/lib/database/retry-strategy.js +122 -0
  28. package/lib/database/schema/alert.d.ts +588 -0
  29. package/lib/database/schema/alert.js +130 -0
  30. package/lib/database/schema/compliance.d.ts +3319 -0
  31. package/lib/database/schema/compliance.js +377 -0
  32. package/lib/database/schema/dashboard.d.ts +474 -0
  33. package/lib/database/schema/dashboard.js +129 -0
  34. package/lib/database/schema/message-attachment.d.ts +183 -0
  35. package/lib/database/schema/message-attachment.js +40 -0
  36. package/lib/database/schema/message.d.ts +411 -0
  37. package/lib/database/schema/message.js +114 -0
  38. package/lib/database/schema/pipeline-template.d.ts +466 -0
  39. package/lib/database/schema/pipeline-template.js +80 -0
  40. package/lib/database/schema/pipeline.d.ts +1613 -0
  41. package/lib/database/schema/pipeline.js +332 -0
  42. package/lib/database/schema/plugin.d.ts +749 -0
  43. package/lib/database/schema/plugin.js +166 -0
  44. package/lib/database/tenancy.d.ts +103 -0
  45. package/lib/database/tenancy.js +167 -0
  46. package/lib/index.d.ts +32 -0
  47. package/lib/index.js +38 -0
  48. 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,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic29mdC1kZWxldGUtc3dlZXAuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvYXBpL3NvZnQtZGVsZXRlLXN3ZWVwLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLCtDQUErQztBQUMvQyxzQ0FBc0M7QUFFdEM7Ozs7Ozs7Ozs7Ozs7Ozs7R0FnQkc7QUFFSCxPQUFPLEVBQUUsWUFBWSxFQUFFLGVBQWUsRUFBRSxrQkFBa0IsRUFBRSxlQUFlLEVBQWtCLE1BQU0sNEJBQTRCLENBQUM7QUFDaEksT0FBTyxFQUFFLG9CQUFvQixFQUFFLE1BQU0sd0JBQXdCLENBQUM7QUFFOUQsTUFBTSxNQUFNLEdBQUcsWUFBWSxDQUFDLG1CQUFtQixDQUFDLENBQUM7QUFrQmpEOzZFQUM2RTtBQUM3RSxNQUFNLFVBQVUsd0JBQXdCO0lBQ3RDLE9BQU8sQ0FBQyxPQUFPLENBQUMsR0FBRyxDQUFDLHlCQUF5QixJQUFJLE1BQU0sQ0FBQyxDQUFDLFdBQVcsRUFBRSxLQUFLLE9BQU8sQ0FBQztBQUNyRixDQUFDO0FBRUQ7Ozs7O0dBS0c7QUFDSCxNQUFNLENBQUMsS0FBSyxVQUFVLGtCQUFrQixDQUN0QyxRQUEyQixFQUMzQixJQUFJLEdBQTJCLEVBQUU7SUFFakMsTUFBTSxNQUFNLEdBQTJCLEVBQUUsQ0FBQztJQUMxQyxJQUFJLENBQUMsd0JBQXdCLEVBQUUsRUFBRSxDQUFDO1FBQ2hDLE1BQU0sQ0FBQyxLQUFLLENBQUMsOERBQThELENBQUMsQ0FBQztRQUM3RSxPQUFPLE1BQU0sQ0FBQztJQUNoQixDQUFDO0lBRUQsTUFBTSxTQUFTLEdBQUcsSUFBSSxDQUFDLFNBQVMsSUFBSSxHQUFHLENBQUM7SUFDeEMsTUFBTSxVQUFVLEdBQUcsSUFBSSxDQUFDLG1CQUFtQixJQUFJLEVBQUUsQ0FBQztJQUNsRCwrRUFBK0U7SUFDL0UsTUFBTSxHQUFHLEdBQUcsSUFBSSxJQUFJLEVBQUUsQ0FBQztJQUV2QiwyRUFBMkU7SUFDM0UseUVBQXlFO0lBQ3pF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QVEsQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLEVBQUUsRUFBRSxDQUFDLENBQUMsQ0FBQyxJQUFJLENBQUM7UUFDMUMsYUFBYSxFQUFFLFVBQVUsR0FBRyxTQUFTO1FBQ3JDLE1BQU0sRUFBRSxDQUFDLENBQUMsSUFBSTtLQUNmLENBQUMsQ0FBQztJQUVILE1BQU0sU0FBUyxHQUFHLGVBQWUsQ0FBQztRQUNoQyxJQUFJLEVBQUUscUJBQXFCLElBQUksQ0FBQyxPQUFPLEVBQUU7UUFDekMsVUFBVTtRQUNWLGNBQWM7UUFDZCxHQUFHLEVBQUUsS0FBSyxJQUFJLEVBQUUsR0FBRyxNQUFNLGtCQUFrQixDQUFDLElBQUksQ0FBQyxRQUFRLEVBQUUsSUFBSSxDQUFDLENBQUMsQ0FBQyxDQUFDO1FBQ25FLEdBQUcsQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLEVBQUUsSUFBSSxFQUFFLEVBQUUsS0FBSyxFQUFFLEdBQUcsRUFBRSxDQUFDLElBQUksRUFBRSxHQUFHLEVBQUUscUJBQXFCLElBQUksQ0FBQyxPQUFPLFNBQVMsRUFBRSxLQUFLLEVBQUUsU0FBUyxFQUFFLEVBQUUsQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDO0tBQ3BILENBQUMsQ0FBQztJQUNILElBQUksQ0FBQyxJQUFJO1FBQUUsT0FBTyxTQUFTLENBQUM7SUFFNUIsdUVBQXVFO0lBQ3ZFLDhFQUE4RTtJQUM5RSw4RUFBOEU7SUFDOUUsdURBQXVEO0lBQ3ZELE9BQU87UUFDTCxLQUFLLEVBQUUsR0FBRyxFQUFFLENBQUMsU0FBUyxDQUFDLEtBQUssRUFBRTtRQUM5QixJQUFJLEVBQUUsR0FBRyxFQUFFLEdBQUcsU0FBUyxDQUFDLElBQUksRUFBRSxDQUFDLENBQUMsS0FBSyxlQUFlLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxDQUFDO0tBQzlELENBQUM7QUFDSixDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiLy8gQ29weXJpZ2h0IDIwMjYgUGlwZWxpbmUgQnVpbGRlciBDb250cmlidXRvcnNcbi8vIFNQRFgtTGljZW5zZS1JZGVudGlmaWVyOiBBcGFjaGUtMi4wXG5cbi8qKlxuICogU2hhcmVkIHNvZnQtZGVsZXRlIHJldGVudGlvbiBwdXJnZS5cbiAqXG4gKiBFdmVyeSB7QGxpbmsgQ3J1ZFNlcnZpY2V9IGVudGl0eSBzb2Z0LWRlbGV0ZXMgKHNldHMgYGRlbGV0ZWRBdGAgKyBhXG4gKiBgcHVyZ2VfYWZ0ZXJgIGRlYWRsaW5lKS4gVGhpcyBvcmNoZXN0cmF0b3IgcnVucyBvbmUgcHVyZ2UgcGFzcyBhY3Jvc3MgYSBzZXRcbiAqIG9mIHN1Y2ggZW50aXRpZXMsIGhhcmQtZGVsZXRpbmcgdG9tYnN0b25lcyB3aG9zZSBkZWFkbGluZSBoYXMgcGFzc2VkLiBJdCBpc1xuICogdGhlIGBydW5gIGNhbGxiYWNrIGEgc2VydmljZSBoYW5kcyB0byBgY3JlYXRlU2NoZWR1bGVyYCAobGVhZGVyLWxvY2tlZCksIHNvXG4gKiBvbmx5IG9uZSBwb2Qgc3dlZXBzIGF0IGEgdGltZS5cbiAqXG4gKiBSdW5zIGluIGFuIGV4cGxpY2l0ICoqc3lzYWRtaW4gdGVuYW50IHNjb3BlKiogKGBydW5XaXRoVGVuYW50Q29udGV4dCh7XG4gKiBpc1N1cGVyQWRtaW46IHRydWUgfSlgKSBzbyB0aGUgdW5kZXJseWluZyBgcHVyZ2VFeHBpcmVkYCBzcGFucyBldmVyeSBvcmcgYW5kXG4gKiBieXBhc3NlcyBSTFMgb24gRk9SQ0UnZCB0YWJsZXMgKHBsdWdpbnMvcGlwZWxpbmVzL2V0Yy4pLiBBIGJhcmUgbm8tdGVuYW50XG4gKiBjb250ZXh0IHdvdWxkIHNlZSB6ZXJvIHJvd3Mgb24gdGhvc2UgdGFibGVzIOKAlCBhbmQgaW4gcHJvZHVjdGlvbiAoYHN0cmljdGBcbiAqIG1vZGUpIGB3aXRoVGVuYW50VHhgIHRocm93cyBvdXRyaWdodCDigJQgc28gdGhlIHNjb3BlIGlzIGVzdGFibGlzaGVkIGhlcmUgcmF0aGVyXG4gKiB0aGFuIGxlZnQgdG8gdGhlIGNhbGxlci4gVGhpcyBpcyBhIGNyb3NzLXRlbmFudCBob3VzZWtlZXBpbmcgam9iLCBub3QgYVxuICogcGVyLW9yZyBvcGVyYXRpb24uXG4gKi9cblxuaW1wb3J0IHsgY3JlYXRlTG9nZ2VyLCBjcmVhdGVTY2hlZHVsZXIsIGNyZWF0ZUVudlJlZGlzTG9jaywgY2xvc2VMZWFkZXJMb2NrLCB0eXBlIFNjaGVkdWxlciB9IGZyb20gJ0BwaXBlbGluZS1idWlsZGVyL2FwaS1jb3JlJztcbmltcG9ydCB7IHJ1bldpdGhUZW5hbnRDb250ZXh0IH0gZnJvbSAnLi4vZGF0YWJhc2UvdGVuYW5jeS5qcyc7XG5cbmNvbnN0IGxvZ2dlciA9IGNyZWF0ZUxvZ2dlcignc29mdC1kZWxldGUtc3dlZXAnKTtcblxuLyoqIFRoZSBzbGljZSBvZiBhIENydWRTZXJ2aWNlIHRoZSBzd2VlcCBuZWVkcywgcGx1cyBhIGxhYmVsIGZvciBsb2dzL21ldHJpY3MuICovXG5leHBvcnQgaW50ZXJmYWNlIFB1cmdlYWJsZUVudGl0eSB7XG4gIC8qKiBUYWJsZS9lbnRpdHkgbGFiZWwgKGUuZy4gJ3BpcGVsaW5lJykgZm9yIHBlci10YWJsZSBsb2dnaW5nLiAqL1xuICBuYW1lOiBzdHJpbmc7XG4gIC8qKiBIYXJkLWRlbGV0ZSB1cCB0byBgbGltaXRgIGV4cGlyZWQgdG9tYnN0b25lczsgcmV0dXJucyByb3dzIHB1cmdlZC4gKi9cbiAgcHVyZ2VFeHBpcmVkKG5vdzogRGF0ZSwgbGltaXQ/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==