@pipeline-builder/pipeline-data 4.1.15 → 4.1.16

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 (60) hide show
  1. package/lib/api/access-control-builder.d.ts +18 -1
  2. package/lib/api/access-control-builder.js +19 -6
  3. package/lib/api/crud-service.d.ts +94 -36
  4. package/lib/api/crud-service.js +188 -166
  5. package/lib/api/plugin-resolution.d.ts +253 -0
  6. package/lib/api/plugin-resolution.js +649 -0
  7. package/lib/api/public-directory.d.ts +281 -0
  8. package/lib/api/public-directory.js +457 -0
  9. package/lib/api/query-builders.d.ts +13 -0
  10. package/lib/api/query-builders.js +74 -9
  11. package/lib/api/reporting/caches.js +4 -4
  12. package/lib/api/reporting/dora-scoring.d.ts +3 -3
  13. package/lib/api/reporting/dora-scoring.js +4 -4
  14. package/lib/api/reporting/dora.d.ts +6 -6
  15. package/lib/api/reporting/dora.js +97 -73
  16. package/lib/api/reporting/plugin-runtime.d.ts +25 -0
  17. package/lib/api/reporting/plugin-runtime.js +106 -0
  18. package/lib/api/reporting/query-scope.d.ts +8 -2
  19. package/lib/api/reporting/query-scope.js +16 -7
  20. package/lib/api/reporting/retention.d.ts +4 -10
  21. package/lib/api/reporting/retention.js +8 -11
  22. package/lib/api/reporting/sql-helpers.d.ts +4 -7
  23. package/lib/api/reporting/sql-helpers.js +8 -9
  24. package/lib/api/reporting/types.d.ts +55 -17
  25. package/lib/api/reporting/types.js +1 -1
  26. package/lib/api/reporting-service.d.ts +35 -26
  27. package/lib/api/reporting-service.js +245 -161
  28. package/lib/api/semver-range.d.ts +73 -0
  29. package/lib/api/semver-range.js +227 -0
  30. package/lib/api/soft-delete-sweep.js +8 -20
  31. package/lib/core/query-filters.d.ts +18 -3
  32. package/lib/core/query-filters.js +1 -1
  33. package/lib/database/drizzle-schema.d.ts +7790 -2461
  34. package/lib/database/drizzle-schema.js +29 -1
  35. package/lib/database/index.d.ts +4 -2
  36. package/lib/database/index.js +5 -3
  37. package/lib/database/pg-result.d.ts +19 -0
  38. package/lib/database/pg-result.js +32 -0
  39. package/lib/database/postgres-connection.js +14 -24
  40. package/lib/database/public-reader.d.ts +14 -0
  41. package/lib/database/public-reader.js +68 -0
  42. package/lib/database/retry-strategy.d.ts +3 -5
  43. package/lib/database/retry-strategy.js +4 -6
  44. package/lib/database/schema/compliance.d.ts +16 -34
  45. package/lib/database/schema/compliance.js +4 -4
  46. package/lib/database/schema/dashboard.js +4 -2
  47. package/lib/database/schema/ecosystem.d.ts +6586 -0
  48. package/lib/database/schema/ecosystem.js +709 -0
  49. package/lib/database/schema/message.d.ts +6 -12
  50. package/lib/database/schema/message.js +3 -1
  51. package/lib/database/schema/pipeline.d.ts +79 -5
  52. package/lib/database/schema/pipeline.js +46 -25
  53. package/lib/database/schema/plugin.d.ts +587 -3
  54. package/lib/database/schema/plugin.js +86 -14
  55. package/lib/database/tenancy.d.ts +6 -7
  56. package/lib/database/tenancy.js +13 -14
  57. package/lib/index.d.ts +7 -4
  58. package/lib/index.js +7 -4
  59. package/lib/testing/exports.json +146 -0
  60. package/package.json +44 -7
