@adminforth/dashboard 1.7.0 → 1.9.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.
Files changed (33) hide show
  1. package/README.md +81 -55
  2. package/custom/model/dashboard.types.ts +17 -9
  3. package/custom/skills/adminforth-dashboard/SKILL.md +28 -12
  4. package/dist/custom/model/dashboard.types.d.ts +15 -8
  5. package/dist/custom/model/dashboard.types.ts +17 -9
  6. package/dist/custom/queries/useDashboardConfig.d.ts +222 -4
  7. package/dist/custom/queries/useWidgetData.d.ts +222 -4
  8. package/dist/custom/skills/adminforth-dashboard/SKILL.md +28 -12
  9. package/dist/schema/api.d.ts +5440 -941
  10. package/dist/schema/api.js +2 -2
  11. package/dist/schema/widget.d.ts +432 -23
  12. package/dist/schema/widget.js +1 -1
  13. package/dist/schema/widgets/charts.d.ts +558 -28
  14. package/dist/schema/widgets/charts.js +2 -2
  15. package/dist/schema/widgets/common.d.ts +17 -6
  16. package/dist/schema/widgets/common.js +16 -7
  17. package/dist/schema/widgets/gauge-card.d.ts +38 -2
  18. package/dist/schema/widgets/kpi-card.d.ts +38 -2
  19. package/dist/schema/widgets/pivot-table.d.ts +38 -2
  20. package/dist/schema/widgets/table.d.ts +38 -2
  21. package/dist/services/calc-evaluator.d.ts +1 -0
  22. package/dist/services/calc-evaluator.js +28 -0
  23. package/dist/services/dashboardFilterService.d.ts +5 -0
  24. package/dist/services/dashboardFilterService.js +125 -0
  25. package/dist/services/widgetDataService.js +53 -201
  26. package/package.json +2 -1
  27. package/schema/api.ts +1 -2
  28. package/schema/widget.ts +0 -1
  29. package/schema/widgets/charts.ts +1 -2
  30. package/schema/widgets/common.ts +16 -7
  31. package/services/calc-evaluator.ts +33 -0
  32. package/services/dashboardFilterService.ts +162 -0
  33. package/services/widgetDataService.ts +88 -263
@@ -1,5 +1,5 @@
1
1
  import { z } from 'zod';
2
- import { ChartFieldRefSchema, FunnelQueryConfigSchema, QueryConfigSchema, WidgetBaseSchema, } from './common.js';
2
+ import { ChartFieldRefSchema, QueryConfigSchema, WidgetBaseSchema, } from './common.js';
3
3
  const ChartBaseSchema = z.object({
4
4
  title: z.string().optional(),
5
5
  }).strict();
