@pipeline-builder/pipeline-data 4.1.24 → 4.1.25

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 (64) hide show
  1. package/lib/api/alert-destinations.d.ts +17 -0
  2. package/lib/api/alert-destinations.js +36 -0
  3. package/lib/api/reporting/analytics-queries.d.ts +274 -0
  4. package/lib/api/reporting/analytics-queries.js +598 -0
  5. package/lib/api/reporting/daily-rollup.d.ts +41 -0
  6. package/lib/api/reporting/daily-rollup.js +173 -0
  7. package/lib/api/reporting/deploy-rollup.d.ts +78 -0
  8. package/lib/api/reporting/deploy-rollup.js +203 -0
  9. package/lib/api/reporting/dora-scoring.d.ts +14 -0
  10. package/lib/api/reporting/dora-scoring.js +25 -1
  11. package/lib/api/reporting/dora.js +30 -6
  12. package/lib/api/reporting/failure-classifier.d.ts +54 -0
  13. package/lib/api/reporting/failure-classifier.js +179 -0
  14. package/lib/api/reporting/ingest.d.ts +2 -2
  15. package/lib/api/reporting/ingest.js +129 -4
  16. package/lib/api/reporting/last-deploy.d.ts +31 -0
  17. package/lib/api/reporting/last-deploy.js +93 -0
  18. package/lib/api/reporting/needs-attention.d.ts +93 -0
  19. package/lib/api/reporting/needs-attention.js +152 -0
  20. package/lib/api/reporting/plugin-exposure.d.ts +129 -0
  21. package/lib/api/reporting/plugin-exposure.js +312 -0
  22. package/lib/api/reporting/retention-sweep.js +9 -1
  23. package/lib/api/reporting/sql-helpers.d.ts +35 -2
  24. package/lib/api/reporting/sql-helpers.js +39 -1
  25. package/lib/api/reporting/stakeholder/compose.d.ts +115 -0
  26. package/lib/api/reporting/stakeholder/compose.js +234 -0
  27. package/lib/api/reporting/stakeholder/index.d.ts +14 -0
  28. package/lib/api/reporting/stakeholder/index.js +17 -0
  29. package/lib/api/reporting/stakeholder/period.d.ts +102 -0
  30. package/lib/api/reporting/stakeholder/period.js +273 -0
  31. package/lib/api/reporting/stakeholder/report-html.d.ts +93 -0
  32. package/lib/api/reporting/stakeholder/report-html.js +208 -0
  33. package/lib/api/reporting/stakeholder/sections.d.ts +117 -0
  34. package/lib/api/reporting/stakeholder/sections.js +249 -0
  35. package/lib/api/reporting/stakeholder/store.d.ts +450 -0
  36. package/lib/api/reporting/stakeholder/store.js +981 -0
  37. package/lib/api/reporting/stakeholder/templates.d.ts +21 -0
  38. package/lib/api/reporting/stakeholder/templates.js +104 -0
  39. package/lib/api/reporting/types.d.ts +73 -0
  40. package/lib/api/reporting/types.js +1 -1
  41. package/lib/api/reporting-service.d.ts +94 -5
  42. package/lib/api/reporting-service.js +169 -10
  43. package/lib/api/soft-delete-sweep.d.ts +11 -2
  44. package/lib/api/soft-delete-sweep.js +17 -6
  45. package/lib/database/drizzle-schema.d.ts +2263 -385
  46. package/lib/database/drizzle-schema.js +18 -7
  47. package/lib/database/index.d.ts +1 -1
  48. package/lib/database/index.js +4 -2
  49. package/lib/database/schema/compliance.d.ts +0 -682
  50. package/lib/database/schema/compliance.js +6 -66
  51. package/lib/database/schema/ecosystem.d.ts +20 -157
  52. package/lib/database/schema/ecosystem.js +23 -16
  53. package/lib/database/schema/pipeline.d.ts +200 -0
  54. package/lib/database/schema/pipeline.js +100 -1
  55. package/lib/database/schema/plugin.d.ts +20 -1
  56. package/lib/database/schema/plugin.js +13 -1
  57. package/lib/database/schema/reporting-analytics.d.ts +1212 -0
  58. package/lib/database/schema/reporting-analytics.js +250 -0
  59. package/lib/database/schema/reporting-stakeholder.d.ts +1405 -0
  60. package/lib/database/schema/reporting-stakeholder.js +251 -0
  61. package/lib/index.d.ts +10 -1
  62. package/lib/index.js +15 -1
  63. package/lib/testing/exports.json +67 -4
  64. package/package.json +4 -3