@@ -0,0 +1,106 @@
1
+ // Copyright 2026 Pipeline Builder Contributors
2
+ // SPDX-License-Identifier: Apache-2.0
3
+ /**
4
+ * Per-plugin RUNTIME telemetry: how plugins behave when
5
+ * pipelines run them, as opposed to the plugin BUILD reports. Reads the
6
+ * `plugin_publisher/plugin_name/plugin_version` that event ingest stamps on
7
+ * ACTION events from the pipeline's step manifest.
8
+ *
9
+ * A "run" is one terminal ACTION event — SUCCEEDED or FAILED. Canceled,
10
+ * abandoned and superseded actions say nothing about the plugin and are left
11
+ * out of both the count and the rate.
12
+ *
13
+ * Two audiences:
14
+ * - the org's own dashboard ({@link getPluginRuntime}): org-scoped (rollup
15
+ * aware), grouped per plugin version;
16
+ * - the ecosystem, service-to-service ({@link getPluginRuntimeAggregate},
17
+ * {@link hasVerifiedPluginUse}): cross-org aggregates keyed on a listing's
18
+ * `(publisher, name)`, feeding `plugin_stats` and the review "verified use"
19
+ * badge. Never exposed to a user token — they read every org's events.
20
+ */
21
+ import { sql } from 'drizzle-orm';
22
+ import { orgScope, runReport } from './query-scope.js';
23
+ import { schema } from '../../database/drizzle-schema.js';
24
+ import { runWithTenantContext, withTenantTx } from '../../database/tenancy.js';
25
+ import { drizzleRows } from '../crud-service.js';
26
+ /** Window for the ecosystem aggregate (`plugin_stats.success_rate_30d`). */
27
+ export const PLUGIN_RUNTIME_AGGREGATE_DAYS = 30;
28
+ /** Window for review "verified use": a successful run in the last 90 days. */
29
+ export const PLUGIN_VERIFIED_USE_DAYS = 90;
30
+ /** The terminal-ACTION, plugin-attributed predicate every runtime read shares (alias `e`). */
31
+ const pluginRuns = sql `e.event_type = 'ACTION' AND e.plugin_name IS NOT NULL
32
+ AND e.status IN ('SUCCEEDED', 'FAILED')`;
33
+ /** `IS NULL` for an own-org (publisher-less) plugin, `=` otherwise. */
34
+ function publisherPredicate(publisher) {
35
+ return publisher === null ? sql `e.plugin_publisher IS NULL` : sql `e.plugin_publisher = ${publisher}`;
36
+ }
37
+ /**
38
+ * Per plugin version: runs, success rate and duration (p50/p95) over
39
+ * `[from, to]` on `completed_at`, for the org (or its rollup subtree).
40
+ * Optional filters narrow to one plugin name / publisher (`null` = own-org
41
+ * plugins) / version.
42
+ */
43
+ export async function getPluginRuntime(orgId, from, to, filter = {}, orgIds) {
44
+ const { pred, multi } = orgScope(orgId, orgIds);
45
+ const nameClause = filter.name !== undefined ? sql `AND e.plugin_name = ${filter.name}` : sql ``;
46
+ const publisherClause = filter.publisher !== undefined ? sql `AND ${publisherPredicate(filter.publisher)}` : sql ``;
47
+ const versionClause = filter.version !== undefined ? sql `AND e.plugin_version = ${filter.version}` : sql ``;
48
+ const exec = () => withTenantTx((tx) => tx.execute(sql `
49
+ SELECT
50
+ e.plugin_publisher AS "pluginPublisher",
51
+ e.plugin_name AS "pluginName",
52
+ e.plugin_version AS "pluginVersion",
53
+ COUNT(*)::int AS runs,
54
+ COUNT(*) FILTER (WHERE e.status = 'SUCCEEDED')::int AS succeeded,
55
+ COUNT(*) FILTER (WHERE e.status = 'FAILED')::int AS failed,
56
+ ROUND(COUNT(*) FILTER (WHERE e.status = 'SUCCEEDED')::numeric
57
+ / NULLIF(COUNT(*), 0) * 100, 1)::float AS "successPct",
58
+ PERCENTILE_CONT(0.5) WITHIN GROUP (ORDER BY e.duration_ms)::int AS "p50Ms",
59
+ PERCENTILE_CONT(0.95) WITHIN GROUP (ORDER BY e.duration_ms)::int AS "p95Ms",
60
+ MAX(e.completed_at)::text AS "lastRun"
61
+ FROM ${schema.pipelineEvent} e
62
+ WHERE e.org_id ${pred} AND ${pluginRuns}
63
+ AND e.completed_at >= ${from}::timestamptz AND e.completed_at <= ${to}::timestamptz
64
+ ${nameClause} ${publisherClause} ${versionClause}
65
+ GROUP BY e.plugin_publisher, e.plugin_name, e.plugin_version
66
+ ORDER BY runs DESC
67
+ `).then(r => drizzleRows(r.rows)));
68
+ const filterKey = `${filter.name ?? ''}:${filter.publisher === null ? '\u0000' : filter.publisher ?? ''}:${filter.version ?? ''}`;
69
+ return runReport(`${orgId}:plugin-runtime:${from}:${to}:${filterKey}`, multi, exec);
70
+ }
71
+ /**
72
+ * Ecosystem aggregate for one listing over the last 30 days, across EVERY org:
73
+ * runs, success rate (0–1; null with no runs) and how many distinct orgs ran it.
74
+ * Runs under system context — the caller is the plugin service computing
75
+ * `plugin_stats`, and `activeOrgCount30d` is only ever shown at ≥ 5.
76
+ */
77
+ export async function getPluginRuntimeAggregate(publisher, name) {
78
+ const rows = await runWithTenantContext({ isSuperAdmin: true }, () => withTenantTx((tx) => tx.execute(sql `
79
+ SELECT
80
+ COUNT(*)::int AS "runs30d",
81
+ (COUNT(*) FILTER (WHERE e.status = 'SUCCEEDED')::float
82
+ / NULLIF(COUNT(*), 0)) AS "successRate30d",
83
+ COUNT(DISTINCT e.org_id)::int AS "activeOrgCount30d"
84
+ FROM ${schema.pipelineEvent} e
85
+ WHERE ${pluginRuns} AND ${publisherPredicate(publisher)} AND e.plugin_name = ${name}
86
+ AND e.completed_at >= now() - make_interval(days => ${PLUGIN_RUNTIME_AGGREGATE_DAYS})
87
+ `).then(r => drizzleRows(r.rows))));
88
+ return rows[0] ?? { runs30d: 0, successRate30d: null, activeOrgCount30d: 0 };
89
+ }
90
+ /**
91
+ * Review "verified use": did `orgId` run `(publisher, name)` successfully
92
+ * in the last 90 days? Bounded by the org's event retention — a run older than
93
+ * the retention horizon has been swept and no longer counts.
94
+ */
95
+ export async function hasVerifiedPluginUse(orgId, publisher, name) {
96
+ const rows = await runWithTenantContext({ orgId, isSuperAdmin: false }, () => withTenantTx((tx) => tx.execute(sql `
97
+ SELECT EXISTS (
98
+ SELECT 1 FROM ${schema.pipelineEvent} e
99
+ WHERE e.org_id = ${orgId} AND ${pluginRuns} AND e.status = 'SUCCEEDED'
100
+ AND ${publisherPredicate(publisher)} AND e.plugin_name = ${name}
101
+ AND e.completed_at >= now() - make_interval(days => ${PLUGIN_VERIFIED_USE_DAYS})
102
+ ) AS "verified"
103
+ `).then(r => drizzleRows(r.rows))));
104
+ return rows[0]?.verified === true;
105
+ }
106
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicGx1Z2luLXJ1bnRpbWUuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvYXBpL3JlcG9ydGluZy9wbHVnaW4tcnVudGltZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSwrQ0FBK0M7QUFDL0Msc0NBQXNDO0FBRXRDOzs7Ozs7Ozs7Ozs7Ozs7OztHQWlCRztBQUVILE9BQU8sRUFBRSxHQUFHLEVBQUUsTUFBTSxhQUFhLENBQUM7QUFDbEMsT0FBTyxFQUFFLFFBQVEsRUFBRSxTQUFTLEVBQUUsTUFBTSxrQkFBa0IsQ0FBQztBQUV2RCxPQUFPLEVBQUUsTUFBTSxFQUFFLE1BQU0sa0NBQWtDLENBQUM7QUFDMUQsT0FBTyxFQUFFLG9CQUFvQixFQUFFLFlBQVksRUFBRSxNQUFNLDJCQUEyQixDQUFDO0FBQy9FLE9BQU8sRUFBRSxXQUFXLEVBQUUsTUFBTSxvQkFBb0IsQ0FBQztBQUVqRCw0RUFBNEU7QUFDNUUsTUFBTSxDQUFDLE1BQU0sNkJBQTZCLEdBQUcsRUFBRSxDQUFDO0FBQ2hELDhFQUE4RTtBQUM5RSxNQUFNLENBQUMsTUFBTSx3QkFBd0IsR0FBRyxFQUFFLENBQUM7QUFFM0MsOEZBQThGO0FBQzlGLE1BQU0sVUFBVSxHQUFHLEdBQUcsQ0FBQTtrREFDNEIsQ0FBQztBQUVuRCx1RUFBdUU7QUFDdkUsU0FBUyxrQkFBa0IsQ0FBQyxTQUF3QjtJQUNsRCxPQUFPLFNBQVMsS0FBSyxJQUFJLENBQUMsQ0FBQyxDQUFDLEdBQUcsQ0FBQSw0QkFBNEIsQ0FBQyxDQUFDLENBQUMsR0FBRyxDQUFBLHdCQUF3QixTQUFTLEVBQUUsQ0FBQztBQUN2RyxDQUFDO0FBRUQ7Ozs7O0dBS0c7QUFDSCxNQUFNLENBQUMsS0FBSyxVQUFVLGdCQUFnQixDQUNwQyxLQUFhLEVBQ2IsSUFBWSxFQUNaLEVBQVUsRUFDVixNQUFNLEdBQXdCLEVBQUUsRUFDaEMsTUFBaUI7SUFFakIsTUFBTSxFQUFFLElBQUksRUFBRSxLQUFLLEVBQUUsR0FBRyxRQUFRLENBQUMsS0FBSyxFQUFFLE1BQU0sQ0FBQyxDQUFDO0lBQ2hELE1BQU0sVUFBVSxHQUFHLE1BQU0sQ0FBQyxJQUFJLEtBQUssU0FBUyxDQUFDLENBQUMsQ0FBQyxHQUFHLENBQUEsdUJBQXVCLE1BQU0sQ0FBQyxJQUFJLEVBQUUsQ0FBQyxDQUFDLENBQUMsR0FBRyxDQUFBLEVBQUUsQ0FBQztJQUMvRixNQUFNLGVBQWUsR0FBRyxNQUFNLENBQUMsU0FBUyxLQUFLLFNBQVMsQ0FBQyxDQUFDLENBQUMsR0FBRyxDQUFBLE9BQU8sa0JBQWtCLENBQUMsTUFBTSxDQUFDLFNBQVMsQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDLEdBQUcsQ0FBQSxFQUFFLENBQUM7SUFDbEgsTUFBTSxhQUFhLEdBQUcsTUFBTSxDQUFDLE9BQU8sS0FBSyxTQUFTLENBQUMsQ0FBQyxDQUFDLEdBQUcsQ0FBQSwwQkFBMEIsTUFBTSxDQUFDLE9BQU8sRUFBRSxDQUFDLENBQUMsQ0FBQyxHQUFHLENBQUEsRUFBRSxDQUFDO0lBQzNHLE1BQU0sSUFBSSxHQUFHLEdBQUcsRUFBRSxDQUFDLFlBQVksQ0FBQyxDQUFDLEVBQUUsRUFBRSxFQUFFLENBQUMsRUFBRSxDQUFDLE9BQU8sQ0FBQyxHQUFHLENBQUE7Ozs7Ozs7Ozs7Ozs7ZUFhekMsTUFBTSxDQUFDLGFBQWE7eUJBQ1YsSUFBSSxRQUFRLFVBQVU7a0NBQ2IsSUFBSSx1Q0FBdUMsRUFBRTtZQUNuRSxVQUFVLElBQUksZUFBZSxJQUFJLGFBQWE7OztPQUduRCxDQUFDLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUMsV0FBVyxDQUFxQixDQUFDLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxDQUFDO0lBQzNELE1BQU0sU0FBUyxHQUFHLEdBQUcsTUFBTSxDQUFDLElBQUksSUFBSSxFQUFFLElBQUksTUFBTSxDQUFDLFNBQVMsS0FBSyxJQUFJLENBQUMsQ0FBQyxDQUFDLFFBQVEsQ0FBQyxDQUFDLENBQUMsTUFBTSxDQUFDLFNBQVMsSUFBSSxFQUFFLElBQUksTUFBTSxDQUFDLE9BQU8sSUFBSSxFQUFFLEVBQUUsQ0FBQztJQUNsSSxPQUFPLFNBQVMsQ0FBQyxHQUFHLEtBQUssbUJBQW1CLElBQUksSUFBSSxFQUFFLElBQUksU0FBUyxFQUFFLEVBQUUsS0FBSyxFQUFFLElBQUksQ0FBQyxDQUFDO0FBQ3RGLENBQUM7QUFFRDs7Ozs7R0FLRztBQUNILE1BQU0sQ0FBQyxLQUFLLFVBQVUseUJBQXlCLENBQUMsU0FBaUIsRUFBRSxJQUFZO0lBQzdFLE1BQU0sSUFBSSxHQUFHLE1BQU0sb0JBQW9CLENBQUMsRUFBRSxZQUFZLEVBQUUsSUFBSSxFQUFFLEVBQUUsR0FBRyxFQUFFLENBQUMsWUFBWSxDQUFDLENBQUMsRUFBRSxFQUFFLEVBQUUsQ0FBQyxFQUFFLENBQUMsT0FBTyxDQUFDLEdBQUcsQ0FBQTs7Ozs7O2VBTTVGLE1BQU0sQ0FBQyxhQUFhO2dCQUNuQixVQUFVLFFBQVEsa0JBQWtCLENBQUMsU0FBUyxDQUFDLHdCQUF3QixJQUFJO2dFQUMzQiw2QkFBNkI7T0FDdEYsQ0FBQyxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDLFdBQVcsQ0FBeUIsQ0FBQyxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDO0lBQ2hFLE9BQU8sSUFBSSxDQUFDLENBQUMsQ0FBQyxJQUFJLEVBQUUsT0FBTyxFQUFFLENBQUMsRUFBRSxjQUFjLEVBQUUsSUFBSSxFQUFFLGlCQUFpQixFQUFFLENBQUMsRUFBRSxDQUFDO0FBQy9FLENBQUM7QUFFRDs7OztHQUlHO0FBQ0gsTUFBTSxDQUFDLEtBQUssVUFBVSxvQkFBb0IsQ0FBQyxLQUFhLEVBQUUsU0FBaUIsRUFBRSxJQUFZO0lBQ3ZGLE1BQU0sSUFBSSxHQUFHLE1BQU0sb0JBQW9CLENBQUMsRUFBRSxLQUFLLEVBQUUsWUFBWSxFQUFFLEtBQUssRUFBRSxFQUFFLEdBQUcsRUFBRSxDQUFDLFlBQVksQ0FBQyxDQUFDLEVBQUUsRUFBRSxFQUFFLENBQUMsRUFBRSxDQUFDLE9BQU8sQ0FBQyxHQUFHLENBQUE7OzBCQUV6RixNQUFNLENBQUMsYUFBYTs2QkFDakIsS0FBSyxRQUFRLFVBQVU7a0JBQ2xDLGtCQUFrQixDQUFDLFNBQVMsQ0FBQyx3QkFBd0IsSUFBSTtrRUFDVCx3QkFBd0I7O09BRW5GLENBQUMsQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxXQUFXLENBQXdCLENBQUMsQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQztJQUMvRCxPQUFPLElBQUksQ0FBQyxDQUFDLENBQUMsRUFBRSxRQUFRLEtBQUssSUFBSSxDQUFDO0FBQ3BDLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyIvLyBDb3B5cmlnaHQgMjAyNiBQaXBlbGluZSBCdWlsZGVyIENvbnRyaWJ1dG9yc1xuLy8gU1BEWC1MaWNlbnNlLUlkZW50aWZpZXI6IEFwYWNoZS0yLjBcblxuLyoqXG4gKiBQZXItcGx1Z2luIFJVTlRJTUUgdGVsZW1ldHJ5OiBob3cgcGx1Z2lucyBiZWhhdmUgd2hlblxuICogcGlwZWxpbmVzIHJ1biB0aGVtLCBhcyBvcHBvc2VkIHRvIHRoZSBwbHVnaW4gQlVJTEQgcmVwb3J0cy4gUmVhZHMgdGhlXG4gKiBgcGx1Z2luX3B1Ymxpc2hlci9wbHVnaW5fbmFtZS9wbHVnaW5fdmVyc2lvbmAgdGhhdCBldmVudCBpbmdlc3Qgc3RhbXBzIG9uXG4gKiBBQ1RJT04gZXZlbnRzIGZyb20gdGhlIHBpcGVsaW5lJ3Mgc3RlcCBtYW5pZmVzdC5cbiAqXG4gKiBBIFwicnVuXCIgaXMgb25lIHRlcm1pbmFsIEFDVElPTiBldmVudCDigJQgU1VDQ0VFREVEIG9yIEZBSUxFRC4gQ2FuY2VsZWQsXG4gKiBhYmFuZG9uZWQgYW5kIHN1cGVyc2VkZWQgYWN0aW9ucyBzYXkgbm90aGluZyBhYm91dCB0aGUgcGx1Z2luIGFuZCBhcmUgbGVmdFxuICogb3V0IG9mIGJvdGggdGhlIGNvdW50IGFuZCB0aGUgcmF0ZS5cbiAqXG4gKiBUd28gYXVkaWVuY2VzOlxuICogICAtIHRoZSBvcmcncyBvd24gZGFzaGJvYXJkICh7QGxpbmsgZ2V0UGx1Z2luUnVudGltZX0pOiBvcmctc2NvcGVkIChyb2xsdXBcbiAqICAgICBhd2FyZSksIGdyb3VwZWQgcGVyIHBsdWdpbiB2ZXJzaW9uO1xuICogICAtIHRoZSBlY29zeXN0ZW0sIHNlcnZpY2UtdG8tc2VydmljZSAoe0BsaW5rIGdldFBsdWdpblJ1bnRpbWVBZ2dyZWdhdGV9LFxuICogICAgIHtAbGluayBoYXNWZXJpZmllZFBsdWdpblVzZX0pOiBjcm9zcy1vcmcgYWdncmVnYXRlcyBrZXllZCBvbiBhIGxpc3Rpbmcnc1xuICogICAgIGAocHVibGlzaGVyLCBuYW1lKWAsIGZlZWRpbmcgYHBsdWdpbl9zdGF0c2AgYW5kIHRoZSByZXZpZXcgXCJ2ZXJpZmllZCB1c2VcIlxuICogICAgIGJhZGdlLiBOZXZlciBleHBvc2VkIHRvIGEgdXNlciB0b2tlbiDigJQgdGhleSByZWFkIGV2ZXJ5IG9yZydzIGV2ZW50cy5cbiAqL1xuXG5pbXBvcnQgeyBzcWwgfSBmcm9tICdkcml6emxlLW9ybSc7XG5pbXBvcnQgeyBvcmdTY29wZSwgcnVuUmVwb3J0IH0gZnJvbSAnLi9xdWVyeS1zY29wZS5qcyc7XG5pbXBvcnQgdHlwZSB7IFBsdWdpblJ1bnRpbWVBZ2dyZWdhdGUsIFBsdWdpblJ1bnRpbWVGaWx0ZXIsIFBsdWdpblJ1bnRpbWVTdGF0cyB9IGZyb20gJy4vdHlwZXMuanMnO1xuaW1wb3J0IHsgc2NoZW1hIH0gZnJvbSAnLi4vLi4vZGF0YWJhc2UvZHJpenpsZS1zY2hlbWEuanMnO1xuaW1wb3J0IHsgcnVuV2l0aFRlbmFudENvbnRleHQsIHdpdGhUZW5hbnRUeCB9IGZyb20gJy4uLy4uL2RhdGFiYXNlL3RlbmFuY3kuanMnO1xuaW1wb3J0IHsgZHJpenpsZVJvd3MgfSBmcm9tICcuLi9jcnVkLXNlcnZpY2UuanMnO1xuXG4vKiogV2luZG93IGZvciB0aGUgZWNvc3lzdGVtIGFnZ3JlZ2F0ZSAoYHBsdWdpbl9zdGF0cy5zdWNjZXNzX3JhdGVfMzBkYCkuICovXG5leHBvcnQgY29uc3QgUExVR0lOX1JVTlRJTUVfQUdHUkVHQVRFX0RBWVMgPSAzMDtcbi8qKiBXaW5kb3cgZm9yIHJldmlldyBcInZlcmlmaWVkIHVzZVwiOiBhIHN1Y2Nlc3NmdWwgcnVuIGluIHRoZSBsYXN0IDkwIGRheXMuICovXG5leHBvcnQgY29uc3QgUExVR0lOX1ZFUklGSUVEX1VTRV9EQVlTID0gOTA7XG5cbi8qKiBUaGUgdGVybWluYWwtQUNUSU9OLCBwbHVnaW4tYXR0cmlidXRlZCBwcmVkaWNhdGUgZXZlcnkgcnVudGltZSByZWFkIHNoYXJlcyAoYWxpYXMgYGVgKS4gKi9cbmNvbnN0IHBsdWdpblJ1bnMgPSBzcWxgZS5ldmVudF90eXBlID0gJ0FDVElPTicgQU5EIGUucGx1Z2luX25hbWUgSVMgTk9UIE5VTExcbiAgICAgICAgICBBTkQgZS5zdGF0dXMgSU4gKCdTVUNDRUVERUQnLCAnRkFJTEVEJylgO1xuXG4vKiogYElTIE5VTExgIGZvciBhbiBvd24tb3JnIChwdWJsaXNoZXItbGVzcykgcGx1Z2luLCBgPWAgb3RoZXJ3aXNlLiAqL1xuZnVuY3Rpb24gcHVibGlzaGVyUHJlZGljYXRlKHB1Ymxpc2hlcjogc3RyaW5nIHwgbnVsbCkge1xuICByZXR1cm4gcHVibGlzaGVyID09PSBudWxsID8gc3FsYGUucGx1Z2luX3B1Ymxpc2hlciBJUyBOVUxMYCA6IHNxbGBlLnBsdWdpbl9wdWJsaXNoZXIgPSAke3B1Ymxpc2hlcn1gO1xufVxuXG4vKipcbiAqIFBlciBwbHVnaW4gdmVyc2lvbjogcnVucywgc3VjY2VzcyByYXRlIGFuZCBkdXJhdGlvbiAocDUwL3A5NSkgb3ZlclxuICogYFtmcm9tLCB0b11gIG9uIGBjb21wbGV0ZWRfYXRgLCBmb3IgdGhlIG9yZyAob3IgaXRzIHJvbGx1cCBzdWJ0cmVlKS5cbiAqIE9wdGlvbmFsIGZpbHRlcnMgbmFycm93IHRvIG9uZSBwbHVnaW4gbmFtZSAvIHB1Ymxpc2hlciAoYG51bGxgID0gb3duLW9yZ1xuICogcGx1Z2lucykgLyB2ZXJzaW9uLlxuICovXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gZ2V0UGx1Z2luUnVudGltZShcbiAgb3JnSWQ6IHN0cmluZyxcbiAgZnJvbTogc3RyaW5nLFxuICB0bzogc3RyaW5nLFxuICBmaWx0ZXI6IFBsdWdpblJ1bnRpbWVGaWx0ZXIgPSB7fSxcbiAgb3JnSWRzPzogc3RyaW5nW10sXG4pOiBQcm9taXNlPFBsdWdpblJ1bnRpbWVTdGF0c1tdPiB7XG4gIGNvbnN0IHsgcHJlZCwgbXVsdGkgfSA9IG9yZ1Njb3BlKG9yZ0lkLCBvcmdJZHMpO1xuICBjb25zdCBuYW1lQ2xhdXNlID0gZmlsdGVyLm5hbWUgIT09IHVuZGVmaW5lZCA/IHNxbGBBTkQgZS5wbHVnaW5fbmFtZSA9ICR7ZmlsdGVyLm5hbWV9YCA6IHNxbGBgO1xuICBjb25zdCBwdWJsaXNoZXJDbGF1c2UgPSBmaWx0ZXIucHVibGlzaGVyICE9PSB1bmRlZmluZWQgPyBzcWxgQU5EICR7cHVibGlzaGVyUHJlZGljYXRlKGZpbHRlci5wdWJsaXNoZXIpfWAgOiBzcWxgYDtcbiAgY29uc3QgdmVyc2lvbkNsYXVzZSA9IGZpbHRlci52ZXJzaW9uICE9PSB1bmRlZmluZWQgPyBzcWxgQU5EIGUucGx1Z2luX3ZlcnNpb24gPSAke2ZpbHRlci52ZXJzaW9ufWAgOiBzcWxgYDtcbiAgY29uc3QgZXhlYyA9ICgpID0+IHdpdGhUZW5hbnRUeCgodHgpID0+IHR4LmV4ZWN1dGUoc3FsYFxuICAgICAgICBTRUxFQ1RcbiAgICAgICAgICBlLnBsdWdpbl9wdWJsaXNoZXIgQVMgXCJwbHVnaW5QdWJsaXNoZXJcIixcbiAgICAgICAgICBlLnBsdWdpbl9uYW1lIEFTIFwicGx1Z2luTmFtZVwiLFxuICAgICAgICAgIGUucGx1Z2luX3ZlcnNpb24gQVMgXCJwbHVnaW5WZXJzaW9uXCIsXG4gICAgICAgICAgQ09VTlQoKik6OmludCBBUyBydW5zLFxuICAgICAgICAgIENPVU5UKCopIEZJTFRFUiAoV0hFUkUgZS5zdGF0dXMgPSAnU1VDQ0VFREVEJyk6OmludCBBUyBzdWNjZWVkZWQsXG4gICAgICAgICAgQ09VTlQoKikgRklMVEVSIChXSEVSRSBlLnN0YXR1cyA9ICdGQUlMRUQnKTo6aW50IEFTIGZhaWxlZCxcbiAgICAgICAgICBST1VORChDT1VOVCgqKSBGSUxURVIgKFdIRVJFIGUuc3RhdHVzID0gJ1NVQ0NFRURFRCcpOjpudW1lcmljXG4gICAgICAgICAgICAvIE5VTExJRihDT1VOVCgqKSwgMCkgKiAxMDAsIDEpOjpmbG9hdCBBUyBcInN1Y2Nlc3NQY3RcIixcbiAgICAgICAgICBQRVJDRU5USUxFX0NPTlQoMC41KSBXSVRISU4gR1JPVVAgKE9SREVSIEJZIGUuZHVyYXRpb25fbXMpOjppbnQgQVMgXCJwNTBNc1wiLFxuICAgICAgICAgIFBFUkNFTlRJTEVfQ09OVCgwLjk1KSBXSVRISU4gR1JPVVAgKE9SREVSIEJZIGUuZHVyYXRpb25fbXMpOjppbnQgQVMgXCJwOTVNc1wiLFxuICAgICAgICAgIE1BWChlLmNvbXBsZXRlZF9hdCk6OnRleHQgQVMgXCJsYXN0UnVuXCJcbiAgICAgICAgRlJPTSAke3NjaGVtYS5waXBlbGluZUV2ZW50fSBlXG4gICAgICAgIFdIRVJFIGUub3JnX2lkICR7cHJlZH0gQU5EICR7cGx1Z2luUnVuc31cbiAgICAgICAgICBBTkQgZS5jb21wbGV0ZWRfYXQgPj0gJHtmcm9tfTo6dGltZXN0YW1wdHogQU5EIGUuY29tcGxldGVkX2F0IDw9ICR7dG99Ojp0aW1lc3RhbXB0elxuICAgICAgICAgICR7bmFtZUNsYXVzZX0gJHtwdWJsaXNoZXJDbGF1c2V9ICR7dmVyc2lvbkNsYXVzZX1cbiAgICAgICAgR1JPVVAgQlkgZS5wbHVnaW5fcHVibGlzaGVyLCBlLnBsdWdpbl9uYW1lLCBlLnBsdWdpbl92ZXJzaW9uXG4gICAgICAgIE9SREVSIEJZIHJ1bnMgREVTQ1xuICAgICAgYCkudGhlbihyID0+IGRyaXp6bGVSb3dzPFBsdWdpblJ1bnRpbWVTdGF0cz4oci5yb3dzKSkpO1xuICBjb25zdCBmaWx0ZXJLZXkgPSBgJHtmaWx0ZXIubmFtZSA/PyAnJ306JHtmaWx0ZXIucHVibGlzaGVyID09PSBudWxsID8gJ1xcdTAwMDAnIDogZmlsdGVyLnB1Ymxpc2hlciA/PyAnJ306JHtmaWx0ZXIudmVyc2lvbiA/PyAnJ31gO1xuICByZXR1cm4gcnVuUmVwb3J0KGAke29yZ0lkfTpwbHVnaW4tcnVudGltZToke2Zyb219OiR7dG99OiR7ZmlsdGVyS2V5fWAsIG11bHRpLCBleGVjKTtcbn1cblxuLyoqXG4gKiBFY29zeXN0ZW0gYWdncmVnYXRlIGZvciBvbmUgbGlzdGluZyBvdmVyIHRoZSBsYXN0IDMwIGRheXMsIGFjcm9zcyBFVkVSWSBvcmc6XG4gKiBydW5zLCBzdWNjZXNzIHJhdGUgKDDigJMxOyBudWxsIHdpdGggbm8gcnVucykgYW5kIGhvdyBtYW55IGRpc3RpbmN0IG9yZ3MgcmFuIGl0LlxuICogUnVucyB1bmRlciBzeXN0ZW0gY29udGV4dCDigJQgdGhlIGNhbGxlciBpcyB0aGUgcGx1Z2luIHNlcnZpY2UgY29tcHV0aW5nXG4gKiBgcGx1Z2luX3N0YXRzYCwgYW5kIGBhY3RpdmVPcmdDb3VudDMwZGAgaXMgb25seSBldmVyIHNob3duIGF0IOKJpSA1LlxuICovXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gZ2V0UGx1Z2luUnVudGltZUFnZ3JlZ2F0ZShwdWJsaXNoZXI6IHN0cmluZywgbmFtZTogc3RyaW5nKTogUHJvbWlzZTxQbHVnaW5SdW50aW1lQWdncmVnYXRlPiB7XG4gIGNvbnN0IHJvd3MgPSBhd2FpdCBydW5XaXRoVGVuYW50Q29udGV4dCh7IGlzU3VwZXJBZG1pbjogdHJ1ZSB9LCAoKSA9PiB3aXRoVGVuYW50VHgoKHR4KSA9PiB0eC5leGVjdXRlKHNxbGBcbiAgICAgICAgU0VMRUNUXG4gICAgICAgICAgQ09VTlQoKik6OmludCBBUyBcInJ1bnMzMGRcIixcbiAgICAgICAgICAoQ09VTlQoKikgRklMVEVSIChXSEVSRSBlLnN0YXR1cyA9ICdTVUNDRUVERUQnKTo6ZmxvYXRcbiAgICAgICAgICAgIC8gTlVMTElGKENPVU5UKCopLCAwKSkgQVMgXCJzdWNjZXNzUmF0ZTMwZFwiLFxuICAgICAgICAgIENPVU5UKERJU1RJTkNUIGUub3JnX2lkKTo6aW50IEFTIFwiYWN0aXZlT3JnQ291bnQzMGRcIlxuICAgICAgICBGUk9NICR7c2NoZW1hLnBpcGVsaW5lRXZlbnR9IGVcbiAgICAgICAgV0hFUkUgJHtwbHVnaW5SdW5zfSBBTkQgJHtwdWJsaXNoZXJQcmVkaWNhdGUocHVibGlzaGVyKX0gQU5EIGUucGx1Z2luX25hbWUgPSAke25hbWV9XG4gICAgICAgICAgQU5EIGUuY29tcGxldGVkX2F0ID49IG5vdygpIC0gbWFrZV9pbnRlcnZhbChkYXlzID0+ICR7UExVR0lOX1JVTlRJTUVfQUdHUkVHQVRFX0RBWVN9KVxuICAgICAgYCkudGhlbihyID0+IGRyaXp6bGVSb3dzPFBsdWdpblJ1bnRpbWVBZ2dyZWdhdGU+KHIucm93cykpKSk7XG4gIHJldHVybiByb3dzWzBdID8/IHsgcnVuczMwZDogMCwgc3VjY2Vzc1JhdGUzMGQ6IG51bGwsIGFjdGl2ZU9yZ0NvdW50MzBkOiAwIH07XG59XG5cbi8qKlxuICogUmV2aWV3IFwidmVyaWZpZWQgdXNlXCI6IGRpZCBgb3JnSWRgIHJ1biBgKHB1Ymxpc2hlciwgbmFtZSlgIHN1Y2Nlc3NmdWxseVxuICogaW4gdGhlIGxhc3QgOTAgZGF5cz8gQm91bmRlZCBieSB0aGUgb3JnJ3MgZXZlbnQgcmV0ZW50aW9uIOKAlCBhIHJ1biBvbGRlciB0aGFuXG4gKiB0aGUgcmV0ZW50aW9uIGhvcml6b24gaGFzIGJlZW4gc3dlcHQgYW5kIG5vIGxvbmdlciBjb3VudHMuXG4gKi9cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBoYXNWZXJpZmllZFBsdWdpblVzZShvcmdJZDogc3RyaW5nLCBwdWJsaXNoZXI6IHN0cmluZywgbmFtZTogc3RyaW5nKTogUHJvbWlzZTxib29sZWFuPiB7XG4gIGNvbnN0IHJvd3MgPSBhd2FpdCBydW5XaXRoVGVuYW50Q29udGV4dCh7IG9yZ0lkLCBpc1N1cGVyQWRtaW46IGZhbHNlIH0sICgpID0+IHdpdGhUZW5hbnRUeCgodHgpID0+IHR4LmV4ZWN1dGUoc3FsYFxuICAgICAgICBTRUxFQ1QgRVhJU1RTIChcbiAgICAgICAgICBTRUxFQ1QgMSBGUk9NICR7c2NoZW1hLnBpcGVsaW5lRXZlbnR9IGVcbiAgICAgICAgICBXSEVSRSBlLm9yZ19pZCA9ICR7b3JnSWR9IEFORCAke3BsdWdpblJ1bnN9IEFORCBlLnN0YXR1cyA9ICdTVUNDRUVERUQnXG4gICAgICAgICAgICBBTkQgJHtwdWJsaXNoZXJQcmVkaWNhdGUocHVibGlzaGVyKX0gQU5EIGUucGx1Z2luX25hbWUgPSAke25hbWV9XG4gICAgICAgICAgICBBTkQgZS5jb21wbGV0ZWRfYXQgPj0gbm93KCkgLSBtYWtlX2ludGVydmFsKGRheXMgPT4gJHtQTFVHSU5fVkVSSUZJRURfVVNFX0RBWVN9KVxuICAgICAgICApIEFTIFwidmVyaWZpZWRcIlxuICAgICAgYCkudGhlbihyID0+IGRyaXp6bGVSb3dzPHsgdmVyaWZpZWQ6IGJvb2xlYW4gfT4oci5yb3dzKSkpKTtcbiAgcmV0dXJuIHJvd3NbMF0/LnZlcmlmaWVkID09PSB0cnVlO1xufVxuIl19
@@ -1,3 +1,4 @@
1
+ import { type SQL } from 'drizzle-orm';
1
2
  /**
2
3
  * Build the org-scope predicate for a report query. With `orgIds` (the
3
4
  * org → team rollup — a parent's `[self, ...descendants]`) it becomes an
@@ -7,7 +8,7 @@
7
8
  * cache key.
8
9
  */
