@happyvertical/smrt-reports 0.49.3 → 0.49.4
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/README.md +11 -1
- package/dist/index.d.ts +60 -3
- package/dist/index.js +11 -5
- package/dist/index.js.map +1 -1
- package/dist/manifest.json +438 -22
- package/dist/scheduler.d.ts +53 -1
- package/dist/scheduler.js +135 -21
- package/dist/scheduler.js.map +1 -1
- package/dist/smrt-knowledge.json +87 -5
- package/package.json +6 -6
package/README.md
CHANGED
|
@@ -224,7 +224,17 @@ state; it redacts lock owners, raw errors, and tenant-fanout identifiers. Pass a
|
|
|
224
224
|
that context; the result then distinguishes a current, stale, or read-triggered
|
|
225
225
|
refresh. `previewReportRefresh()` and `applyReportRefresh()` require an
|
|
226
226
|
application action host to authorize and audit the caller before a durable
|
|
227
|
-
report-refresh job is queued.
|
|
227
|
+
report-refresh job is queued. Manual refresh hosts must also return a versioned,
|
|
228
|
+
non-secret `executionAuthority` binding. Each worker process registers the named
|
|
229
|
+
host with `registerReportRefreshExecutionAuthorityHost()`; the task checks the
|
|
230
|
+
persisted tenant binding, resolves current membership and permission, and records
|
|
231
|
+
an allowed or denied execution audit immediately before refresh. Every enqueue
|
|
232
|
+
path also receives a `DurableJobPayloadSigner`, and every worker registers it
|
|
233
|
+
with `registerReportRefreshJobIntegritySigner()`. This authenticates the task
|
|
234
|
+
target, trigger, tenant scope, authority reference, and payload across storage;
|
|
235
|
+
the signing key is never persisted. Scheduled and on-change maintenance jobs
|
|
236
|
+
remain system-authority jobs and do not carry an initiating user, but their job
|
|
237
|
+
payloads use the same integrity boundary. Only a registered `SmrtReportCollection` can
|
|
228
238
|
synchronously refresh a stale read, and only when its TTL policy is positive and
|
|
229
239
|
not manual.
|
|
230
240
|
|
package/dist/index.d.ts
CHANGED
|
@@ -13,7 +13,10 @@ import { DataQueryRequest } from '@happyvertical/smrt-types';
|
|
|
13
13
|
import { DataQueryResult } from '@happyvertical/smrt-types';
|
|
14
14
|
import { DataQuerySchema } from '@happyvertical/smrt-types';
|
|
15
15
|
import { DataQuerySort } from '@happyvertical/smrt-types';
|
|
16
|
+
import { DurableJobPayloadIntegrity } from '@happyvertical/smrt-jobs';
|
|
17
|
+
import { DurableJobPayloadSigner } from '@happyvertical/smrt-jobs';
|
|
16
18
|
import { EventEmitter } from 'node:events';
|
|
19
|
+
import { JobExecutionContext } from '@happyvertical/smrt-jobs';
|
|
17
20
|
import { SmrtCollection } from '@happyvertical/smrt-core';
|
|
18
21
|
import { SmrtJob } from '@happyvertical/smrt-jobs';
|
|
19
22
|
import { SmrtListOptions } from '@happyvertical/smrt-core';
|
|
@@ -70,6 +73,7 @@ export declare function applyReportExport(descriptor: ReportAdapterDescriptor, r
|
|
|
70
73
|
export declare function applyReportRefresh(reportCtor: ReportCtor, options: ApplyReportRefreshOptions): Promise<AppliedReportRefresh>;
|
|
71
74
|
|
|
72
75
|
export declare interface ApplyReportRefreshOptions extends PreviewReportRefreshOptions {
|
|
76
|
+
jobIntegritySigner?: DurableJobPayloadSigner;
|
|
73
77
|
queue?: string;
|
|
74
78
|
priority?: number;
|
|
75
79
|
timeout?: number;
|
|
@@ -147,6 +151,8 @@ export declare interface EnqueueReportRefreshOptions extends ReportRefreshJobArg
|
|
|
147
151
|
timeout?: number;
|
|
148
152
|
maxAttempts?: number;
|
|
149
153
|
tenantJobCap?: number;
|
|
154
|
+
/** Server-only signer; register the same key in every worker process. */
|
|
155
|
+
integritySigner?: DurableJobPayloadSigner;
|
|
150
156
|
}
|
|
151
157
|
|
|
152
158
|
export declare function ensureReportRefreshSchedules(options: EnsureReportSchedulesOptions): Promise<void>;
|
|
@@ -232,8 +238,12 @@ export declare function queryReportMaterializedRows(reportCtor: new (...args: an
|
|
|
232
238
|
|
|
233
239
|
export declare function refreshReport(reportCtor: ReportCtor_2, options?: ReportRefreshOptions): Promise<ReportRefreshResult>;
|
|
234
240
|
|
|
241
|
+
export declare function registerReportRefreshExecutionAuthorityHost(hostId: string, host: ReportRefreshExecutionAuthorityHost): () => void;
|
|
242
|
+
|
|
235
243
|
export declare function registerReportRefreshInterceptor(options: ReportRefreshInterceptorOptions): () => boolean;
|
|
236
244
|
|
|
245
|
+
export declare function registerReportRefreshJobIntegritySigner(signer: DurableJobPayloadSigner): () => void;
|
|
246
|
+
|
|
237
247
|
export declare function report(options: ReportOptions): <T extends abstract new (...args: any[]) => any>(ctor: T) => T;
|
|
238
248
|
|
|
239
249
|
export declare const REPORT_LOCKS_TABLE = "_smrt_report_locks";
|
|
@@ -521,6 +531,15 @@ export declare interface ReportDrilldownQuery {
|
|
|
521
531
|
inherits: Array<'principal' | 'tenant' | 'report-definition' | 'field-policy'>;
|
|
522
532
|
}
|
|
523
533
|
|
|
534
|
+
export declare interface ReportExecutionPrincipalReference {
|
|
535
|
+
version: 1;
|
|
536
|
+
actorUserId: string;
|
|
537
|
+
tenantId: string | null;
|
|
538
|
+
onBehalfOfUserId?: string | null;
|
|
539
|
+
actsAsProfileId?: string | null;
|
|
540
|
+
agentClass?: string | null;
|
|
541
|
+
}
|
|
542
|
+
|
|
524
543
|
export declare interface ReportExportActionContext {
|
|
525
544
|
phase: 'preview' | 'apply';
|
|
526
545
|
reportClassName: string;
|
|
@@ -824,8 +843,12 @@ export declare interface ReportRefreshActionDescriptor {
|
|
|
824
843
|
|
|
825
844
|
/** Authority and audit stay with the application action host, not reports. */
|
|
826
845
|
export declare interface ReportRefreshActionHost {
|
|
827
|
-
authorize(context: ReportRefreshActionContext): Promise<void> | void;
|
|
828
|
-
audit(context: ReportRefreshActionContext): Promise<void> | void;
|
|
846
|
+
authorize(context: ReportRefreshActionContext, authority?: ReportRefreshExecutionAuthority): Promise<void> | void;
|
|
847
|
+
audit(context: ReportRefreshActionContext, authority?: ReportRefreshExecutionAuthority): Promise<void> | void;
|
|
848
|
+
/** Capture only a non-secret identity reference for worker-time reauthorization. */
|
|
849
|
+
executionAuthority?(context: ReportRefreshActionContext): ReportRefreshExecutionAuthority | Promise<ReportRefreshExecutionAuthority>;
|
|
850
|
+
/** Server-only signer shared with report worker processes. */
|
|
851
|
+
jobIntegritySigner?(context: ReportRefreshActionContext): DurableJobPayloadSigner | Promise<DurableJobPayloadSigner>;
|
|
829
852
|
}
|
|
830
853
|
|
|
831
854
|
export declare interface ReportRefreshConfig {
|
|
@@ -860,6 +883,31 @@ export declare interface ReportRefreshDescriptor {
|
|
|
860
883
|
action: ReportRefreshActionDescriptor;
|
|
861
884
|
}
|
|
862
885
|
|
|
886
|
+
export declare interface ReportRefreshExecutionAuditEvent extends ReportRefreshExecutionAuthorityContext {
|
|
887
|
+
outcome: 'allowed' | 'denied';
|
|
888
|
+
principal: ReportExecutionPrincipalReference;
|
|
889
|
+
reason?: string;
|
|
890
|
+
}
|
|
891
|
+
|
|
892
|
+
export declare interface ReportRefreshExecutionAuthority {
|
|
893
|
+
version: 1;
|
|
894
|
+
hostId: string;
|
|
895
|
+
principal: ReportExecutionPrincipalReference;
|
|
896
|
+
}
|
|
897
|
+
|
|
898
|
+
export declare interface ReportRefreshExecutionAuthorityContext {
|
|
899
|
+
phase: 'execute';
|
|
900
|
+
reportClass: string;
|
|
901
|
+
mode: ReportRefreshMode;
|
|
902
|
+
trigger: ReportRefreshTrigger;
|
|
903
|
+
tenantId: string | null;
|
|
904
|
+
}
|
|
905
|
+
|
|
906
|
+
export declare interface ReportRefreshExecutionAuthorityHost {
|
|
907
|
+
authorize(principal: Readonly<ReportExecutionPrincipalReference>, context: Readonly<ReportRefreshExecutionAuthorityContext>): Promise<void> | void;
|
|
908
|
+
audit(event: Readonly<ReportRefreshExecutionAuditEvent>): Promise<void> | void;
|
|
909
|
+
}
|
|
910
|
+
|
|
863
911
|
export declare interface ReportRefreshInterceptorOptions {
|
|
864
912
|
db: DatabaseInterface;
|
|
865
913
|
reports: ReportCtor_3[];
|
|
@@ -869,6 +917,7 @@ export declare interface ReportRefreshInterceptorOptions {
|
|
|
869
917
|
timeout?: number;
|
|
870
918
|
tenantJobCap?: number;
|
|
871
919
|
name?: string;
|
|
920
|
+
integritySigner?: DurableJobPayloadSigner;
|
|
872
921
|
}
|
|
873
922
|
|
|
874
923
|
export declare interface ReportRefreshJobArgs {
|
|
@@ -881,6 +930,8 @@ export declare interface ReportRefreshJobArgs {
|
|
|
881
930
|
adapterType?: SqlAdapterType;
|
|
882
931
|
changedRows?: Record<string, unknown>[];
|
|
883
932
|
_scheduleId?: string;
|
|
933
|
+
executionAuthority?: ReportRefreshExecutionAuthority;
|
|
934
|
+
integrity?: DurableJobPayloadIntegrity;
|
|
884
935
|
}
|
|
885
936
|
|
|
886
937
|
export declare interface ReportRefreshJobHandle {
|
|
@@ -1011,6 +1062,7 @@ export declare interface ReportScheduleRunnerConfig {
|
|
|
1011
1062
|
id?: string;
|
|
1012
1063
|
pollInterval?: number;
|
|
1013
1064
|
batchSize?: number;
|
|
1065
|
+
integritySigner?: DurableJobPayloadSigner;
|
|
1014
1066
|
}
|
|
1015
1067
|
|
|
1016
1068
|
export declare interface ReportScheduleRunnerEvents {
|
|
@@ -1051,6 +1103,11 @@ declare interface SavedViewInput {
|
|
|
1051
1103
|
|
|
1052
1104
|
export declare function scopeKeyForTenant(tenantId: string | null | undefined): string;
|
|
1053
1105
|
|
|
1106
|
+
/** Worker target whose authority requirement cannot be downgraded by job args. */
|
|
1107
|
+
export declare class SmrtPrincipalReportRefreshTask extends SmrtReportRefreshTask {
|
|
1108
|
+
run(args?: ReportRefreshJobArgs, context?: JobExecutionContext): Promise<unknown>;
|
|
1109
|
+
}
|
|
1110
|
+
|
|
1054
1111
|
export declare class SmrtReport extends SmrtObject {
|
|
1055
1112
|
static readonly _isReportBase: true;
|
|
1056
1113
|
refreshedAt: Date | null;
|
|
@@ -1108,7 +1165,7 @@ export declare class SmrtReportRefreshTask extends SmrtObject {
|
|
|
1108
1165
|
mode: ReportRefreshMode;
|
|
1109
1166
|
trigger: ReportRefreshTrigger;
|
|
1110
1167
|
args: ReportRefreshJobArgs;
|
|
1111
|
-
run(args?: ReportRefreshJobArgs): Promise<unknown>;
|
|
1168
|
+
run(args?: ReportRefreshJobArgs, context?: JobExecutionContext): Promise<unknown>;
|
|
1112
1169
|
}
|
|
1113
1170
|
|
|
1114
1171
|
export declare class SmrtReportRun extends SmrtObject {
|
package/dist/index.js
CHANGED
|
@@ -2,7 +2,7 @@ import { aggregate, avg, count, day, getRuntimeReportOptions, groupBy, hour, max
|
|
|
2
2
|
import { buildReportDefinition, compileReportDefinition, compileReportSpec, getReportGroupingColumns } from "./compiler.js";
|
|
3
3
|
import { REPORT_LOCKS_TABLE, REPORT_REFRESH_TASKS_TABLE, REPORT_RUNS_TABLE, REPORT_RUNTIME_TABLES, REPORT_SCHEDULER_TABLES, REPORT_SCHEDULES_TABLE, REPORT_WATERMARKS_TABLE, SmrtReportLock, SmrtReportLockCollection, SmrtReportRun, SmrtReportRunCollection, SmrtReportSchedule, SmrtReportScheduleCollection, SmrtReportWatermark, SmrtReportWatermarkCollection, assertReportTablesReady, scopeKeyForTenant } from "./state.js";
|
|
4
4
|
import { refreshReport, reportRowIdentity } from "./refresh.js";
|
|
5
|
-
import { ReportScheduleRunner, SmrtReportRefreshTask, enqueueReportRefresh, ensureReportRefreshSchedules, registerReportRefreshInterceptor } from "./scheduler.js";
|
|
5
|
+
import { ReportScheduleRunner, SmrtPrincipalReportRefreshTask, SmrtReportRefreshTask, enqueueReportRefresh, ensureReportRefreshSchedules, registerReportRefreshExecutionAuthorityHost, registerReportRefreshInterceptor, registerReportRefreshJobIntegritySigner } from "./scheduler.js";
|
|
6
6
|
import { bucketExpr, buildAggregate } from "./aggregate.js";
|
|
7
7
|
import { DataQueryValidationError, ObjectRegistry, SmrtCollection, SmrtObject, createDataQueryFingerprint, normalizeDataQueryRequest, normalizeDataQueryResult } from "@happyvertical/smrt-core";
|
|
8
8
|
import { toSnakeCase } from "@happyvertical/smrt-core/utils";
|
|
@@ -159,8 +159,12 @@ async function previewReportRefresh(reportCtor, options) {
|
|
|
159
159
|
async function applyReportRefresh(reportCtor, options) {
|
|
160
160
|
const mode = await actionMode(reportCtor, options.mode);
|
|
161
161
|
const action = actionContext$1(reportCtor, "apply", mode, options.refreshAction);
|
|
162
|
-
await options.host.
|
|
163
|
-
|
|
162
|
+
const executionAuthority = await options.host.executionAuthority?.(action);
|
|
163
|
+
if (!executionAuthority) throw new Error("Manual report refresh requires execution-time authority");
|
|
164
|
+
await options.host.authorize(action, executionAuthority);
|
|
165
|
+
await options.host.audit(action, executionAuthority);
|
|
166
|
+
const integritySigner = options.jobIntegritySigner ?? await options.host.jobIntegritySigner?.(action);
|
|
167
|
+
if (!integritySigner) throw new Error("Report refresh queue requires a durable job integrity signer");
|
|
164
168
|
const tenantId = lifecycleTenantId(reportCtor);
|
|
165
169
|
const enqueue = () => enqueueReportRefresh({
|
|
166
170
|
db: options.db,
|
|
@@ -168,11 +172,13 @@ async function applyReportRefresh(reportCtor, options) {
|
|
|
168
172
|
mode,
|
|
169
173
|
trigger: "manual",
|
|
170
174
|
tenantId,
|
|
175
|
+
executionAuthority,
|
|
171
176
|
queue: options.queue,
|
|
172
177
|
priority: options.priority,
|
|
173
178
|
timeout: options.timeout,
|
|
174
179
|
maxAttempts: options.maxAttempts,
|
|
175
|
-
tenantJobCap: options.tenantJobCap
|
|
180
|
+
tenantJobCap: options.tenantJobCap,
|
|
181
|
+
integritySigner
|
|
176
182
|
});
|
|
177
183
|
return {
|
|
178
184
|
phase: "apply",
|
|
@@ -1509,6 +1515,6 @@ function validateReportExportArtifact(descriptor, artifact, now = /* @__PURE__ *
|
|
|
1509
1515
|
};
|
|
1510
1516
|
}
|
|
1511
1517
|
//#endregion
|
|
1512
|
-
export { REPORT_LOCKS_TABLE, REPORT_REFRESH_TASKS_TABLE, REPORT_RUNS_TABLE, REPORT_RUNTIME_TABLES, REPORT_SCHEDULER_TABLES, REPORT_SCHEDULES_TABLE, REPORT_WATERMARKS_TABLE, ReportScheduleRunner, ReportSurfaceValidationError, SmrtReport, SmrtReportCollection, SmrtReportLock, SmrtReportLockCollection, SmrtReportRefreshTask, SmrtReportRun, SmrtReportRunCollection, SmrtReportSchedule, SmrtReportScheduleCollection, SmrtReportWatermark, SmrtReportWatermarkCollection, aggregate, applyReportExport, applyReportRefresh, assertReportTablesReady, avg, bucketExpr, buildAggregate, buildReportAdapterDescriptor, buildReportDefinition, buildReportDrilldownQuery, compileReportDefinition, compileReportSpec, count, createReportExportPageRequest, createReportExportRequest, createReportExportSnapshot, day, enqueueReportRefresh, ensureReportRefreshSchedules, getReportGroupingColumns, getReportLifecycle, getRuntimeReportOptions, groupBy, hour, max, migrateReportSavedView, min, minute, month, normalizeReportSavedView, previewReportExport, previewReportRefresh, quarter, queryReportMaterializedRows, refreshReport, registerReportRefreshInterceptor, report, reportDefinitionFingerprint, reportMaterializedRowKey, reportRefreshOutcome, reportRowIdentity, restoreReportSavedView, scopeKeyForTenant, splitReportFilterScopes, sum, validateReportExportArtifact, validateReportExportExecution, validateReportExportRequest, verifyReportExportSnapshot, week, year };
|
|
1518
|
+
export { REPORT_LOCKS_TABLE, REPORT_REFRESH_TASKS_TABLE, REPORT_RUNS_TABLE, REPORT_RUNTIME_TABLES, REPORT_SCHEDULER_TABLES, REPORT_SCHEDULES_TABLE, REPORT_WATERMARKS_TABLE, ReportScheduleRunner, ReportSurfaceValidationError, SmrtPrincipalReportRefreshTask, SmrtReport, SmrtReportCollection, SmrtReportLock, SmrtReportLockCollection, SmrtReportRefreshTask, SmrtReportRun, SmrtReportRunCollection, SmrtReportSchedule, SmrtReportScheduleCollection, SmrtReportWatermark, SmrtReportWatermarkCollection, aggregate, applyReportExport, applyReportRefresh, assertReportTablesReady, avg, bucketExpr, buildAggregate, buildReportAdapterDescriptor, buildReportDefinition, buildReportDrilldownQuery, compileReportDefinition, compileReportSpec, count, createReportExportPageRequest, createReportExportRequest, createReportExportSnapshot, day, enqueueReportRefresh, ensureReportRefreshSchedules, getReportGroupingColumns, getReportLifecycle, getRuntimeReportOptions, groupBy, hour, max, migrateReportSavedView, min, minute, month, normalizeReportSavedView, previewReportExport, previewReportRefresh, quarter, queryReportMaterializedRows, refreshReport, registerReportRefreshExecutionAuthorityHost, registerReportRefreshInterceptor, registerReportRefreshJobIntegritySigner, report, reportDefinitionFingerprint, reportMaterializedRowKey, reportRefreshOutcome, reportRowIdentity, restoreReportSavedView, scopeKeyForTenant, splitReportFilterScopes, sum, validateReportExportArtifact, validateReportExportExecution, validateReportExportRequest, verifyReportExportSnapshot, week, year };
|
|
1513
1519
|
|
|
1514
1520
|
//# sourceMappingURL=index.js.map
|