@@ -0,0 +1,450 @@
1
+ import type { ReportCadence, ReportDefinition, ReportPauseReason, ReportRecipient, ReportRun, ReportRunStatus, ReportScope, ReportShareLink, ReportTemplate } from '../../../database/schema/reporting-stakeholder.js';
2
+ /** How long a freshly minted share link lives when the caller names no window. */
3
+ export declare const DEFAULT_SHARE_LINK_TTL_DAYS = 30;
4
+ /** The longest a share link may live. Beyond this it is a permanent URL. */
5
+ export declare const MAX_SHARE_LINK_TTL_DAYS = 180;
6
+ /** A recipient's verification link. Short: it is clicked within minutes or never. */
7
+ export declare const VERIFICATION_TTL_MS: number;
8
+ /**
9
+ * Bounces before an address is treated as undeliverable and skipped. Three, not
10
+ * one: a single bounce is often an out-of-office autoresponder or a full mailbox,
11
+ * and dropping a manager off the list for one of those is a silent failure.
12
+ */
13
+ export declare const MAX_BOUNCES = 3;
14
+ /** SHA-256 hex of a token. The only form any token is ever stored in. */
15
+ export declare function hashToken(token: string): string;
16
+ /** A fresh URL-safe token, and its hash. The raw value is returned exactly once. */
17
+ export declare function mintToken(): {
18
+ token: string;
19
+ tokenHash: string;
20
+ };
21
+ /** What creating a definition needs. */
22
+ export interface CreateDefinitionInput {
23
+ orgId: string;
24
+ name: string;
25
+ template: ReportTemplate;
26
+ sections: string[];
27
+ cadence: ReportCadence;
28
+ timezone: string;
29
+ weekStart: 'monday' | 'sunday';
30
+ scope: ReportScope;
31
+ recipients: string[];
32
+ autoSend: boolean;
33
+ ownerId: string;
34
+ createdBy: string;
35
+ nextRunAt?: Date | null;
36
+ }
37
+ /** The mutable half of a definition. */
38
+ export interface UpdateDefinitionInput {
39
+ name?: string;
40
+ template?: ReportTemplate;
41
+ sections?: string[];
42
+ cadence?: ReportCadence;
43
+ timezone?: string;
44
+ weekStart?: 'monday' | 'sunday';
45
+ scope?: ReportScope;
46
+ recipients?: string[];
47
+ autoSend?: boolean;
48
+ isActive?: boolean;
49
+ pausedReason?: ReportPauseReason | null;
50
+ nextRunAt?: Date | null;
51
+ }
52
+ /** A share link plus the one-time token, returned only from the mint call. */
53
+ export interface MintedShareLink {
54
+ link: ReportShareLink;
55
+ /** Shown once. Never stored, never logged, never in a response again. */
56
+ token: string;
57
+ }
58
+ /** What the public route needs: the link, its run, and the owning org. */
59
+ export interface ResolvedShareLink {
60
+ link: ReportShareLink;
61
+ run: ReportRun;
62
+ }
63
+ export declare class StakeholderReportStore {
64
+ createDefinition(input: CreateDefinitionInput): Promise<ReportDefinition>;
65
+ listDefinitions(orgId: string): Promise<ReportDefinition[]>;
66
+ getDefinition(orgId: string, id: string): Promise<ReportDefinition | null>;
67
+ /** Throws {@link NotFoundError} rather than returning null, for route bodies. */
68
+ requireDefinition(orgId: string, id: string): Promise<ReportDefinition>;
69
+ updateDefinition(orgId: string, id: string, patch: UpdateDefinitionInput, updatedBy: string): Promise<ReportDefinition>;
70
+ /**
71
+ * Hand a definition to a new owner. The owner is who a scheduled run is
72
+ * authorized AS, so this is a privilege move, not a metadata edit — the route
73
+ * checks the new owner is a live member of the org before calling.
74
+ */
75
+ transferOwner(orgId: string, id: string, newOwnerId: string, actorId: string): Promise<ReportDefinition>;
76
+ /**
77
+ * Pause every definition a user owns, with the reason recorded. Called when the
78
+ * owner is deactivated or loses `reports:author` — a report must stop when the
79
+ * person accountable for it can no longer see the data behind it.
80
+ *
81
+ * Returns the paused definitions so the caller can notify an org admin: a
82
+ * silently stopped weekly report is discovered by a manager not receiving it.
83
+ */
84
+ pauseDefinitionsForOwner(orgId: string, ownerId: string, reason: ReportPauseReason): Promise<ReportDefinition[]>;
85
+ deleteDefinition(orgId: string, id: string, deletedBy: string): Promise<void>;
86
+ /**
87
+ * Insert a run for a period, or return the existing one.
88
+ *
89
+ * Idempotent on (definition, periodStart, version): a retry, a catch-up pass
90
+ * and a manual backfill can all ask for the same period, and without this each
91
+ * would insert a row and the lead would review three copies. `onConflictDoNothing`
92
+ * plus a re-read is deliberate — the unique index is the arbiter, so two pods
93
+ * racing produce one row whichever wins.
94
+ */
95
+ createRun(input: {
96
+ orgId: string;
97
+ definitionId: string;
98
+ periodStart: Date;
99
+ periodEnd: Date;
100
+ periodLabel: string;
101
+ version?: number;
102
+ status?: ReportRunStatus;
103
+ snapshot?: Record<string, unknown> | null;
104
+ failureReason?: string | null;
105
+ }): Promise<{
106
+ run: ReportRun;
107
+ created: boolean;
108
+ }>;
109
+ /** The next version number for a period: `max(version) + 1`. */
110
+ nextVersion(definitionId: string, periodStart: Date): Promise<number>;
111
+ /** Point an older run at the version that replaced it. */
112
+ supersede(orgId: string, oldRunId: string, newRunId: string): Promise<void>;
113
+ listRuns(orgId: string, definitionId: string, limit?: number): Promise<ReportRun[]>;
114
+ getRun(orgId: string, id: string): Promise<ReportRun | null>;
115
+ requireRun(orgId: string, id: string): Promise<ReportRun>;
116
+ /** Store a computed snapshot and move the run to `ready_for_review`. */
117
+ completeRun(orgId: string, id: string, snapshot: Record<string, unknown>, status?: ReportRunStatus): Promise<ReportRun>;
118
+ failRun(orgId: string, id: string, failureReason: string): Promise<void>;
119
+ /**
120
+ * Edit the lead's own words on a run that has NOT been published.
121
+ *
122
+ * Refused after publish: the notes are part of what the manager read, and a
123
+ * report whose narrative can be edited after delivery is a report whose
124
+ * delivered version cannot be reconstructed. Regenerating produces version N+1,
125
+ * which is the supported way to correct a published report.
126
+ */
127
+ setRunNotes(orgId: string, id: string, patch: {
128
+ leadNotes?: string;
129
+ aiDraft?: string;
130
+ }): Promise<ReportRun>;
131
+ /**
132
+ * Record what happened when a run was delivered.
133
+ *
134
+ * Deliberately NOT part of {@link setRunNotes}, which refuses a published run: delivery
135
+ * happens AT publish, so a method that refused published runs could never record it.
136
+ * This one writes exactly one column and nothing else, which is why it is safe to allow
137
+ * after publish — it cannot change a number a recipient has read.
138
+ */
139
+ recordDelivery(orgId: string, id: string, delivery: Record<string, unknown>): Promise<void>;
140
+ /**
141
+ * Publish a run.
142
+ *
143
+ * Conditional on the row still being unpublished (`published_at IS NULL`), so
144
+ * two clicks — or two tabs — produce one publish and one set of deliveries
145
+ * rather than two. A run with no snapshot cannot be published: there would be
146
+ * nothing for a recipient to read.
147
+ */
148
+ publishRun(orgId: string, id: string, publishedBy: string): Promise<{
149
+ run: ReportRun;
150
+ alreadyPublished: boolean;
151
+ }>;
152
+ /**
153
+ * Mint a read-only link to a published run. The raw token is returned here and
154
+ * nowhere else — only its hash is stored, so a database copy cannot be turned
155
+ * back into working URLs.
156
+ */
157
+ createShareLink(input: {
158
+ orgId: string;
159
+ runId: string;
160
+ createdBy: string;
161
+ ttlDays?: number;
162
+ redactNames?: boolean;
163
+ now?: Date;
164
+ }): Promise<MintedShareLink>;
165
+ listShareLinks(orgId: string, runId: string): Promise<ReportShareLink[]>;
166
+ revokeShareLink(orgId: string, id: string, revokedBy: string): Promise<ReportShareLink>;
167
+ /** Revoke every live link to any run of a definition. Used on delete. */
168
+ revokeLinksForDefinition(orgId: string, definitionId: string, revokedBy: string): Promise<number>;
169
+ /**
170
+ * Resolve a share token to its link and run, for the UNAUTHENTICATED public
171
+ * route.
172
+ *
173
+ * This is the one read in this module that runs as sysadmin, and the reason is
174
+ * structural: the reader holds a token and nothing else — no account, no org,
175
+ * no JWT — so there is no tenant context for RLS to scope by, and the org can
176
+ * only be learned FROM the row. The escalation is kept as narrow as the problem:
177
+ *
178
+ * - The sysadmin scope covers the token-hash lookup ONLY. The run is read back
179
+ * under the link's OWN org, so a bug in the run query cannot reach another
180
+ * tenant's rows.
181
+ * - The lookup is by a 256-bit hash on a unique index. It is not a filter a
182
+ * caller can widen — there is no other predicate to influence.
183
+ * - Expired and revoked links resolve to null here, so the caller cannot
184
+ * accidentally serve one by forgetting a check.
185
+ *
186
+ * Returns null for every failure — unknown, revoked, expired, or pointing at a
187
+ * run that is no longer published — so the route answers one indistinguishable
188
+ * 404 and a holder of a dead link learns nothing about which of those it was.
189
+ */
190
+ resolveShareLink(token: string, now?: Date): Promise<ResolvedShareLink | null>;
191
+ /**
192
+ * Count one human view of a shared report.
193
+ *
194
+ * Separate from {@link resolveShareLink} so the route can serve a link preview,
195
+ * a HEAD probe or a mail scanner's fetch WITHOUT counting it — a view count that
196
+ * jumps the moment a link is pasted into Slack tells the lead their manager read
197
+ * the report when nobody has.
198
+ */
199
+ recordShareView(link: ReportShareLink, now?: Date): Promise<void>;
200
+ /**
201
+ * Add (or re-add) a delivery address.
202
+ *
203
+ * Upserts on (org, email) and deliberately does NOT reset `unsubscribed_at` or
204
+ * `verified_at`: a lead must not be able to undo someone's unsubscribe by
205
+ * removing and re-adding them, and an address already verified should not have
206
+ * to confirm twice. A verification token is minted only when the address is not
207
+ * yet verified.
208
+ */
209
+ upsertRecipient(input: {
210
+ orgId: string;
211
+ email: string;
212
+ displayName?: string;
213
+ createdBy: string;
214
+ /** Set when an admin pre-approved an out-of-domain address. */
215
+ approvedBy?: string | null;
216
+ /** Org members skip verification — they already authenticated to this org. */
217
+ preVerified?: boolean;
218
+ now?: Date;
219
+ }): Promise<{
220
+ recipient: ReportRecipient;
221
+ verificationToken?: string;
222
+ }>;
223
+ listRecipients(orgId: string): Promise<ReportRecipient[]>;
224
+ getRecipients(orgId: string, ids: string[]): Promise<ReportRecipient[]>;
225
+ /** Mint a fresh verification token for a recipient that has not confirmed yet. */
226
+ resendVerification(orgId: string, id: string): Promise<{
227
+ recipient: ReportRecipient;
228
+ token: string;
229
+ }>;
230
+ /**
231
+ * Confirm an address from the emailed token. Cross-org by necessity (the person
232
+ * clicking has no session), so it runs as sysadmin over a unique 256-bit hash —
233
+ * the same shape, and the same reasoning, as {@link resolveShareLink}.
234
+ *
235
+ * The token is CONSUMED: it is cleared on success, so a forwarded confirmation
236
+ * link cannot be replayed by whoever the mail was forwarded to.
237
+ */
238
+ verifyRecipientByToken(token: string, now?: Date): Promise<ReportRecipient | null>;
239
+ /** Honour an unsubscribe across every definition in the org. */
240
+ unsubscribeByEmail(orgId: string, email: string, now?: Date): Promise<boolean>;
241
+ /**
242
+ * Honour an unsubscribe from the link in a report email.
243
+ *
244
+ * Looked up by TOKEN across orgs, as sysadmin, for the same reason the share-link
245
+ * resolve is: the person clicking has no account and no tenant, and the token is the
246
+ * only thing that identifies the row. It is the narrowest possible shape — one indexed
247
+ * lookup, one column written, nothing returned to the caller but whether a row
248
+ * matched.
249
+ *
250
+ * Idempotent. A mail client that sends the one-click POST twice, or a manager who
251
+ * clicks again months later, gets the same answer rather than an error page — the
252
+ * second call finds the row already unsubscribed and reports success, because from the
253
+ * clicker's point of view it is.
254
+ */
255
+ unsubscribeByToken(token: string, now?: Date): Promise<boolean>;
256
+ /** Record a delivery bounce. At {@link MAX_BOUNCES} the address is skipped. */
257
+ recordBounce(orgId: string, email: string, now?: Date): Promise<number>;
258
+ deleteRecipient(orgId: string, id: string, deletedBy: string): Promise<void>;
259
+ /**
260
+ * Is this address deliverable right now? The single place the delivery rules
261
+ * live, so the scheduler and the UI agree about why a recipient is being
262
+ * skipped.
263
+ */
264
+ deliverability(recipient: ReportRecipient): {
265
+ deliverable: boolean;
266
+ reason?: string;
267
+ };
268
+ /**
269
+ * The org's admin-owned report policy. Read through the reporting settings row,
270
+ * which may not exist — an org that has never configured anything gets the
271
+ * closed defaults (no external sharing, no external domains, approval required).
272
+ */
273
+ getReportPolicy(orgId: string): Promise<{
274
+ externalSharing: boolean;
275
+ recipientDomains: string[] | null;
276
+ requireApproval: boolean;
277
+ defaultTimezone: string | null;
278
+ defaultWeekStart: string | null;
279
+ }>;
280
+ setReportPolicy(orgId: string, patch: {
281
+ externalSharing?: boolean;
282
+ recipientDomains?: string[] | null;
283
+ requireApproval?: boolean;
284
+ defaultTimezone?: string | null;
285
+ defaultWeekStart?: string | null;
286
+ }): Promise<void>;
287
+ /**
288
+ * Apply a Stakeholder Reports entitlement change from billing: pause everything, or
289
+ * resume what the lapse paused.
290
+ *
291
+ * THE WATERMARK AND THE WORK ARE ONE TRANSACTION, and the watermark update is what
292
+ * serializes concurrent pushes. Billing's legs are best-effort and retried, so
293
+ * "lapsed at 10:00" and "renewed at 10:05" can arrive in either order; applying the
294
+ * older one last would leave a lapsed account producing reports, or a paying one
295
+ * paused. The conditional update takes a row lock on `dora_settings`, so a second
296
+ * push waits and then sees the newer watermark — no advisory lock needed.
297
+ *
298
+ * RESUME IS SCOPED TO `entitlement`. It must not un-pause a definition whose OWNER was
299
+ * deactivated or who lost the permission: those are different problems with different
300
+ * fixes, and resuming one by fixing the other is how a report starts running under
301
+ * somebody who left.
302
+ *
303
+ * `nextRunFor` is a callback because the period arithmetic needs each definition's
304
+ * cadence, timezone and week start, and that belongs with the period resolver rather
305
+ * than the store — while the write still has to happen inside this transaction.
306
+ *
307
+ * This leg makes the change IMMEDIATE; it is not what makes it safe. Every scheduled
308
+ * run re-checks the entitlement against platform anyway, so a lost push delays
309
+ * enforcement to the next run rather than defeating it.
310
+ */
311
+ syncReportEntitlement(orgId: string, entitled: boolean, opts?: {
312
+ occurredAt?: Date;
313
+ nextRunFor?: (d: ReportDefinition) => Date;
314
+ now?: Date;
315
+ }): Promise<{
316
+ skipped: boolean;
317
+ paused: ReportDefinition[];
318
+ resumed: ReportDefinition[];
319
+ }>;
320
+ /**
321
+ * Claim the org's ONE free preview, or report that it is already spent.
322
+ *
323
+ * A CONDITIONAL insert-or-update, not read-then-write: two tabs clicking "see a sample"
324
+ * at the same moment must produce one preview, and a check followed by a separate write
325
+ * has a window between them wide enough for both to pass. `WHERE report_preview_used_at
326
+ * IS NULL` on the update, and `onConflictDoUpdate` for the row that may not exist yet,
327
+ * make the claim itself the guard.
328
+ *
329
+ * Returns whether THIS caller won it. A loser is told the preview is spent, which is
330
+ * the truth and is also the upsell.
331
+ */
332
+ claimReportPreview(orgId: string, now?: Date): Promise<boolean>;
333
+ /** Whether the org has already spent its free preview. */
334
+ reportPreviewUsed(orgId: string): Promise<boolean>;
335
+ /**
336
+ * Is `email` admissible as a recipient for this org, and does it need an
337
+ * admin's approval first?
338
+ *
339
+ * `orgMemberEmails` is the set of addresses that already authenticate to this
340
+ * org — they are always admissible and never need verification, because the org
341
+ * has already established they belong to it. Everything else is measured against
342
+ * the allowed-domain list, and a NULL list means "no external addresses at all",
343
+ * not "any address": the closed reading is the one that cannot leak a report by
344
+ * an admin forgetting to configure something.
345
+ */
346
+ admitRecipient(email: string, policy: {
347
+ recipientDomains: string[] | null;
348
+ requireApproval: boolean;
349
+ }, orgMemberEmails: ReadonlySet<string>): {
350
+ admitted: true;
351
+ member: boolean;
352
+ needsApproval: boolean;
353
+ } | {
354
+ admitted: false;
355
+ reason: string;
356
+ };
357
+ /**
358
+ * Hard-delete expired tombstones across every org, for the shared soft-delete
359
+ * sweep. Runs inside the sweep's own sysadmin scope.
360
+ *
361
+ * Runs go first: a purged definition with orphaned runs would leave snapshots
362
+ * nothing can reach, and share links are deleted with their runs so a purge
363
+ * cannot leave a live token pointing at a row that no longer exists.
364
+ */
365
+ purgeableEntities(): Array<{
366
+ name: string;
367
+ purgeExpired(now: Date, limit?: number): Promise<number>;
368
+ }>;
369
+ private purgeRuns;
370
+ private purgeDefinitions;
371
+ private purgeRecipients;
372
+ /** Every definition the owner must be re-checked for, for the pause sweep. */
373
+ listOwnedDefinitions(orgId: string, ownerId: string): Promise<ReportDefinition[]>;
374
+ /**
375
+ * Definitions whose next run is due, across every org.
376
+ *
377
+ * Runs as SYSADMIN, because the scheduler has no tenant: it is looking for work
378
+ * in orgs it has not been told about. This is the one read here that crosses org
379
+ * boundaries, and it is kept to the narrowest possible shape — the rows needed to
380
+ * claim and execute, ordered oldest-due first so a backlog drains in order rather
381
+ * than starving whichever org sorts last by id.
382
+ *
383
+ * `limit` is the per-cycle ceiling: a cycle that tried to drain everything would
384
+ * hold the leader lock for as long as the slowest org's compose takes, times the
385
+ * number of definitions.
386
+ */
387
+ dueDefinitions(now: Date, limit: number): Promise<ReportDefinition[]>;
388
+ /**
389
+ * Claim a due definition by advancing its `nextRunAt`, but only if it still holds
390
+ * the value the scan saw.
391
+ *
392
+ * THE CONDITIONAL UPDATE IS THE CONCURRENCY GUARD, not the leader lock. The lock
393
+ * stops two replicas sweeping in the same window; it does not stop a sweep that
394
+ * outlives its lock TTL from overlapping the next leader's sweep, and both would
395
+ * then select the same still-due definition. Without the `next_run_at = <seen>`
396
+ * predicate each would advance the schedule and each would compose and DELIVER a
397
+ * report — the same manager gets the same report twice, from two pods, which is
398
+ * the failure everyone notices.
399
+ *
400
+ * Runs as sysadmin for the same reason as the scan, and returns whether the claim
401
+ * won so the caller can simply skip a lost race.
402
+ */
403
+ claimDefinition(id: string, seenNextRunAt: Date, nextRunAt: Date, now?: Date): Promise<boolean>;
404
+ /**
405
+ * Set (or clear) a definition's `nextRunAt` without claiming it.
406
+ *
407
+ * Used when a definition is created, resumed, or has its cadence/timezone changed
408
+ * — the schedule has to be re-derived from the calendar rather than left at
409
+ * whatever the old cadence produced.
410
+ */
411
+ setNextRun(orgId: string, id: string, nextRunAt: Date | null): Promise<void>;
412
+ /**
413
+ * Pause ONE definition with the reason, from the scheduler.
414
+ *
415
+ * Separate from {@link pauseDefinitionsForOwner} because the trigger is different:
416
+ * that one is a membership change affecting every definition a person owns, this
417
+ * one is a per-run recheck that failed. Clears `nextRunAt` so a paused definition
418
+ * stops appearing in the due scan at all, rather than being re-claimed and
419
+ * re-rejected every cycle.
420
+ *
421
+ * Runs as sysadmin: the caller is the scheduler, which has no tenant, and the id
422
+ * came from its own cross-org scan.
423
+ */
424
+ pauseDefinition(id: string, reason: ReportPauseReason): Promise<void>;
425
+ /**
426
+ * Resume a paused definition, clearing the reason and re-deriving its schedule.
427
+ *
428
+ * `nextRunAt` is supplied by the caller rather than computed here: the period
429
+ * arithmetic needs the definition's timezone and week start, and that belongs with
430
+ * the period resolver, not the store.
431
+ */
432
+ resumeDefinition(orgId: string, id: string, nextRunAt: Date, actorId: string): Promise<ReportDefinition>;
433
+ /**
434
+ * Pause every ACTIVE definition in an org, with the reason.
435
+ *
436
+ * The entitlement lapse leg: billing tells reporting the add-on is gone, and every
437
+ * definition in the account stops. Returns the rows so the caller can notify.
438
+ */
439
+ pauseDefinitionsForOrg(orgId: string, reason: ReportPauseReason): Promise<ReportDefinition[]>;
440
+ /**
441
+ * Every definition in an org paused for `reason`, for the resume leg.
442
+ *
443
+ * Scoped to the reason on purpose: re-subscribing must not un-pause a definition
444
+ * whose owner was deactivated. Those are different problems with different fixes,
445
+ * and resuming one by fixing the other is how a report starts running under a
446
+ * person who left.
447
+ */
448
+ definitionsPausedFor(orgId: string, reason: ReportPauseReason): Promise<ReportDefinition[]>;
449
+ }
450
+ export declare const stakeholderReportStore: StakeholderReportStore;