9
10
  export declare function orgScope(orgId: string, orgIds?: string[]): {
10
- pred: import("drizzle-orm").SQL<unknown>;
11
+ pred: SQL<unknown>;
11
12
  multi: boolean;
12
13
  };
13
14
  /**
@@ -18,4 +19,9 @@ export declare function orgScope(orgId: string, orgIds?: string[]): {
18
19
  * has no org tree), so caching them would serve stale aggregates. Always fresh.
19
20
  */
20
21
  export declare function runReport<T>(cacheKey: string, multi: boolean, exec: () => Promise<T>): Promise<T>;
21
- /** 1.1 Execution count per pipeline with status breakdown. */
22
+ /**
23
+ * One org-scoped report read: build the SQL from the org-scope predicate, run it
24
+ * in the tenant transaction and return the rows, through {@link runReport}'s
25
+ * cache/rollup policy. `key` is the cache key below the org.
26
+ */
27
+ export declare function report<T>(key: string, orgId: string, orgIds: string[] | undefined, query: (pred: SQL) => SQL): Promise<T[]>;
@@ -3,15 +3,15 @@
3
3
  /**
4
4
  * Tenancy scoping and cache/context policy for reporting reads.
5
5
  *
6
- * These were private methods on ReportingService. They hold no instance state —
7
- * only the module-level logger and timeseries cache — so they are plain
8
- * functions here, which is what lets the per-domain query modules (dora.ts)
9
- * use the identical scoping rules without reaching back into the class.
6
+ * Plain functions (no instance state — only the module-level logger and
7
+ * timeseries cache) so the per-domain query modules (dora.ts) use the identical
8
+ * scoping rules as ReportingService.
10
9
  */
11
10
  import { createLogger } from '@pipeline-builder/api-core';
12
11
  import { sql } from 'drizzle-orm';
13
12
  import { timeseriesCache } from './caches.js';
14
- import { runWithTenantContext } from '../../database/tenancy.js';
13
+ import { resultRows } from '../../database/pg-result.js';
14
+ import { runWithTenantContext, withTenantTx } from '../../database/tenancy.js';
15
15
  const logger = createLogger('reporting-service');
