@happyvertical/smrt-reports 0.42.6 → 0.42.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts CHANGED
@@ -6,6 +6,11 @@ import { AggregateTimeBucketUnit } from '@happyvertical/sql';
6
6
  import { bucketExpr } from '@happyvertical/sql';
7
7
  import { buildAggregate } from '@happyvertical/sql';
8
8
  import { DatabaseInterface } from '@happyvertical/sql';
9
+ import { DataQueryFieldDescriptor } from '@happyvertical/smrt-types';
10
+ import { DataQueryFilter } from '@happyvertical/smrt-types';
11
+ import { DataQueryRequest } from '@happyvertical/smrt-types';
12
+ import { DataQueryResult } from '@happyvertical/smrt-types';
13
+ import { DataQuerySchema } from '@happyvertical/smrt-types';
9
14
  import { EventEmitter } from 'node:events';
10
15
  import { SmrtCollection } from '@happyvertical/smrt-core';
11
16
  import { SmrtJob } from '@happyvertical/smrt-jobs';
@@ -28,6 +33,22 @@ export { AggregateSelectExpr }
28
33
 
29
34
  export { AggregateSpec }
30
35
 
36
+ export declare interface AppliedReportRefresh {
37
+ phase: 'apply';
38
+ job: ReportRefreshJobHandle;
39
+ }
40
+
41
+ /** Queue a manual refresh only after the action host authorizes and audits it. */
42
+ export declare function applyReportRefresh(reportCtor: ReportCtor, options: ApplyReportRefreshOptions): Promise<AppliedReportRefresh>;
43
+
44
+ export declare interface ApplyReportRefreshOptions extends PreviewReportRefreshOptions {
45
+ queue?: string;
46
+ priority?: number;
47
+ timeout?: number;
48
+ maxAttempts?: number;
49
+ tenantJobCap?: number;
50
+ }
51
+
31
52
  export declare function assertReportTablesReady(db: DatabaseInterface, tables?: readonly string[]): Promise<void>;
32
53
 
