@happyvertical/smrt-reports 0.55.24 → 0.56.1
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 +11 -2
- package/dist/index.d.ts +4 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +476 -109
- package/dist/index.js.map +1 -1
- package/dist/manifest.json +174 -5
- package/dist/materialized-host.d.ts +72 -0
- package/dist/materialized-host.d.ts.map +1 -0
- 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/MaterializedReportTable.svelte +104 -0
- package/dist/svelte/MaterializedReportTable.svelte.d.ts +14 -0
- package/dist/svelte/MaterializedReportTable.svelte.d.ts.map +1 -0
- 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 +17 -0
- package/dist/svelte/index.d.ts.map +1 -0
- package/dist/svelte/index.js +14 -0
- package/dist/svelte/materialized.d.ts +19 -0
- package/dist/svelte/materialized.d.ts.map +1 -0
- package/dist/svelte/materialized.js +1 -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,108 +972,13 @@ function reportMaterializedRowKey(row) {
|
|
|
971
972
|
return id;
|
|
972
973
|
}
|
|
973
974
|
//#endregion
|
|
974
|
-
//#region src/
|
|
975
|
-
|
|
976
|
-
|
|
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));
|
|
975
|
+
//#region src/materialized-host.ts
|
|
976
|
+
function assertMaterializedReportRead(host, context) {
|
|
977
|
+
if (!context.userId?.trim() || !context.tenantId?.trim() || !context.permissions?.includes(host.readPermission)) throw new Error("Materialized report access denied.");
|
|
1003
978
|
}
|
|
1004
|
-
function
|
|
1005
|
-
|
|
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);
|
|
979
|
+
function findMaterializedReportHost(hosts, id) {
|
|
980
|
+
return hosts.find((host) => host.id === id);
|
|
1010
981
|
}
|
|
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
982
|
//#endregion
|
|
1077
983
|
//#region src/runtime-spec.ts
|
|
1078
984
|
var RUNTIME_REPORT_SPEC_VERSION = 1;
|
|
@@ -1137,7 +1043,7 @@ var RUNTIME_REPORT_CHART_TYPES = [
|
|
|
1137
1043
|
"pie",
|
|
1138
1044
|
"stat"
|
|
1139
1045
|
];
|
|
1140
|
-
var RuntimeReportError = class extends
|
|
1046
|
+
var RuntimeReportError = class extends SmrtError {
|
|
1141
1047
|
code;
|
|
1142
1048
|
path;
|
|
1143
1049
|
/**
|
|
@@ -1147,7 +1053,7 @@ var RuntimeReportError = class extends Error {
|
|
|
1147
1053
|
*/
|
|
1148
1054
|
status;
|
|
1149
1055
|
constructor(code, path, message) {
|
|
1150
|
-
super(path ? `${path}: ${message}` : message);
|
|
1056
|
+
super(path ? `${path}: ${message}` : message, code, "validation");
|
|
1151
1057
|
this.name = "RuntimeReportError";
|
|
1152
1058
|
this.code = code;
|
|
1153
1059
|
this.path = path;
|
|
@@ -1909,6 +1815,248 @@ async function runRuntimeReport(compiled, options) {
|
|
|
1909
1815
|
};
|
|
1910
1816
|
}
|
|
1911
1817
|
//#endregion
|
|
1818
|
+
//#region src/runtime-server.ts
|
|
1819
|
+
var RuntimeReportHttpError = class extends Error {
|
|
1820
|
+
constructor(status, code, message) {
|
|
1821
|
+
super(message);
|
|
1822
|
+
this.status = status;
|
|
1823
|
+
this.code = code;
|
|
1824
|
+
this.name = "RuntimeReportHttpError";
|
|
1825
|
+
}
|
|
1826
|
+
status;
|
|
1827
|
+
code;
|
|
1828
|
+
};
|
|
1829
|
+
function isRuntimeReportAccessError(error) {
|
|
1830
|
+
return error.code === "unknown_field" || error.code === "unknown_source";
|
|
1831
|
+
}
|
|
1832
|
+
function assertRuntimeReportPrincipal(context, permission) {
|
|
1833
|
+
if (!context?.userId) throw new RuntimeReportHttpError(401, "unauthenticated", "Sign in required");
|
|
1834
|
+
const active = getCurrentTenant();
|
|
1835
|
+
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");
|
|
1836
|
+
}
|
|
1837
|
+
function runtimeReportPrincipalCompileContext(options, principal) {
|
|
1838
|
+
return {
|
|
1839
|
+
sources: options.sources.filter((source) => principal.permissions.includes(`${source.collection}.read`)),
|
|
1840
|
+
permissions: principal.permissions,
|
|
1841
|
+
tenantId: principal.tenantId
|
|
1842
|
+
};
|
|
1843
|
+
}
|
|
1844
|
+
function createRuntimeReportConfirmHandler(options) {
|
|
1845
|
+
return async (request, context) => {
|
|
1846
|
+
try {
|
|
1847
|
+
if (request.method !== "POST") return Response.json({ code: "method_not_allowed" }, {
|
|
1848
|
+
status: 405,
|
|
1849
|
+
headers: { Allow: "POST" }
|
|
1850
|
+
});
|
|
1851
|
+
const origin = request.headers.get("origin");
|
|
1852
|
+
const site = request.headers.get("sec-fetch-site");
|
|
1853
|
+
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");
|
|
1854
|
+
assertRuntimeReportPrincipal(context, "runtimereports.create");
|
|
1855
|
+
let body;
|
|
1856
|
+
try {
|
|
1857
|
+
body = await request.json();
|
|
1858
|
+
} catch {
|
|
1859
|
+
throw new RuntimeReportHttpError(422, "invalid_spec", "Invalid JSON body");
|
|
1860
|
+
}
|
|
1861
|
+
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");
|
|
1862
|
+
const input = body;
|
|
1863
|
+
const spec = parseRuntimeReportSpec(input.spec);
|
|
1864
|
+
const hash = runtimeReportSpecHash(spec);
|
|
1865
|
+
if (input.specHash !== hash) throw new RuntimeReportHttpError(422, "spec_hash_mismatch", "The approved spec hash does not match");
|
|
1866
|
+
const principal = context;
|
|
1867
|
+
return await withTenant({
|
|
1868
|
+
tenantId: principal.tenantId,
|
|
1869
|
+
userId: principal.userId,
|
|
1870
|
+
permissions: new Set(principal.permissions)
|
|
1871
|
+
}, async () => {
|
|
1872
|
+
const serverOptions = options ?? getRuntimeReportServerOptions();
|
|
1873
|
+
const transaction = principal.db.transaction?.bind(principal.db);
|
|
1874
|
+
if (!transaction) throw new RuntimeReportHttpError(500, "transaction_required", "Runtime report confirmation requires transaction support");
|
|
1875
|
+
const { existing, archived } = await transaction(async (tx) => {
|
|
1876
|
+
const lookup = {
|
|
1877
|
+
db: tx,
|
|
1878
|
+
tenantId: principal.tenantId,
|
|
1879
|
+
createdByUserId: principal.userId,
|
|
1880
|
+
specHash: hash,
|
|
1881
|
+
limit: 1
|
|
1882
|
+
};
|
|
1883
|
+
const [existing2] = await listRuntimeReports(lookup);
|
|
1884
|
+
const [archived2] = existing2 ? [] : await listRuntimeReports({
|
|
1885
|
+
...lookup,
|
|
1886
|
+
status: "archived"
|
|
1887
|
+
});
|
|
1888
|
+
return {
|
|
1889
|
+
existing: existing2,
|
|
1890
|
+
archived: archived2
|
|
1891
|
+
};
|
|
1892
|
+
});
|
|
1893
|
+
if (archived) throw new RuntimeReportHttpError(409, "report_archived", "Restore the archived report before confirming it again");
|
|
1894
|
+
let compiled;
|
|
1895
|
+
try {
|
|
1896
|
+
compiled = await compileRuntimeReportSpec(spec, runtimeReportPrincipalCompileContext(serverOptions, principal));
|
|
1897
|
+
} catch (error) {
|
|
1898
|
+
if (existing && error instanceof RuntimeReportError && isRuntimeReportAccessError(error)) throw new RuntimeReportHttpError(403, "forbidden", "Report access denied");
|
|
1899
|
+
throw error;
|
|
1900
|
+
}
|
|
1901
|
+
let created = false;
|
|
1902
|
+
let report = existing ? {
|
|
1903
|
+
id: existing.id,
|
|
1904
|
+
specHash: hash,
|
|
1905
|
+
title: existing.title
|
|
1906
|
+
} : void 0;
|
|
1907
|
+
if (!report) report = await runOnce({
|
|
1908
|
+
db: principal.db,
|
|
1909
|
+
tenantId: principal.tenantId,
|
|
1910
|
+
actor: principal.userId,
|
|
1911
|
+
token: "runtime-report-confirm",
|
|
1912
|
+
content: spec
|
|
1913
|
+
}, async (tx) => {
|
|
1914
|
+
const [current] = await listRuntimeReports({
|
|
1915
|
+
db: tx,
|
|
1916
|
+
tenantId: principal.tenantId,
|
|
1917
|
+
createdByUserId: principal.userId,
|
|
1918
|
+
specHash: hash,
|
|
1919
|
+
limit: 1
|
|
1920
|
+
});
|
|
1921
|
+
const saved = current ?? await saveRuntimeReport({
|
|
1922
|
+
db: tx,
|
|
1923
|
+
tenantId: principal.tenantId,
|
|
1924
|
+
createdByUserId: principal.userId,
|
|
1925
|
+
compiled,
|
|
1926
|
+
confirmedSpecHash: hash
|
|
1927
|
+
});
|
|
1928
|
+
created = !current;
|
|
1929
|
+
if (!saved.id) throw new Error("Saved report has no id");
|
|
1930
|
+
return {
|
|
1931
|
+
id: saved.id,
|
|
1932
|
+
specHash: hash,
|
|
1933
|
+
title: saved.title
|
|
1934
|
+
};
|
|
1935
|
+
});
|
|
1936
|
+
if (!report.id) throw new Error("Saved report has no id");
|
|
1937
|
+
await serverOptions.audit?.({
|
|
1938
|
+
action: "confirm",
|
|
1939
|
+
userId: principal.userId,
|
|
1940
|
+
tenantId: principal.tenantId,
|
|
1941
|
+
specHash: hash,
|
|
1942
|
+
reportId: report.id,
|
|
1943
|
+
reused: !created
|
|
1944
|
+
});
|
|
1945
|
+
return Response.json({
|
|
1946
|
+
id: report.id,
|
|
1947
|
+
specHash: hash,
|
|
1948
|
+
title: report.title
|
|
1949
|
+
}, {
|
|
1950
|
+
status: created ? 201 : 200,
|
|
1951
|
+
headers: { "Cache-Control": "no-store" }
|
|
1952
|
+
});
|
|
1953
|
+
});
|
|
1954
|
+
} catch (error) {
|
|
1955
|
+
if (error instanceof RuntimeReportHttpError || error instanceof RuntimeReportError) return Response.json({
|
|
1956
|
+
code: error.code,
|
|
1957
|
+
message: error.message
|
|
1958
|
+
}, {
|
|
1959
|
+
status: error instanceof RuntimeReportError ? 422 : error.status,
|
|
1960
|
+
headers: { "Cache-Control": "no-store" }
|
|
1961
|
+
});
|
|
1962
|
+
return Response.json({
|
|
1963
|
+
code: "internal_error",
|
|
1964
|
+
message: "Unable to confirm report"
|
|
1965
|
+
}, {
|
|
1966
|
+
status: 500,
|
|
1967
|
+
headers: { "Cache-Control": "no-store" }
|
|
1968
|
+
});
|
|
1969
|
+
}
|
|
1970
|
+
};
|
|
1971
|
+
}
|
|
1972
|
+
function getRuntimeReportServerOptions() {
|
|
1973
|
+
return getPackageConfig("reports").runtime ?? { sources: [] };
|
|
1974
|
+
}
|
|
1975
|
+
function currentRuntimeReportPrincipal(db) {
|
|
1976
|
+
const context = getCurrentTenant();
|
|
1977
|
+
return {
|
|
1978
|
+
db,
|
|
1979
|
+
userId: context?.userId ?? "",
|
|
1980
|
+
tenantId: context?.tenantId ?? "",
|
|
1981
|
+
permissions: [...context?.permissions ?? []]
|
|
1982
|
+
};
|
|
1983
|
+
}
|
|
1984
|
+
async function runRuntimeReportForPrincipal(ref, principal, options = getRuntimeReportServerOptions()) {
|
|
1985
|
+
assertRuntimeReportPrincipal(principal, "runtimereports.read");
|
|
1986
|
+
return withTenant({
|
|
1987
|
+
tenantId: principal.tenantId,
|
|
1988
|
+
userId: principal.userId,
|
|
1989
|
+
permissions: new Set(principal.permissions)
|
|
1990
|
+
}, async () => {
|
|
1991
|
+
const report = await getRuntimeReport({
|
|
1992
|
+
db: principal.db,
|
|
1993
|
+
ref,
|
|
1994
|
+
tenantId: principal.tenantId
|
|
1995
|
+
});
|
|
1996
|
+
if (!report) throw new RuntimeReportHttpError(404, "not_found", "Report not found");
|
|
1997
|
+
if (report.status === "archived") throw new RuntimeReportHttpError(409, "report_archived", "Restore the archived report before running it");
|
|
1998
|
+
try {
|
|
1999
|
+
return await runStoredRuntimeReport({
|
|
2000
|
+
db: principal.db,
|
|
2001
|
+
report,
|
|
2002
|
+
context: runtimeReportPrincipalCompileContext(options, principal)
|
|
2003
|
+
});
|
|
2004
|
+
} catch (error) {
|
|
2005
|
+
if (error instanceof RuntimeReportError) {
|
|
2006
|
+
if (isRuntimeReportAccessError(error)) throw new RuntimeReportHttpError(403, "forbidden", "Report access denied");
|
|
2007
|
+
throw new RuntimeReportHttpError(422, error.code, error.message);
|
|
2008
|
+
}
|
|
2009
|
+
throw error;
|
|
2010
|
+
}
|
|
2011
|
+
});
|
|
2012
|
+
}
|
|
2013
|
+
async function archiveRuntimeReportForPrincipal(ref, archived, principal) {
|
|
2014
|
+
assertRuntimeReportPrincipal(principal, "runtimereports.create");
|
|
2015
|
+
if (typeof archived !== "boolean") throw new RuntimeReportHttpError(422, "invalid_value", "archived must be a boolean");
|
|
2016
|
+
return withTenant({
|
|
2017
|
+
tenantId: principal.tenantId,
|
|
2018
|
+
userId: principal.userId,
|
|
2019
|
+
permissions: new Set(principal.permissions)
|
|
2020
|
+
}, async () => {
|
|
2021
|
+
const report = await getRuntimeReport({
|
|
2022
|
+
db: principal.db,
|
|
2023
|
+
ref,
|
|
2024
|
+
tenantId: principal.tenantId
|
|
2025
|
+
});
|
|
2026
|
+
if (!report?.id) throw new RuntimeReportHttpError(404, "not_found", "Report not found");
|
|
2027
|
+
const status = archived ? "archived" : "active";
|
|
2028
|
+
if (report.status !== status) {
|
|
2029
|
+
report.status = status;
|
|
2030
|
+
await report.save();
|
|
2031
|
+
}
|
|
2032
|
+
return {
|
|
2033
|
+
id: report.id,
|
|
2034
|
+
status
|
|
2035
|
+
};
|
|
2036
|
+
});
|
|
2037
|
+
}
|
|
2038
|
+
async function loadRuntimeReportChart(options, context) {
|
|
2039
|
+
assertRuntimeReportPrincipal(context.reportPrincipal, "runtimereports.read");
|
|
2040
|
+
if (typeof options.reportId !== "string" || typeof options.measure !== "string") throw new RuntimeReportHttpError(422, "invalid_value", "Select a report and measure");
|
|
2041
|
+
const result = await runRuntimeReportForPrincipal(options.reportId, context.reportPrincipal);
|
|
2042
|
+
const measure = result.columns.find((column) => column.id === options.measure && column.role === "measure");
|
|
2043
|
+
const dimension = options.dimension === void 0 ? result.columns.find((column) => column.role === "dimension") : result.columns.find((column) => column.id === options.dimension && column.role === "dimension");
|
|
2044
|
+
if (!measure || options.dimension !== void 0 && !dimension) throw new RuntimeReportHttpError(422, "invalid_value", "Invalid report measure or dimension");
|
|
2045
|
+
return {
|
|
2046
|
+
points: result.rows.map((row) => {
|
|
2047
|
+
const value = row[measure.id];
|
|
2048
|
+
if (typeof value !== "number" || !Number.isFinite(value)) throw new RuntimeReportHttpError(422, "invalid_result", "Chart requires numeric measures");
|
|
2049
|
+
return {
|
|
2050
|
+
label: dimension ? String(row[dimension.id] ?? "") : result.title,
|
|
2051
|
+
value
|
|
2052
|
+
};
|
|
2053
|
+
}),
|
|
2054
|
+
format: measure.format === "money" ? "money" : measure.type === "integer" ? "integer" : "decimal",
|
|
2055
|
+
...context.currency ? { currency: context.currency } : {},
|
|
2056
|
+
href: `/reports/${encodeURIComponent(options.reportId)}`
|
|
2057
|
+
};
|
|
2058
|
+
}
|
|
2059
|
+
//#endregion
|
|
1912
2060
|
//#region src/runtime-report.ts
|
|
1913
2061
|
var __defProp = Object.defineProperty;
|
|
1914
2062
|
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
@@ -1941,6 +2089,14 @@ var RuntimeReport = class extends SmrtObject {
|
|
|
1941
2089
|
const proof = options[CONFIRMED_SAVE];
|
|
1942
2090
|
if (typeof proof === "string") confirmedSaves.set(this, proof);
|
|
1943
2091
|
}
|
|
2092
|
+
/** Run fresh totals using the authenticated viewer's current permissions. */
|
|
2093
|
+
async run() {
|
|
2094
|
+
return runRuntimeReportForPrincipal(this.id ?? "", currentRuntimeReportPrincipal(this.db));
|
|
2095
|
+
}
|
|
2096
|
+
/** Archive or restore this definition; no report content can be changed. */
|
|
2097
|
+
async archive(options) {
|
|
2098
|
+
return archiveRuntimeReportForPrincipal(this.id ?? "", options?.archived, currentRuntimeReportPrincipal(this.db));
|
|
2099
|
+
}
|
|
1944
2100
|
/** Re-parse the stored JSON; never trust the column without validation. */
|
|
1945
2101
|
getSpec() {
|
|
1946
2102
|
const parsed = parseRuntimeReportSpec(this.spec);
|
|
@@ -1999,13 +2155,60 @@ __decorateClass([field({
|
|
|
1999
2155
|
__decorateClass([field({ type: "text" })], RuntimeReport.prototype, "createdByUserId", 2);
|
|
2000
2156
|
RuntimeReport = __decorateClass([TenantScoped({ mode: "required" }), smrt({
|
|
2001
2157
|
tableName: "runtime_reports",
|
|
2002
|
-
|
|
2158
|
+
indexes: [{
|
|
2159
|
+
name: "idx_runtime_reports_confirm",
|
|
2160
|
+
columns: [
|
|
2161
|
+
"tenantId",
|
|
2162
|
+
"createdByUserId",
|
|
2163
|
+
"specHash",
|
|
2164
|
+
"status"
|
|
2165
|
+
]
|
|
2166
|
+
}],
|
|
2167
|
+
operationPermissions: {
|
|
2168
|
+
run: { action: "read" },
|
|
2169
|
+
archive: {
|
|
2170
|
+
action: "create",
|
|
2171
|
+
databaseActions: ["SELECT", "UPDATE"]
|
|
2172
|
+
}
|
|
2173
|
+
},
|
|
2174
|
+
api: {
|
|
2175
|
+
include: [
|
|
2176
|
+
"list",
|
|
2177
|
+
"get",
|
|
2178
|
+
"create",
|
|
2179
|
+
"run",
|
|
2180
|
+
"archive"
|
|
2181
|
+
],
|
|
2182
|
+
principalContext: true,
|
|
2183
|
+
routes: {
|
|
2184
|
+
run: {
|
|
2185
|
+
method: "POST",
|
|
2186
|
+
scope: "item",
|
|
2187
|
+
effect: "read",
|
|
2188
|
+
idempotent: true,
|
|
2189
|
+
openWorld: false
|
|
2190
|
+
},
|
|
2191
|
+
archive: {
|
|
2192
|
+
method: "POST",
|
|
2193
|
+
scope: "item",
|
|
2194
|
+
effect: "write",
|
|
2195
|
+
idempotent: true,
|
|
2196
|
+
openWorld: false
|
|
2197
|
+
}
|
|
2198
|
+
}
|
|
2199
|
+
},
|
|
2200
|
+
mcp: { include: [
|
|
2003
2201
|
"list",
|
|
2004
2202
|
"get",
|
|
2005
|
-
"
|
|
2203
|
+
"run",
|
|
2204
|
+
"archive"
|
|
2006
2205
|
] },
|
|
2007
|
-
|
|
2008
|
-
|
|
2206
|
+
cli: { include: [
|
|
2207
|
+
"list",
|
|
2208
|
+
"get",
|
|
2209
|
+
"run",
|
|
2210
|
+
"archive"
|
|
2211
|
+
] }
|
|
2009
2212
|
})], RuntimeReport);
|
|
2010
2213
|
var RuntimeReportCollection = class extends SmrtCollection {
|
|
2011
2214
|
static _itemClass = RuntimeReport;
|
|
@@ -2064,6 +2267,170 @@ async function runStoredRuntimeReport(options) {
|
|
|
2064
2267
|
});
|
|
2065
2268
|
}
|
|
2066
2269
|
//#endregion
|
|
2270
|
+
//#region src/recipes.ts
|
|
2271
|
+
var MaterializedReportsRecipe = class extends SmrtRecipe {
|
|
2272
|
+
static id = "reports.materialized";
|
|
2273
|
+
static help = "./materialized.recipe.md";
|
|
2274
|
+
static label = "Reports";
|
|
2275
|
+
static summary = "Keep totals and trends ready to read, refreshed on a schedule and open to the assistant.";
|
|
2276
|
+
static synonyms = [
|
|
2277
|
+
"reports",
|
|
2278
|
+
"totals",
|
|
2279
|
+
"summaries",
|
|
2280
|
+
"rollups",
|
|
2281
|
+
"kpis",
|
|
2282
|
+
"trends",
|
|
2283
|
+
"dashboards"
|
|
2284
|
+
];
|
|
2285
|
+
static models = [
|
|
2286
|
+
SmrtReportRun,
|
|
2287
|
+
SmrtReportWatermark,
|
|
2288
|
+
SmrtReportLock,
|
|
2289
|
+
SmrtReportSchedule,
|
|
2290
|
+
SmrtReportRefreshTask,
|
|
2291
|
+
SmrtPrincipalReportRefreshTask
|
|
2292
|
+
];
|
|
2293
|
+
static runtime = "server";
|
|
2294
|
+
};
|
|
2295
|
+
var RuntimeReportsRecipe = class extends SmrtRecipe {
|
|
2296
|
+
static id = "reports.runtime";
|
|
2297
|
+
static label = "Reports";
|
|
2298
|
+
static summary = "Ask for a report, approve it, and share its live totals with your team.";
|
|
2299
|
+
static help = "./runtime.recipe.md";
|
|
2300
|
+
static models = [RuntimeReport];
|
|
2301
|
+
static nav = [{
|
|
2302
|
+
label: "Reports",
|
|
2303
|
+
model: RuntimeReport,
|
|
2304
|
+
icon: "fileText"
|
|
2305
|
+
}];
|
|
2306
|
+
static surfaces = [
|
|
2307
|
+
{
|
|
2308
|
+
kind: "route",
|
|
2309
|
+
path: "/reports",
|
|
2310
|
+
export: "@happyvertical/smrt-reports/svelte#RuntimeReportsRoute",
|
|
2311
|
+
label: "Reports"
|
|
2312
|
+
},
|
|
2313
|
+
{
|
|
2314
|
+
kind: "route",
|
|
2315
|
+
path: "/reports/:id",
|
|
2316
|
+
export: "@happyvertical/smrt-reports/svelte#RuntimeReportDetailRoute",
|
|
2317
|
+
label: "Report detail"
|
|
2318
|
+
},
|
|
2319
|
+
{
|
|
2320
|
+
kind: "widget",
|
|
2321
|
+
type: "runtime-report-chart",
|
|
2322
|
+
export: "@happyvertical/smrt-reports/svelte#RuntimeReportChartWidget",
|
|
2323
|
+
label: "Report chart",
|
|
2324
|
+
description: "Chart a measure from a saved report.",
|
|
2325
|
+
icon: "chart",
|
|
2326
|
+
optionsEditor: "@happyvertical/smrt-reports/svelte#RuntimeReportWidgetOptions",
|
|
2327
|
+
options: [
|
|
2328
|
+
{
|
|
2329
|
+
key: "reportId",
|
|
2330
|
+
type: "text",
|
|
2331
|
+
label: "Report",
|
|
2332
|
+
required: true
|
|
2333
|
+
},
|
|
2334
|
+
{
|
|
2335
|
+
key: "measure",
|
|
2336
|
+
type: "identifier",
|
|
2337
|
+
label: "Measure",
|
|
2338
|
+
required: true
|
|
2339
|
+
},
|
|
2340
|
+
{
|
|
2341
|
+
key: "dimension",
|
|
2342
|
+
type: "identifier",
|
|
2343
|
+
label: "Dimension"
|
|
2344
|
+
}
|
|
2345
|
+
],
|
|
2346
|
+
data: {
|
|
2347
|
+
load: "@happyvertical/smrt-reports#loadRuntimeReportChart",
|
|
2348
|
+
models: ["@happyvertical/smrt-reports:RuntimeReport"]
|
|
2349
|
+
},
|
|
2350
|
+
defaultSpan: 2,
|
|
2351
|
+
maxSpan: 4
|
|
2352
|
+
}
|
|
2353
|
+
];
|
|
2354
|
+
static runtime = "server";
|
|
2355
|
+
};
|
|
2356
|
+
//#endregion
|
|
2357
|
+
//#region src/report.ts
|
|
2358
|
+
function registryColumnName(fieldName, field) {
|
|
2359
|
+
return validateColumnName(field?.columnName ?? field?._meta?.columnName ?? toSnakeCase(fieldName));
|
|
2360
|
+
}
|
|
2361
|
+
function findFieldColumn(fields, fieldName) {
|
|
2362
|
+
const direct = fields.get(fieldName);
|
|
2363
|
+
if (direct) return registryColumnName(fieldName, direct);
|
|
2364
|
+
const requestedColumn = toSnakeCase(fieldName);
|
|
2365
|
+
for (const [name, field] of fields.entries()) if (toSnakeCase(name) === requestedColumn) return registryColumnName(name, field);
|
|
2366
|
+
return validateColumnName(requestedColumn);
|
|
2367
|
+
}
|
|
2368
|
+
function findTenantColumn(fields, configuredField) {
|
|
2369
|
+
if (configuredField) return registryColumnName(configuredField, fields.get(configuredField));
|
|
2370
|
+
for (const [fieldName, field] of fields.entries()) if (fieldName === "tenantId" || field?._meta?.__tenancy?.isTenantIdField) return registryColumnName(fieldName, field);
|
|
2371
|
+
return null;
|
|
2372
|
+
}
|
|
2373
|
+
var SmrtReport = class extends SmrtObject {
|
|
2374
|
+
static _isReportBase = true;
|
|
2375
|
+
refreshedAt = null;
|
|
2376
|
+
constructor(options = {}) {
|
|
2377
|
+
super(options);
|
|
2378
|
+
if (options.refreshedAt !== void 0) this.refreshedAt = options.refreshedAt instanceof Date ? options.refreshedAt : options.refreshedAt ? new Date(options.refreshedAt) : null;
|
|
2379
|
+
}
|
|
2380
|
+
isStale(ttlMs) {
|
|
2381
|
+
if (!this.refreshedAt) return true;
|
|
2382
|
+
if (ttlMs === void 0) return false;
|
|
2383
|
+
return Date.now() - this.refreshedAt.getTime() > ttlMs;
|
|
2384
|
+
}
|
|
2385
|
+
async refresh(options = {}) {
|
|
2386
|
+
const result = await refreshReport(this.constructor, {
|
|
2387
|
+
...options,
|
|
2388
|
+
db: this.db
|
|
2389
|
+
});
|
|
2390
|
+
this.refreshedAt = result.refreshedAt;
|
|
2391
|
+
return result;
|
|
2392
|
+
}
|
|
2393
|
+
};
|
|
2394
|
+
var SmrtReportCollection = class extends SmrtCollection {
|
|
2395
|
+
async refreshIfStale() {
|
|
2396
|
+
const reportCtor = this.getItemClass();
|
|
2397
|
+
const refresh = (await buildReportDefinition(reportCtor)).refresh;
|
|
2398
|
+
if (!refresh?.ttl || refresh.manual) return;
|
|
2399
|
+
const registered = ObjectRegistry.getClassByConstructor(reportCtor) ?? ObjectRegistry.getClass(reportCtor.name);
|
|
2400
|
+
const reportClass = registered?.qualifiedName ?? registered?.name ?? reportCtor.name;
|
|
2401
|
+
const tableName = ObjectRegistry.getTableName(reportClass);
|
|
2402
|
+
if (!tableName) return;
|
|
2403
|
+
const fields = await ObjectRegistry.getAllFields(reportClass);
|
|
2404
|
+
const safeTableName = validateColumnName(tableName);
|
|
2405
|
+
const refreshedAtColumn = findFieldColumn(fields, "refreshedAt");
|
|
2406
|
+
const tenantColumn = findTenantColumn(fields, registered?.tenantScopedConfig?.field);
|
|
2407
|
+
const tenantId = getTenantId() ?? null;
|
|
2408
|
+
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}`);
|
|
2409
|
+
const refreshedAt = result.rows[0]?.refreshed_at ? new Date(result.rows[0].refreshed_at) : null;
|
|
2410
|
+
if (!(!refreshedAt || Date.now() - refreshedAt.getTime() > refresh.ttl)) return;
|
|
2411
|
+
await refreshReport(reportCtor, {
|
|
2412
|
+
db: this.db,
|
|
2413
|
+
mode: refresh.mode ?? "rebuild",
|
|
2414
|
+
trigger: "ttl",
|
|
2415
|
+
tenantId
|
|
2416
|
+
});
|
|
2417
|
+
}
|
|
2418
|
+
async refresh(options = {}) {
|
|
2419
|
+
return refreshReport(this.getItemClass(), {
|
|
2420
|
+
...options,
|
|
2421
|
+
db: this.db
|
|
2422
|
+
});
|
|
2423
|
+
}
|
|
2424
|
+
async list(options = {}) {
|
|
2425
|
+
await this.refreshIfStale();
|
|
2426
|
+
return super.list(options);
|
|
2427
|
+
}
|
|
2428
|
+
async get(filter, options = {}) {
|
|
2429
|
+
await this.refreshIfStale();
|
|
2430
|
+
return super.get(filter, options);
|
|
2431
|
+
}
|
|
2432
|
+
};
|
|
2433
|
+
//#endregion
|
|
2067
2434
|
//#region src/views.ts
|
|
2068
2435
|
var INHERITED_REPORT_SCOPE = [
|
|
2069
2436
|
"principal",
|
|
@@ -2584,6 +2951,6 @@ function validateReportExportArtifact(descriptor, artifact, now = /* @__PURE__ *
|
|
|
2584
2951
|
};
|
|
2585
2952
|
}
|
|
2586
2953
|
//#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 };
|
|
2954
|
+
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, assertMaterializedReportRead, assertReportTablesReady, avg, bucketExpr, buildAggregate, buildReportAdapterDescriptor, buildReportDefinition, buildReportDrilldownQuery, compileReportDefinition, compileReportSpec, compileRuntimeReportSpec, count, createReportExportPageRequest, createReportExportRequest, createReportExportSnapshot, createRuntimeReportConfirmHandler, day, describeRuntimeReportSource, enqueueReportRefresh, ensureReportRefreshSchedules, findMaterializedReportHost, 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
2955
|
|
|
2589
2956
|
//# sourceMappingURL=index.js.map
|