16
16
  /**
17
17
  * Build the org-scope predicate for a report query. With `orgIds` (the
@@ -58,5 +58,14 @@ export function runReport(cacheKey, multi, exec) {
58
58
  ? runWithTenantContext({ isSuperAdmin: true }, exec)
59
59
  : timeseriesCache.getOrSet(cacheKey, exec);
60
60
  }
61
- /** 1.1 Execution count per pipeline with status breakdown. */
62
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicXVlcnktc2NvcGUuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvYXBpL3JlcG9ydGluZy9xdWVyeS1zY29wZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSwrQ0FBK0M7QUFDL0Msc0NBQXNDO0FBRXRDOzs7Ozs7O0dBT0c7QUFFSCxPQUFPLEVBQUUsWUFBWSxFQUFFLE1BQU0sNEJBQTRCLENBQUM7QUFDMUQsT0FBTyxFQUFFLEdBQUcsRUFBRSxNQUFNLGFBQWEsQ0FBQztBQUNsQyxPQUFPLEVBQUUsZUFBZSxFQUFFLE1BQU0sYUFBYSxDQUFDO0FBQzlDLE9BQU8sRUFBRSxvQkFBb0IsRUFBRSxNQUFNLDJCQUEyQixDQUFDO0FBRWpFLE1BQU0sTUFBTSxHQUFHLFlBQVksQ0FBQyxtQkFBbUIsQ0FBQyxDQUFDO0FBRWpEOzs7Ozs7O0dBT0c7QUFDSCxNQUFNLFVBQVUsUUFBUSxDQUFDLEtBQWEsRUFBRSxNQUFpQjtJQUN2RCwwRUFBMEU7SUFDMUUsNkVBQTZFO0lBQzdFLDhFQUE4RTtJQUM5RSw2RUFBNkU7SUFDN0UsNkVBQTZFO0lBQzdFLDZFQUE2RTtJQUM3RSw2RUFBNkU7SUFDN0Usd0VBQXdFO0lBQ3hFLGdEQUFnRDtJQUNoRCxNQUFNLE1BQU0sR0FBRyxLQUFLLENBQUMsV0FBVyxFQUFFLENBQUM7SUFDbkMsTUFBTSxRQUFRLEdBQUcsQ0FBQyxNQUFNLElBQUksRUFBRSxDQUFDLENBQUMsTUFBTSxDQUFDLENBQUMsRUFBRSxFQUFFLEVBQUUsQ0FBQyxPQUFPLEVBQUUsS0FBSyxRQUFRLElBQUksRUFBRSxDQUFDLE1BQU0sR0FBRyxDQUFDLENBQUMsQ0FBQztJQUN4RixNQUFNLFFBQVEsR0FBRyxRQUFRLENBQUMsSUFBSSxDQUFDLENBQUMsRUFBRSxFQUFFLEVBQUUsQ0FBQyxFQUFFLENBQUMsV0FBVyxFQUFFLEtBQUssTUFBTSxDQUFDLENBQUM7SUFDcEUsSUFBSSxRQUFRLENBQUMsTUFBTSxHQUFHLENBQUMsSUFBSSxDQUFDLFFBQVEsRUFBRSxDQUFDO1FBQ3JDLE1BQU0sQ0FBQyxJQUFJLENBQUMsZ0dBQWdHLEVBQUU7WUFDNUcsS0FBSyxFQUFFLE1BQU0sRUFBRSxXQUFXLEVBQUUsUUFBUSxDQUFDLE1BQU07U0FDNUMsQ0FBQyxDQUFDO0lBQ0wsQ0FBQztJQUNELE1BQU0sR0FBRyxHQUFHLFFBQVEsQ0FBQyxNQUFNLEdBQUcsQ0FBQyxJQUFJLFFBQVEsQ0FBQyxDQUFDLENBQUMsUUFBUSxDQUFDLENBQUMsQ0FBQyxDQUFDLEtBQUssQ0FBQyxDQUFDO0lBQ2pFLE1BQU0sS0FBSyxHQUFHLEdBQUcsQ0FBQyxNQUFNLEdBQUcsQ0FBQyxDQUFDO0lBQzdCLE1BQU0sSUFBSSxHQUFHLEtBQUs7UUFDaEIsQ0FBQyxDQUFDLEdBQUcsQ0FBQSxPQUFPLEdBQUcsQ0FBQyxJQUFJLENBQUMsR0FBRyxDQUFDLEdBQUcsQ0FBQyxDQUFDLEVBQUUsRUFBRSxFQUFFLENBQUMsR0FBRyxDQUFBLEdBQUcsRUFBRSxFQUFFLENBQUMsRUFBRSxHQUFHLENBQUEsSUFBSSxDQUFDLEdBQUc7UUFDN0QsQ0FBQyxDQUFDLEdBQUcsQ0FBQSxLQUFLLEdBQUcsQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDO0lBQ3JCLE9BQU8sRUFBRSxJQUFJLEVBQUUsS0FBSyxFQUFFLENBQUM7QUFDekIsQ0FBQztBQUVEOzs7Ozs7R0FNRztBQUNILE1BQU0sVUFBVSxTQUFTLENBQUksUUFBZ0IsRUFBRSxLQUFjLEVBQUUsSUFBc0I7SUFDbkYsT0FBTyxLQUFLO1FBQ1YsQ0FBQyxDQUFDLG9CQUFvQixDQUFDLEVBQUUsWUFBWSxFQUFFLElBQUksRUFBRSxFQUFFLElBQUksQ0FBQztRQUNwRCxDQUFDLENBQUMsZUFBZSxDQUFDLFFBQVEsQ0FBQyxRQUFRLEVBQUUsSUFBSSxDQUFDLENBQUM7QUFDL0MsQ0FBQztBQUVELDhEQUE4RCIsInNvdXJjZXNDb250ZW50IjpbIi8vIENvcHlyaWdodCAyMDI2IFBpcGVsaW5lIEJ1aWxkZXIgQ29udHJpYnV0b3JzXG4vLyBTUERYLUxpY2Vuc2UtSWRlbnRpZmllcjogQXBhY2hlLTIuMFxuXG4vKipcbiAqIFRlbmFuY3kgc2NvcGluZyBhbmQgY2FjaGUvY29udGV4dCBwb2xpY3kgZm9yIHJlcG9ydGluZyByZWFkcy5cbiAqXG4gKiBUaGVzZSB3ZXJlIHByaXZhdGUgbWV0aG9kcyBvbiBSZXBvcnRpbmdTZXJ2aWNlLiBUaGV5IGhvbGQgbm8gaW5zdGFuY2Ugc3RhdGUg4oCUXG4gKiBvbmx5IHRoZSBtb2R1bGUtbGV2ZWwgbG9nZ2VyIGFuZCB0aW1lc2VyaWVzIGNhY2hlIOKAlCBzbyB0aGV5IGFyZSBwbGFpblxuICogZnVuY3Rpb25zIGhlcmUsIHdoaWNoIGlzIHdoYXQgbGV0cyB0aGUgcGVyLWRvbWFpbiBxdWVyeSBtb2R1bGVzIChkb3JhLnRzKVxuICogdXNlIHRoZSBpZGVudGljYWwgc2NvcGluZyBydWxlcyB3aXRob3V0IHJlYWNoaW5nIGJhY2sgaW50byB0aGUgY2xhc3MuXG4gKi9cblxuaW1wb3J0IHsgY3JlYXRlTG9nZ2VyIH0gZnJvbSAnQHBpcGVsaW5lLWJ1aWxkZXIvYXBpLWNvcmUnO1xuaW1wb3J0IHsgc3FsIH0gZnJvbSAnZHJpenpsZS1vcm0nO1xuaW1wb3J0IHsgdGltZXNlcmllc0NhY2hlIH0gZnJvbSAnLi9jYWNoZXMuanMnO1xuaW1wb3J0IHsgcnVuV2l0aFRlbmFudENvbnRleHQgfSBmcm9tICcuLi8uLi9kYXRhYmFzZS90ZW5hbmN5LmpzJztcblxuY29uc3QgbG9nZ2VyID0gY3JlYXRlTG9nZ2VyKCdyZXBvcnRpbmctc2VydmljZScpO1xuXG4vKipcbiAqIEJ1aWxkIHRoZSBvcmctc2NvcGUgcHJlZGljYXRlIGZvciBhIHJlcG9ydCBxdWVyeS4gV2l0aCBgb3JnSWRzYCAodGhlXG4gKiBvcmcg4oaSIHRlYW0gcm9sbHVwIOKAlCBhIHBhcmVudCdzIGBbc2VsZiwgLi4uZGVzY2VuZGFudHNdYCkgaXQgYmVjb21lcyBhblxuICogYElOICguLi4pYCBvdmVyIHRoZSBzdWJ0cmVlOyBvdGhlcndpc2UgdGhlIHNpbmdsZS1vcmcgYD0gJG9yZ2AuIFJldHVybnMgYVxuICogYG11bHRpYCBmbGFnIHNvIGNhbGxlcnMgY2FuIHJ1biBtdWx0aS1vcmcgcmVhZHMgdW5kZXIgc3lzYWRtaW4gY29udGV4dFxuICogKHRoZSBzdWJ0cmVlIHNwYW5zIG9yZ3Mgb3V0c2lkZSB0aGUgcmVxdWVzdCdzIFJMUyBzY29wZSkgYW5kIHNhbHQgdGhlXG4gKiBjYWNoZSBrZXkuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBvcmdTY29wZShvcmdJZDogc3RyaW5nLCBvcmdJZHM/OiBzdHJpbmdbXSkge1xuICAvLyBEZWZlbnNlLWluLWRlcHRoOiB0aGUgbXVsdGktb3JnIHJvbGx1cCBydW5zIHVuZGVyIHN5c2FkbWluIGNvbnRleHQgKFJMU1xuICAvLyBPRkYsIHNlZSBydW5SZXBvcnQpLCBzbyBgb3JnSWRzYCBpcyB0aGUgT05MWSB0ZW5hbmN5IGdhdGUgb24gdGhlIHJlYWQuIFRoZVxuICAvLyByb3V0ZSByZXNvbHZlcyBpdCBmcm9tIHRoZSBwbGF0Zm9ybSdzIGF1dGhvcml0YXRpdmUgZGVzY2VuZGFudHMgZW5kcG9pbnQgYXNcbiAgLy8gYFtzZWxmLCAuLi5kZXNjZW5kYW50c11gLCBidXQgdmFsaWRhdGUgdGhlIHN1YnRyZWUgZGVmZW5zaXZlbHkgaGVyZSBiZWZvcmVcbiAgLy8gdGhlIGJ5cGFzczogdGhlIHJlcXVlc3RpbmcgKGFuY2hvcikgb3JnIE1VU1QgYXBwZWFyIGluIHRoZSBzZXQuIEEgc2V0IHRoYXRcbiAgLy8gb21pdHMgdGhlIGNhbGxlcidzIG93biBvcmcgaXMgYSBtYWxmb3JtZWQvc3Bvb2ZlZCByb2xsdXAg4oCUIGNvbGxhcHNlIHRvIHRoZVxuICAvLyBzYWZlIHNpbmdsZS1vcmcgc2NvcGUgcmF0aGVyIHRoYW4gcmVhZGluZyBhbiBhcmJpdHJhcnkgb3JnIHVuZGVyIHN5c2FkbWluLlxuICAvLyAoRnVsbCBkZXNjZW5kYW50LW1lbWJlcnNoaXAgdmFsaWRhdGlvbiBuZWVkcyB0aGUgb3JnIHRyZWUsIHdoaWNoIHRoaXNcbiAgLy8gc2VydmljZSBkb2VzIG5vdCBob2xkIOKAlCBzZWUgdGhlIHJlcG9ydCBGTEFHLilcbiAgY29uc3QgYW5jaG9yID0gb3JnSWQudG9Mb3dlckNhc2UoKTtcbiAgY29uc3QgcHJvdmlkZWQgPSAob3JnSWRzID8/IFtdKS5maWx0ZXIoKGlkKSA9PiB0eXBlb2YgaWQgPT09ICdzdHJpbmcnICYmIGlkLmxlbmd0aCA+IDApO1xuICBjb25zdCBhbmNob3JlZCA9IHByb3ZpZGVkLnNvbWUoKGlkKSA9PiBpZC50b0xvd2VyQ2FzZSgpID09PSBhbmNob3IpO1xuICBpZiAocHJvdmlkZWQubGVuZ3RoID4gMCAmJiAhYW5jaG9yZWQpIHtcbiAgICBsb2dnZXIud2FybignUmVwb3J0aW5nIHJvbGx1cCByZWplY3RlZDogcmVxdWVzdGluZyBvcmcgYWJzZW50IGZyb20gcmVzb2x2ZWQgc3VidHJlZTsgdXNpbmcgc2luZ2xlLW9yZyBzY29wZScsIHtcbiAgICAgIG9yZ0lkOiBhbmNob3IsIHN1YnRyZWVTaXplOiBwcm92aWRlZC5sZW5ndGgsXG4gICAgfSk7XG4gIH1cbiAgY29uc3QgaWRzID0gcHJvdmlkZWQubGVuZ3RoID4gMCAmJiBhbmNob3JlZCA/IHByb3ZpZGVkIDogW29yZ0lkXTtcbiAgY29uc3QgbXVsdGkgPSBpZHMubGVuZ3RoID4gMTtcbiAgY29uc3QgcHJlZCA9IG11bHRpXG4gICAgPyBzcWxgSU4gKCR7c3FsLmpvaW4oaWRzLm1hcCgoaWQpID0+IHNxbGAke2lkfWApLCBzcWxgLCBgKX0pYFxuICAgIDogc3FsYD0gJHtpZHNbMF19YDtcbiAgcmV0dXJuIHsgcHJlZCwgbXVsdGkgfTtcbn1cblxuLyoqXG4gKiBSdW4gYSByZXBvcnQgcmVhZC4gU2luZ2xlLW9yZyByZWFkcyB1c2UgdGhlIHBlci1vcmcgY2FjaGUgKGludmFsaWRhdGVkIG9uXG4gKiB0aGF0IG9yZydzIGV2ZW50IGluZ2VzdCkuIFJvbGx1cCAobXVsdGktb3JnKSByZWFkcyAqKmJ5cGFzcyB0aGUgY2FjaGUqKiBhbmRcbiAqIHJ1biB1bmRlciBzeXNhZG1pbiBjb250ZXh0OiB0aGV5J3JlIGFkbWluLW9ubHkgYW5kIGxvd2VyLWZyZXF1ZW5jeSwgYW5kIGFcbiAqIGNoaWxkIG9yZydzIGV2ZW50IGluZ2VzdCBjYW4ndCBpbnZhbGlkYXRlIGEgcGFyZW50J3Mgcm9sbHVwIGVudHJ5IChyZXBvcnRpbmdcbiAqIGhhcyBubyBvcmcgdHJlZSksIHNvIGNhY2hpbmcgdGhlbSB3b3VsZCBzZXJ2ZSBzdGFsZSBhZ2dyZWdhdGVzLiBBbHdheXMgZnJlc2guXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBydW5SZXBvcnQ8VD4oY2FjaGVLZXk6IHN0cmluZywgbXVsdGk6IGJvb2xlYW4sIGV4ZWM6ICgpID0+IFByb21pc2U8VD4pOiBQcm9taXNlPFQ+IHtcbiAgcmV0dXJuIG11bHRpXG4gICAgPyBydW5XaXRoVGVuYW50Q29udGV4dCh7IGlzU3VwZXJBZG1pbjogdHJ1ZSB9LCBleGVjKVxuICAgIDogdGltZXNlcmllc0NhY2hlLmdldE9yU2V0KGNhY2hlS2V5LCBleGVjKTtcbn1cblxuLyoqIDEuMSBFeGVjdXRpb24gY291bnQgcGVyIHBpcGVsaW5lIHdpdGggc3RhdHVzIGJyZWFrZG93bi4gKi9cbiJdfQ==
61
+ /**
62
+ * One org-scoped report read: build the SQL from the org-scope predicate, run it
63
+ * in the tenant transaction and return the rows, through {@link runReport}'s
64
+ * cache/rollup policy. `key` is the cache key below the org.
65
+ */
66
+ export function report(key, orgId, orgIds, query) {
67
+ const { pred, multi } = orgScope(orgId, orgIds);
68
+ const exec = () => withTenantTx((tx) => tx.execute(query(pred))).then((r) => resultRows(r));
69
+ return runReport(`${orgId}:${key}`, multi, exec);
70
+ }
71
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicXVlcnktc2NvcGUuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvYXBpL3JlcG9ydGluZy9xdWVyeS1zY29wZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSwrQ0FBK0M7QUFDL0Msc0NBQXNDO0FBRXRDOzs7Ozs7R0FNRztBQUVILE9BQU8sRUFBRSxZQUFZLEVBQUUsTUFBTSw0QkFBNEIsQ0FBQztBQUMxRCxPQUFPLEVBQUUsR0FBRyxFQUFZLE1BQU0sYUFBYSxDQUFDO0FBQzVDLE9BQU8sRUFBRSxlQUFlLEVBQUUsTUFBTSxhQUFhLENBQUM7QUFDOUMsT0FBTyxFQUFFLFVBQVUsRUFBRSxNQUFNLDZCQUE2QixDQUFDO0FBQ3pELE9BQU8sRUFBRSxvQkFBb0IsRUFBRSxZQUFZLEVBQUUsTUFBTSwyQkFBMkIsQ0FBQztBQUUvRSxNQUFNLE1BQU0sR0FBRyxZQUFZLENBQUMsbUJBQW1CLENBQUMsQ0FBQztBQUVqRDs7Ozs7OztHQU9HO0FBQ0gsTUFBTSxVQUFVLFFBQVEsQ0FBQyxLQUFhLEVBQUUsTUFBaUI7SUFDdkQsMEVBQTBFO0lBQzFFLDZFQUE2RTtJQUM3RSw4RUFBOEU7SUFDOUUsNkVBQTZFO0lBQzdFLDZFQUE2RTtJQUM3RSw2RUFBNkU7SUFDN0UsNkVBQTZFO0lBQzdFLHdFQUF3RTtJQUN4RSxnREFBZ0Q7SUFDaEQsTUFBTSxNQUFNLEdBQUcsS0FBSyxDQUFDLFdBQVcsRUFBRSxDQUFDO0lBQ25DLE1BQU0sUUFBUSxHQUFHLENBQUMsTUFBTSxJQUFJLEVBQUUsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxDQUFDLEVBQUUsRUFBRSxFQUFFLENBQUMsT0FBTyxFQUFFLEtBQUssUUFBUSxJQUFJLEVBQUUsQ0FBQyxNQUFNLEdBQUcsQ0FBQyxDQUFDLENBQUM7SUFDeEYsTUFBTSxRQUFRLEdBQUcsUUFBUSxDQUFDLElBQUksQ0FBQyxDQUFDLEVBQUUsRUFBRSxFQUFFLENBQUMsRUFBRSxDQUFDLFdBQVcsRUFBRSxLQUFLLE1BQU0sQ0FBQyxDQUFDO0lBQ3BFLElBQUksUUFBUSxDQUFDLE1BQU0sR0FBRyxDQUFDLElBQUksQ0FBQyxRQUFRLEVBQUUsQ0FBQztRQUNyQyxNQUFNLENBQUMsSUFBSSxDQUFDLGdHQUFnRyxFQUFFO1lBQzVHLEtBQUssRUFBRSxNQUFNLEVBQUUsV0FBVyxFQUFFLFFBQVEsQ0FBQyxNQUFNO1NBQzVDLENBQUMsQ0FBQztJQUNMLENBQUM7SUFDRCxNQUFNLEdBQUcsR0FBRyxRQUFRLENBQUMsTUFBTSxHQUFHLENBQUMsSUFBSSxRQUFRLENBQUMsQ0FBQyxDQUFDLFFBQVEsQ0FBQyxDQUFDLENBQUMsQ0FBQyxLQUFLLENBQUMsQ0FBQztJQUNqRSxNQUFNLEtBQUssR0FBRyxHQUFHLENBQUMsTUFBTSxHQUFHLENBQUMsQ0FBQztJQUM3QixNQUFNLElBQUksR0FBRyxLQUFLO1FBQ2hCLENBQUMsQ0FBQyxHQUFHLENBQUEsT0FBTyxHQUFHLENBQUMsSUFBSSxDQUFDLEdBQUcsQ0FBQyxHQUFHLENBQUMsQ0FBQyxFQUFFLEVBQUUsRUFBRSxDQUFDLEdBQUcsQ0FBQSxHQUFHLEVBQUUsRUFBRSxDQUFDLEVBQUUsR0FBRyxDQUFBLElBQUksQ0FBQyxHQUFHO1FBQzdELENBQUMsQ0FBQyxHQUFHLENBQUEsS0FBSyxHQUFHLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQztJQUNyQixPQUFPLEVBQUUsSUFBSSxFQUFFLEtBQUssRUFBRSxDQUFDO0FBQ3pCLENBQUM7QUFFRDs7Ozs7O0dBTUc7QUFDSCxNQUFNLFVBQVUsU0FBUyxDQUFJLFFBQWdCLEVBQUUsS0FBYyxFQUFFLElBQXNCO0lBQ25GLE9BQU8sS0FBSztRQUNWLENBQUMsQ0FBQyxvQkFBb0IsQ0FBQyxFQUFFLFlBQVksRUFBRSxJQUFJLEVBQUUsRUFBRSxJQUFJLENBQUM7UUFDcEQsQ0FBQyxDQUFDLGVBQWUsQ0FBQyxRQUFRLENBQUMsUUFBUSxFQUFFLElBQUksQ0FBQyxDQUFDO0FBQy9DLENBQUM7QUFFRDs7OztHQUlHO0FBQ0gsTUFBTSxVQUFVLE1BQU0sQ0FBSSxHQUFXLEVBQUUsS0FBYSxFQUFFLE1BQTRCLEVBQUUsS0FBeUI7SUFDM0csTUFBTSxFQUFFLElBQUksRUFBRSxLQUFLLEVBQUUsR0FBRyxRQUFRLENBQUMsS0FBSyxFQUFFLE1BQU0sQ0FBQyxDQUFDO0lBQ2hELE1BQU0sSUFBSSxHQUFHLEdBQUcsRUFBRSxDQUFDLFlBQVksQ0FBQyxDQUFDLEVBQUUsRUFBRSxFQUFFLENBQUMsRUFBRSxDQUFDLE9BQU8sQ0FBQyxLQUFLLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsRUFBRSxFQUFFLENBQUMsVUFBVSxDQUFJLENBQUMsQ0FBQyxDQUFDLENBQUM7SUFDL0YsT0FBTyxTQUFTLENBQUMsR0FBRyxLQUFLLElBQUksR0FBRyxFQUFFLEVBQUUsS0FBSyxFQUFFLElBQUksQ0FBQyxDQUFDO0FBQ25ELENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyIvLyBDb3B5cmlnaHQgMjAyNiBQaXBlbGluZSBCdWlsZGVyIENvbnRyaWJ1dG9yc1xuLy8gU1BEWC1MaWNlbnNlLUlkZW50aWZpZXI6IEFwYWNoZS0yLjBcblxuLyoqXG4gKiBUZW5hbmN5IHNjb3BpbmcgYW5kIGNhY2hlL2NvbnRleHQgcG9saWN5IGZvciByZXBvcnRpbmcgcmVhZHMuXG4gKlxuICogUGxhaW4gZnVuY3Rpb25zIChubyBpbnN0YW5jZSBzdGF0ZSDigJQgb25seSB0aGUgbW9kdWxlLWxldmVsIGxvZ2dlciBhbmRcbiAqIHRpbWVzZXJpZXMgY2FjaGUpIHNvIHRoZSBwZXItZG9tYWluIHF1ZXJ5IG1vZHVsZXMgKGRvcmEudHMpIHVzZSB0aGUgaWRlbnRpY2FsXG4gKiBzY29waW5nIHJ1bGVzIGFzIFJlcG9ydGluZ1NlcnZpY2UuXG4gKi9cblxuaW1wb3J0IHsgY3JlYXRlTG9nZ2VyIH0gZnJvbSAnQHBpcGVsaW5lLWJ1aWxkZXIvYXBpLWNvcmUnO1xuaW1wb3J0IHsgc3FsLCB0eXBlIFNRTCB9IGZyb20gJ2RyaXp6bGUtb3JtJztcbmltcG9ydCB7IHRpbWVzZXJpZXNDYWNoZSB9IGZyb20gJy4vY2FjaGVzLmpzJztcbmltcG9ydCB7IHJlc3VsdFJvd3MgfSBmcm9tICcuLi8uLi9kYXRhYmFzZS9wZy1yZXN1bHQuanMnO1xuaW1wb3J0IHsgcnVuV2l0aFRlbmFudENvbnRleHQsIHdpdGhUZW5hbnRUeCB9IGZyb20gJy4uLy4uL2RhdGFiYXNlL3RlbmFuY3kuanMnO1xuXG5jb25zdCBsb2dnZXIgPSBjcmVhdGVMb2dnZXIoJ3JlcG9ydGluZy1zZXJ2aWNlJyk7XG5cbi8qKlxuICogQnVpbGQgdGhlIG9yZy1zY29wZSBwcmVkaWNhdGUgZm9yIGEgcmVwb3J0IHF1ZXJ5LiBXaXRoIGBvcmdJZHNgICh0aGVcbiAqIG9yZyDihpIgdGVhbSByb2xsdXAg4oCUIGEgcGFyZW50J3MgYFtzZWxmLCAuLi5kZXNjZW5kYW50c11gKSBpdCBiZWNvbWVzIGFuXG4gKiBgSU4gKC4uLilgIG92ZXIgdGhlIHN1YnRyZWU7IG90aGVyd2lzZSB0aGUgc2luZ2xlLW9yZyBgPSAkb3JnYC4gUmV0dXJucyBhXG4gKiBgbXVsdGlgIGZsYWcgc28gY2FsbGVycyBjYW4gcnVuIG11bHRpLW9yZyByZWFkcyB1bmRlciBzeXNhZG1pbiBjb250ZXh0XG4gKiAodGhlIHN1YnRyZWUgc3BhbnMgb3JncyBvdXRzaWRlIHRoZSByZXF1ZXN0J3MgUkxTIHNjb3BlKSBhbmQgc2FsdCB0aGVcbiAqIGNhY2hlIGtleS5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIG9yZ1Njb3BlKG9yZ0lkOiBzdHJpbmcsIG9yZ0lkcz86IHN0cmluZ1tdKSB7XG4gIC8vIERlZmVuc2UtaW4tZGVwdGg6IHRoZSBtdWx0aS1vcmcgcm9sbHVwIHJ1bnMgdW5kZXIgc3lzYWRtaW4gY29udGV4dCAoUkxTXG4gIC8vIE9GRiwgc2VlIHJ1blJlcG9ydCksIHNvIGBvcmdJZHNgIGlzIHRoZSBPTkxZIHRlbmFuY3kgZ2F0ZSBvbiB0aGUgcmVhZC4gVGhlXG4gIC8vIHJvdXRlIHJlc29sdmVzIGl0IGZyb20gdGhlIHBsYXRmb3JtJ3MgYXV0aG9yaXRhdGl2ZSBkZXNjZW5kYW50cyBlbmRwb2ludCBhc1xuICAvLyBgW3NlbGYsIC4uLmRlc2NlbmRhbnRzXWAsIGJ1dCB2YWxpZGF0ZSB0aGUgc3VidHJlZSBkZWZlbnNpdmVseSBoZXJlIGJlZm9yZVxuICAvLyB0aGUgYnlwYXNzOiB0aGUgcmVxdWVzdGluZyAoYW5jaG9yKSBvcmcgTVVTVCBhcHBlYXIgaW4gdGhlIHNldC4gQSBzZXQgdGhhdFxuICAvLyBvbWl0cyB0aGUgY2FsbGVyJ3Mgb3duIG9yZyBpcyBhIG1hbGZvcm1lZC9zcG9vZmVkIHJvbGx1cCDigJQgY29sbGFwc2UgdG8gdGhlXG4gIC8vIHNhZmUgc2luZ2xlLW9yZyBzY29wZSByYXRoZXIgdGhhbiByZWFkaW5nIGFuIGFyYml0cmFyeSBvcmcgdW5kZXIgc3lzYWRtaW4uXG4gIC8vIChGdWxsIGRlc2NlbmRhbnQtbWVtYmVyc2hpcCB2YWxpZGF0aW9uIG5lZWRzIHRoZSBvcmcgdHJlZSwgd2hpY2ggdGhpc1xuICAvLyBzZXJ2aWNlIGRvZXMgbm90IGhvbGQg4oCUIHNlZSB0aGUgcmVwb3J0IEZMQUcuKVxuICBjb25zdCBhbmNob3IgPSBvcmdJZC50b0xvd2VyQ2FzZSgpO1xuICBjb25zdCBwcm92aWRlZCA9IChvcmdJZHMgPz8gW10pLmZpbHRlcigoaWQpID0+IHR5cGVvZiBpZCA9PT0gJ3N0cmluZycgJiYgaWQubGVuZ3RoID4gMCk7XG4gIGNvbnN0IGFuY2hvcmVkID0gcHJvdmlkZWQuc29tZSgoaWQpID0+IGlkLnRvTG93ZXJDYXNlKCkgPT09IGFuY2hvcik7XG4gIGlmIChwcm92aWRlZC5sZW5ndGggPiAwICYmICFhbmNob3JlZCkge1xuICAgIGxvZ2dlci53YXJuKCdSZXBvcnRpbmcgcm9sbHVwIHJlamVjdGVkOiByZXF1ZXN0aW5nIG9yZyBhYnNlbnQgZnJvbSByZXNvbHZlZCBzdWJ0cmVlOyB1c2luZyBzaW5nbGUtb3JnIHNjb3BlJywge1xuICAgICAgb3JnSWQ6IGFuY2hvciwgc3VidHJlZVNpemU6IHByb3ZpZGVkLmxlbmd0aCxcbiAgICB9KTtcbiAgfVxuICBjb25zdCBpZHMgPSBwcm92aWRlZC5sZW5ndGggPiAwICYmIGFuY2hvcmVkID8gcHJvdmlkZWQgOiBbb3JnSWRdO1xuICBjb25zdCBtdWx0aSA9IGlkcy5sZW5ndGggPiAxO1xuICBjb25zdCBwcmVkID0gbXVsdGlcbiAgICA/IHNxbGBJTiAoJHtzcWwuam9pbihpZHMubWFwKChpZCkgPT4gc3FsYCR7aWR9YCksIHNxbGAsIGApfSlgXG4gICAgOiBzcWxgPSAke2lkc1swXX1gO1xuICByZXR1cm4geyBwcmVkLCBtdWx0aSB9O1xufVxuXG4vKipcbiAqIFJ1biBhIHJlcG9ydCByZWFkLiBTaW5nbGUtb3JnIHJlYWRzIHVzZSB0aGUgcGVyLW9yZyBjYWNoZSAoaW52YWxpZGF0ZWQgb25cbiAqIHRoYXQgb3JnJ3MgZXZlbnQgaW5nZXN0KS4gUm9sbHVwIChtdWx0aS1vcmcpIHJlYWRzICoqYnlwYXNzIHRoZSBjYWNoZSoqIGFuZFxuICogcnVuIHVuZGVyIHN5c2FkbWluIGNvbnRleHQ6IHRoZXkncmUgYWRtaW4tb25seSBhbmQgbG93ZXItZnJlcXVlbmN5LCBhbmQgYVxuICogY2hpbGQgb3JnJ3MgZXZlbnQgaW5nZXN0IGNhbid0IGludmFsaWRhdGUgYSBwYXJlbnQncyByb2xsdXAgZW50cnkgKHJlcG9ydGluZ1xuICogaGFzIG5vIG9yZyB0cmVlKSwgc28gY2FjaGluZyB0aGVtIHdvdWxkIHNlcnZlIHN0YWxlIGFnZ3JlZ2F0ZXMuIEFsd2F5cyBmcmVzaC5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHJ1blJlcG9ydDxUPihjYWNoZUtleTogc3RyaW5nLCBtdWx0aTogYm9vbGVhbiwgZXhlYzogKCkgPT4gUHJvbWlzZTxUPik6IFByb21pc2U8VD4ge1xuICByZXR1cm4gbXVsdGlcbiAgICA/IHJ1bldpdGhUZW5hbnRDb250ZXh0KHsgaXNTdXBlckFkbWluOiB0cnVlIH0sIGV4ZWMpXG4gICAgOiB0aW1lc2VyaWVzQ2FjaGUuZ2V0T3JTZXQoY2FjaGVLZXksIGV4ZWMpO1xufVxuXG4vKipcbiAqIE9uZSBvcmctc2NvcGVkIHJlcG9ydCByZWFkOiBidWlsZCB0aGUgU1FMIGZyb20gdGhlIG9yZy1zY29wZSBwcmVkaWNhdGUsIHJ1biBpdFxuICogaW4gdGhlIHRlbmFudCB0cmFuc2FjdGlvbiBhbmQgcmV0dXJuIHRoZSByb3dzLCB0aHJvdWdoIHtAbGluayBydW5SZXBvcnR9J3NcbiAqIGNhY2hlL3JvbGx1cCBwb2xpY3kuIGBrZXlgIGlzIHRoZSBjYWNoZSBrZXkgYmVsb3cgdGhlIG9yZy5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHJlcG9ydDxUPihrZXk6IHN0cmluZywgb3JnSWQ6IHN0cmluZywgb3JnSWRzOiBzdHJpbmdbXSB8IHVuZGVmaW5lZCwgcXVlcnk6IChwcmVkOiBTUUwpID0+IFNRTCk6IFByb21pc2U8VFtdPiB7XG4gIGNvbnN0IHsgcHJlZCwgbXVsdGkgfSA9IG9yZ1Njb3BlKG9yZ0lkLCBvcmdJZHMpO1xuICBjb25zdCBleGVjID0gKCkgPT4gd2l0aFRlbmFudFR4KCh0eCkgPT4gdHguZXhlY3V0ZShxdWVyeShwcmVkKSkpLnRoZW4oKHIpID0+IHJlc3VsdFJvd3M8VD4ocikpO1xuICByZXR1cm4gcnVuUmVwb3J0KGAke29yZ0lkfToke2tleX1gLCBtdWx0aSwgZXhlYyk7XG59XG4iXX0=
@@ -1,9 +1,5 @@
1
1
  /**
2
- * Retention windows for reporting data: env-configurable, clamped to a sane
3
- * range, and overridable per-org by the settings row.
4
- */
5
- /**
6
- * Reporting retention windows (Phase 7). Records in `pipeline_events`,
2
+ * Reporting retention windows. Records in `pipeline_events`,
7
3
  * `deployment_outcomes`, and `incidents` grow unbounded without a sweep, so a
8
4
  * split, per-org retention purge (see {@link ReportingService.purgeExpiredReportingData})
9
5
  * hard-deletes rows older than these windows, by `created_at`:
@@ -17,22 +13,20 @@
17
13
  * `ingest_health` and `dora_settings` are never purged. Env-overridable globals;
18
14
  * a per-org override in `dora_settings` wins (see {@link resolveEventRetentionDays}).
19
15
  */
20
- export declare const RETENTION_MIN_DAYS = 1;
21
- export declare const RETENTION_MAX_DAYS = 730;
22
16
  /** Parse a positive-int env day-count, clamped to [MIN, MAX], else `fallback`. */