33
54
  export declare const avg: (column?: string, options?: {
@@ -38,8 +59,18 @@ export { bucketExpr }
38
59
 
39
60
  export { buildAggregate }
40
61
 
62
+ export declare function buildReportAdapterDescriptor(reportCtor: new (...args: any[]) => SmrtObject, options?: ReportAdapterOptions): Promise<ReportAdapterDescriptor>;
63
+
41
64
  export declare function buildReportDefinition(reportCtor: new (...args: any[]) => SmrtObject): Promise<ReportDefinition>;
42
65
 
66
+ /**
67
+ * Bind a materialized report row to its declared source dimensions. This is a
68
+ * query handoff, not an executor: an authenticated source adapter must apply
69
+ * the inherited principal, tenant, definition, and field policy before it
70
+ * reads source records.
71
+ */
72
+ export declare function buildReportDrilldownQuery(reportCtor: new (...args: any[]) => SmrtObject, row: Readonly<Record<string, unknown>>, options?: ReportAdapterOptions): Promise<ReportDrilldownQuery>;
73
+
43
74
  export declare function compileReportDefinition(definition: ReportDefinition): AggregateSpec;
44
75
 
45
76
  export declare function compileReportSpec(reportCtor: new (...args: any[]) => SmrtObject): Promise<AggregateSpec>;
@@ -59,7 +90,7 @@ export declare const day: (sourceColumn: string) => PropertyDecorator;
59
90
  export declare function enqueueReportRefresh(options: EnqueueReportRefreshOptions): Promise<SmrtJob>;
60
91
 
61
92
  export declare interface EnqueueReportRefreshOptions extends ReportRefreshJobArgs {
62
- report?: ReportCtor_2;
93
+ report?: ReportCtor_3;
63
94
  reportClass: string;
64
95
  db: DatabaseInterface;
65
96
  queue?: string;
@@ -73,7 +104,7 @@ export declare function ensureReportRefreshSchedules(options: EnsureReportSchedu
73
104
 
74
105
  export declare interface EnsureReportSchedulesOptions {
75
106
  db: DatabaseInterface;
76
- reports: ReportCtor_2[];
107
+ reports: ReportCtor_3[];
77
108
  tenantIds?: string[];
78
109
  queue?: string;
79
110
  priority?: number;
@@ -82,6 +113,13 @@ export declare interface EnsureReportSchedulesOptions {
82
113
 
83
114
  export declare function getReportGroupingColumns(definition: Pick<ReportDefinition, 'fields'>): string[];
84
115
 
116
+ /**
117
+ * Read only the ambient tenant's report state. The caller cannot supply a
118
+ * tenant selector, which prevents lifecycle lookup from becoming a tenant
119
+ * enumeration surface.
120
+ */
121
+ export declare function getReportLifecycle(reportCtor: ReportCtor, options: ReportLifecycleOptions): Promise<ReportLifecycleSnapshot>;
122
+
85
123
  export declare function getRuntimeReportOptions(ctor: Function): ReportOptions | undefined;
86
124
 
87
125
  export declare function groupBy(sourceColumn?: string): PropertyDecorator;
@@ -100,9 +138,32 @@ export declare const minute: (sourceColumn: string) => PropertyDecorator;
100
138
 
101
139
  export declare const month: (sourceColumn: string) => PropertyDecorator;
102
140
 
141
+ /** Preview only declares a separately authorized and audited refresh request. */
142
+ export declare function previewReportRefresh(reportCtor: ReportCtor, options: PreviewReportRefreshOptions): Promise<ReportRefreshPreview>;
143
+
144
+ export declare interface PreviewReportRefreshOptions extends ReportLifecycleOptions {
145
+ host: ReportRefreshActionHost;
146
+ mode?: ReportRefreshMode;
147
+ /**
148
+ * Pass `descriptor.refresh.action` when the adapter declares a custom
149
+ * refresh permission, so the displayed and enforced action stay aligned.
150
+ */
151
+ refreshAction?: Pick<ReportRefreshActionDescriptor, 'requiredPermission'>;
152
+ }
153
+
103
154
  export declare const quarter: (sourceColumn: string) => PropertyDecorator;
104
155
 
105
- export declare function refreshReport(reportCtor: ReportCtor, options?: ReportRefreshOptions): Promise<ReportRefreshResult>;
156
+ /**
157
+ * Execute bounded materialized report reads through the canonical query
158
+ * envelope. Every predicate is an adapter-declared field/operator pair; the
159
+ * collection converts it to parameterized SQL and applies tenant interceptors
160
+ * to list, count, and facet reads alike.
161
+ */
162
+ export declare function queryReportMaterializedRows(reportCtor: new (...args: any[]) => SmrtObject, input: unknown, options: ReportBackgroundQueryOptions): Promise<ReportBackgroundQueryResult>;
163
+
164
+ export declare function queryReportMaterializedRows(reportCtor: new (...args: any[]) => SmrtObject, input: unknown, options?: ReportQueryOptions): Promise<ReportDataQueryResult>;
165
+
166
+ export declare function refreshReport(reportCtor: ReportCtor_2, options?: ReportRefreshOptions): Promise<ReportRefreshResult>;
106
167
 
107
168
  export declare function registerReportRefreshInterceptor(options: ReportRefreshInterceptorOptions): () => boolean;
108
169
 
@@ -122,6 +183,36 @@ export declare const REPORT_SCHEDULES_TABLE = "_smrt_report_schedules";
122
183
 
123
184
  export declare const REPORT_WATERMARKS_TABLE = "_smrt_report_watermarks";
124
185
 
186
+ /**
187
+ * The report-owned, transport-neutral descriptor. Consumers can map `schema`
188
+ * to the canonical data-query runtime and `columns` to their presentation
189
+ * contract without importing smrt-ui or a report domain class.
190
+ */
191
+ export declare interface ReportAdapterDescriptor {
192
+ version: 1;
193
+ resourceId: string;
194
+ reportClassName: string;
195
+ sourceClassName: string;
196
+ tenantScoped: boolean;
197
+ tenantField?: string;
198
+ identityField: 'id';
199
+ columns: ReportColumnDescriptor[];
200
+ schema: DataQuerySchema;
201
+ queryExecution: ReportQueryExecutionDescriptor;
202
+ dataTable: ReportDataTableDescriptor;
203
+ drilldown: ReportDrilldownDescriptor;
204
+ refresh: ReportRefreshDescriptor;
205
+ }
206
+
207
+ export declare interface ReportAdapterOptions {
208
+ /** Scope used only to make a stable resource id; it is not authority. */
209
+ tenantScope?: 'current' | 'global' | 'tenant';
210
+ /** Permission that a lifecycle action host must require before refresh. */
211
+ refreshPermission?: string;
212
+ /** Consumer-owned presentational preferences; they never affect query rows. */
213
+ dataTable?: ReportDataTablePresentationOptions;
214
+ }
215
+
125
216
  export declare interface ReportAggregateFieldMetadata {
126
217
  kind: 'aggregate';
127
218
  fn: ReportAggregateFn;
@@ -131,16 +222,170 @@ export declare interface ReportAggregateFieldMetadata {
131
222
 
132
223
  export declare type ReportAggregateFn = AggregateFunction;
133
224
 
225
+ /** Background execution is possible only through an application-owned queue host. */
226
+ export declare interface ReportBackgroundQueryOptions extends ReportQueryCommonOptions {
227
+ execution: 'background';
228
+ enqueueBackgroundQuery(task: ReportBackgroundQueryTask): Promise<{
229
+ taskId: string;
230
+ }>;
231
+ }
232
+
233
+ /** Queuing a background query returns a handle, never rows from another scope. */
234
+ export declare interface ReportBackgroundQueryResult {
235
+ version: 1;
236
+ execution: 'background';
237
+ status: 'queued';
238
+ taskId: string;
239
+ queryFingerprint: string;
240
+ }
241
+
242
+ /**
243
+ * The exact bounded request a background host may persist. Tenant, principal,
244
+ * collection, database, and display state deliberately remain with that host.
245
+ */
246
+ export declare interface ReportBackgroundQueryTask {
247
+ version: 1;
248
+ execution: 'background';
249
+ resourceId: string;
250
+ reportClassName: string;
251
+ request: DataQueryRequest;
252
+ inherits: Array<'principal' | 'tenant' | 'report-definition' | 'field-policy'>;
253
+ }
254
+
134
255
  export declare interface ReportBucketFieldMetadata {
135
256
  kind: 'bucket';
136
257
  unit: ReportTimeBucketUnit;
137
258
  sourceColumn: string;
138
259
  }
139
260
 
261
+ export declare type ReportColumnCapability = 'read' | 'project' | 'filter' | 'sort' | 'facet' | 'group' | 'aggregate';
262
+
263
+ export declare interface ReportColumnDescriptor extends DataQueryFieldDescriptor {
264
+ /** Stable output column id (never a property path). */
265
+ id: string;
266
+ fieldName: string;
267
+ label: string;
268
+ kind: ReportColumnKind;
269
+ filterScope: ReportFilterScope;
270
+ /** Capabilities available from this adapter revision. */
271
+ capabilities: ReportColumnCapability[];
272
+ format?: string;
273
+ sensitivity?: ReportColumnSensitivity;
274
+ sourceColumn?: string;
275
+ bucket?: ReportTimeBucketUnit;
276
+ aggregate?: ReportAggregateFn;
277
+ distinct?: boolean;
278
+ }
279
+
280
+ export declare type ReportColumnKind = 'identity' | 'group' | 'bucket' | 'aggregate';
281
+
282
+ /** Presentation and policy metadata understood by the report adapter. */
283
+ export declare type ReportColumnSensitivity = 'public' | 'personal' | 'sensitive' | 'secret';
284
+
140
285
  declare type ReportCtor = new (...args: any[]) => SmrtObject;
141
286
 
142
287
  declare type ReportCtor_2 = new (...args: any[]) => SmrtObject;
143
288
 
289
+ declare type ReportCtor_3 = new (...args: any[]) => SmrtObject;
290
+
291
+ export declare interface ReportDataQueryResult extends DataQueryResult {
292
+ /** Delivery intent only; the adapter never mutates a visible surface. */
293
+ execution: 'visible' | 'silent';
294
+ reportLifecycle?: ReportMaterializedReadLifecycle;
295
+ }
296
+
297
+ export declare interface ReportDataTableColumn {
298
+ id: string;
299
+ label: string;
300
+ accessor: string;
301
+ sortable: boolean;
302
+ searchable: false;
303
+ filterable: boolean;
304
+ /** Group ancestry for consumers with multi-level table headers. */
305
+ headerPath: ReportDataTableHeaderPathSegment[];
306
+ /** Consumer-side display instruction; materialized rows remain raw. */
307
+ valueFormat: ReportDataTableValueFormat;
308
+ /** The default alignment for the formatted display value. */
309
+ align: 'left' | 'right';
310
+ /** Generic semantic role for status/action columns introduced by later slices. */
311
+ role: ReportDataTableColumnRole;
312
+ responsive: ReportDataTableColumnResponsive;
313
+ }
314
+
315
+ /** Per-column presentation overrides owned by the consuming report surface. */
316
+ export declare interface ReportDataTableColumnOverride {
317
+ label?: string;
318
+ headerPath?: readonly ReportDataTableHeaderPathSegment[];
319
+ valueFormat?: ReportDataTableValueFormat;
320
+ align?: 'left' | 'right';
321
+ role?: ReportDataTableColumnRole;
322
+ responsive?: ReportDataTableColumnResponsive;
323
+ }
324
+
325
+ /** Responsive metadata that maps directly to a consumer's table contract. */
326
+ export declare interface ReportDataTableColumnResponsive {
327
+ /** Higher values make a column more important during responsive collapse. */
328
+ priority?: number;
329
+ /** Keep key dimensions reachable during responsive collapse. */
330
+ keepVisible?: boolean;
331
+ }
332
+
333
+ export declare type ReportDataTableColumnRole = 'data' | 'status' | 'action';
334
+
335
+ export declare interface ReportDataTableDescriptor {
336
+ rowKey: 'id';
337
+ manualPagination: true;
338
+ manualSorting: true;
339
+ enableFiltering: true;
340
+ enableSearch: false;
341
+ columns: ReportDataTableColumn[];
342
+ structuralRows: ReportDataTableStructuralRow[];
343
+ }
344
+
345
+ /** Structural DataTable view hints; deliberately not a smrt-ui dependency. */
346
+ export declare interface ReportDataTableHeaderPathSegment {
347
+ /** Stable group identity within a header level. */
348
+ id: string;
349
+ /** Human-readable grouped-header label. */
350
+ label: string;
351
+ }
352
+
353
+ export declare interface ReportDataTablePresentationOptions {
354
+ /** Overrides are keyed by stable adapter column id, not display labels. */
355
+ columns?: Readonly<Record<string, ReportDataTableColumnOverride>>;
356
+ /** Summary/subtotal rows remain structural rather than materialized data rows. */
357
+ structuralRows?: readonly ReportDataTableStructuralRowInput[];
358
+ }
359
+
360
+ /**
361
+ * Structural rows are intentionally separate from materialized data rows.
362
+ * Consumers pass them to their DataTable's structural-row slot/prop, never its
363
+ * selectable data collection.
364
+ */
365
+ export declare interface ReportDataTableStructuralRow extends ReportDataTableStructuralRowInput {
366
+ selection: 'excluded';
367
+ actions: 'excluded';
368
+ }
369
+
370
+ /** Input supplied by a report consumer that computes a summary or subtotal. */
371
+ export declare interface ReportDataTableStructuralRowInput {
372
+ id: string;
373
+ kind: ReportDataTableStructuralRowKind;
374
+ label: string;
375
+ /** Raw values keyed by the adapter's stable column id. */
376
+ values?: Readonly<Record<string, unknown>>;
377
+ /** Column that renders this row's accessible row header. */
378
+ labelColumnId?: string;
379
+ }
380
+
381
+ export declare type ReportDataTableStructuralRowKind = 'summary' | 'subtotal' | 'aggregate' | 'footer';
382
+
383
+ /**
384
+ * A rendering instruction for a raw materialized value. Formatting is never
385
+ * applied to a query row, so sorting, export, and agent consumers retain it.
386
+ */
387
+ export declare type ReportDataTableValueFormat = 'text' | 'date' | 'datetime' | 'percentage' | 'count' | 'money' | 'number';
388
+
144
389
  export declare interface ReportDefinition {
145
390
  reportClassName: string;
146
391
  sourceClassName: string;
@@ -151,6 +396,46 @@ export declare interface ReportDefinition {
151
396
  refresh?: ReportRefreshConfig;
152
397
  }
153
398
 
399
+ export declare interface ReportDrilldownConstraint {
400
+ id: string;
401
+ sourceColumn: string;
402
+ kind: 'group' | 'bucket';
403
+ value: unknown;
404
+ bucket?: ReportTimeBucketUnit;
405
+ }
406
+
407
+ /**
408
+ * Declarative source-query handoff for a report row. No client can supply a
409
+ * principal, tenant, report definition, or arbitrary source field here.
410
+ */
411
+ export declare interface ReportDrilldownDescriptor {
412
+ id: 'drilldown';
413
+ sourceClassName: string;
414
+ fields: ReportDrilldownFieldDescriptor[];
415
+ inherits: Array<'principal' | 'tenant' | 'report-definition' | 'field-policy'>;
416
+ }
417
+
418
+ /** One row value that can safely constrain a source-record drilldown. */
419
+ export declare interface ReportDrilldownFieldDescriptor {
420
+ /** Stable report column id; never a display label. */
421
+ id: string;
422
+ /** Declared source field/column chosen by report metadata, not caller input. */
423
+ sourceColumn: string;
424
+ kind: 'group' | 'bucket';
425
+ /** A bucket stays declarative so the source adapter preserves report timezone semantics. */
426
+ bucket?: ReportTimeBucketUnit;
427
+ }
428
+
429
+ /** A server adapter uses this authority-free handoff to execute a source drilldown. */
430
+ export declare interface ReportDrilldownQuery {
431
+ version: 1;
432
+ resourceId: string;
433
+ reportClassName: string;
434
+ sourceClassName: string;
435
+ constraints: ReportDrilldownConstraint[];
436
+ inherits: Array<'principal' | 'tenant' | 'report-definition' | 'field-policy'>;
437
+ }
438
+
154
439
  export declare interface ReportFieldDefinition {
155
440
  fieldName: string;
156
441
  columnName?: string;
@@ -160,11 +445,74 @@ export declare interface ReportFieldDefinition {
160
445
 
161
446
  export declare type ReportFieldMetadata = ReportGroupFieldMetadata | ReportBucketFieldMetadata | ReportAggregateFieldMetadata;
162
447
 
448
+ /**
449
+ * Source-query clause a field belongs to. The materialized read executor
450
+ * applies both kinds through its tenant-scoped collection, but consumers use
451
+ * this declaration to keep dimensions/periods (WHERE) distinct from measures
452
+ * (HAVING) when constructing drilldowns, saved views, or a live query.
453
+ */
454
+ export declare type ReportFilterScope = 'where' | 'having';
455
+
163
456
  export declare interface ReportGroupFieldMetadata {
164
457
  kind: 'group';
165
458
  sourceColumn?: string;
166
459
  }
167
460
 
461
+ export declare interface ReportLifecycleOptions {
462
+ db: DatabaseInterface;
463
+ /** Test seam; production callers use the current clock. */
464
+ now?: Date;
465
+ }
466
+
467
+ export declare interface ReportLifecycleRun {
468
+ id: string;
469
+ status: 'running' | 'success' | 'failed' | 'skipped';
470
+ mode: ReportRefreshMode;
471
+ trigger: ReportRefreshTrigger;
472
+ startedAt?: string;
473
+ completedAt?: string;
474
+ rowCount: number;
475
+ changedGroupCount: number;
476
+ /** A failed run is safe to retry through the separately permissioned action. */
477
+ mayRetry: boolean;
478
+ }
479
+
480
+ /**
481
+ * Transport-neutral report lifecycle state. It deliberately never includes a
482
+ * lock owner, a raw failure message, or tenant fanout identifiers.
483
+ */
484
+ export declare interface ReportLifecycleSnapshot {
485
+ version: 1;
486
+ state: ReportLifecycleState;
487
+ asOf?: string;
488
+ refreshedAt?: string;
489
+ /** Whether existing materialized rows can remain visible while work changes state. */
490
+ hasUsableRows: boolean;
491
+ mode: ReportRefreshMode;
492
+ run?: ReportLifecycleRun;
493
+ /** A stable, redacted failure signal; raw executor errors stay server-side. */
494
+ failure?: {
495
+ code: 'refresh_failed';
496
+ retryable: true;
497
+ };
498
+ lock: {
499
+ held: boolean;
500
+ expiresAt?: string;
501
+ };
502
+ }
503
+
504
+ export declare type ReportLifecycleState = 'current' | 'stale' | 'refreshing' | 'lock-skipped' | 'failed';
505
+
506
+ /** Lifecycle context attached only when a caller explicitly opts in. */
507
+ export declare interface ReportMaterializedReadLifecycle {
508
+ snapshot: ReportLifecycleSnapshot;
509
+ /** Whether this collection read appears to have completed a TTL refresh. */
510
+ read: 'current' | 'stale' | 'refresh-triggered';
511
+ }
512
+
513
+ /** Read the already-materialized primary key; never use a display/page index. */
514
+ export declare function reportMaterializedRowKey(row: Record<string, unknown>): string;
515
+
168
516
  export declare interface ReportOptions {
169
517
  source: ReportSource;
170
518
  where?: WhereClause;
@@ -172,6 +520,82 @@ export declare interface ReportOptions {
172
520
  refresh?: ReportRefreshConfig;
173
521
  }
174
522
 
523
+ declare interface ReportQueryCommonOptions {
524
+ /** Injected collection seam for tests and application-owned adapters. */
525
+ collection?: {
526
+ list(options: Record<string, unknown>): Promise<Array<Record<string, unknown>>>;
527
+ count(options?: Record<string, unknown>): Promise<number>;
528
+ facets?(options: Record<string, unknown>): Promise<Array<{
529
+ field: string;
530
+ values: Array<{
531
+ value: string | number | boolean | null;
532
+ count: number;
533
+ }>;
534
+ }>>;
535
+ };
536
+ db?: DatabaseInterface;
537
+ /**
538
+ * Opt in to a tenant-safe lifecycle snapshot alongside this materialized
539
+ * read. It never makes a generic read mutate.
540
+ */
541
+ lifecycle?: Omit<ReportLifecycleOptions, 'db'>;
542
+ }
543
+
544
+ export declare interface ReportQueryExecutionDescriptor {
545
+ modes: ReportQueryExecutionMode[];
546
+ /** The caller may apply the returned rows to an already-authorized surface. */
547
+ visible: {
548
+ delivery: 'result';
549
+ };
550
+ /** A host queues the authority-free task and returns no materialized rows yet. */
551
+ background: {
552
+ delivery: 'queued';
553
+ requiresHost: true;
554
+ };
555
+ /** The caller receives rows but the adapter makes no visible-surface change. */
556
+ silent: {
557
+ delivery: 'result';
558
+ mutatesVisibleSurface: false;
559
+ };
560
+ }
561
+
562
+ /**
563
+ * Delivery choices for the same bounded report query. They never add
564
+ * authority: a host owns visible state and background-job execution.
565
+ */
566
+ export declare type ReportQueryExecutionMode = 'visible' | 'background' | 'silent';
567
+
568
+ /** Visible is the default; silent has identical data authority but no UI intent. */
569
+ export declare interface ReportQueryOptions extends ReportQueryCommonOptions {
570
+ execution?: 'visible' | 'silent';
571
+ }
572
+
573
+ export declare interface ReportRefreshActionContext {
574
+ phase: 'preview' | 'apply';
575
+ reportClassName: string;
576
+ /** The action always applies to the caller's already-bound tenant scope. */
577
+ tenantScope: 'ambient';
578
+ mode: ReportRefreshMode;
579
+ requiredPermission: string;
580
+ }
581
+
582
+ /** A report-wide lifecycle action, never a mutation performed by this adapter. */
583
+ export declare interface ReportRefreshActionDescriptor {
584
+ id: 'refresh';
585
+ label: 'Refresh report';
586
+ scope: 'surface';
587
+ phases: Array<'preview' | 'apply'>;
588
+ requiresPermission: true;
589
+ requiredPermission: string;
590
+ auditRequired: true;
591
+ }
592
+
593
+ /** Authority and audit stay with the application action host, not reports. */
594
+ export declare interface ReportRefreshActionHost {
595
+ authorize(context: ReportRefreshActionContext): Promise<void> | void;
596
+ audit(context: ReportRefreshActionContext): Promise<void> | void;
597
+ }
598
+
175
599
  export declare interface ReportRefreshConfig {
176
600
  mode?: ReportRefreshMode;
177
601
  schedule?: string;
@@ -190,9 +614,23 @@ export declare interface ReportRefreshConfig {
190
614
  tenantFanout?: boolean;
191
615
  }
192
616
 
617
+ export declare interface ReportRefreshDescriptor {
618
+ mode: 'rebuild' | 'incremental';
619
+ /**
620
+ * Whether the report configuration lets a registered SmrtReportCollection
621
+ * synchronously refresh a stale read. Generic collection reads stay
622
+ * read-only and report unknown freshness until the lifecycle adapter runs.
623
+ */
624
+ mayRefreshOnRead: boolean;
625
+ ttlMs?: number;
626
+ triggers: Array<'manual' | 'schedule' | 'change' | 'ttl' | 'job'>;
627
+ /** Declared only; the lifecycle adapter owns authorization, audit, and run state. */
628
+ action: ReportRefreshActionDescriptor;
629
+ }
630
+
193
631
  export declare interface ReportRefreshInterceptorOptions {
194
632
  db: DatabaseInterface;
195
- reports: ReportCtor_2[];
633
+ reports: ReportCtor_3[];
196
634
  enqueue?: boolean;
197
635
  queue?: string;
198
636
  priority?: number;
@@ -213,6 +651,15 @@ export declare interface ReportRefreshJobArgs {
213
651
  _scheduleId?: string;
214
652
  }
215
653
 
654
+ export declare interface ReportRefreshJobHandle {
655
+ jobId: string;
656
+ status: 'pending' | 'running' | 'completed' | 'failed' | 'cancelled';
657
+ attempts: number;
658
+ maxAttempts: number;
659
+ /** Bounded polling guidance; this API does not create a second queue. */
660
+ pollAfterMs: number;
661
+ }
662
+
216
663
  export declare type ReportRefreshMode = 'rebuild' | 'incremental';
217
664
 
218
665
  export declare interface ReportRefreshOptions {
@@ -229,6 +676,27 @@ export declare interface ReportRefreshOptions {
229
676
  changedRows?: Record<string, unknown>[];
230
677
  }
231
678
 
679
+ export declare interface ReportRefreshOutcome {
680
+ state: 'current' | 'lock-skipped' | 'partial';
681
+ rowCount: number;
682
+ changedGroupCount: number;
683
+ completedScopes: number;
684
+ lockSkippedScopes: number;
685
+ mode: ReportRefreshMode;
686
+ refreshedAt: string;
687
+ runId?: string;
688
+ }
689
+
690
+ /** Normalize executor results without exposing the tenant identifiers in a fanout. */
691
+ export declare function reportRefreshOutcome(result: ReportRefreshResult): ReportRefreshOutcome;
692
+
693
+ export declare interface ReportRefreshPreview {
694
+ phase: 'preview';
695
+ lifecycle: ReportLifecycleSnapshot;
696
+ action: ReportRefreshActionContext;
697
+ execution: 'background';
698
+ }
699
+
232
700
  export declare interface ReportRefreshResult {
233
701
  rowCount: number;
234
702
  refreshedAt: Date;
@@ -396,6 +864,17 @@ export declare class SmrtReportWatermarkCollection extends SmrtCollection<SmrtRe
396
864
  static readonly _itemClass: typeof SmrtReportWatermark;
397
865
  }
398
866
 
867
+ /**
868
+ * Split the declared filter language by report semantics for consumers that
869
+ * construct a live source query. Mixed AND expressions are represented as two
870
+ * independent clauses; mixed OR/NOT expressions are rejected because moving
871
+ * either half across WHERE/HAVING would change their meaning.
872
+ */
873
+ export declare function splitReportFilterScopes(descriptor: ReportAdapterDescriptor, filter: DataQueryFilter | undefined): {
874
+ where?: DataQueryFilter;
875
+ having?: DataQueryFilter;
876
+ };
877
+
399
878
  export declare const sum: (column?: string, options?: {
400
879
  distinct?: boolean;
401
880
  }) => PropertyDecorator;