@happyvertical/smrt-reports 0.55.23 → 0.56.0
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/AGENTS.md +26 -3
- package/README.md +9 -0
- package/dist/index.d.ts +3 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +471 -112
- package/dist/index.js.map +1 -1
- package/dist/manifest.json +174 -5
- package/dist/playground.d.ts +2 -0
- package/dist/playground.d.ts.map +1 -0
- package/dist/playground.js +154 -0
- package/dist/playground.js.map +1 -0
- package/dist/recipes.d.ts +55 -0
- package/dist/recipes.d.ts.map +1 -1
- package/dist/runtime-report.d.ts +9 -0
- package/dist/runtime-report.d.ts.map +1 -1
- package/dist/runtime-server.d.ts +77 -0
- package/dist/runtime-server.d.ts.map +1 -0
- package/dist/runtime-spec.d.ts +2 -1
- package/dist/runtime-spec.d.ts.map +1 -1
- package/dist/smrt-knowledge.json +203 -11
- package/dist/state.js +1 -1
- package/dist/state.js.map +1 -1
- package/dist/svelte/ReportConfirmation.svelte +99 -0
- package/dist/svelte/ReportConfirmation.svelte.d.ts +15 -0
- package/dist/svelte/ReportConfirmation.svelte.d.ts.map +1 -0
- package/dist/svelte/ReportDetail.svelte +69 -0
- package/dist/svelte/ReportDetail.svelte.d.ts +11 -0
- package/dist/svelte/ReportDetail.svelte.d.ts.map +1 -0
- package/dist/svelte/ReportPicker.svelte +73 -0
- package/dist/svelte/ReportPicker.svelte.d.ts +16 -0
- package/dist/svelte/ReportPicker.svelte.d.ts.map +1 -0
- package/dist/svelte/ReportResult.svelte +69 -0
- package/dist/svelte/ReportResult.svelte.d.ts +10 -0
- package/dist/svelte/ReportResult.svelte.d.ts.map +1 -0
- package/dist/svelte/RuntimeReportChartWidget.svelte +20 -0
- package/dist/svelte/RuntimeReportChartWidget.svelte.d.ts +11 -0
- package/dist/svelte/RuntimeReportChartWidget.svelte.d.ts.map +1 -0
- package/dist/svelte/RuntimeReportDetailRoute.svelte +67 -0
- package/dist/svelte/RuntimeReportDetailRoute.svelte.d.ts +21 -0
- package/dist/svelte/RuntimeReportDetailRoute.svelte.d.ts.map +1 -0
- package/dist/svelte/RuntimeReportToolResult.svelte +26 -0
- package/dist/svelte/RuntimeReportToolResult.svelte.d.ts +8 -0
- package/dist/svelte/RuntimeReportToolResult.svelte.d.ts.map +1 -0
- package/dist/svelte/RuntimeReportWidgetOptions.svelte +58 -0
- package/dist/svelte/RuntimeReportWidgetOptions.svelte.d.ts +14 -0
- package/dist/svelte/RuntimeReportWidgetOptions.svelte.d.ts.map +1 -0
- package/dist/svelte/RuntimeReportsRoute.svelte +67 -0
- package/dist/svelte/RuntimeReportsRoute.svelte.d.ts +19 -0
- package/dist/svelte/RuntimeReportsRoute.svelte.d.ts.map +1 -0
- package/dist/svelte/SavedReports.svelte +114 -0
- package/dist/svelte/SavedReports.svelte.d.ts +11 -0
- package/dist/svelte/SavedReports.svelte.d.ts.map +1 -0
- package/dist/svelte/browser-client.d.ts +10 -0
- package/dist/svelte/browser-client.d.ts.map +1 -0
- package/dist/svelte/browser-client.js +16 -0
- package/dist/svelte/client.d.ts +15 -0
- package/dist/svelte/client.d.ts.map +1 -0
- package/dist/svelte/client.js +179 -0
- package/dist/svelte/index.d.ts +15 -0
- package/dist/svelte/index.d.ts.map +1 -0
- package/dist/svelte/index.js +13 -0
- package/dist/svelte/messages.d.ts +72 -0
- package/dist/svelte/messages.d.ts.map +1 -0
- package/dist/svelte/messages.js +72 -0
- package/dist/svelte/playground.d.ts +132 -0
- package/dist/svelte/playground.d.ts.map +1 -0
- package/dist/svelte/playground.js +62 -0
- package/dist/svelte/preview-data.d.ts +7 -0
- package/dist/svelte/preview-data.d.ts.map +1 -0
- package/dist/svelte/preview-data.js +59 -0
- package/dist/svelte/result.d.ts +8 -0
- package/dist/svelte/result.d.ts.map +1 -0
- package/dist/svelte/result.js +99 -0
- package/dist/svelte/spec.d.ts +5 -0
- package/dist/svelte/spec.d.ts.map +1 -0
- package/dist/svelte/spec.js +282 -0
- package/dist/svelte/tool-result.d.ts +11 -0
- package/dist/svelte/tool-result.d.ts.map +1 -0
- package/dist/svelte/tool-result.js +19 -0
- package/dist/svelte/types.d.ts +38 -0
- package/dist/svelte/types.d.ts.map +1 -0
- package/dist/svelte/types.js +1 -0
- package/package.json +36 -12
package/dist/index.js
CHANGED
|
@@ -4,11 +4,12 @@ import { REPORT_LOCKS_TABLE, REPORT_REFRESH_TASKS_TABLE, REPORT_RUNS_TABLE, REPO
|
|
|
4
4
|
import { adapterTypeFromDb, refreshReport, reportRowIdentity, tenantColumn } from "./refresh.js";
|
|
5
5
|
import { ReportScheduleRunner, SmrtPrincipalReportRefreshTask, SmrtReportRefreshTask, enqueueReportRefresh, ensureReportRefreshSchedules, registerReportRefreshExecutionAuthorityHost, registerReportRefreshInterceptor, registerReportRefreshJobIntegritySigner } from "./scheduler.js";
|
|
6
6
|
import { bucketExpr, buildAggregate } from "./aggregate.js";
|
|
7
|
-
import { DataQueryValidationError, ObjectRegistry, SmrtCollection, SmrtObject, SmrtRecipe, createDataQueryFingerprint, field, normalizeDataQueryRequest, normalizeDataQueryResult, smrt } from "@happyvertical/smrt-core";
|
|
7
|
+
import { DataQueryValidationError, ObjectRegistry, SmrtCollection, SmrtError, SmrtObject, SmrtRecipe, createDataQueryFingerprint, field, normalizeDataQueryRequest, normalizeDataQueryResult, runOnce, smrt } from "@happyvertical/smrt-core";
|
|
8
8
|
import { toSnakeCase } from "@happyvertical/smrt-core/utils";
|
|
9
|
-
import { TenantScoped, getTenantId, isTenancyEnabled, isTenantScopedClass, tenantId, withSystemContext } from "@happyvertical/smrt-tenancy";
|
|
9
|
+
import { TenantScoped, getCurrentTenant, getTenantId, isTenancyEnabled, isTenantScopedClass, tenantId, withSystemContext, withTenant } from "@happyvertical/smrt-tenancy";
|
|
10
10
|
import { tableExists, validateColumnName } from "@happyvertical/sql";
|
|
11
11
|
import { createHash } from "node:crypto";
|
|
12
|
+
import { getPackageConfig } from "@happyvertical/smrt-config";
|
|
12
13
|
//#region src/lifecycle.ts
|
|
13
14
|
function registeredReport(reportCtor) {
|
|
14
15
|
return ObjectRegistry.getClassByConstructor(reportCtor) ?? ObjectRegistry.getClass(reportCtor.name);
|
|
@@ -971,109 +972,6 @@ function reportMaterializedRowKey(row) {
|
|
|
971
972
|
return id;
|
|
972
973
|
}
|
|
973
974
|
//#endregion
|
|
974
|
-
//#region src/recipes.ts
|
|
975
|
-
var MaterializedReportsRecipe = class extends SmrtRecipe {
|
|
976
|
-
static id = "reports.materialized";
|
|
977
|
-
static help = "./materialized.recipe.md";
|
|
978
|
-
static label = "Reports";
|
|
979
|
-
static summary = "Keep totals and trends ready to read, refreshed on a schedule and open to the assistant.";
|
|
980
|
-
static synonyms = [
|
|
981
|
-
"reports",
|
|
982
|
-
"totals",
|
|
983
|
-
"summaries",
|
|
984
|
-
"rollups",
|
|
985
|
-
"kpis",
|
|
986
|
-
"trends",
|
|
987
|
-
"dashboards"
|
|
988
|
-
];
|
|
989
|
-
static models = [
|
|
990
|
-
SmrtReportRun,
|
|
991
|
-
SmrtReportWatermark,
|
|
992
|
-
SmrtReportLock,
|
|
993
|
-
SmrtReportSchedule,
|
|
994
|
-
SmrtReportRefreshTask,
|
|
995
|
-
SmrtPrincipalReportRefreshTask
|
|
996
|
-
];
|
|
997
|
-
static runtime = "server";
|
|
998
|
-
};
|
|
999
|
-
//#endregion
|
|
1000
|
-
//#region src/report.ts
|
|
1001
|
-
function registryColumnName(fieldName, field) {
|
|
1002
|
-
return validateColumnName(field?.columnName ?? field?._meta?.columnName ?? toSnakeCase(fieldName));
|
|
1003
|
-
}
|
|
1004
|
-
function findFieldColumn(fields, fieldName) {
|
|
1005
|
-
const direct = fields.get(fieldName);
|
|
1006
|
-
if (direct) return registryColumnName(fieldName, direct);
|
|
1007
|
-
const requestedColumn = toSnakeCase(fieldName);
|
|
1008
|
-
for (const [name, field] of fields.entries()) if (toSnakeCase(name) === requestedColumn) return registryColumnName(name, field);
|
|
1009
|
-
return validateColumnName(requestedColumn);
|
|
1010
|
-
}
|
|
1011
|
-
function findTenantColumn(fields, configuredField) {
|
|
1012
|
-
if (configuredField) return registryColumnName(configuredField, fields.get(configuredField));
|
|
1013
|
-
for (const [fieldName, field] of fields.entries()) if (fieldName === "tenantId" || field?._meta?.__tenancy?.isTenantIdField) return registryColumnName(fieldName, field);
|
|
1014
|
-
return null;
|
|
1015
|
-
}
|
|
1016
|
-
var SmrtReport = class extends SmrtObject {
|
|
1017
|
-
static _isReportBase = true;
|
|
1018
|
-
refreshedAt = null;
|
|
1019
|
-
constructor(options = {}) {
|
|
1020
|
-
super(options);
|
|
1021
|
-
if (options.refreshedAt !== void 0) this.refreshedAt = options.refreshedAt instanceof Date ? options.refreshedAt : options.refreshedAt ? new Date(options.refreshedAt) : null;
|
|
1022
|
-
}
|
|
1023
|
-
isStale(ttlMs) {
|
|
1024
|
-
if (!this.refreshedAt) return true;
|
|
1025
|
-
if (ttlMs === void 0) return false;
|
|
1026
|
-
return Date.now() - this.refreshedAt.getTime() > ttlMs;
|
|
1027
|
-
}
|
|
1028
|
-
async refresh(options = {}) {
|
|
1029
|
-
const result = await refreshReport(this.constructor, {
|
|
1030
|
-
...options,
|
|
1031
|
-
db: this.db
|
|
1032
|
-
});
|
|
1033
|
-
this.refreshedAt = result.refreshedAt;
|
|
1034
|
-
return result;
|
|
1035
|
-
}
|
|
1036
|
-
};
|
|
1037
|
-
var SmrtReportCollection = class extends SmrtCollection {
|
|
1038
|
-
async refreshIfStale() {
|
|
1039
|
-
const reportCtor = this.getItemClass();
|
|
1040
|
-
const refresh = (await buildReportDefinition(reportCtor)).refresh;
|
|
1041
|
-
if (!refresh?.ttl || refresh.manual) return;
|
|
1042
|
-
const registered = ObjectRegistry.getClassByConstructor(reportCtor) ?? ObjectRegistry.getClass(reportCtor.name);
|
|
1043
|
-
const reportClass = registered?.qualifiedName ?? registered?.name ?? reportCtor.name;
|
|
1044
|
-
const tableName = ObjectRegistry.getTableName(reportClass);
|
|
1045
|
-
if (!tableName) return;
|
|
1046
|
-
const fields = await ObjectRegistry.getAllFields(reportClass);
|
|
1047
|
-
const safeTableName = validateColumnName(tableName);
|
|
1048
|
-
const refreshedAtColumn = findFieldColumn(fields, "refreshedAt");
|
|
1049
|
-
const tenantColumn = findTenantColumn(fields, registered?.tenantScopedConfig?.field);
|
|
1050
|
-
const tenantId = getTenantId() ?? null;
|
|
1051
|
-
const result = tenantColumn ? await this.db.query(`SELECT MAX(${refreshedAtColumn}) AS refreshed_at FROM ${safeTableName} WHERE ${tenantColumn} ${tenantId ? "= ?" : "IS NULL"}`, ...tenantId ? [tenantId] : []) : await this.db.query(`SELECT MAX(${refreshedAtColumn}) AS refreshed_at FROM ${safeTableName}`);
|
|
1052
|
-
const refreshedAt = result.rows[0]?.refreshed_at ? new Date(result.rows[0].refreshed_at) : null;
|
|
1053
|
-
if (!(!refreshedAt || Date.now() - refreshedAt.getTime() > refresh.ttl)) return;
|
|
1054
|
-
await refreshReport(reportCtor, {
|
|
1055
|
-
db: this.db,
|
|
1056
|
-
mode: refresh.mode ?? "rebuild",
|
|
1057
|
-
trigger: "ttl",
|
|
1058
|
-
tenantId
|
|
1059
|
-
});
|
|
1060
|
-
}
|
|
1061
|
-
async refresh(options = {}) {
|
|
1062
|
-
return refreshReport(this.getItemClass(), {
|
|
1063
|
-
...options,
|
|
1064
|
-
db: this.db
|
|
1065
|
-
});
|
|
1066
|
-
}
|
|
1067
|
-
async list(options = {}) {
|
|
1068
|
-
await this.refreshIfStale();
|
|
1069
|
-
return super.list(options);
|
|
1070
|
-
}
|
|
1071
|
-
async get(filter, options = {}) {
|
|
1072
|
-
await this.refreshIfStale();
|
|
1073
|
-
return super.get(filter, options);
|
|
1074
|
-
}
|
|
1075
|
-
};
|
|
1076
|
-
//#endregion
|
|
1077
975
|
//#region src/runtime-spec.ts
|
|
1078
976
|
var RUNTIME_REPORT_SPEC_VERSION = 1;
|
|
1079
977
|
var RUNTIME_REPORT_LIMITS = Object.freeze({
|
|
@@ -1137,7 +1035,7 @@ var RUNTIME_REPORT_CHART_TYPES = [
|
|
|
1137
1035
|
"pie",
|
|
1138
1036
|
"stat"
|
|
1139
1037
|
];
|
|
1140
|
-
var RuntimeReportError = class extends
|
|
1038
|
+
var RuntimeReportError = class extends SmrtError {
|
|
1141
1039
|
code;
|
|
1142
1040
|
path;
|
|
1143
1041
|
/**
|
|
@@ -1147,7 +1045,7 @@ var RuntimeReportError = class extends Error {
|
|
|
1147
1045
|
*/
|
|
1148
1046
|
status;
|
|
1149
1047
|
constructor(code, path, message) {
|
|
1150
|
-
super(path ? `${path}: ${message}` : message);
|
|
1048
|
+
super(path ? `${path}: ${message}` : message, code, "validation");
|
|
1151
1049
|
this.name = "RuntimeReportError";
|
|
1152
1050
|
this.code = code;
|
|
1153
1051
|
this.path = path;
|
|
@@ -1909,6 +1807,248 @@ async function runRuntimeReport(compiled, options) {
|
|
|
1909
1807
|
};
|
|
1910
1808
|
}
|
|
1911
1809
|
//#endregion
|
|
1810
|
+
//#region src/runtime-server.ts
|
|
1811
|
+
var RuntimeReportHttpError = class extends Error {
|
|
1812
|
+
constructor(status, code, message) {
|
|
1813
|
+
super(message);
|
|
1814
|
+
this.status = status;
|
|
1815
|
+
this.code = code;
|
|
1816
|
+
this.name = "RuntimeReportHttpError";
|
|
1817
|
+
}
|
|
1818
|
+
status;
|
|
1819
|
+
code;
|
|
1820
|
+
};
|
|
1821
|
+
function isRuntimeReportAccessError(error) {
|
|
1822
|
+
return error.code === "unknown_field" || error.code === "unknown_source";
|
|
1823
|
+
}
|
|
1824
|
+
function assertRuntimeReportPrincipal(context, permission) {
|
|
1825
|
+
if (!context?.userId) throw new RuntimeReportHttpError(401, "unauthenticated", "Sign in required");
|
|
1826
|
+
const active = getCurrentTenant();
|
|
1827
|
+
if (!context.tenantId || active && active.tenantId !== context.tenantId || active?.userId && active.userId !== context.userId || !context.permissions.includes(permission)) throw new RuntimeReportHttpError(403, "forbidden", "Report access denied");
|
|
1828
|
+
}
|
|
1829
|
+
function runtimeReportPrincipalCompileContext(options, principal) {
|
|
1830
|
+
return {
|
|
1831
|
+
sources: options.sources.filter((source) => principal.permissions.includes(`${source.collection}.read`)),
|
|
1832
|
+
permissions: principal.permissions,
|
|
1833
|
+
tenantId: principal.tenantId
|
|
1834
|
+
};
|
|
1835
|
+
}
|
|
1836
|
+
function createRuntimeReportConfirmHandler(options) {
|
|
1837
|
+
return async (request, context) => {
|
|
1838
|
+
try {
|
|
1839
|
+
if (request.method !== "POST") return Response.json({ code: "method_not_allowed" }, {
|
|
1840
|
+
status: 405,
|
|
1841
|
+
headers: { Allow: "POST" }
|
|
1842
|
+
});
|
|
1843
|
+
const origin = request.headers.get("origin");
|
|
1844
|
+
const site = request.headers.get("sec-fetch-site");
|
|
1845
|
+
if (origin !== null && origin !== new URL(request.url).origin || site !== null && site !== "same-origin" || origin === null && site !== "same-origin") throw new RuntimeReportHttpError(403, "cross_origin", "Same-origin request required");
|
|
1846
|
+
assertRuntimeReportPrincipal(context, "runtimereports.create");
|
|
1847
|
+
let body;
|
|
1848
|
+
try {
|
|
1849
|
+
body = await request.json();
|
|
1850
|
+
} catch {
|
|
1851
|
+
throw new RuntimeReportHttpError(422, "invalid_spec", "Invalid JSON body");
|
|
1852
|
+
}
|
|
1853
|
+
if (!body || typeof body !== "object" || Array.isArray(body) || Object.keys(body).some((key) => key !== "spec" && key !== "specHash")) throw new RuntimeReportHttpError(422, "invalid_spec", "Expected spec and specHash");
|
|
1854
|
+
const input = body;
|
|
1855
|
+
const spec = parseRuntimeReportSpec(input.spec);
|
|
1856
|
+
const hash = runtimeReportSpecHash(spec);
|
|
1857
|
+
if (input.specHash !== hash) throw new RuntimeReportHttpError(422, "spec_hash_mismatch", "The approved spec hash does not match");
|
|
1858
|
+
const principal = context;
|
|
1859
|
+
return await withTenant({
|
|
1860
|
+
tenantId: principal.tenantId,
|
|
1861
|
+
userId: principal.userId,
|
|
1862
|
+
permissions: new Set(principal.permissions)
|
|
1863
|
+
}, async () => {
|
|
1864
|
+
const serverOptions = options ?? getRuntimeReportServerOptions();
|
|
1865
|
+
const transaction = principal.db.transaction?.bind(principal.db);
|
|
1866
|
+
if (!transaction) throw new RuntimeReportHttpError(500, "transaction_required", "Runtime report confirmation requires transaction support");
|
|
1867
|
+
const { existing, archived } = await transaction(async (tx) => {
|
|
1868
|
+
const lookup = {
|
|
1869
|
+
db: tx,
|
|
1870
|
+
tenantId: principal.tenantId,
|
|
1871
|
+
createdByUserId: principal.userId,
|
|
1872
|
+
specHash: hash,
|
|
1873
|
+
limit: 1
|
|
1874
|
+
};
|
|
1875
|
+
const [existing2] = await listRuntimeReports(lookup);
|
|
1876
|
+
const [archived2] = existing2 ? [] : await listRuntimeReports({
|
|
1877
|
+
...lookup,
|
|
1878
|
+
status: "archived"
|
|
1879
|
+
});
|
|
1880
|
+
return {
|
|
1881
|
+
existing: existing2,
|
|
1882
|
+
archived: archived2
|
|
1883
|
+
};
|
|
1884
|
+
});
|
|
1885
|
+
if (archived) throw new RuntimeReportHttpError(409, "report_archived", "Restore the archived report before confirming it again");
|
|
1886
|
+
let compiled;
|
|
1887
|
+
try {
|
|
1888
|
+
compiled = await compileRuntimeReportSpec(spec, runtimeReportPrincipalCompileContext(serverOptions, principal));
|
|
1889
|
+
} catch (error) {
|
|
1890
|
+
if (existing && error instanceof RuntimeReportError && isRuntimeReportAccessError(error)) throw new RuntimeReportHttpError(403, "forbidden", "Report access denied");
|
|
1891
|
+
throw error;
|
|
1892
|
+
}
|
|
1893
|
+
let created = false;
|
|
1894
|
+
let report = existing ? {
|
|
1895
|
+
id: existing.id,
|
|
1896
|
+
specHash: hash,
|
|
1897
|
+
title: existing.title
|
|
1898
|
+
} : void 0;
|
|
1899
|
+
if (!report) report = await runOnce({
|
|
1900
|
+
db: principal.db,
|
|
1901
|
+
tenantId: principal.tenantId,
|
|
1902
|
+
actor: principal.userId,
|
|
1903
|
+
token: "runtime-report-confirm",
|
|
1904
|
+
content: spec
|
|
1905
|
+
}, async (tx) => {
|
|
1906
|
+
const [current] = await listRuntimeReports({
|
|
1907
|
+
db: tx,
|
|
1908
|
+
tenantId: principal.tenantId,
|
|
1909
|
+
createdByUserId: principal.userId,
|
|
1910
|
+
specHash: hash,
|
|
1911
|
+
limit: 1
|
|
1912
|
+
});
|
|
1913
|
+
const saved = current ?? await saveRuntimeReport({
|
|
1914
|
+
db: tx,
|
|
1915
|
+
tenantId: principal.tenantId,
|
|
1916
|
+
createdByUserId: principal.userId,
|
|
1917
|
+
compiled,
|
|
1918
|
+
confirmedSpecHash: hash
|
|
1919
|
+
});
|
|
1920
|
+
created = !current;
|
|
1921
|
+
if (!saved.id) throw new Error("Saved report has no id");
|
|
1922
|
+
return {
|
|
1923
|
+
id: saved.id,
|
|
1924
|
+
specHash: hash,
|
|
1925
|
+
title: saved.title
|
|
1926
|
+
};
|
|
1927
|
+
});
|
|
1928
|
+
if (!report.id) throw new Error("Saved report has no id");
|
|
1929
|
+
await serverOptions.audit?.({
|
|
1930
|
+
action: "confirm",
|
|
1931
|
+
userId: principal.userId,
|
|
1932
|
+
tenantId: principal.tenantId,
|
|
1933
|
+
specHash: hash,
|
|
1934
|
+
reportId: report.id,
|
|
1935
|
+
reused: !created
|
|
1936
|
+
});
|
|
1937
|
+
return Response.json({
|
|
1938
|
+
id: report.id,
|
|
1939
|
+
specHash: hash,
|
|
1940
|
+
title: report.title
|
|
1941
|
+
}, {
|
|
1942
|
+
status: created ? 201 : 200,
|
|
1943
|
+
headers: { "Cache-Control": "no-store" }
|
|
1944
|
+
});
|
|
1945
|
+
});
|
|
1946
|
+
} catch (error) {
|
|
1947
|
+
if (error instanceof RuntimeReportHttpError || error instanceof RuntimeReportError) return Response.json({
|
|
1948
|
+
code: error.code,
|
|
1949
|
+
message: error.message
|
|
1950
|
+
}, {
|
|
1951
|
+
status: error instanceof RuntimeReportError ? 422 : error.status,
|
|
1952
|
+
headers: { "Cache-Control": "no-store" }
|
|
1953
|
+
});
|
|
1954
|
+
return Response.json({
|
|
1955
|
+
code: "internal_error",
|
|
1956
|
+
message: "Unable to confirm report"
|
|
1957
|
+
}, {
|
|
1958
|
+
status: 500,
|
|
1959
|
+
headers: { "Cache-Control": "no-store" }
|
|
1960
|
+
});
|
|
1961
|
+
}
|
|
1962
|
+
};
|
|
1963
|
+
}
|
|
1964
|
+
function getRuntimeReportServerOptions() {
|
|
1965
|
+
return getPackageConfig("reports").runtime ?? { sources: [] };
|
|
1966
|
+
}
|
|
1967
|
+
function currentRuntimeReportPrincipal(db) {
|
|
1968
|
+
const context = getCurrentTenant();
|
|
1969
|
+
return {
|
|
1970
|
+
db,
|
|
1971
|
+
userId: context?.userId ?? "",
|
|
1972
|
+
tenantId: context?.tenantId ?? "",
|
|
1973
|
+
permissions: [...context?.permissions ?? []]
|
|
1974
|
+
};
|
|
1975
|
+
}
|
|
1976
|
+
async function runRuntimeReportForPrincipal(ref, principal, options = getRuntimeReportServerOptions()) {
|
|
1977
|
+
assertRuntimeReportPrincipal(principal, "runtimereports.read");
|
|
1978
|
+
return withTenant({
|
|
1979
|
+
tenantId: principal.tenantId,
|
|
1980
|
+
userId: principal.userId,
|
|
1981
|
+
permissions: new Set(principal.permissions)
|
|
1982
|
+
}, async () => {
|
|
1983
|
+
const report = await getRuntimeReport({
|
|
1984
|
+
db: principal.db,
|
|
1985
|
+
ref,
|
|
1986
|
+
tenantId: principal.tenantId
|
|
1987
|
+
});
|
|
1988
|
+
if (!report) throw new RuntimeReportHttpError(404, "not_found", "Report not found");
|
|
1989
|
+
if (report.status === "archived") throw new RuntimeReportHttpError(409, "report_archived", "Restore the archived report before running it");
|
|
1990
|
+
try {
|
|
1991
|
+
return await runStoredRuntimeReport({
|
|
1992
|
+
db: principal.db,
|
|
1993
|
+
report,
|
|
1994
|
+
context: runtimeReportPrincipalCompileContext(options, principal)
|
|
1995
|
+
});
|
|
1996
|
+
} catch (error) {
|
|
1997
|
+
if (error instanceof RuntimeReportError) {
|
|
1998
|
+
if (isRuntimeReportAccessError(error)) throw new RuntimeReportHttpError(403, "forbidden", "Report access denied");
|
|
1999
|
+
throw new RuntimeReportHttpError(422, error.code, error.message);
|
|
2000
|
+
}
|
|
2001
|
+
throw error;
|
|
2002
|
+
}
|
|
2003
|
+
});
|
|
2004
|
+
}
|
|
2005
|
+
async function archiveRuntimeReportForPrincipal(ref, archived, principal) {
|
|
2006
|
+
assertRuntimeReportPrincipal(principal, "runtimereports.create");
|
|
2007
|
+
if (typeof archived !== "boolean") throw new RuntimeReportHttpError(422, "invalid_value", "archived must be a boolean");
|
|
2008
|
+
return withTenant({
|
|
2009
|
+
tenantId: principal.tenantId,
|
|
2010
|
+
userId: principal.userId,
|
|
2011
|
+
permissions: new Set(principal.permissions)
|
|
2012
|
+
}, async () => {
|
|
2013
|
+
const report = await getRuntimeReport({
|
|
2014
|
+
db: principal.db,
|
|
2015
|
+
ref,
|
|
2016
|
+
tenantId: principal.tenantId
|
|
2017
|
+
});
|
|
2018
|
+
if (!report?.id) throw new RuntimeReportHttpError(404, "not_found", "Report not found");
|
|
2019
|
+
const status = archived ? "archived" : "active";
|
|
2020
|
+
if (report.status !== status) {
|
|
2021
|
+
report.status = status;
|
|
2022
|
+
await report.save();
|
|
2023
|
+
}
|
|
2024
|
+
return {
|
|
2025
|
+
id: report.id,
|
|
2026
|
+
status
|
|
2027
|
+
};
|
|
2028
|
+
});
|
|
2029
|
+
}
|
|
2030
|
+
async function loadRuntimeReportChart(options, context) {
|
|
2031
|
+
assertRuntimeReportPrincipal(context.reportPrincipal, "runtimereports.read");
|
|
2032
|
+
if (typeof options.reportId !== "string" || typeof options.measure !== "string") throw new RuntimeReportHttpError(422, "invalid_value", "Select a report and measure");
|
|
2033
|
+
const result = await runRuntimeReportForPrincipal(options.reportId, context.reportPrincipal);
|
|
2034
|
+
const measure = result.columns.find((column) => column.id === options.measure && column.role === "measure");
|
|
2035
|
+
const dimension = options.dimension === void 0 ? result.columns.find((column) => column.role === "dimension") : result.columns.find((column) => column.id === options.dimension && column.role === "dimension");
|
|
2036
|
+
if (!measure || options.dimension !== void 0 && !dimension) throw new RuntimeReportHttpError(422, "invalid_value", "Invalid report measure or dimension");
|
|
2037
|
+
return {
|
|
2038
|
+
points: result.rows.map((row) => {
|
|
2039
|
+
const value = row[measure.id];
|
|
2040
|
+
if (typeof value !== "number" || !Number.isFinite(value)) throw new RuntimeReportHttpError(422, "invalid_result", "Chart requires numeric measures");
|
|
2041
|
+
return {
|
|
2042
|
+
label: dimension ? String(row[dimension.id] ?? "") : result.title,
|
|
2043
|
+
value
|
|
2044
|
+
};
|
|
2045
|
+
}),
|
|
2046
|
+
format: measure.format === "money" ? "money" : measure.type === "integer" ? "integer" : "decimal",
|
|
2047
|
+
...context.currency ? { currency: context.currency } : {},
|
|
2048
|
+
href: `/reports/${encodeURIComponent(options.reportId)}`
|
|
2049
|
+
};
|
|
2050
|
+
}
|
|
2051
|
+
//#endregion
|
|
1912
2052
|
//#region src/runtime-report.ts
|
|
1913
2053
|
var __defProp = Object.defineProperty;
|
|
1914
2054
|
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
@@ -1941,6 +2081,14 @@ var RuntimeReport = class extends SmrtObject {
|
|
|
1941
2081
|
const proof = options[CONFIRMED_SAVE];
|
|
1942
2082
|
if (typeof proof === "string") confirmedSaves.set(this, proof);
|
|
1943
2083
|
}
|
|
2084
|
+
/** Run fresh totals using the authenticated viewer's current permissions. */
|
|
2085
|
+
async run() {
|
|
2086
|
+
return runRuntimeReportForPrincipal(this.id ?? "", currentRuntimeReportPrincipal(this.db));
|
|
2087
|
+
}
|
|
2088
|
+
/** Archive or restore this definition; no report content can be changed. */
|
|
2089
|
+
async archive(options) {
|
|
2090
|
+
return archiveRuntimeReportForPrincipal(this.id ?? "", options?.archived, currentRuntimeReportPrincipal(this.db));
|
|
2091
|
+
}
|
|
1944
2092
|
/** Re-parse the stored JSON; never trust the column without validation. */
|
|
1945
2093
|
getSpec() {
|
|
1946
2094
|
const parsed = parseRuntimeReportSpec(this.spec);
|
|
@@ -1999,13 +2147,60 @@ __decorateClass([field({
|
|
|
1999
2147
|
__decorateClass([field({ type: "text" })], RuntimeReport.prototype, "createdByUserId", 2);
|
|
2000
2148
|
RuntimeReport = __decorateClass([TenantScoped({ mode: "required" }), smrt({
|
|
2001
2149
|
tableName: "runtime_reports",
|
|
2002
|
-
|
|
2150
|
+
indexes: [{
|
|
2151
|
+
name: "idx_runtime_reports_confirm",
|
|
2152
|
+
columns: [
|
|
2153
|
+
"tenantId",
|
|
2154
|
+
"createdByUserId",
|
|
2155
|
+
"specHash",
|
|
2156
|
+
"status"
|
|
2157
|
+
]
|
|
2158
|
+
}],
|
|
2159
|
+
operationPermissions: {
|
|
2160
|
+
run: { action: "read" },
|
|
2161
|
+
archive: {
|
|
2162
|
+
action: "create",
|
|
2163
|
+
databaseActions: ["SELECT", "UPDATE"]
|
|
2164
|
+
}
|
|
2165
|
+
},
|
|
2166
|
+
api: {
|
|
2167
|
+
include: [
|
|
2168
|
+
"list",
|
|
2169
|
+
"get",
|
|
2170
|
+
"create",
|
|
2171
|
+
"run",
|
|
2172
|
+
"archive"
|
|
2173
|
+
],
|
|
2174
|
+
principalContext: true,
|
|
2175
|
+
routes: {
|
|
2176
|
+
run: {
|
|
2177
|
+
method: "POST",
|
|
2178
|
+
scope: "item",
|
|
2179
|
+
effect: "read",
|
|
2180
|
+
idempotent: true,
|
|
2181
|
+
openWorld: false
|
|
2182
|
+
},
|
|
2183
|
+
archive: {
|
|
2184
|
+
method: "POST",
|
|
2185
|
+
scope: "item",
|
|
2186
|
+
effect: "write",
|
|
2187
|
+
idempotent: true,
|
|
2188
|
+
openWorld: false
|
|
2189
|
+
}
|
|
2190
|
+
}
|
|
2191
|
+
},
|
|
2192
|
+
mcp: { include: [
|
|
2003
2193
|
"list",
|
|
2004
2194
|
"get",
|
|
2005
|
-
"
|
|
2195
|
+
"run",
|
|
2196
|
+
"archive"
|
|
2006
2197
|
] },
|
|
2007
|
-
|
|
2008
|
-
|
|
2198
|
+
cli: { include: [
|
|
2199
|
+
"list",
|
|
2200
|
+
"get",
|
|
2201
|
+
"run",
|
|
2202
|
+
"archive"
|
|
2203
|
+
] }
|
|
2009
2204
|
})], RuntimeReport);
|
|
2010
2205
|
var RuntimeReportCollection = class extends SmrtCollection {
|
|
2011
2206
|
static _itemClass = RuntimeReport;
|
|
@@ -2064,6 +2259,170 @@ async function runStoredRuntimeReport(options) {
|
|
|
2064
2259
|
});
|
|
2065
2260
|
}
|
|
2066
2261
|
//#endregion
|
|
2262
|
+
//#region src/recipes.ts
|
|
2263
|
+
var MaterializedReportsRecipe = class extends SmrtRecipe {
|
|
2264
|
+
static id = "reports.materialized";
|
|
2265
|
+
static help = "./materialized.recipe.md";
|
|
2266
|
+
static label = "Reports";
|
|
2267
|
+
static summary = "Keep totals and trends ready to read, refreshed on a schedule and open to the assistant.";
|
|
2268
|
+
static synonyms = [
|
|
2269
|
+
"reports",
|
|
2270
|
+
"totals",
|
|
2271
|
+
"summaries",
|
|
2272
|
+
"rollups",
|
|
2273
|
+
"kpis",
|
|
2274
|
+
"trends",
|
|
2275
|
+
"dashboards"
|
|
2276
|
+
];
|
|
2277
|
+
static models = [
|
|
2278
|
+
SmrtReportRun,
|
|
2279
|
+
SmrtReportWatermark,
|
|
2280
|
+
SmrtReportLock,
|
|
2281
|
+
SmrtReportSchedule,
|
|
2282
|
+
SmrtReportRefreshTask,
|
|
2283
|
+
SmrtPrincipalReportRefreshTask
|
|
2284
|
+
];
|
|
2285
|
+
static runtime = "server";
|
|
2286
|
+
};
|
|
2287
|
+
var RuntimeReportsRecipe = class extends SmrtRecipe {
|
|
2288
|
+
static id = "reports.runtime";
|
|
2289
|
+
static label = "Reports";
|
|
2290
|
+
static summary = "Ask for a report, approve it, and share its live totals with your team.";
|
|
2291
|
+
static help = "./runtime.recipe.md";
|
|
2292
|
+
static models = [RuntimeReport];
|
|
2293
|
+
static nav = [{
|
|
2294
|
+
label: "Reports",
|
|
2295
|
+
model: RuntimeReport,
|
|
2296
|
+
icon: "fileText"
|
|
2297
|
+
}];
|
|
2298
|
+
static surfaces = [
|
|
2299
|
+
{
|
|
2300
|
+
kind: "route",
|
|
2301
|
+
path: "/reports",
|
|
2302
|
+
export: "@happyvertical/smrt-reports/svelte#RuntimeReportsRoute",
|
|
2303
|
+
label: "Reports"
|
|
2304
|
+
},
|
|
2305
|
+
{
|
|
2306
|
+
kind: "route",
|
|
2307
|
+
path: "/reports/:id",
|
|
2308
|
+
export: "@happyvertical/smrt-reports/svelte#RuntimeReportDetailRoute",
|
|
2309
|
+
label: "Report detail"
|
|
2310
|
+
},
|
|
2311
|
+
{
|
|
2312
|
+
kind: "widget",
|
|
2313
|
+
type: "runtime-report-chart",
|
|
2314
|
+
export: "@happyvertical/smrt-reports/svelte#RuntimeReportChartWidget",
|
|
2315
|
+
label: "Report chart",
|
|
2316
|
+
description: "Chart a measure from a saved report.",
|
|
2317
|
+
icon: "chart",
|
|
2318
|
+
optionsEditor: "@happyvertical/smrt-reports/svelte#RuntimeReportWidgetOptions",
|
|
2319
|
+
options: [
|
|
2320
|
+
{
|
|
2321
|
+
key: "reportId",
|
|
2322
|
+
type: "text",
|
|
2323
|
+
label: "Report",
|
|
2324
|
+
required: true
|
|
2325
|
+
},
|
|
2326
|
+
{
|
|
2327
|
+
key: "measure",
|
|
2328
|
+
type: "identifier",
|
|
2329
|
+
label: "Measure",
|
|
2330
|
+
required: true
|
|
2331
|
+
},
|
|
2332
|
+
{
|
|
2333
|
+
key: "dimension",
|
|
2334
|
+
type: "identifier",
|
|
2335
|
+
label: "Dimension"
|
|
2336
|
+
}
|
|
2337
|
+
],
|
|
2338
|
+
data: {
|
|
2339
|
+
load: "@happyvertical/smrt-reports#loadRuntimeReportChart",
|
|
2340
|
+
models: ["@happyvertical/smrt-reports:RuntimeReport"]
|
|
2341
|
+
},
|
|
2342
|
+
defaultSpan: 2,
|
|
2343
|
+
maxSpan: 4
|
|
2344
|
+
}
|
|
2345
|
+
];
|
|
2346
|
+
static runtime = "server";
|
|
2347
|
+
};
|
|
2348
|
+
//#endregion
|
|
2349
|
+
//#region src/report.ts
|
|
2350
|
+
function registryColumnName(fieldName, field) {
|
|
2351
|
+
return validateColumnName(field?.columnName ?? field?._meta?.columnName ?? toSnakeCase(fieldName));
|
|
2352
|
+
}
|
|
2353
|
+
function findFieldColumn(fields, fieldName) {
|
|
2354
|
+
const direct = fields.get(fieldName);
|
|
2355
|
+
if (direct) return registryColumnName(fieldName, direct);
|
|
2356
|
+
const requestedColumn = toSnakeCase(fieldName);
|
|
2357
|
+
for (const [name, field] of fields.entries()) if (toSnakeCase(name) === requestedColumn) return registryColumnName(name, field);
|
|
2358
|
+
return validateColumnName(requestedColumn);
|
|
2359
|
+
}
|
|
2360
|
+
function findTenantColumn(fields, configuredField) {
|
|
2361
|
+
if (configuredField) return registryColumnName(configuredField, fields.get(configuredField));
|
|
2362
|
+
for (const [fieldName, field] of fields.entries()) if (fieldName === "tenantId" || field?._meta?.__tenancy?.isTenantIdField) return registryColumnName(fieldName, field);
|
|
2363
|
+
return null;
|
|
2364
|
+
}
|
|
2365
|
+
var SmrtReport = class extends SmrtObject {
|
|
2366
|
+
static _isReportBase = true;
|
|
2367
|
+
refreshedAt = null;
|
|
2368
|
+
constructor(options = {}) {
|
|
2369
|
+
super(options);
|
|
2370
|
+
if (options.refreshedAt !== void 0) this.refreshedAt = options.refreshedAt instanceof Date ? options.refreshedAt : options.refreshedAt ? new Date(options.refreshedAt) : null;
|
|
2371
|
+
}
|
|
2372
|
+
isStale(ttlMs) {
|
|
2373
|
+
if (!this.refreshedAt) return true;
|
|
2374
|
+
if (ttlMs === void 0) return false;
|
|
2375
|
+
return Date.now() - this.refreshedAt.getTime() > ttlMs;
|
|
2376
|
+
}
|
|
2377
|
+
async refresh(options = {}) {
|
|
2378
|
+
const result = await refreshReport(this.constructor, {
|
|
2379
|
+
...options,
|
|
2380
|
+
db: this.db
|
|
2381
|
+
});
|
|
2382
|
+
this.refreshedAt = result.refreshedAt;
|
|
2383
|
+
return result;
|
|
2384
|
+
}
|
|
2385
|
+
};
|
|
2386
|
+
var SmrtReportCollection = class extends SmrtCollection {
|
|
2387
|
+
async refreshIfStale() {
|
|
2388
|
+
const reportCtor = this.getItemClass();
|
|
2389
|
+
const refresh = (await buildReportDefinition(reportCtor)).refresh;
|
|
2390
|
+
if (!refresh?.ttl || refresh.manual) return;
|
|
2391
|
+
const registered = ObjectRegistry.getClassByConstructor(reportCtor) ?? ObjectRegistry.getClass(reportCtor.name);
|
|
2392
|
+
const reportClass = registered?.qualifiedName ?? registered?.name ?? reportCtor.name;
|
|
2393
|
+
const tableName = ObjectRegistry.getTableName(reportClass);
|
|
2394
|
+
if (!tableName) return;
|
|
2395
|
+
const fields = await ObjectRegistry.getAllFields(reportClass);
|
|
2396
|
+
const safeTableName = validateColumnName(tableName);
|
|
2397
|
+
const refreshedAtColumn = findFieldColumn(fields, "refreshedAt");
|
|
2398
|
+
const tenantColumn = findTenantColumn(fields, registered?.tenantScopedConfig?.field);
|
|
2399
|
+
const tenantId = getTenantId() ?? null;
|
|
2400
|
+
const result = tenantColumn ? await this.db.query(`SELECT MAX(${refreshedAtColumn}) AS refreshed_at FROM ${safeTableName} WHERE ${tenantColumn} ${tenantId ? "= ?" : "IS NULL"}`, ...tenantId ? [tenantId] : []) : await this.db.query(`SELECT MAX(${refreshedAtColumn}) AS refreshed_at FROM ${safeTableName}`);
|
|
2401
|
+
const refreshedAt = result.rows[0]?.refreshed_at ? new Date(result.rows[0].refreshed_at) : null;
|
|
2402
|
+
if (!(!refreshedAt || Date.now() - refreshedAt.getTime() > refresh.ttl)) return;
|
|
2403
|
+
await refreshReport(reportCtor, {
|
|
2404
|
+
db: this.db,
|
|
2405
|
+
mode: refresh.mode ?? "rebuild",
|
|
2406
|
+
trigger: "ttl",
|
|
2407
|
+
tenantId
|
|
2408
|
+
});
|
|
2409
|
+
}
|
|
2410
|
+
async refresh(options = {}) {
|
|
2411
|
+
return refreshReport(this.getItemClass(), {
|
|
2412
|
+
...options,
|
|
2413
|
+
db: this.db
|
|
2414
|
+
});
|
|
2415
|
+
}
|
|
2416
|
+
async list(options = {}) {
|
|
2417
|
+
await this.refreshIfStale();
|
|
2418
|
+
return super.list(options);
|
|
2419
|
+
}
|
|
2420
|
+
async get(filter, options = {}) {
|
|
2421
|
+
await this.refreshIfStale();
|
|
2422
|
+
return super.get(filter, options);
|
|
2423
|
+
}
|
|
2424
|
+
};
|
|
2425
|
+
//#endregion
|
|
2067
2426
|
//#region src/views.ts
|
|
2068
2427
|
var INHERITED_REPORT_SCOPE = [
|
|
2069
2428
|
"principal",
|
|
@@ -2584,6 +2943,6 @@ function validateReportExportArtifact(descriptor, artifact, now = /* @__PURE__ *
|
|
|
2584
2943
|
};
|
|
2585
2944
|
}
|
|
2586
2945
|
//#endregion
|
|
2587
|
-
export { MaterializedReportsRecipe, REPORT_LOCKS_TABLE, REPORT_REFRESH_TASKS_TABLE, REPORT_RUNS_TABLE, REPORT_RUNTIME_TABLES, REPORT_SCHEDULER_TABLES, REPORT_SCHEDULES_TABLE, REPORT_WATERMARKS_TABLE, RUNTIME_REPORT_BUCKETS, RUNTIME_REPORT_CHART_TYPES, RUNTIME_REPORT_FILTER_OPS, RUNTIME_REPORT_HAVING_OPS, RUNTIME_REPORT_LIMITS, RUNTIME_REPORT_MEASURE_FNS, RUNTIME_REPORT_SPEC_VERSION, ReportScheduleRunner, ReportSurfaceValidationError, RuntimeReport, RuntimeReportCollection, RuntimeReportError, SmrtPrincipalReportRefreshTask, SmrtReport, SmrtReportCollection, SmrtReportLock, SmrtReportLockCollection, SmrtReportRefreshTask, SmrtReportRun, SmrtReportRunCollection, SmrtReportSchedule, SmrtReportScheduleCollection, SmrtReportWatermark, SmrtReportWatermarkCollection, aggregate, applyReportExport, applyReportRefresh, archiveRuntimeReport, assertReportTablesReady, avg, bucketExpr, buildAggregate, buildReportAdapterDescriptor, buildReportDefinition, buildReportDrilldownQuery, compileReportDefinition, compileReportSpec, compileRuntimeReportSpec, count, createReportExportPageRequest, createReportExportRequest, createReportExportSnapshot, day, describeRuntimeReportSource, enqueueReportRefresh, ensureReportRefreshSchedules, getReportGroupingColumns, getReportLifecycle, getRuntimeReport, getRuntimeReportOptions, groupBy, hour, listRuntimeReports, max, migrateReportSavedView, min, minute, month, normalizeReportSavedView, parseRuntimeReportSpec, previewReportExport, previewReportRefresh, quarter, queryReportMaterializedRows, refreshReport, registerReportRefreshExecutionAuthorityHost, registerReportRefreshInterceptor, registerReportRefreshJobIntegritySigner, report, reportDefinitionFingerprint, reportMaterializedRowKey, reportRefreshOutcome, reportRowIdentity, restoreReportSavedView, runRuntimeReport, runStoredRuntimeReport, runtimeReportSpecHash, saveRuntimeReport, scopeKeyForTenant, serializeRuntimeReportSpec, splitReportFilterScopes, sum, validateReportExportArtifact, validateReportExportExecution, validateReportExportRequest, verifyReportExportSnapshot, week, year };
|
|
2946
|
+
export { MaterializedReportsRecipe, REPORT_LOCKS_TABLE, REPORT_REFRESH_TASKS_TABLE, REPORT_RUNS_TABLE, REPORT_RUNTIME_TABLES, REPORT_SCHEDULER_TABLES, REPORT_SCHEDULES_TABLE, REPORT_WATERMARKS_TABLE, RUNTIME_REPORT_BUCKETS, RUNTIME_REPORT_CHART_TYPES, RUNTIME_REPORT_FILTER_OPS, RUNTIME_REPORT_HAVING_OPS, RUNTIME_REPORT_LIMITS, RUNTIME_REPORT_MEASURE_FNS, RUNTIME_REPORT_SPEC_VERSION, ReportScheduleRunner, ReportSurfaceValidationError, RuntimeReport, RuntimeReportCollection, RuntimeReportError, RuntimeReportHttpError, RuntimeReportsRecipe, SmrtPrincipalReportRefreshTask, SmrtReport, SmrtReportCollection, SmrtReportLock, SmrtReportLockCollection, SmrtReportRefreshTask, SmrtReportRun, SmrtReportRunCollection, SmrtReportSchedule, SmrtReportScheduleCollection, SmrtReportWatermark, SmrtReportWatermarkCollection, aggregate, applyReportExport, applyReportRefresh, archiveRuntimeReport, archiveRuntimeReportForPrincipal, assertReportTablesReady, avg, bucketExpr, buildAggregate, buildReportAdapterDescriptor, buildReportDefinition, buildReportDrilldownQuery, compileReportDefinition, compileReportSpec, compileRuntimeReportSpec, count, createReportExportPageRequest, createReportExportRequest, createReportExportSnapshot, createRuntimeReportConfirmHandler, day, describeRuntimeReportSource, enqueueReportRefresh, ensureReportRefreshSchedules, getReportGroupingColumns, getReportLifecycle, getRuntimeReport, getRuntimeReportOptions, getRuntimeReportServerOptions, groupBy, hour, listRuntimeReports, loadRuntimeReportChart, max, migrateReportSavedView, min, minute, month, normalizeReportSavedView, parseRuntimeReportSpec, previewReportExport, previewReportRefresh, quarter, queryReportMaterializedRows, refreshReport, registerReportRefreshExecutionAuthorityHost, registerReportRefreshInterceptor, registerReportRefreshJobIntegritySigner, report, reportDefinitionFingerprint, reportMaterializedRowKey, reportRefreshOutcome, reportRowIdentity, restoreReportSavedView, runRuntimeReport, runRuntimeReportForPrincipal, runStoredRuntimeReport, runtimeReportSpecHash, saveRuntimeReport, scopeKeyForTenant, serializeRuntimeReportSpec, splitReportFilterScopes, sum, validateReportExportArtifact, validateReportExportExecution, validateReportExportRequest, verifyReportExportSnapshot, week, year };
|
|
2588
2947
|
|
|
2589
2948
|
//# sourceMappingURL=index.js.map
|