23
17
  export declare function retentionEnvDays(name: string, fallback: number): number;
24
18
  export declare const REPORTING_EVENT_RETENTION_DAYS: number;
25
19
  export declare const REPORTING_DORA_RETENTION_DAYS: number;
26
20
  /** Effective standard-event retention (days): a valid per-org override wins,
27
21
  * else the global env default. Shared by the sweep + the settings surface so
28
- * they can't drift. The `-1` unlimited sentinel (Phase 8) passes straight
22
+ * they can't drift. The `-1` unlimited sentinel passes straight
29
23
  * through — the sweep reads it as "keep forever, skip this org's standard
30
24
  * events". A positive override clamps to [1, RETENTION_MAX_DAYS]; a `null`, a
31
25
  * non-integer, or any other out-of-range value (e.g. 0, -2) falls back to the
32
26
  * env default. */
33
27
  export declare function resolveEventRetentionDays(override?: number | null): number;
34
28
  /** Effective DORA-source retention (days): a valid per-org override wins, else
35
- * the global env default. The `-1` unlimited sentinel (Phase 8) passes straight
29
+ * the global env default. The `-1` unlimited sentinel passes straight
36
30
  * through — the sweep reads it as "keep forever, skip this org's DORA-source
37
31
  * windows". A positive override clamps to [1, RETENTION_MAX_DAYS]; a `null`, a
38
32
  * non-integer, or any other out-of-range value (e.g. 0, -2) falls back to the
@@ -41,4 +35,4 @@ export declare function resolveDoraRetentionDays(override?: number | null): numb
41
35
  /** The cutoff instant for a retention window: rows with `created_at` strictly
42
36
  * before this (`< cutoff`) are expired. Deterministic for a fixed `now`. */
43
37
  export declare function retentionCutoff(now: Date, days: number): Date;
44
- /** Per-org retention override row (Phase 7). Both nullable ⇒ global defaults. */
38
+ /** Per-org retention override row. Both nullable ⇒ global defaults. */
@@ -4,8 +4,9 @@
4
4
  * Retention windows for reporting data: env-configurable, clamped to a sane
5
5
  * range, and overridable per-org by the settings row.
6
6
  */
7
+ import { envInt, RETENTION_MAX_DAYS, RETENTION_MIN_DAYS } from '@pipeline-builder/api-core';
7
8
  /**
8
- * Reporting retention windows (Phase 7). Records in `pipeline_events`,
9
+ * Reporting retention windows. Records in `pipeline_events`,
9
10
  * `deployment_outcomes`, and `incidents` grow unbounded without a sweep, so a
10
11
  * split, per-org retention purge (see {@link ReportingService.purgeExpiredReportingData})
11
12
  * hard-deletes rows older than these windows, by `created_at`:
@@ -19,20 +20,16 @@
19
20
  * `ingest_health` and `dora_settings` are never purged. Env-overridable globals;
20
21
  * a per-org override in `dora_settings` wins (see {@link resolveEventRetentionDays}).
21
22
  */
22
- export const RETENTION_MIN_DAYS = 1;
23
- export const RETENTION_MAX_DAYS = 730;
24
23
  /** Parse a positive-int env day-count, clamped to [MIN, MAX], else `fallback`. */
25
24
  export function retentionEnvDays(name, fallback) {
26
- const raw = Number(process.env[name]);
27
- if (!Number.isFinite(raw) || !Number.isInteger(raw) || raw < RETENTION_MIN_DAYS)
28
- return fallback;
29
- return Math.min(raw, RETENTION_MAX_DAYS);
25
+ const days = envInt(name, fallback);
26
+ return days < RETENTION_MIN_DAYS ? fallback : Math.min(days, RETENTION_MAX_DAYS);
30
27
  }
31
28
  export const REPORTING_EVENT_RETENTION_DAYS = retentionEnvDays('REPORTING_EVENT_RETENTION_DAYS', 30);
32
29
  export const REPORTING_DORA_RETENTION_DAYS = retentionEnvDays('REPORTING_DORA_RETENTION_DAYS', 180);