@@ -80,7 +80,7 @@ export const HistogramChartWidgetConfigSchema = WidgetBaseSchema.extend({
80
80
  export const FunnelChartWidgetConfigSchema = WidgetBaseSchema.extend({
81
81
  target: z.literal('chart'),
82
82
  chart: FunnelChartSchema,
83
- query: FunnelQueryConfigSchema,
83
+ query: QueryConfigSchema,
84
84
  });
85
85
  export const ChartWidgetTargetConfigSchema = z.union([
86
86
  LineChartWidgetConfigSchema,
@@ -117,7 +117,8 @@ export declare const QueryCalcItemSchema: z.ZodObject<{
117
117
  calc: z.ZodString;
118
118
  as: z.ZodString;
119
119
  }, z.core.$strict>;
120
- export declare const QueryConfigSchema: z.ZodObject<{
120
+ export declare const QueryConfigSchema: z.ZodUnion<readonly [z.ZodObject<{
121
+ source: z.ZodOptional<z.ZodLiteral<"resource">>;
121
122
  resource: z.ZodString;
122
123
  select: z.ZodOptional<z.ZodArray<z.ZodUnion<readonly [z.ZodObject<{
123
124
  field: z.ZodString;
@@ -190,12 +191,12 @@ export declare const QueryConfigSchema: z.ZodObject<{
190
191
  as: z.ZodString;
191
192
  }, z.core.$strict>>>;
192
193
  formatting: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
193
- }, z.core.$strict>;
194
- export declare const FunnelQueryConfigSchema: z.ZodObject<{
194
+ }, z.core.$strict>, z.ZodObject<{
195
+ source: z.ZodLiteral<"steps">;
195
196
  steps: z.ZodArray<z.ZodObject<{
196
197
  name: z.ZodString;
197
198
  resource: z.ZodString;
198
- metric: z.ZodObject<{
199
+ select: z.ZodArray<z.ZodObject<{
199
200
  agg: z.ZodEnum<{
200
201
  sum: "sum";
201
202
  count: "count";
@@ -208,14 +209,24 @@ export declare const FunnelQueryConfigSchema: z.ZodObject<{
208
209
  field: z.ZodOptional<z.ZodString>;
209
210
  as: z.ZodString;
210
211
  filters: z.ZodOptional<z.ZodType<unknown, unknown, z.core.$ZodTypeInternals<unknown, unknown>>>;
211
- }, z.core.$strict>;
212
+ }, z.core.$strict>>;
212
213
  filters: z.ZodOptional<z.ZodType<unknown, unknown, z.core.$ZodTypeInternals<unknown, unknown>>>;
213
214
  }, z.core.$strict>>;
214
215
  calcs: z.ZodOptional<z.ZodArray<z.ZodObject<{
215
216
  calc: z.ZodString;
216
217
  as: z.ZodString;
217
218
  }, z.core.$strict>>>;
218
- }, z.core.$strict>;
219
+ order_by: z.ZodOptional<z.ZodArray<z.ZodObject<{
220
+ field: z.ZodString;
221
+ direction: z.ZodOptional<z.ZodEnum<{
222
+ asc: "asc";
223
+ desc: "desc";
224
+ }>>;
225
+ }, z.core.$strict>>>;
226
+ limit: z.ZodOptional<z.ZodNumber>;
227
+ offset: z.ZodOptional<z.ZodNumber>;
228
+ formatting: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
229
+ }, z.core.$strict>]>;
219
230
  export declare const WidgetPersistedFieldsSchema: z.ZodObject<{
220
231
  id: z.ZodString;
221
232
  group_id: z.ZodString;
@@ -123,7 +123,8 @@ export const QueryCalcItemSchema = z.object({
123
123
  calc: z.string(),
124
124
  as: z.string(),
125
125
  }).strict();
126
- export const QueryConfigSchema = z.object({
126
+ const ResourceQueryConfigSchema = z.object({
127
+ source: z.literal('resource').optional(),
127
128
  resource: z.string(),
128
129
  select: z.array(QuerySelectItemSchema).optional(),
129
130
  sparkline: z.object({
@@ -141,16 +142,24 @@ export const QueryConfigSchema = z.object({
141
142
  calcs: z.array(QueryCalcItemSchema).optional(),
142
143
  formatting: z.record(z.string(), z.unknown()).optional(),
143
144
  }).strict();
144
- const FunnelQueryStepSchema = z.object({
145
+ const StepsQuerySelectStepSchema = z.object({
145
146
  name: z.string(),
146
147
  resource: z.string(),
147
- metric: QueryAggregateSelectItemSchema,
148
+ select: z.array(QueryAggregateSelectItemSchema).min(1),
148
149
  filters: FilterExpressionSchema.optional(),
149
150
  }).strict();
150
- export const FunnelQueryConfigSchema = z.object({
151
- steps: z.array(FunnelQueryStepSchema).min(1),
152
- calcs: z.array(QueryCalcItemSchema).optional(),
153
- }).strict();
151
+ export const QueryConfigSchema = z.union([
152
+ ResourceQueryConfigSchema,
153
+ z.object({
154
+ source: z.literal('steps'),
155
+ steps: z.array(StepsQuerySelectStepSchema).min(1),
156
+ calcs: z.array(QueryCalcItemSchema).optional(),
157
+ order_by: z.array(QueryOrderByItemSchema).optional(),
158
+ limit: z.number().int().positive().optional(),
159
+ offset: z.number().int().nonnegative().optional(),
160
+ formatting: z.record(z.string(), z.unknown()).optional(),
161
+ }).strict(),
162
+ ]);
154
163
  export const WidgetPersistedFieldsSchema = z.object({
155
164
  id: z.string(),
156
165
  group_id: z.string(),
@@ -95,7 +95,8 @@ export declare const GaugeCardWidgetConfigSchema: z.ZodObject<{
95
95
  }, z.core.$strict>>;
96
96
  color: z.ZodOptional<z.ZodString>;
97
97
  }, z.core.$strict>;
98
- query: z.ZodObject<{
98
+ query: z.ZodUnion<readonly [z.ZodObject<{
99
+ source: z.ZodOptional<z.ZodLiteral<"resource">>;
99
100
  resource: z.ZodString;
100
101
  select: z.ZodOptional<z.ZodArray<z.ZodUnion<readonly [z.ZodObject<{
101
102
  field: z.ZodString;
@@ -168,5 +169,40 @@ export declare const GaugeCardWidgetConfigSchema: z.ZodObject<{
168
169
  as: z.ZodString;
169
170
  }, z.core.$strict>>>;
170
171
  formatting: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
171
- }, z.core.$strict>;
172
+ }, z.core.$strict>, z.ZodObject<{
173
+ source: z.ZodLiteral<"steps">;
174
+ steps: z.ZodArray<z.ZodObject<{
175
+ name: z.ZodString;
176
+ resource: z.ZodString;
177
+ select: z.ZodArray<z.ZodObject<{
178
+ agg: z.ZodEnum<{
179
+ sum: "sum";
180
+ count: "count";
181
+ count_distinct: "count_distinct";
182
+ avg: "avg";
183
+ min: "min";
184
+ max: "max";
185
+ median: "median";
186
+ }>;
187
+ field: z.ZodOptional<z.ZodString>;
188
+ as: z.ZodString;
189
+ filters: z.ZodOptional<z.ZodType<unknown, unknown, z.core.$ZodTypeInternals<unknown, unknown>>>;
190
+ }, z.core.$strict>>;
191
+ filters: z.ZodOptional<z.ZodType<unknown, unknown, z.core.$ZodTypeInternals<unknown, unknown>>>;
192
+ }, z.core.$strict>>;
193
+ calcs: z.ZodOptional<z.ZodArray<z.ZodObject<{
194
+ calc: z.ZodString;
195
+ as: z.ZodString;
196
+ }, z.core.$strict>>>;
197
+ order_by: z.ZodOptional<z.ZodArray<z.ZodObject<{
198
+ field: z.ZodString;
199
+ direction: z.ZodOptional<z.ZodEnum<{
200
+ asc: "asc";
201
+ desc: "desc";
202
+ }>>;
203
+ }, z.core.$strict>>>;
204
+ limit: z.ZodOptional<z.ZodNumber>;
205
+ offset: z.ZodOptional<z.ZodNumber>;
206
+ formatting: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
207
+ }, z.core.$strict>]>;
172
208
  }, z.core.$strict>;
@@ -135,7 +135,8 @@ export declare const KpiCardWidgetConfigSchema: z.ZodObject<{
135
135
  }, z.core.$strict>>;
136
136
  }, z.core.$strict>>;
137
137
  }, z.core.$strict>;
138
- query: z.ZodObject<{
138
+ query: z.ZodUnion<readonly [z.ZodObject<{
139
+ source: z.ZodOptional<z.ZodLiteral<"resource">>;
139
140
  resource: z.ZodString;
140
141
  select: z.ZodOptional<z.ZodArray<z.ZodUnion<readonly [z.ZodObject<{
141
142
  field: z.ZodString;
@@ -208,5 +209,40 @@ export declare const KpiCardWidgetConfigSchema: z.ZodObject<{
208
209
  as: z.ZodString;
209
210
  }, z.core.$strict>>>;
210
211
  formatting: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
211
- }, z.core.$strict>;
212
+ }, z.core.$strict>, z.ZodObject<{
213
+ source: z.ZodLiteral<"steps">;
214
+ steps: z.ZodArray<z.ZodObject<{
215
+ name: z.ZodString;
216
+ resource: z.ZodString;
217
+ select: z.ZodArray<z.ZodObject<{
218
+ agg: z.ZodEnum<{
219
+ sum: "sum";
220
+ count: "count";
221
+ count_distinct: "count_distinct";
222
+ avg: "avg";
223
+ min: "min";
224
+ max: "max";
225
+ median: "median";
226
+ }>;
227
+ field: z.ZodOptional<z.ZodString>;
228
+ as: z.ZodString;
229
+ filters: z.ZodOptional<z.ZodType<unknown, unknown, z.core.$ZodTypeInternals<unknown, unknown>>>;
230
+ }, z.core.$strict>>;
231
+ filters: z.ZodOptional<z.ZodType<unknown, unknown, z.core.$ZodTypeInternals<unknown, unknown>>>;
232
+ }, z.core.$strict>>;
233
+ calcs: z.ZodOptional<z.ZodArray<z.ZodObject<{
234
+ calc: z.ZodString;
235
+ as: z.ZodString;
236
+ }, z.core.$strict>>>;
237
+ order_by: z.ZodOptional<z.ZodArray<z.ZodObject<{
238
+ field: z.ZodString;
239
+ direction: z.ZodOptional<z.ZodEnum<{
240
+ asc: "asc";
241
+ desc: "desc";
242
+ }>>;
243
+ }, z.core.$strict>>>;
244
+ limit: z.ZodOptional<z.ZodNumber>;
245
+ offset: z.ZodOptional<z.ZodNumber>;
246
+ formatting: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
247
+ }, z.core.$strict>]>;
212
248
  }, z.core.$strict>;
@@ -119,7 +119,8 @@ export declare const PivotTableWidgetConfigSchema: z.ZodObject<{
119
119
  }>>;
120
120
  }, z.core.$strict>>;
121
121
  }, z.core.$strict>;
122
- query: z.ZodObject<{
122
+ query: z.ZodUnion<readonly [z.ZodObject<{
123
+ source: z.ZodOptional<z.ZodLiteral<"resource">>;
123
124
  resource: z.ZodString;
124
125
  select: z.ZodOptional<z.ZodArray<z.ZodUnion<readonly [z.ZodObject<{
125
126
  field: z.ZodString;
@@ -192,5 +193,40 @@ export declare const PivotTableWidgetConfigSchema: z.ZodObject<{
192
193
  as: z.ZodString;
193
194
  }, z.core.$strict>>>;
194
195
  formatting: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
195
- }, z.core.$strict>;
196
+ }, z.core.$strict>, z.ZodObject<{
197
+ source: z.ZodLiteral<"steps">;
198
+ steps: z.ZodArray<z.ZodObject<{
199
+ name: z.ZodString;
200
+ resource: z.ZodString;
201
+ select: z.ZodArray<z.ZodObject<{
202
+ agg: z.ZodEnum<{
203
+ sum: "sum";
204
+ count: "count";
205
+ count_distinct: "count_distinct";
206
+ avg: "avg";
207
+ min: "min";
208
+ max: "max";
209
+ median: "median";
210
+ }>;
211
+ field: z.ZodOptional<z.ZodString>;
212
+ as: z.ZodString;
213
+ filters: z.ZodOptional<z.ZodType<unknown, unknown, z.core.$ZodTypeInternals<unknown, unknown>>>;
214
+ }, z.core.$strict>>;
215
+ filters: z.ZodOptional<z.ZodType<unknown, unknown, z.core.$ZodTypeInternals<unknown, unknown>>>;
216
+ }, z.core.$strict>>;
217
+ calcs: z.ZodOptional<z.ZodArray<z.ZodObject<{
218
+ calc: z.ZodString;
219
+ as: z.ZodString;
220
+ }, z.core.$strict>>>;
221
+ order_by: z.ZodOptional<z.ZodArray<z.ZodObject<{
222
+ field: z.ZodString;
223
+ direction: z.ZodOptional<z.ZodEnum<{
224
+ asc: "asc";
225
+ desc: "desc";
226
+ }>>;
227
+ }, z.core.$strict>>>;
228
+ limit: z.ZodOptional<z.ZodNumber>;
229
+ offset: z.ZodOptional<z.ZodNumber>;
230
+ formatting: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
231
+ }, z.core.$strict>]>;
196
232
  }, z.core.$strict>;
@@ -53,7 +53,8 @@ export declare const TableWidgetConfigSchema: z.ZodObject<{
53
53
  pagination: z.ZodOptional<z.ZodBoolean>;
54
54
  page_size: z.ZodOptional<z.ZodNumber>;
55
55
  }, z.core.$strict>>;
56
- query: z.ZodObject<{
56
+ query: z.ZodUnion<readonly [z.ZodObject<{
57
+ source: z.ZodOptional<z.ZodLiteral<"resource">>;
57
58
  resource: z.ZodString;
58
59
  select: z.ZodOptional<z.ZodArray<z.ZodUnion<readonly [z.ZodObject<{
59
60
  field: z.ZodString;
@@ -126,5 +127,40 @@ export declare const TableWidgetConfigSchema: z.ZodObject<{
126
127
  as: z.ZodString;
127
128
  }, z.core.$strict>>>;
128
129
  formatting: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
129
- }, z.core.$strict>;
130
+ }, z.core.$strict>, z.ZodObject<{
131
+ source: z.ZodLiteral<"steps">;
132
+ steps: z.ZodArray<z.ZodObject<{
133
+ name: z.ZodString;
134
+ resource: z.ZodString;
135
+ select: z.ZodArray<z.ZodObject<{
136
+ agg: z.ZodEnum<{
137
+ sum: "sum";
138
+ count: "count";
139
+ count_distinct: "count_distinct";
140
+ avg: "avg";
141
+ min: "min";
142
+ max: "max";
143
+ median: "median";
144
+ }>;
145
+ field: z.ZodOptional<z.ZodString>;
146
+ as: z.ZodString;
147
+ filters: z.ZodOptional<z.ZodType<unknown, unknown, z.core.$ZodTypeInternals<unknown, unknown>>>;
148
+ }, z.core.$strict>>;
149
+ filters: z.ZodOptional<z.ZodType<unknown, unknown, z.core.$ZodTypeInternals<unknown, unknown>>>;
150
+ }, z.core.$strict>>;
151
+ calcs: z.ZodOptional<z.ZodArray<z.ZodObject<{
152
+ calc: z.ZodString;
153
+ as: z.ZodString;
154
+ }, z.core.$strict>>>;
155
+ order_by: z.ZodOptional<z.ZodArray<z.ZodObject<{
156
+ field: z.ZodString;
157
+ direction: z.ZodOptional<z.ZodEnum<{
158
+ asc: "asc";
159
+ desc: "desc";
160
+ }>>;
161
+ }, z.core.$strict>>>;
162
+ limit: z.ZodOptional<z.ZodNumber>;
163
+ offset: z.ZodOptional<z.ZodNumber>;
164
+ formatting: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
165
+ }, z.core.$strict>]>;
130
166
  }, z.core.$strict>;
@@ -0,0 +1 @@
1
+ export declare function evaluateCalc(calc: string, values: Record<string, unknown>): any;
@@ -0,0 +1,28 @@
1
+ import { Parser } from 'expr-eval-fork';
2
+ const CALC_PARSER_OPTIONS = {
3
+ allowMemberAccess: false,
4
+ operators: {
5
+ assignment: false,
6
+ concatenate: false,
7
+ conditional: true,
8
+ comparison: true,
9
+ fndef: false,
10
+ in: false,
11
+ logical: true,
12
+ random: false,
13
+ },
14
+ };
15
+ const CALC_PARSER = new Parser(CALC_PARSER_OPTIONS);
16
+ export function evaluateCalc(calc, values) {
17
+ return CALC_PARSER.parse(calc).evaluate(normalizeCalcValues(values));
18
+ }
19
+ function normalizeCalcValues(values) {
20
+ return Object.fromEntries(Object.entries(values).map(([key, value]) => [
21
+ key,
22
+ typeof value === 'string' ? value : toFiniteNumber(value),
23
+ ]));
24
+ }
25
+ function toFiniteNumber(value) {
26
+ const numberValue = typeof value === 'number' ? value : Number(value);
27
+ return Number.isFinite(numberValue) ? numberValue : 0;
28
+ }
@@ -0,0 +1,5 @@
1
+ import type { IAdminForthAndOrFilter, IAdminForthSingleFilter } from 'adminforth';
2
+ import type { FilterExpression } from '../custom/model/dashboard.types.js';
3
+ export type DashboardQueryFilters = IAdminForthSingleFilter | IAdminForthAndOrFilter | Array<IAdminForthSingleFilter | IAdminForthAndOrFilter>;
4
+ export declare function getAdminForthFilters(filters: FilterExpression | DashboardQueryFilters | undefined): DashboardQueryFilters;
5
+ export declare function mergeFilters(...filters: Array<FilterExpression | DashboardQueryFilters | undefined>): DashboardQueryFilters;
@@ -0,0 +1,125 @@
1
+ import { Filters } from 'adminforth';
2
+ const RELATIVE_DURATION_RE = /^(\d+)(h|d|w|mo|y)$/;
3
+ const FILTER_OPERATORS = {
4
+ eq: Filters.EQ,
5
+ neq: Filters.NEQ,
6
+ gt: Filters.GT,
7
+ gte: Filters.GTE,
8
+ lt: Filters.LT,
9
+ lte: Filters.LTE,
10
+ in: Filters.IN,
11
+ not_in: Filters.NOT_IN,
12
+ like: Filters.LIKE,
13
+ ilike: Filters.ILIKE,
14
+ };
15
+ export function getAdminForthFilters(filters) {
16
+ if (Array.isArray(filters)) {
17
+ return filters.map((filter) => isDashboardFilterExpression(filter)
18
+ ? toAdminForthFilter(filter)
19
+ : filter);
20
+ }
21
+ if (isDashboardFilterExpression(filters)) {
22
+ return toAdminForthFilter(filters);
23
+ }
24
+ if (filters) {
25
+ return filters;
26
+ }
27
+ return [];
28
+ }
29
+ export function mergeFilters(...filters) {
30
+ const merged = [];
31
+ for (const filter of filters) {
32
+ const normalized = getAdminForthFilters(filter);
33
+ if (Array.isArray(normalized)) {
34
+ merged.push(...normalized);
35
+ continue;
36
+ }
37
+ if (normalized) {
38
+ merged.push(normalized);
39
+ }
40
+ }
41
+ if (!merged.length) {
42
+ return [];
43
+ }
44
+ return merged.length === 1 ? merged[0] : merged;
45
+ }
46
+ function isDashboardFilterExpression(value) {
47
+ if (Array.isArray(value)) {
48
+ return true;
49
+ }
50
+ if (!isRecord(value)) {
51
+ return false;
52
+ }
53
+ return 'and' in value
54
+ || 'or' in value
55
+ || 'eq' in value
56
+ || 'neq' in value
57
+ || 'gt' in value
58
+ || 'gte' in value
59
+ || 'lt' in value
60
+ || 'lte' in value
61
+ || 'in' in value
62
+ || 'not_in' in value
63
+ || 'like' in value
64
+ || 'ilike' in value;
65
+ }
66
+ function toAdminForthFilter(filter) {
67
+ if (Array.isArray(filter)) {
68
+ return Filters.AND(filter.map((item) => toAdminForthFilter(item)));
69
+ }
70
+ if ('and' in filter) {
71
+ return Filters.AND(filter.and.map((item) => toAdminForthFilter(item)));
72
+ }
73
+ if ('or' in filter) {
74
+ return Filters.OR(filter.or.map((item) => toAdminForthFilter(item)));
75
+ }
76
+ for (const [operator, createFilter] of Object.entries(FILTER_OPERATORS)) {
77
+ if (Object.prototype.hasOwnProperty.call(filter, operator)) {
78
+ return createFilter(filter.field, resolveFilterValue(filter[operator]));
79
+ }
80
+ }
81
+ return Filters.AND([]);
82
+ }
83
+ function resolveFilterValue(value) {
84
+ if (Array.isArray(value)) {
85
+ return value.map((item) => resolveFilterValue(item));
86
+ }
87
+ if (!isRecord(value)) {
88
+ return value;
89
+ }
90
+ if (value.now === true) {
91
+ return new Date().toISOString();
92
+ }
93
+ if (typeof value.now_minus === 'string') {
94
+ return subtractDuration(new Date(), value.now_minus).toISOString();
95
+ }
96
+ return value;
97
+ }
98
+ function subtractDuration(now, duration) {
99
+ const match = duration.match(RELATIVE_DURATION_RE);
100
+ if (!match) {
101
+ throw new Error(`Unsupported relative date duration: ${duration}`);
102
+ }
103
+ const amount = Number(match[1]);
104
+ const unit = match[2];
105
+ const date = new Date(now);
106
+ if (unit === 'h') {
107
+ date.setUTCHours(date.getUTCHours() - amount);
108
+ }
109
+ else if (unit === 'd') {
110
+ date.setUTCDate(date.getUTCDate() - amount);
111
+ }
112
+ else if (unit === 'w') {
113
+ date.setUTCDate(date.getUTCDate() - amount * 7);
114
+ }
115
+ else if (unit === 'mo') {
116
+ date.setUTCMonth(date.getUTCMonth() - amount);
117
+ }
118
+ else if (unit === 'y') {
119
+ date.setUTCFullYear(date.getUTCFullYear() - amount);
120
+ }
121
+ return date;
122
+ }
123
+ function isRecord(value) {
124
+ return typeof value === 'object' && value !== null;
125
+ }