33
30
  /** Effective standard-event retention (days): a valid per-org override wins,
34
31
  * else the global env default. Shared by the sweep + the settings surface so
35
- * they can't drift. The `-1` unlimited sentinel (Phase 8) passes straight
32
+ * they can't drift. The `-1` unlimited sentinel passes straight
36
33
  * through — the sweep reads it as "keep forever, skip this org's standard
37
34
  * events". A positive override clamps to [1, RETENTION_MAX_DAYS]; a `null`, a
38
35
  * non-integer, or any other out-of-range value (e.g. 0, -2) falls back to the
@@ -44,7 +41,7 @@ export function resolveEventRetentionDays(override) {
44
41
  ? Math.min(override, RETENTION_MAX_DAYS) : REPORTING_EVENT_RETENTION_DAYS;
45
42
  }
46
43
  /** Effective DORA-source retention (days): a valid per-org override wins, else
47
- * the global env default. The `-1` unlimited sentinel (Phase 8) passes straight
44
+ * the global env default. The `-1` unlimited sentinel passes straight
48
45
  * through — the sweep reads it as "keep forever, skip this org's DORA-source
49
46
  * windows". A positive override clamps to [1, RETENTION_MAX_DAYS]; a `null`, a
50
47
  * non-integer, or any other out-of-range value (e.g. 0, -2) falls back to the
@@ -60,5 +57,5 @@ export function resolveDoraRetentionDays(override) {
60
57
  export function retentionCutoff(now, days) {
61
58
  return new Date(now.getTime() - days * 86_400_000);
62
59
  }
63
- /** Per-org retention override row (Phase 7). Both nullable ⇒ global defaults. */
64
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicmV0ZW50aW9uLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vc3JjL2FwaS9yZXBvcnRpbmcvcmV0ZW50aW9uLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLCtDQUErQztBQUMvQyxzQ0FBc0M7QUFFdEM7OztHQUdHO0FBRUg7Ozs7Ozs7Ozs7Ozs7O0dBY0c7QUFDSCxNQUFNLENBQUMsTUFBTSxrQkFBa0IsR0FBRyxDQUFDLENBQUM7QUFDcEMsTUFBTSxDQUFDLE1BQU0sa0JBQWtCLEdBQUcsR0FBRyxDQUFDO0FBRXRDLGtGQUFrRjtBQUNsRixNQUFNLFVBQVUsZ0JBQWdCLENBQUMsSUFBWSxFQUFFLFFBQWdCO0lBQzdELE1BQU0sR0FBRyxHQUFHLE1BQU0sQ0FBQyxPQUFPLENBQUMsR0FBRyxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUM7SUFDdEMsSUFBSSxDQUFDLE1BQU0sQ0FBQyxRQUFRLENBQUMsR0FBRyxDQUFDLElBQUksQ0FBQyxNQUFNLENBQUMsU0FBUyxDQUFDLEdBQUcsQ0FBQyxJQUFJLEdBQUcsR0FBRyxrQkFBa0I7UUFBRSxPQUFPLFFBQVEsQ0FBQztJQUNqRyxPQUFPLElBQUksQ0FBQyxHQUFHLENBQUMsR0FBRyxFQUFFLGtCQUFrQixDQUFDLENBQUM7QUFDM0MsQ0FBQztBQUVELE1BQU0sQ0FBQyxNQUFNLDhCQUE4QixHQUFHLGdCQUFnQixDQUFDLGdDQUFnQyxFQUFFLEVBQUUsQ0FBQyxDQUFDO0FBQ3JHLE1BQU0sQ0FBQyxNQUFNLDZCQUE2QixHQUFHLGdCQUFnQixDQUFDLCtCQUErQixFQUFFLEdBQUcsQ0FBQyxDQUFDO0FBRXBHOzs7Ozs7bUJBTW1CO0FBQ25CLE1BQU0sVUFBVSx5QkFBeUIsQ0FBQyxRQUF3QjtJQUNoRSxJQUFJLFFBQVEsS0FBSyxDQUFDLENBQUM7UUFBRSxPQUFPLENBQUMsQ0FBQyxDQUFDO0lBQy9CLE9BQU8sUUFBUSxJQUFJLElBQUksSUFBSSxNQUFNLENBQUMsU0FBUyxDQUFDLFFBQVEsQ0FBQyxJQUFJLFFBQVEsSUFBSSxrQkFBa0I7UUFDckYsQ0FBQyxDQUFDLElBQUksQ0FBQyxHQUFHLENBQUMsUUFBUSxFQUFFLGtCQUFrQixDQUFDLENBQUMsQ0FBQyxDQUFDLDhCQUE4QixDQUFDO0FBQzlFLENBQUM7QUFFRDs7Ozs7bUJBS21CO0FBQ25CLE1BQU0sVUFBVSx3QkFBd0IsQ0FBQyxRQUF3QjtJQUMvRCxJQUFJLFFBQVEsS0FBSyxDQUFDLENBQUM7UUFBRSxPQUFPLENBQUMsQ0FBQyxDQUFDO0lBQy9CLE9BQU8sUUFBUSxJQUFJLElBQUksSUFBSSxNQUFNLENBQUMsU0FBUyxDQUFDLFFBQVEsQ0FBQyxJQUFJLFFBQVEsSUFBSSxrQkFBa0I7UUFDckYsQ0FBQyxDQUFDLElBQUksQ0FBQyxHQUFHLENBQUMsUUFBUSxFQUFFLGtCQUFrQixDQUFDLENBQUMsQ0FBQyxDQUFDLDZCQUE2QixDQUFDO0FBQzdFLENBQUM7QUFFRDs2RUFDNkU7QUFDN0UsTUFBTSxVQUFVLGVBQWUsQ0FBQyxHQUFTLEVBQUUsSUFBWTtJQUNyRCxPQUFPLElBQUksSUFBSSxDQUFDLEdBQUcsQ0FBQyxPQUFPLEVBQUUsR0FBRyxJQUFJLEdBQUcsVUFBVSxDQUFDLENBQUM7QUFDckQsQ0FBQztBQUVELGlGQUFpRiIsInNvdXJjZXNDb250ZW50IjpbIi8vIENvcHlyaWdodCAyMDI2IFBpcGVsaW5lIEJ1aWxkZXIgQ29udHJpYnV0b3JzXG4vLyBTUERYLUxpY2Vuc2UtSWRlbnRpZmllcjogQXBhY2hlLTIuMFxuXG4vKipcbiAqIFJldGVudGlvbiB3aW5kb3dzIGZvciByZXBvcnRpbmcgZGF0YTogZW52LWNvbmZpZ3VyYWJsZSwgY2xhbXBlZCB0byBhIHNhbmVcbiAqIHJhbmdlLCBhbmQgb3ZlcnJpZGFibGUgcGVyLW9yZyBieSB0aGUgc2V0dGluZ3Mgcm93LlxuICovXG5cbi8qKlxuICogUmVwb3J0aW5nIHJldGVudGlvbiB3aW5kb3dzIChQaGFzZSA3KS4gUmVjb3JkcyBpbiBgcGlwZWxpbmVfZXZlbnRzYCxcbiAqIGBkZXBsb3ltZW50X291dGNvbWVzYCwgYW5kIGBpbmNpZGVudHNgIGdyb3cgdW5ib3VuZGVkIHdpdGhvdXQgYSBzd2VlcCwgc28gYVxuICogc3BsaXQsIHBlci1vcmcgcmV0ZW50aW9uIHB1cmdlIChzZWUge0BsaW5rIFJlcG9ydGluZ1NlcnZpY2UucHVyZ2VFeHBpcmVkUmVwb3J0aW5nRGF0YX0pXG4gKiBoYXJkLWRlbGV0ZXMgcm93cyBvbGRlciB0aGFuIHRoZXNlIHdpbmRvd3MsIGJ5IGBjcmVhdGVkX2F0YDpcbiAqICAtICoqU3RhbmRhcmQgZXZlbnRzKiog4oCUIGBwaXBlbGluZV9ldmVudHNgIHdpdGggYGVudmlyb25tZW50IElTIE5VTExgXG4gKiAgICAobm9uLWRlcGxveSBTVEFHRS9BQ1RJT04vYnVpbGQpLiBIaWdoIHZvbHVtZSDihpIgc2hvcnQgZGVmYXVsdCAoMzAgZGF5cykuXG4gKiAgLSAqKkRPUkEgc291cmNlKiog4oCUIGBwaXBlbGluZV9ldmVudHNgIHdpdGggYGVudmlyb25tZW50IElTIE5PVCBOVUxMYCAoZGVwbG95XG4gKiAgICBzdGFnZXMpIHBsdXMgYWxsIG9mIGBkZXBsb3ltZW50X291dGNvbWVzYCBhbmQgYGluY2lkZW50c2AuIExvdyB2b2x1bWUg4oaSXG4gKiAgICBsb25nZXIgZGVmYXVsdCAoMTgwIGRheXMpLiBET1JBIGhpc3RvcnkgaXMgdGhlcmVmb3JlIGJvdW5kZWQgYnkgdGhpcyB3aW5kb3c7XG4gKiAgICB0aGUgcmVwb3J0IHF1ZXJ5IHN0aWxsIGhhcmQtY2FwcyBhdCAzNjUgZGF5cyAoYSBsb25nZXIgcGVyLW9yZyBvdmVycmlkZSBvbmx5XG4gKiAgICByZXRhaW5zIHJhdyBzb3VyY2Ugcm93cywgbmV2ZXIgd2lkZW5zIGEgcmVwb3J0KS5cbiAqIGBpbmdlc3RfaGVhbHRoYCBhbmQgYGRvcmFfc2V0dGluZ3NgIGFyZSBuZXZlciBwdXJnZWQuIEVudi1vdmVycmlkYWJsZSBnbG9iYWxzO1xuICogYSBwZXItb3JnIG92ZXJyaWRlIGluIGBkb3JhX3NldHRpbmdzYCB3aW5zIChzZWUge0BsaW5rIHJlc29sdmVFdmVudFJldGVudGlvbkRheXN9KS5cbiAqL1xuZXhwb3J0IGNvbnN0IFJFVEVOVElPTl9NSU5fREFZUyA9IDE7XG5leHBvcnQgY29uc3QgUkVURU5USU9OX01BWF9EQVlTID0gNzMwO1xuXG4vKiogUGFyc2UgYSBwb3NpdGl2ZS1pbnQgZW52IGRheS1jb3VudCwgY2xhbXBlZCB0byBbTUlOLCBNQVhdLCBlbHNlIGBmYWxsYmFja2AuICovXG5leHBvcnQgZnVuY3Rpb24gcmV0ZW50aW9uRW52RGF5cyhuYW1lOiBzdHJpbmcsIGZhbGxiYWNrOiBudW1iZXIpOiBudW1iZXIge1xuICBjb25zdCByYXcgPSBOdW1iZXIocHJvY2Vzcy5lbnZbbmFtZV0pO1xuICBpZiAoIU51bWJlci5pc0Zpbml0ZShyYXcpIHx8ICFOdW1iZXIuaXNJbnRlZ2VyKHJhdykgfHwgcmF3IDwgUkVURU5USU9OX01JTl9EQVlTKSByZXR1cm4gZmFsbGJhY2s7XG4gIHJldHVybiBNYXRoLm1pbihyYXcsIFJFVEVOVElPTl9NQVhfREFZUyk7XG59XG5cbmV4cG9ydCBjb25zdCBSRVBPUlRJTkdfRVZFTlRfUkVURU5USU9OX0RBWVMgPSByZXRlbnRpb25FbnZEYXlzKCdSRVBPUlRJTkdfRVZFTlRfUkVURU5USU9OX0RBWVMnLCAzMCk7XG5leHBvcnQgY29uc3QgUkVQT1JUSU5HX0RPUkFfUkVURU5USU9OX0RBWVMgPSByZXRlbnRpb25FbnZEYXlzKCdSRVBPUlRJTkdfRE9SQV9SRVRFTlRJT05fREFZUycsIDE4MCk7XG5cbi8qKiBFZmZlY3RpdmUgc3RhbmRhcmQtZXZlbnQgcmV0ZW50aW9uIChkYXlzKTogYSB2YWxpZCBwZXItb3JnIG92ZXJyaWRlIHdpbnMsXG4gKiAgZWxzZSB0aGUgZ2xvYmFsIGVudiBkZWZhdWx0LiBTaGFyZWQgYnkgdGhlIHN3ZWVwICsgdGhlIHNldHRpbmdzIHN1cmZhY2Ugc29cbiAqICB0aGV5IGNhbid0IGRyaWZ0LiBUaGUgYC0xYCB1bmxpbWl0ZWQgc2VudGluZWwgKFBoYXNlIDgpIHBhc3NlcyBzdHJhaWdodFxuICogIHRocm91Z2gg4oCUIHRoZSBzd2VlcCByZWFkcyBpdCBhcyBcImtlZXAgZm9yZXZlciwgc2tpcCB0aGlzIG9yZydzIHN0YW5kYXJkXG4gKiAgZXZlbnRzXCIuIEEgcG9zaXRpdmUgb3ZlcnJpZGUgY2xhbXBzIHRvIFsxLCBSRVRFTlRJT05fTUFYX0RBWVNdOyBhIGBudWxsYCwgYVxuICogIG5vbi1pbnRlZ2VyLCBvciBhbnkgb3RoZXIgb3V0LW9mLXJhbmdlIHZhbHVlIChlLmcuIDAsIC0yKSBmYWxscyBiYWNrIHRvIHRoZVxuICogIGVudiBkZWZhdWx0LiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHJlc29sdmVFdmVudFJldGVudGlvbkRheXMob3ZlcnJpZGU/OiBudW1iZXIgfCBudWxsKTogbnVtYmVyIHtcbiAgaWYgKG92ZXJyaWRlID09PSAtMSkgcmV0dXJuIC0xO1xuICByZXR1cm4gb3ZlcnJpZGUgIT0gbnVsbCAmJiBOdW1iZXIuaXNJbnRlZ2VyKG92ZXJyaWRlKSAmJiBvdmVycmlkZSA+PSBSRVRFTlRJT05fTUlOX0RBWVNcbiAgICA/IE1hdGgubWluKG92ZXJyaWRlLCBSRVRFTlRJT05fTUFYX0RBWVMpIDogUkVQT1JUSU5HX0VWRU5UX1JFVEVOVElPTl9EQVlTO1xufVxuXG4vKiogRWZmZWN0aXZlIERPUkEtc291cmNlIHJldGVudGlvbiAoZGF5cyk6IGEgdmFsaWQgcGVyLW9yZyBvdmVycmlkZSB3aW5zLCBlbHNlXG4gKiAgdGhlIGdsb2JhbCBlbnYgZGVmYXVsdC4gVGhlIGAtMWAgdW5saW1pdGVkIHNlbnRpbmVsIChQaGFzZSA4KSBwYXNzZXMgc3RyYWlnaHRcbiAqICB0aHJvdWdoIOKAlCB0aGUgc3dlZXAgcmVhZHMgaXQgYXMgXCJrZWVwIGZvcmV2ZXIsIHNraXAgdGhpcyBvcmcncyBET1JBLXNvdXJjZVxuICogIHdpbmRvd3NcIi4gQSBwb3NpdGl2ZSBvdmVycmlkZSBjbGFtcHMgdG8gWzEsIFJFVEVOVElPTl9NQVhfREFZU107IGEgYG51bGxgLCBhXG4gKiAgbm9uLWludGVnZXIsIG9yIGFueSBvdGhlciBvdXQtb2YtcmFuZ2UgdmFsdWUgKGUuZy4gMCwgLTIpIGZhbGxzIGJhY2sgdG8gdGhlXG4gKiAgZW52IGRlZmF1bHQuICovXG5leHBvcnQgZnVuY3Rpb24gcmVzb2x2ZURvcmFSZXRlbnRpb25EYXlzKG92ZXJyaWRlPzogbnVtYmVyIHwgbnVsbCk6IG51bWJlciB7XG4gIGlmIChvdmVycmlkZSA9PT0gLTEpIHJldHVybiAtMTtcbiAgcmV0dXJuIG92ZXJyaWRlICE9IG51bGwgJiYgTnVtYmVyLmlzSW50ZWdlcihvdmVycmlkZSkgJiYgb3ZlcnJpZGUgPj0gUkVURU5USU9OX01JTl9EQVlTXG4gICAgPyBNYXRoLm1pbihvdmVycmlkZSwgUkVURU5USU9OX01BWF9EQVlTKSA6IFJFUE9SVElOR19ET1JBX1JFVEVOVElPTl9EQVlTO1xufVxuXG4vKiogVGhlIGN1dG9mZiBpbnN0YW50IGZvciBhIHJldGVudGlvbiB3aW5kb3c6IHJvd3Mgd2l0aCBgY3JlYXRlZF9hdGAgc3RyaWN0bHlcbiAqICBiZWZvcmUgdGhpcyAoYDwgY3V0b2ZmYCkgYXJlIGV4cGlyZWQuIERldGVybWluaXN0aWMgZm9yIGEgZml4ZWQgYG5vd2AuICovXG5leHBvcnQgZnVuY3Rpb24gcmV0ZW50aW9uQ3V0b2ZmKG5vdzogRGF0ZSwgZGF5czogbnVtYmVyKTogRGF0ZSB7XG4gIHJldHVybiBuZXcgRGF0ZShub3cuZ2V0VGltZSgpIC0gZGF5cyAqIDg2XzQwMF8wMDApO1xufVxuXG4vKiogUGVyLW9yZyByZXRlbnRpb24gb3ZlcnJpZGUgcm93IChQaGFzZSA3KS4gQm90aCBudWxsYWJsZSDih5IgZ2xvYmFsIGRlZmF1bHRzLiAqL1xuIl19
60
+ /** Per-org retention override row. Both nullable ⇒ global defaults. */
61
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicmV0ZW50aW9uLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vc3JjL2FwaS9yZXBvcnRpbmcvcmV0ZW50aW9uLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLCtDQUErQztBQUMvQyxzQ0FBc0M7QUFFdEM7OztHQUdHO0FBRUgsT0FBTyxFQUFFLE1BQU0sRUFBRSxrQkFBa0IsRUFBRSxrQkFBa0IsRUFBRSxNQUFNLDRCQUE0QixDQUFDO0FBRTVGOzs7Ozs7Ozs7Ozs7OztHQWNHO0FBRUgsa0ZBQWtGO0FBQ2xGLE1BQU0sVUFBVSxnQkFBZ0IsQ0FBQyxJQUFZLEVBQUUsUUFBZ0I7SUFDN0QsTUFBTSxJQUFJLEdBQUcsTUFBTSxDQUFDLElBQUksRUFBRSxRQUFRLENBQUMsQ0FBQztJQUNwQyxPQUFPLElBQUksR0FBRyxrQkFBa0IsQ0FBQyxDQUFDLENBQUMsUUFBUSxDQUFDLENBQUMsQ0FBQyxJQUFJLENBQUMsR0FBRyxDQUFDLElBQUksRUFBRSxrQkFBa0IsQ0FBQyxDQUFDO0FBQ25GLENBQUM7QUFFRCxNQUFNLENBQUMsTUFBTSw4QkFBOEIsR0FBRyxnQkFBZ0IsQ0FBQyxnQ0FBZ0MsRUFBRSxFQUFFLENBQUMsQ0FBQztBQUNyRyxNQUFNLENBQUMsTUFBTSw2QkFBNkIsR0FBRyxnQkFBZ0IsQ0FBQywrQkFBK0IsRUFBRSxHQUFHLENBQUMsQ0FBQztBQUVwRzs7Ozs7O21CQU1tQjtBQUNuQixNQUFNLFVBQVUseUJBQXlCLENBQUMsUUFBd0I7SUFDaEUsSUFBSSxRQUFRLEtBQUssQ0FBQyxDQUFDO1FBQUUsT0FBTyxDQUFDLENBQUMsQ0FBQztJQUMvQixPQUFPLFFBQVEsSUFBSSxJQUFJLElBQUksTUFBTSxDQUFDLFNBQVMsQ0FBQyxRQUFRLENBQUMsSUFBSSxRQUFRLElBQUksa0JBQWtCO1FBQ3JGLENBQUMsQ0FBQyxJQUFJLENBQUMsR0FBRyxDQUFDLFFBQVEsRUFBRSxrQkFBa0IsQ0FBQyxDQUFDLENBQUMsQ0FBQyw4QkFBOEIsQ0FBQztBQUM5RSxDQUFDO0FBRUQ7Ozs7O21CQUttQjtBQUNuQixNQUFNLFVBQVUsd0JBQXdCLENBQUMsUUFBd0I7SUFDL0QsSUFBSSxRQUFRLEtBQUssQ0FBQyxDQUFDO1FBQUUsT0FBTyxDQUFDLENBQUMsQ0FBQztJQUMvQixPQUFPLFFBQVEsSUFBSSxJQUFJLElBQUksTUFBTSxDQUFDLFNBQVMsQ0FBQyxRQUFRLENBQUMsSUFBSSxRQUFRLElBQUksa0JBQWtCO1FBQ3JGLENBQUMsQ0FBQyxJQUFJLENBQUMsR0FBRyxDQUFDLFFBQVEsRUFBRSxrQkFBa0IsQ0FBQyxDQUFDLENBQUMsQ0FBQyw2QkFBNkIsQ0FBQztBQUM3RSxDQUFDO0FBRUQ7NkVBQzZFO0FBQzdFLE1BQU0sVUFBVSxlQUFlLENBQUMsR0FBUyxFQUFFLElBQVk7SUFDckQsT0FBTyxJQUFJLElBQUksQ0FBQyxHQUFHLENBQUMsT0FBTyxFQUFFLEdBQUcsSUFBSSxHQUFHLFVBQVUsQ0FBQyxDQUFDO0FBQ3JELENBQUM7QUFFRCx1RUFBdUUiLCJzb3VyY2VzQ29udGVudCI6WyIvLyBDb3B5cmlnaHQgMjAyNiBQaXBlbGluZSBCdWlsZGVyIENvbnRyaWJ1dG9yc1xuLy8gU1BEWC1MaWNlbnNlLUlkZW50aWZpZXI6IEFwYWNoZS0yLjBcblxuLyoqXG4gKiBSZXRlbnRpb24gd2luZG93cyBmb3IgcmVwb3J0aW5nIGRhdGE6IGVudi1jb25maWd1cmFibGUsIGNsYW1wZWQgdG8gYSBzYW5lXG4gKiByYW5nZSwgYW5kIG92ZXJyaWRhYmxlIHBlci1vcmcgYnkgdGhlIHNldHRpbmdzIHJvdy5cbiAqL1xuXG5pbXBvcnQgeyBlbnZJbnQsIFJFVEVOVElPTl9NQVhfREFZUywgUkVURU5USU9OX01JTl9EQVlTIH0gZnJvbSAnQHBpcGVsaW5lLWJ1aWxkZXIvYXBpLWNvcmUnO1xuXG4vKipcbiAqIFJlcG9ydGluZyByZXRlbnRpb24gd2luZG93cy4gUmVjb3JkcyBpbiBgcGlwZWxpbmVfZXZlbnRzYCxcbiAqIGBkZXBsb3ltZW50X291dGNvbWVzYCwgYW5kIGBpbmNpZGVudHNgIGdyb3cgdW5ib3VuZGVkIHdpdGhvdXQgYSBzd2VlcCwgc28gYVxuICogc3BsaXQsIHBlci1vcmcgcmV0ZW50aW9uIHB1cmdlIChzZWUge0BsaW5rIFJlcG9ydGluZ1NlcnZpY2UucHVyZ2VFeHBpcmVkUmVwb3J0aW5nRGF0YX0pXG4gKiBoYXJkLWRlbGV0ZXMgcm93cyBvbGRlciB0aGFuIHRoZXNlIHdpbmRvd3MsIGJ5IGBjcmVhdGVkX2F0YDpcbiAqICAtICoqU3RhbmRhcmQgZXZlbnRzKiog4oCUIGBwaXBlbGluZV9ldmVudHNgIHdpdGggYGVudmlyb25tZW50IElTIE5VTExgXG4gKiAgICAobm9uLWRlcGxveSBTVEFHRS9BQ1RJT04vYnVpbGQpLiBIaWdoIHZvbHVtZSDihpIgc2hvcnQgZGVmYXVsdCAoMzAgZGF5cykuXG4gKiAgLSAqKkRPUkEgc291cmNlKiog4oCUIGBwaXBlbGluZV9ldmVudHNgIHdpdGggYGVudmlyb25tZW50IElTIE5PVCBOVUxMYCAoZGVwbG95XG4gKiAgICBzdGFnZXMpIHBsdXMgYWxsIG9mIGBkZXBsb3ltZW50X291dGNvbWVzYCBhbmQgYGluY2lkZW50c2AuIExvdyB2b2x1bWUg4oaSXG4gKiAgICBsb25nZXIgZGVmYXVsdCAoMTgwIGRheXMpLiBET1JBIGhpc3RvcnkgaXMgdGhlcmVmb3JlIGJvdW5kZWQgYnkgdGhpcyB3aW5kb3c7XG4gKiAgICB0aGUgcmVwb3J0IHF1ZXJ5IHN0aWxsIGhhcmQtY2FwcyBhdCAzNjUgZGF5cyAoYSBsb25nZXIgcGVyLW9yZyBvdmVycmlkZSBvbmx5XG4gKiAgICByZXRhaW5zIHJhdyBzb3VyY2Ugcm93cywgbmV2ZXIgd2lkZW5zIGEgcmVwb3J0KS5cbiAqIGBpbmdlc3RfaGVhbHRoYCBhbmQgYGRvcmFfc2V0dGluZ3NgIGFyZSBuZXZlciBwdXJnZWQuIEVudi1vdmVycmlkYWJsZSBnbG9iYWxzO1xuICogYSBwZXItb3JnIG92ZXJyaWRlIGluIGBkb3JhX3NldHRpbmdzYCB3aW5zIChzZWUge0BsaW5rIHJlc29sdmVFdmVudFJldGVudGlvbkRheXN9KS5cbiAqL1xuXG4vKiogUGFyc2UgYSBwb3NpdGl2ZS1pbnQgZW52IGRheS1jb3VudCwgY2xhbXBlZCB0byBbTUlOLCBNQVhdLCBlbHNlIGBmYWxsYmFja2AuICovXG5leHBvcnQgZnVuY3Rpb24gcmV0ZW50aW9uRW52RGF5cyhuYW1lOiBzdHJpbmcsIGZhbGxiYWNrOiBudW1iZXIpOiBudW1iZXIge1xuICBjb25zdCBkYXlzID0gZW52SW50KG5hbWUsIGZhbGxiYWNrKTtcbiAgcmV0dXJuIGRheXMgPCBSRVRFTlRJT05fTUlOX0RBWVMgPyBmYWxsYmFjayA6IE1hdGgubWluKGRheXMsIFJFVEVOVElPTl9NQVhfREFZUyk7XG59XG5cbmV4cG9ydCBjb25zdCBSRVBPUlRJTkdfRVZFTlRfUkVURU5USU9OX0RBWVMgPSByZXRlbnRpb25FbnZEYXlzKCdSRVBPUlRJTkdfRVZFTlRfUkVURU5USU9OX0RBWVMnLCAzMCk7XG5leHBvcnQgY29uc3QgUkVQT1JUSU5HX0RPUkFfUkVURU5USU9OX0RBWVMgPSByZXRlbnRpb25FbnZEYXlzKCdSRVBPUlRJTkdfRE9SQV9SRVRFTlRJT05fREFZUycsIDE4MCk7XG5cbi8qKiBFZmZlY3RpdmUgc3RhbmRhcmQtZXZlbnQgcmV0ZW50aW9uIChkYXlzKTogYSB2YWxpZCBwZXItb3JnIG92ZXJyaWRlIHdpbnMsXG4gKiAgZWxzZSB0aGUgZ2xvYmFsIGVudiBkZWZhdWx0LiBTaGFyZWQgYnkgdGhlIHN3ZWVwICsgdGhlIHNldHRpbmdzIHN1cmZhY2Ugc29cbiAqICB0aGV5IGNhbid0IGRyaWZ0LiBUaGUgYC0xYCB1bmxpbWl0ZWQgc2VudGluZWwgcGFzc2VzIHN0cmFpZ2h0XG4gKiAgdGhyb3VnaCDigJQgdGhlIHN3ZWVwIHJlYWRzIGl0IGFzIFwia2VlcCBmb3JldmVyLCBza2lwIHRoaXMgb3JnJ3Mgc3RhbmRhcmRcbiAqICBldmVudHNcIi4gQSBwb3NpdGl2ZSBvdmVycmlkZSBjbGFtcHMgdG8gWzEsIFJFVEVOVElPTl9NQVhfREFZU107IGEgYG51bGxgLCBhXG4gKiAgbm9uLWludGVnZXIsIG9yIGFueSBvdGhlciBvdXQtb2YtcmFuZ2UgdmFsdWUgKGUuZy4gMCwgLTIpIGZhbGxzIGJhY2sgdG8gdGhlXG4gKiAgZW52IGRlZmF1bHQuICovXG5leHBvcnQgZnVuY3Rpb24gcmVzb2x2ZUV2ZW50UmV0ZW50aW9uRGF5cyhvdmVycmlkZT86IG51bWJlciB8IG51bGwpOiBudW1iZXIge1xuICBpZiAob3ZlcnJpZGUgPT09IC0xKSByZXR1cm4gLTE7XG4gIHJldHVybiBvdmVycmlkZSAhPSBudWxsICYmIE51bWJlci5pc0ludGVnZXIob3ZlcnJpZGUpICYmIG92ZXJyaWRlID49IFJFVEVOVElPTl9NSU5fREFZU1xuICAgID8gTWF0aC5taW4ob3ZlcnJpZGUsIFJFVEVOVElPTl9NQVhfREFZUykgOiBSRVBPUlRJTkdfRVZFTlRfUkVURU5USU9OX0RBWVM7XG59XG5cbi8qKiBFZmZlY3RpdmUgRE9SQS1zb3VyY2UgcmV0ZW50aW9uIChkYXlzKTogYSB2YWxpZCBwZXItb3JnIG92ZXJyaWRlIHdpbnMsIGVsc2VcbiAqICB0aGUgZ2xvYmFsIGVudiBkZWZhdWx0LiBUaGUgYC0xYCB1bmxpbWl0ZWQgc2VudGluZWwgcGFzc2VzIHN0cmFpZ2h0XG4gKiAgdGhyb3VnaCDigJQgdGhlIHN3ZWVwIHJlYWRzIGl0IGFzIFwia2VlcCBmb3JldmVyLCBza2lwIHRoaXMgb3JnJ3MgRE9SQS1zb3VyY2VcbiAqICB3aW5kb3dzXCIuIEEgcG9zaXRpdmUgb3ZlcnJpZGUgY2xhbXBzIHRvIFsxLCBSRVRFTlRJT05fTUFYX0RBWVNdOyBhIGBudWxsYCwgYVxuICogIG5vbi1pbnRlZ2VyLCBvciBhbnkgb3RoZXIgb3V0LW9mLXJhbmdlIHZhbHVlIChlLmcuIDAsIC0yKSBmYWxscyBiYWNrIHRvIHRoZVxuICogIGVudiBkZWZhdWx0LiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHJlc29sdmVEb3JhUmV0ZW50aW9uRGF5cyhvdmVycmlkZT86IG51bWJlciB8IG51bGwpOiBudW1iZXIge1xuICBpZiAob3ZlcnJpZGUgPT09IC0xKSByZXR1cm4gLTE7XG4gIHJldHVybiBvdmVycmlkZSAhPSBudWxsICYmIE51bWJlci5pc0ludGVnZXIob3ZlcnJpZGUpICYmIG92ZXJyaWRlID49IFJFVEVOVElPTl9NSU5fREFZU1xuICAgID8gTWF0aC5taW4ob3ZlcnJpZGUsIFJFVEVOVElPTl9NQVhfREFZUykgOiBSRVBPUlRJTkdfRE9SQV9SRVRFTlRJT05fREFZUztcbn1cblxuLyoqIFRoZSBjdXRvZmYgaW5zdGFudCBmb3IgYSByZXRlbnRpb24gd2luZG93OiByb3dzIHdpdGggYGNyZWF0ZWRfYXRgIHN0cmljdGx5XG4gKiAgYmVmb3JlIHRoaXMgKGA8IGN1dG9mZmApIGFyZSBleHBpcmVkLiBEZXRlcm1pbmlzdGljIGZvciBhIGZpeGVkIGBub3dgLiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHJldGVudGlvbkN1dG9mZihub3c6IERhdGUsIGRheXM6IG51bWJlcik6IERhdGUge1xuICByZXR1cm4gbmV3IERhdGUobm93LmdldFRpbWUoKSAtIGRheXMgKiA4Nl80MDBfMDAwKTtcbn1cblxuLyoqIFBlci1vcmcgcmV0ZW50aW9uIG92ZXJyaWRlIHJvdy4gQm90aCBudWxsYWJsZSDih5IgZ2xvYmFsIGRlZmF1bHRzLiAqL1xuIl19
@@ -15,11 +15,6 @@ export declare function assertReportInterval(interval: string): void;
15
15
  * string field is funneled through this before insert.
16
16
  */
17
17
  export declare function scrubOptional(value: string | undefined): string | undefined;
18
- /**
19
- * Cache for reporting aggregations. Two tiers:
20
- * - Inventory queries (plugin summary/distribution/versions): 5 min TTL — changes on plugin CRUD
21
- * - Execution/build queries with date ranges: 2 min TTL — new events arrive continuously
22
- */
23
18
  /**
24
19
  * Roll a group of deploy/stage events (grouped per execution) up to one terminal
25
20
  * status: FAILED wins, then SUCCEEDED, else OTHER (still-running / non-terminal).
@@ -28,6 +23,8 @@ export declare function scrubOptional(value: string | undefined): string | undef
28
23
  * grouped event alias is `e`.
29
24
  */
30
25
  export declare const terminalStatusRollup: import("drizzle-orm").SQL<unknown>;
26
+ /** The report window on `e.started_at` (inclusive `[from, to]`). */
27
+ export declare function startedAtWindow(from: string, to: string): ReturnType<typeof sql>;
31
28
  /** Optional `[from,to]` window on `e.started_at` for the execution reports —
32
29
  * a no-op `sql` fragment when either bound is absent (all-time). Shared by the
33
30
  * execution-count and per-pipeline-execution reports so they narrow identically. */
@@ -36,10 +33,10 @@ export declare function optionalStartedAtRange(range?: {
36
33
  to?: string;
37
34
  }): ReturnType<typeof sql>;
38
35
  /**
39
- * Per-execution terminal deploy row (D1 — one row per (environment, execution),
36
+ * Per-execution terminal deploy row (one row per (environment, execution),
40
37
  * NOT per stage). The SQL rolls every deploy STAGE targeting an env within an
41
38
  * execution up to a single terminal status; the JS shaping buckets these by
42
- * environment. `commit_ts` (D2) is the execution's EARLIEST commit time across
39
+ * environment. `commit_ts` is the execution's EARLIEST commit time across
43
40
  * all its events — commit enrichment rides the PIPELINE/source event, not the
44
41
  * deploy STAGE — joined by execution_id (null when unresolved → lead `unknown`).
45
42
  * `in_window` is false for a look-back-only row kept solely so incidents opened
@@ -27,11 +27,6 @@ export function assertReportInterval(interval) {
27
27
  export function scrubOptional(value) {
28
28
  return value !== undefined ? scrubAwsIdentifiersFromString(value) : undefined;
29
29
  }
30
- /**
31
- * Cache for reporting aggregations. Two tiers:
32
- * - Inventory queries (plugin summary/distribution/versions): 5 min TTL — changes on plugin CRUD
33
- * - Execution/build queries with date ranges: 2 min TTL — new events arrive continuously
34
- */
35
30
  /**
36
31
  * Roll a group of deploy/stage events (grouped per execution) up to one terminal
37
32
  * status: FAILED wins, then SUCCEEDED, else OTHER (still-running / non-terminal).
@@ -44,22 +39,26 @@ export const terminalStatusRollup = sql `CASE
44
39
  WHEN bool_or(e.status = 'SUCCEEDED') THEN 'SUCCEEDED'
45
40
  ELSE 'OTHER'
46
41
  END`;
42
+ /** The report window on `e.started_at` (inclusive `[from, to]`). */
43
+ export function startedAtWindow(from, to) {
44
+ return sql `e.started_at >= ${from}::timestamptz AND e.started_at <= ${to}::timestamptz`;
45
+ }
47
46
  /** Optional `[from,to]` window on `e.started_at` for the execution reports —
48
47
  * a no-op `sql` fragment when either bound is absent (all-time). Shared by the
49
48
  * execution-count and per-pipeline-execution reports so they narrow identically. */
50
49
  export function optionalStartedAtRange(range) {
51
50
  return range?.from && range?.to
52
- ? sql `AND e.started_at >= ${range.from}::timestamptz AND e.started_at <= ${range.to}::timestamptz`
51
+ ? sql `AND ${startedAtWindow(range.from, range.to)}`
53
52
  : sql ``;
54
53
  }
55
54
  /**
56
- * Per-execution terminal deploy row (D1 — one row per (environment, execution),
55
+ * Per-execution terminal deploy row (one row per (environment, execution),
57
56
  * NOT per stage). The SQL rolls every deploy STAGE targeting an env within an
58
57
  * execution up to a single terminal status; the JS shaping buckets these by
59
- * environment. `commit_ts` (D2) is the execution's EARLIEST commit time across
58
+ * environment. `commit_ts` is the execution's EARLIEST commit time across
60
59
  * all its events — commit enrichment rides the PIPELINE/source event, not the
61
60
  * deploy STAGE — joined by execution_id (null when unresolved → lead `unknown`).
62
61
  * `in_window` is false for a look-back-only row kept solely so incidents opened
63
62
  * near `from` can correlate to a deploy that completed just before the window.
64
63
  */
65
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic3FsLWhlbHBlcnMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvYXBpL3JlcG9ydGluZy9zcWwtaGVscGVycy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSwrQ0FBK0M7QUFDL0Msc0NBQXNDO0FBRXRDOztHQUVHO0FBRUgsT0FBTyxFQUFFLGdCQUFnQixFQUFFLDZCQUE2QixFQUFFLE1BQU0sNEJBQTRCLENBQUM7QUFDN0YsT0FBTyxFQUFFLEdBQUcsRUFBRSxNQUFNLGFBQWEsQ0FBQztBQUVsQzs7Ozs7OztHQU9HO0FBQ0gsTUFBTSxVQUFVLG9CQUFvQixDQUFDLFFBQWdCO0lBQ25ELElBQUksQ0FBRSxnQkFBc0MsQ0FBQyxRQUFRLENBQUMsUUFBUSxDQUFDLEVBQUUsQ0FBQztRQUNoRSxNQUFNLElBQUksS0FBSyxDQUFDLDRCQUE0QixRQUFRLHNCQUFzQixnQkFBZ0IsQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLEVBQUUsQ0FBQyxDQUFDO0lBQzNHLENBQUM7QUFDSCxDQUFDO0FBRUQ7Ozs7O0dBS0c7QUFDSCxNQUFNLFVBQVUsYUFBYSxDQUFDLEtBQXlCO0lBQ3JELE9BQU8sS0FBSyxLQUFLLFNBQVMsQ0FBQyxDQUFDLENBQUMsNkJBQTZCLENBQUMsS0FBSyxDQUFDLENBQUMsQ0FBQyxDQUFDLFNBQVMsQ0FBQztBQUNoRixDQUFDO0FBRUQ7Ozs7R0FJRztBQUVIOzs7Ozs7R0FNRztBQUNILE1BQU0sQ0FBQyxNQUFNLG9CQUFvQixHQUFHLEdBQUcsQ0FBQTs7OztnQkFJdkIsQ0FBQztBQUVqQjs7cUZBRXFGO0FBQ3JGLE1BQU0sVUFBVSxzQkFBc0IsQ0FBQyxLQUFzQztJQUMzRSxPQUFPLEtBQUssRUFBRSxJQUFJLElBQUksS0FBSyxFQUFFLEVBQUU7UUFDN0IsQ0FBQyxDQUFDLEdBQUcsQ0FBQSx1QkFBdUIsS0FBSyxDQUFDLElBQUkscUNBQXFDLEtBQUssQ0FBQyxFQUFFLGVBQWU7UUFDbEcsQ0FBQyxDQUFDLEdBQUcsQ0FBQSxFQUFFLENBQUM7QUFDWixDQUFDO0FBRUQ7Ozs7Ozs7OztHQVNHIiwic291cmNlc0NvbnRlbnQiOlsiLy8gQ29weXJpZ2h0IDIwMjYgUGlwZWxpbmUgQnVpbGRlciBDb250cmlidXRvcnNcbi8vIFNQRFgtTGljZW5zZS1JZGVudGlmaWVyOiBBcGFjaGUtMi4wXG5cbi8qKlxuICogU21hbGwgU1FMIGZyYWdtZW50cyBhbmQgaW5wdXQgZ3VhcmRzIHNoYXJlZCBhY3Jvc3MgdGhlIHJlcG9ydGluZyBxdWVyaWVzLlxuICovXG5cbmltcG9ydCB7IFJFUE9SVF9JTlRFUlZBTFMsIHNjcnViQXdzSWRlbnRpZmllcnNGcm9tU3RyaW5nIH0gZnJvbSAnQHBpcGVsaW5lLWJ1aWxkZXIvYXBpLWNvcmUnO1xuaW1wb3J0IHsgc3FsIH0gZnJvbSAnZHJpenpsZS1vcm0nO1xuXG4vKipcbiAqIERlZmVuc2UtaW4tZGVwdGggZ3VhcmQgZm9yIHRoZSBgREFURV9UUlVOQygke2ludGVydmFsfSwg4oCmKWAgYnVja2V0IGFyZ3VtZW50LlxuICogVGhlIHJvdXRlIGxheWVyIChgcGFyc2VSZXBvcnRJbnRlcnZhbGApIGlzIHRoZSBzZWN1cml0eSBib3VuZGFyeSBhbmQgYWxyZWFkeVxuICogcmVqZWN0cyB1bmtub3duIGludGVydmFsczsgdGhpcyBhc3NlcnQgbWFrZXMgYW4gaW52YWxpZCB2YWx1ZSBmYWlsIGZhc3QgYXQgdGhlXG4gKiBzZXJ2aWNlIGJvdW5kYXJ5IHdpdGggYSBjbGVhciBlcnJvciBpbnN0ZWFkIG9mIHN1cmZhY2luZyBhIHJhdyBQb3N0Z3JlcyBlcnJvclxuICogaWYgYSBjYWxsZXIgZXZlciBieXBhc3NlcyB0aGUgcm91dGUgdmFsaWRhdGlvbi4gU2hhcmVzIGFwaS1jb3JlJ3NcbiAqIFJFUE9SVF9JTlRFUlZBTFMgYWxsb3ctbGlzdCBzbyB0aGUgdHdvIGNhbid0IGRyaWZ0LlxuICovXG5leHBvcnQgZnVuY3Rpb24gYXNzZXJ0UmVwb3J0SW50ZXJ2YWwoaW50ZXJ2YWw6IHN0cmluZyk6IHZvaWQge1xuICBpZiAoIShSRVBPUlRfSU5URVJWQUxTIGFzIHJlYWRvbmx5IHN0cmluZ1tdKS5pbmNsdWRlcyhpbnRlcnZhbCkpIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IoYEludmFsaWQgcmVwb3J0IGludGVydmFsOiAke2ludGVydmFsfS4gRXhwZWN0ZWQgb25lIG9mOiAke1JFUE9SVF9JTlRFUlZBTFMuam9pbignLCAnKX1gKTtcbiAgfVxufVxuXG4vKipcbiAqIFNjcnViIEFXUyBpZGVudGlmaWVycyBmcm9tIGFuIG9wdGlvbmFsIGZyZWUtZm9ybSBzdHJpbmcsIHByZXNlcnZpbmcgYHVuZGVmaW5lZGBcbiAqIChzbyBhbiBhYnNlbnQgZmllbGQgc3RheXMgYWJzZW50IHJhdGhlciB0aGFuIGJlY29taW5nIGFuIGVtcHR5IHNjcnViYmVkIHN0cmluZykuXG4gKiBUaGUgRFVSQUJMRSBwZXJzaXN0ZW5jZSBib3VuZGFyeSBmb3IgdGhlIGluZ2VzdCBwYXRocyDigJQgZXZlcnkgdXNlci9BV1MtZGVyaXZlZFxuICogc3RyaW5nIGZpZWxkIGlzIGZ1bm5lbGVkIHRocm91Z2ggdGhpcyBiZWZvcmUgaW5zZXJ0LlxuICovXG5leHBvcnQgZnVuY3Rpb24gc2NydWJPcHRpb25hbCh2YWx1ZTogc3RyaW5nIHwgdW5kZWZpbmVkKTogc3RyaW5nIHwgdW5kZWZpbmVkIHtcbiAgcmV0dXJuIHZhbHVlICE9PSB1bmRlZmluZWQgPyBzY3J1YkF3c0lkZW50aWZpZXJzRnJvbVN0cmluZyh2YWx1ZSkgOiB1bmRlZmluZWQ7XG59XG5cbi8qKlxuICogQ2FjaGUgZm9yIHJlcG9ydGluZyBhZ2dyZWdhdGlvbnMuIFR3byB0aWVyczpcbiAqIC0gSW52ZW50b3J5IHF1ZXJpZXMgKHBsdWdpbiBzdW1tYXJ5L2Rpc3RyaWJ1dGlvbi92ZXJzaW9ucyk6IDUgbWluIFRUTCDigJQgY2hhbmdlcyBvbiBwbHVnaW4gQ1JVRFxuICogLSBFeGVjdXRpb24vYnVpbGQgcXVlcmllcyB3aXRoIGRhdGUgcmFuZ2VzOiAyIG1pbiBUVEwg4oCUIG5ldyBldmVudHMgYXJyaXZlIGNvbnRpbnVvdXNseVxuICovXG5cbi8qKlxuICogUm9sbCBhIGdyb3VwIG9mIGRlcGxveS9zdGFnZSBldmVudHMgKGdyb3VwZWQgcGVyIGV4ZWN1dGlvbikgdXAgdG8gb25lIHRlcm1pbmFsXG4gKiBzdGF0dXM6IEZBSUxFRCB3aW5zLCB0aGVuIFNVQ0NFRURFRCwgZWxzZSBPVEhFUiAoc3RpbGwtcnVubmluZyAvIG5vbi10ZXJtaW5hbCkuXG4gKiBTaGFyZWQgYnkgdGhlIHRocmVlIHBlci0oZW52fHN0YWdlLCBleGVjdXRpb24pIHJvbGx1cCBDVEVzIOKAlCBET1JBIG1ldHJpY3MsIERPUkFcbiAqIHRyZW5kLCBhbmQgYnVpbGQgaGVhbHRoIOKAlCBzbyB0aGUgcHJlY2VkZW5jZSBjYW4ndCBkcmlmdCBiZXR3ZWVuIHRoZW0uIEFzc3VtZXMgdGhlXG4gKiBncm91cGVkIGV2ZW50IGFsaWFzIGlzIGBlYC5cbiAqL1xuZXhwb3J0IGNvbnN0IHRlcm1pbmFsU3RhdHVzUm9sbHVwID0gc3FsYENBU0VcbiAgICAgICAgICAgICAgV0hFTiBib29sX29yKGUuc3RhdHVzID0gJ0ZBSUxFRCcpIFRIRU4gJ0ZBSUxFRCdcbiAgICAgICAgICAgICAgV0hFTiBib29sX29yKGUuc3RhdHVzID0gJ1NVQ0NFRURFRCcpIFRIRU4gJ1NVQ0NFRURFRCdcbiAgICAgICAgICAgICAgRUxTRSAnT1RIRVInXG4gICAgICAgICAgICBFTkRgO1xuXG4vKiogT3B0aW9uYWwgYFtmcm9tLHRvXWAgd2luZG93IG9uIGBlLnN0YXJ0ZWRfYXRgIGZvciB0aGUgZXhlY3V0aW9uIHJlcG9ydHMg4oCUXG4gKiAgYSBuby1vcCBgc3FsYCBmcmFnbWVudCB3aGVuIGVpdGhlciBib3VuZCBpcyBhYnNlbnQgKGFsbC10aW1lKS4gU2hhcmVkIGJ5IHRoZVxuICogIGV4ZWN1dGlvbi1jb3VudCBhbmQgcGVyLXBpcGVsaW5lLWV4ZWN1dGlvbiByZXBvcnRzIHNvIHRoZXkgbmFycm93IGlkZW50aWNhbGx5LiAqL1xuZXhwb3J0IGZ1bmN0aW9uIG9wdGlvbmFsU3RhcnRlZEF0UmFuZ2UocmFuZ2U/OiB7IGZyb20/OiBzdHJpbmc7IHRvPzogc3RyaW5nIH0pOiBSZXR1cm5UeXBlPHR5cGVvZiBzcWw+IHtcbiAgcmV0dXJuIHJhbmdlPy5mcm9tICYmIHJhbmdlPy50b1xuICAgID8gc3FsYEFORCBlLnN0YXJ0ZWRfYXQgPj0gJHtyYW5nZS5mcm9tfTo6dGltZXN0YW1wdHogQU5EIGUuc3RhcnRlZF9hdCA8PSAke3JhbmdlLnRvfTo6dGltZXN0YW1wdHpgXG4gICAgOiBzcWxgYDtcbn1cblxuLyoqXG4gKiBQZXItZXhlY3V0aW9uIHRlcm1pbmFsIGRlcGxveSByb3cgKEQxIOKAlCBvbmUgcm93IHBlciAoZW52aXJvbm1lbnQsIGV4ZWN1dGlvbiksXG4gKiBOT1QgcGVyIHN0YWdlKS4gVGhlIFNRTCByb2xscyBldmVyeSBkZXBsb3kgU1RBR0UgdGFyZ2V0aW5nIGFuIGVudiB3aXRoaW4gYW5cbiAqIGV4ZWN1dGlvbiB1cCB0byBhIHNpbmdsZSB0ZXJtaW5hbCBzdGF0dXM7IHRoZSBKUyBzaGFwaW5nIGJ1Y2tldHMgdGhlc2UgYnlcbiAqIGVudmlyb25tZW50LiBgY29tbWl0X3RzYCAoRDIpIGlzIHRoZSBleGVjdXRpb24ncyBFQVJMSUVTVCBjb21taXQgdGltZSBhY3Jvc3NcbiAqIGFsbCBpdHMgZXZlbnRzIOKAlCBjb21taXQgZW5yaWNobWVudCByaWRlcyB0aGUgUElQRUxJTkUvc291cmNlIGV2ZW50LCBub3QgdGhlXG4gKiBkZXBsb3kgU1RBR0Ug4oCUIGpvaW5lZCBieSBleGVjdXRpb25faWQgKG51bGwgd2hlbiB1bnJlc29sdmVkIOKGkiBsZWFkIGB1bmtub3duYCkuXG4gKiBgaW5fd2luZG93YCBpcyBmYWxzZSBmb3IgYSBsb29rLWJhY2stb25seSByb3cga2VwdCBzb2xlbHkgc28gaW5jaWRlbnRzIG9wZW5lZFxuICogbmVhciBgZnJvbWAgY2FuIGNvcnJlbGF0ZSB0byBhIGRlcGxveSB0aGF0IGNvbXBsZXRlZCBqdXN0IGJlZm9yZSB0aGUgd2luZG93LlxuICovXG4iXX0=
64
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic3FsLWhlbHBlcnMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvYXBpL3JlcG9ydGluZy9zcWwtaGVscGVycy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSwrQ0FBK0M7QUFDL0Msc0NBQXNDO0FBRXRDOztHQUVHO0FBRUgsT0FBTyxFQUFFLGdCQUFnQixFQUFFLDZCQUE2QixFQUFFLE1BQU0sNEJBQTRCLENBQUM7QUFDN0YsT0FBTyxFQUFFLEdBQUcsRUFBRSxNQUFNLGFBQWEsQ0FBQztBQUVsQzs7Ozs7OztHQU9HO0FBQ0gsTUFBTSxVQUFVLG9CQUFvQixDQUFDLFFBQWdCO0lBQ25ELElBQUksQ0FBRSxnQkFBc0MsQ0FBQyxRQUFRLENBQUMsUUFBUSxDQUFDLEVBQUUsQ0FBQztRQUNoRSxNQUFNLElBQUksS0FBSyxDQUFDLDRCQUE0QixRQUFRLHNCQUFzQixnQkFBZ0IsQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLEVBQUUsQ0FBQyxDQUFDO0lBQzNHLENBQUM7QUFDSCxDQUFDO0FBRUQ7Ozs7O0dBS0c7QUFDSCxNQUFNLFVBQVUsYUFBYSxDQUFDLEtBQXlCO0lBQ3JELE9BQU8sS0FBSyxLQUFLLFNBQVMsQ0FBQyxDQUFDLENBQUMsNkJBQTZCLENBQUMsS0FBSyxDQUFDLENBQUMsQ0FBQyxDQUFDLFNBQVMsQ0FBQztBQUNoRixDQUFDO0FBRUQ7Ozs7OztHQU1HO0FBQ0gsTUFBTSxDQUFDLE1BQU0sb0JBQW9CLEdBQUcsR0FBRyxDQUFBOzs7O2dCQUl2QixDQUFDO0FBRWpCLG9FQUFvRTtBQUNwRSxNQUFNLFVBQVUsZUFBZSxDQUFDLElBQVksRUFBRSxFQUFVO0lBQ3RELE9BQU8sR0FBRyxDQUFBLG1CQUFtQixJQUFJLHFDQUFxQyxFQUFFLGVBQWUsQ0FBQztBQUMxRixDQUFDO0FBRUQ7O3FGQUVxRjtBQUNyRixNQUFNLFVBQVUsc0JBQXNCLENBQUMsS0FBc0M7SUFDM0UsT0FBTyxLQUFLLEVBQUUsSUFBSSxJQUFJLEtBQUssRUFBRSxFQUFFO1FBQzdCLENBQUMsQ0FBQyxHQUFHLENBQUEsT0FBTyxlQUFlLENBQUMsS0FBSyxDQUFDLElBQUksRUFBRSxLQUFLLENBQUMsRUFBRSxDQUFDLEVBQUU7UUFDbkQsQ0FBQyxDQUFDLEdBQUcsQ0FBQSxFQUFFLENBQUM7QUFDWixDQUFDO0FBRUQ7Ozs7Ozs7OztHQVNHIiwic291cmNlc0NvbnRlbnQiOlsiLy8gQ29weXJpZ2h0IDIwMjYgUGlwZWxpbmUgQnVpbGRlciBDb250cmlidXRvcnNcbi8vIFNQRFgtTGljZW5zZS1JZGVudGlmaWVyOiBBcGFjaGUtMi4wXG5cbi8qKlxuICogU21hbGwgU1FMIGZyYWdtZW50cyBhbmQgaW5wdXQgZ3VhcmRzIHNoYXJlZCBhY3Jvc3MgdGhlIHJlcG9ydGluZyBxdWVyaWVzLlxuICovXG5cbmltcG9ydCB7IFJFUE9SVF9JTlRFUlZBTFMsIHNjcnViQXdzSWRlbnRpZmllcnNGcm9tU3RyaW5nIH0gZnJvbSAnQHBpcGVsaW5lLWJ1aWxkZXIvYXBpLWNvcmUnO1xuaW1wb3J0IHsgc3FsIH0gZnJvbSAnZHJpenpsZS1vcm0nO1xuXG4vKipcbiAqIERlZmVuc2UtaW4tZGVwdGggZ3VhcmQgZm9yIHRoZSBgREFURV9UUlVOQygke2ludGVydmFsfSwg4oCmKWAgYnVja2V0IGFyZ3VtZW50LlxuICogVGhlIHJvdXRlIGxheWVyIChgcGFyc2VSZXBvcnRJbnRlcnZhbGApIGlzIHRoZSBzZWN1cml0eSBib3VuZGFyeSBhbmQgYWxyZWFkeVxuICogcmVqZWN0cyB1bmtub3duIGludGVydmFsczsgdGhpcyBhc3NlcnQgbWFrZXMgYW4gaW52YWxpZCB2YWx1ZSBmYWlsIGZhc3QgYXQgdGhlXG4gKiBzZXJ2aWNlIGJvdW5kYXJ5IHdpdGggYSBjbGVhciBlcnJvciBpbnN0ZWFkIG9mIHN1cmZhY2luZyBhIHJhdyBQb3N0Z3JlcyBlcnJvclxuICogaWYgYSBjYWxsZXIgZXZlciBieXBhc3NlcyB0aGUgcm91dGUgdmFsaWRhdGlvbi4gU2hhcmVzIGFwaS1jb3JlJ3NcbiAqIFJFUE9SVF9JTlRFUlZBTFMgYWxsb3ctbGlzdCBzbyB0aGUgdHdvIGNhbid0IGRyaWZ0LlxuICovXG5leHBvcnQgZnVuY3Rpb24gYXNzZXJ0UmVwb3J0SW50ZXJ2YWwoaW50ZXJ2YWw6IHN0cmluZyk6IHZvaWQge1xuICBpZiAoIShSRVBPUlRfSU5URVJWQUxTIGFzIHJlYWRvbmx5IHN0cmluZ1tdKS5pbmNsdWRlcyhpbnRlcnZhbCkpIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IoYEludmFsaWQgcmVwb3J0IGludGVydmFsOiAke2ludGVydmFsfS4gRXhwZWN0ZWQgb25lIG9mOiAke1JFUE9SVF9JTlRFUlZBTFMuam9pbignLCAnKX1gKTtcbiAgfVxufVxuXG4vKipcbiAqIFNjcnViIEFXUyBpZGVudGlmaWVycyBmcm9tIGFuIG9wdGlvbmFsIGZyZWUtZm9ybSBzdHJpbmcsIHByZXNlcnZpbmcgYHVuZGVmaW5lZGBcbiAqIChzbyBhbiBhYnNlbnQgZmllbGQgc3RheXMgYWJzZW50IHJhdGhlciB0aGFuIGJlY29taW5nIGFuIGVtcHR5IHNjcnViYmVkIHN0cmluZykuXG4gKiBUaGUgRFVSQUJMRSBwZXJzaXN0ZW5jZSBib3VuZGFyeSBmb3IgdGhlIGluZ2VzdCBwYXRocyDigJQgZXZlcnkgdXNlci9BV1MtZGVyaXZlZFxuICogc3RyaW5nIGZpZWxkIGlzIGZ1bm5lbGVkIHRocm91Z2ggdGhpcyBiZWZvcmUgaW5zZXJ0LlxuICovXG5leHBvcnQgZnVuY3Rpb24gc2NydWJPcHRpb25hbCh2YWx1ZTogc3RyaW5nIHwgdW5kZWZpbmVkKTogc3RyaW5nIHwgdW5kZWZpbmVkIHtcbiAgcmV0dXJuIHZhbHVlICE9PSB1bmRlZmluZWQgPyBzY3J1YkF3c0lkZW50aWZpZXJzRnJvbVN0cmluZyh2YWx1ZSkgOiB1bmRlZmluZWQ7XG59XG5cbi8qKlxuICogUm9sbCBhIGdyb3VwIG9mIGRlcGxveS9zdGFnZSBldmVudHMgKGdyb3VwZWQgcGVyIGV4ZWN1dGlvbikgdXAgdG8gb25lIHRlcm1pbmFsXG4gKiBzdGF0dXM6IEZBSUxFRCB3aW5zLCB0aGVuIFNVQ0NFRURFRCwgZWxzZSBPVEhFUiAoc3RpbGwtcnVubmluZyAvIG5vbi10ZXJtaW5hbCkuXG4gKiBTaGFyZWQgYnkgdGhlIHRocmVlIHBlci0oZW52fHN0YWdlLCBleGVjdXRpb24pIHJvbGx1cCBDVEVzIOKAlCBET1JBIG1ldHJpY3MsIERPUkFcbiAqIHRyZW5kLCBhbmQgYnVpbGQgaGVhbHRoIOKAlCBzbyB0aGUgcHJlY2VkZW5jZSBjYW4ndCBkcmlmdCBiZXR3ZWVuIHRoZW0uIEFzc3VtZXMgdGhlXG4gKiBncm91cGVkIGV2ZW50IGFsaWFzIGlzIGBlYC5cbiAqL1xuZXhwb3J0IGNvbnN0IHRlcm1pbmFsU3RhdHVzUm9sbHVwID0gc3FsYENBU0VcbiAgICAgICAgICAgICAgV0hFTiBib29sX29yKGUuc3RhdHVzID0gJ0ZBSUxFRCcpIFRIRU4gJ0ZBSUxFRCdcbiAgICAgICAgICAgICAgV0hFTiBib29sX29yKGUuc3RhdHVzID0gJ1NVQ0NFRURFRCcpIFRIRU4gJ1NVQ0NFRURFRCdcbiAgICAgICAgICAgICAgRUxTRSAnT1RIRVInXG4gICAgICAgICAgICBFTkRgO1xuXG4vKiogVGhlIHJlcG9ydCB3aW5kb3cgb24gYGUuc3RhcnRlZF9hdGAgKGluY2x1c2l2ZSBgW2Zyb20sIHRvXWApLiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHN0YXJ0ZWRBdFdpbmRvdyhmcm9tOiBzdHJpbmcsIHRvOiBzdHJpbmcpOiBSZXR1cm5UeXBlPHR5cGVvZiBzcWw+IHtcbiAgcmV0dXJuIHNxbGBlLnN0YXJ0ZWRfYXQgPj0gJHtmcm9tfTo6dGltZXN0YW1wdHogQU5EIGUuc3RhcnRlZF9hdCA8PSAke3RvfTo6dGltZXN0YW1wdHpgO1xufVxuXG4vKiogT3B0aW9uYWwgYFtmcm9tLHRvXWAgd2luZG93IG9uIGBlLnN0YXJ0ZWRfYXRgIGZvciB0aGUgZXhlY3V0aW9uIHJlcG9ydHMg4oCUXG4gKiAgYSBuby1vcCBgc3FsYCBmcmFnbWVudCB3aGVuIGVpdGhlciBib3VuZCBpcyBhYnNlbnQgKGFsbC10aW1lKS4gU2hhcmVkIGJ5IHRoZVxuICogIGV4ZWN1dGlvbi1jb3VudCBhbmQgcGVyLXBpcGVsaW5lLWV4ZWN1dGlvbiByZXBvcnRzIHNvIHRoZXkgbmFycm93IGlkZW50aWNhbGx5LiAqL1xuZXhwb3J0IGZ1bmN0aW9uIG9wdGlvbmFsU3RhcnRlZEF0UmFuZ2UocmFuZ2U/OiB7IGZyb20/OiBzdHJpbmc7IHRvPzogc3RyaW5nIH0pOiBSZXR1cm5UeXBlPHR5cGVvZiBzcWw+IHtcbiAgcmV0dXJuIHJhbmdlPy5mcm9tICYmIHJhbmdlPy50b1xuICAgID8gc3FsYEFORCAke3N0YXJ0ZWRBdFdpbmRvdyhyYW5nZS5mcm9tLCByYW5nZS50byl9YFxuICAgIDogc3FsYGA7XG59XG5cbi8qKlxuICogUGVyLWV4ZWN1dGlvbiB0ZXJtaW5hbCBkZXBsb3kgcm93IChvbmUgcm93IHBlciAoZW52aXJvbm1lbnQsIGV4ZWN1dGlvbiksXG4gKiBOT1QgcGVyIHN0YWdlKS4gVGhlIFNRTCByb2xscyBldmVyeSBkZXBsb3kgU1RBR0UgdGFyZ2V0aW5nIGFuIGVudiB3aXRoaW4gYW5cbiAqIGV4ZWN1dGlvbiB1cCB0byBhIHNpbmdsZSB0ZXJtaW5hbCBzdGF0dXM7IHRoZSBKUyBzaGFwaW5nIGJ1Y2tldHMgdGhlc2UgYnlcbiAqIGVudmlyb25tZW50LiBgY29tbWl0X3RzYCBpcyB0aGUgZXhlY3V0aW9uJ3MgRUFSTElFU1QgY29tbWl0IHRpbWUgYWNyb3NzXG4gKiBhbGwgaXRzIGV2ZW50cyDigJQgY29tbWl0IGVucmljaG1lbnQgcmlkZXMgdGhlIFBJUEVMSU5FL3NvdXJjZSBldmVudCwgbm90IHRoZVxuICogZGVwbG95IFNUQUdFIOKAlCBqb2luZWQgYnkgZXhlY3V0aW9uX2lkIChudWxsIHdoZW4gdW5yZXNvbHZlZCDihpIgbGVhZCBgdW5rbm93bmApLlxuICogYGluX3dpbmRvd2AgaXMgZmFsc2UgZm9yIGEgbG9vay1iYWNrLW9ubHkgcm93IGtlcHQgc29sZWx5IHNvIGluY2lkZW50cyBvcGVuZWRcbiAqIG5lYXIgYGZyb21gIGNhbiBjb3JyZWxhdGUgdG8gYSBkZXBsb3kgdGhhdCBjb21wbGV0ZWQganVzdCBiZWZvcmUgdGhlIHdpbmRvdy5cbiAqL1xuIl19
@@ -103,6 +103,37 @@ export interface BuildDuration {
103
103
  maxMs: number;
104
104
  builds: number;
105
105
  }
106
+ /**
107
+ * Plugin runtime report filters. `publisher: null` selects own-org
108
+ * (publisher-less) plugins; an omitted field doesn't filter.
109
+ */
110
+ export interface PluginRuntimeFilter {
111
+ name?: string;
112
+ publisher?: string | null;
113
+ version?: string;
114
+ }
115
+ /** Per plugin version runtime stats over a window (terminal ACTION runs). */
116
+ export interface PluginRuntimeStats {
117
+ pluginPublisher: string | null;
118
+ pluginName: string;
119
+ pluginVersion: string;
120
+ runs: number;
121
+ succeeded: number;
122
+ failed: number;
123
+ /** 0–100, one decimal. */
124
+ successPct: number;
125
+ /** Null when no run in the group carried a duration. */
126
+ p50Ms: number | null;
127
+ p95Ms: number | null;
128
+ lastRun: string;
129
+ }
130
+ /** Cross-org 30-day aggregate for one `(publisher, name)` listing. */
131
+ export interface PluginRuntimeAggregate {
132
+ runs30d: number;
133
+ /** 0–1; null when there were no runs. */
134
+ successRate30d: number | null;
135
+ activeOrgCount30d: number;
136
+ }
106
137
  export interface BuildFailure {
107
138
  pluginName: string;
108
139
  errorMessage: string;
@@ -114,7 +145,7 @@ export interface BuildFailure {
114
145
  * industry-standard DORA signal; MTTR is measured production-only, and this
115
146
  * environment's card is the summary shown at the top of the panel.
116
147
  */
117
- /** Per-org retention override row (Phase 7). Both nullable ⇒ global defaults. */
148
+ /** Per-org retention override row. Both nullable ⇒ global defaults. */
118
149
  export interface ReportingRetentionSettings {
119
150
  eventRetentionDays: number | null;
120
151
  doraRetentionDays: number | null;
@@ -130,6 +161,15 @@ export interface ReportingRetentionOptions {
130
161
  maxBatchesPerTable?: number;
131
162
  /** Fixed "now" for the whole sweep (default `new Date()`). */
132
163
  now?: Date;
164
+ /**
165
+ * Resolve the org whose `dora_settings` retention governs `orgId`'s rows — its
166
+ * account ROOT. Retention is a billing entitlement synced onto the root only,
167
+ * so a team's rows must follow the root's (purchased) window, not the env
168
+ * default. Return `null` when the root can't be resolved: that org is SKIPPED
169
+ * this tick (never purged on a possibly-shorter window). Default: identity
170
+ * (every org is its own root — a flat deployment).
171
+ */
172
+ resolveRetentionOrgId?: (orgId: string) => Promise<string | null>;
133
173
  }
134
174
  /** Per-run purge tallies (also logged). */
135
175
  export interface ReportingRetentionCounts {
@@ -160,32 +200,32 @@ export interface DoraOptions {
160
200
  * Per-org incident→deploy correlation window override (hours). When set (a
161
201
  * positive finite number), the incident correlation uses it instead of the
162
202
  * global `DORA_INCIDENT_WINDOW_HOURS`. The route resolves this from the org's
163
- * `dora_settings` row (see {@link ReportingService.getIncidentSettings}) and
203
+ * `dora_settings` row (see {@link ReportingService.getReportingSettings}) and
164
204
  * passes it in; unset falls back to the env default.
165
205
  */
166
206
  incidentWindowHours?: number;
167
207
  }
168
208
  /**
169
209
  * Per-org reporting settings surfaced to the org-admin panel. `incidentWindowHours`
170
- * (Phase 5b) is the incident→deploy correlation window; `eventRetentionDays` /
171
- * `doraRetentionDays` (Phase 7) are the two retention-sweep windows. Each override
210
+ * is the incident→deploy correlation window; `eventRetentionDays` /
211
+ * `doraRetentionDays` are the two retention-sweep windows. Each override
172
212
  * is `null` when unset (the paired `default*` field shows the env fallback applied).
173
213
  */
174
- export interface IncidentSettings {
214
+ export interface ReportingSettings {
175
215
  /** The org's stored correlation-window override in hours, or `null` when unset. */
176
216
  incidentWindowHours: number | null;
177
217
  /** The global env default applied when no override is stored. */
178
218
  defaultWindowHours: number;
179
- /** Standard-event retention override in days, or `null` when unset (Phase 7). */
219
+ /** Standard-event retention override in days, or `null` when unset. */
180
220
  eventRetentionDays: number | null;
181
- /** DORA-source retention override in days, or `null` when unset (Phase 7). */
221
+ /** DORA-source retention override in days, or `null` when unset. */
182
222
  doraRetentionDays: number | null;
183
223
  /** Global standard-event retention default applied when unset (days). */
184
224
  defaultEventRetentionDays: number;
185
225
  /** Global DORA-source retention default applied when unset (days). */
186
226
  defaultDoraRetentionDays: number;
187
227
  }
188
- /** A partial reporting-settings write (Phase 5b + 7). Only provided fields are
228
+ /** A partial reporting-settings write (7). Only provided fields are
189
229
  * upserted; omitted fields are left unchanged (an omitted retention field keeps
190
230
  * its stored override / the global default). */
191
231
  export interface ReportingSettingsPatch {
@@ -327,7 +367,7 @@ export interface DoraTrendPoint {
327
367
  /** failed/total as a percent (0 when total is 0). Deploy-time CFR only. */
328
368
  changeFailurePct: number;
329
369
  }
330
- /** Per-stage build-health metrics (Phase 6) for one pipeline over a window. */
370
+ /** Per-stage build-health metrics for one pipeline over a window. */
331
371
  export interface BuildHealthStage {
332
372
  stage: string;
333
373
  /** Terminal stage runs (succeeded + failed) in the window. */
@@ -342,7 +382,7 @@ export interface BuildHealthStage {
342
382
  p99Ms: number | null;
343
383
  }
344
384
  /**
345
- * Per-pipeline build-health breakdown (Phase 6). Standard reporting (NOT
385
+ * Per-pipeline build-health breakdown. Standard reporting (NOT
346
386
  * `advanced_reporting`-gated) — per-stage success rate + timing percentiles, with
347
387
  * totals summed across stages.
348
388
  */
@@ -354,7 +394,7 @@ export interface BuildHealth {
354
394
  failureRate: number;
355
395
  };
356
396
  }
357
- /** Post-deploy incident marker (Phase 5) accepted by `ReportingService.recordIncident`. */
397
+ /** Post-deploy incident marker accepted by `ReportingService.recordIncident`. */
358
398
  export interface IncidentInput {
359
399
  incidentId: string;
360
400
  environment: string;
@@ -414,16 +454,14 @@ export interface IngestResult {
414
454
  * Every org with at least one row in this batch, deduped.
415
455
  *
416
456
  * Already computed for post-commit cache invalidation; surfaced because the
417
- * ingest route needs the same set to push its live SSE frame. That fan-out
418
- * used to be driven off the stage-metric hook, which only fires for STAGE
419
- * events — so a batch of PIPELINE or BUILD events landed rows and pushed no
420
- * frame at all, and the dashboard silently went back to needing a manual
421
- * refresh for exactly the events an execution view is about.
457
+ * ingest route needs the same set to push its live SSE frame. The stage-metric
458
+ * hook can't drive that fan-out: it only fires for STAGE events, so a batch of
459
+ * PIPELINE or BUILD events would land rows and push no frame at all.
422
460
  */
423
461
  affectedOrgs: string[];
424
462
  }
425
463
  /**
426
- * One org's ingestion-health row as READ back by the Reports UI (Phase 3). The
464
+ * One org's ingestion-health row as READ back by the Reports UI. The
427
465
  * AWS events Lambda writes it; this is the shape that lets the UI tell
428
466
  * "ingestion is healthy, there were simply no deploys in the range" apart from
429
467
  * "we haven't heard from the ingest pipeline since X".