@automate.ax/integration-contracts 0.130.3 → 0.130.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -9,6 +9,7 @@ export interface AxiomRequestOptions<TSchema extends z.ZodType> {
9
9
  body?: Encodable;
10
10
  headers?: Record<string, string>;
11
11
  method?: "DELETE" | "GET" | "PATCH" | "POST" | "PUT";
12
+ numericStringFields?: readonly string[];
12
13
  query?: Record<string, boolean | number | string | undefined>;
13
14
  responseSchema: TSchema;
14
15
  version?: "v1" | "v2";
package/dist/axiom/api.js CHANGED
@@ -1,4 +1,5 @@
1
1
  import { encodableSchema } from "@automate.ax/codec";
2
+ import { JSONParse, JSONStringify } from "json-with-bigint";
2
3
  import * as z from "zod";
3
4
  const AXIOM_API_ORIGIN = "https://api.axiom.co";
4
5
  const AXIOM_SECRET_SCHEMA = z.object({ apiKey: z.string().trim().min(1) });
@@ -68,7 +69,7 @@ export function getAxiomApi(account, edgeUrl = AXIOM_API_ORIGIN) {
68
69
  const response = await fetch(url, {
69
70
  body: options.body === undefined
70
71
  ? undefined
71
- : JSON.stringify(encodableSchema.parse(options.body)),
72
+ : serializeRequestBody(options.body, options.numericStringFields),
72
73
  headers: {
73
74
  Accept: "application/json",
74
75
  Authorization: `Bearer ${apiKey}`,
@@ -146,12 +147,60 @@ function parseResponse(text) {
146
147
  if (!text)
147
148
  return null;
148
149
  try {
149
- return encodableSchema.parse(JSON.parse(text));
150
+ return encodableSchema.parse(normalizeBigInts(JSONParse(text)));
150
151
  }
151
152
  catch {
152
153
  return { response: text };
153
154
  }
154
155
  }
156
+ /**
157
+ * Serializes selected decimal strings as lossless JSON integers.
158
+ *
159
+ * @param body - Encodable request body.
160
+ * @param numericStringFields - Field names to emit as JSON integers.
161
+ */
162
+ function serializeRequestBody(body, numericStringFields) {
163
+ const parsed = encodableSchema.parse(body);
164
+ if (!numericStringFields?.length)
165
+ return JSON.stringify(parsed);
166
+ return JSONStringify(mapTopLevelNumericStringFields(parsed, new Set(numericStringFields)));
167
+ }
168
+ /**
169
+ * Converts selected top-level fields from decimal strings to bigint wire
170
+ * values.
171
+ *
172
+ * @param value - Encodable value to convert.
173
+ * @param numericStringFields - Field names to convert.
174
+ */
175
+ function mapTopLevelNumericStringFields(value, numericStringFields) {
176
+ if (!isPlainObject(value))
177
+ return value;
178
+ return Object.fromEntries(Object.entries(value).map(([key, item]) => [
179
+ key,
180
+ numericStringFields.has(key) &&
181
+ typeof item === "string" &&
182
+ /^-?\d+$/.test(item)
183
+ ? BigInt(item)
184
+ : item,
185
+ ]));
186
+ }
187
+ /**
188
+ * Converts losslessly parsed bigint values to encodable decimal strings.
189
+ *
190
+ * @param value - Parsed JSON value.
191
+ */
192
+ function normalizeBigInts(value) {
193
+ if (typeof value === "bigint")
194
+ return value.toString();
195
+ if (Array.isArray(value))
196
+ return value.map(normalizeBigInts);
197
+ if (typeof value !== "object" ||
198
+ value === null ||
199
+ Object.getPrototypeOf(value) !== Object.prototype) {
200
+ return value;
201
+ }
202
+ return Object.fromEntries(Object.entries(value).map(([key, item]) => [key, normalizeBigInts(item)]));
203
+ }
155
204
  /**
156
205
  * Parses a finite numeric response header.
157
206
  *
@@ -286,7 +286,7 @@ export declare const AXIOM_MONITOR_SCHEMA: z.ZodObject<{
286
286
  Threshold: "Threshold";
287
287
  }>;
288
288
  }, z.core.$strip>;
289
- export declare const AXIOM_MONITOR_WITH_ID_SCHEMA: z.ZodIntersection<z.ZodObject<{
289
+ export declare const AXIOM_MONITOR_WITH_ID_SCHEMA: z.ZodPreprocess<z.ZodIntersection<z.ZodObject<{
290
290
  alertOnNoData: z.ZodOptional<z.ZodBoolean>;
291
291
  aplQuery: z.ZodOptional<z.ZodString>;
292
292
  columnName: z.ZodOptional<z.ZodString>;
@@ -325,7 +325,7 @@ export declare const AXIOM_MONITOR_WITH_ID_SCHEMA: z.ZodIntersection<z.ZodObject
325
325
  createdBy: z.ZodOptional<z.ZodString>;
326
326
  id: z.ZodString;
327
327
  updatedAt: z.ZodOptional<z.ZodString>;
328
- }, z.core.$catchall<z.ZodOptional<z.ZodCustom<import("@automate.ax/codec").Encodable, import("@automate.ax/codec").Encodable>>>>>;
328
+ }, z.core.$catchall<z.ZodOptional<z.ZodCustom<import("@automate.ax/codec").Encodable, import("@automate.ax/codec").Encodable>>>>>>;
329
329
  export declare const AXIOM_ALERT_HISTORY_SCHEMA: z.ZodObject<{
330
330
  checkId: z.ZodString;
331
331
  name: z.ZodString;
@@ -540,7 +540,7 @@ export declare const AXIOM_SAVED_QUERY_SCHEMA: z.ZodObject<{
540
540
  }, z.core.$strip>;
541
541
  who: z.ZodString;
542
542
  }, z.core.$strip>;
543
- export declare const AXIOM_SAVED_QUERY_WITH_ID_SCHEMA: z.ZodObject<{
543
+ export declare const AXIOM_SAVED_QUERY_WITH_ID_SCHEMA: z.ZodPreprocess<z.ZodObject<{
544
544
  dataset: z.ZodOptional<z.ZodString>;
545
545
  kind: z.ZodLiteral<"apl">;
546
546
  metadata: z.ZodRecord<z.ZodString, z.ZodString>;
@@ -599,7 +599,7 @@ export declare const AXIOM_SAVED_QUERY_WITH_ID_SCHEMA: z.ZodObject<{
599
599
  }, z.core.$strip>;
600
600
  who: z.ZodString;
601
601
  id: z.ZodString;
602
- }, z.core.$strip>;
602
+ }, z.core.$strip>>;
603
603
  export declare const AXIOM_DASHBOARD_CHART_SCHEMA: z.ZodDiscriminatedUnion<[z.ZodObject<{
604
604
  type: z.ZodLiteral<"TimeSeries">;
605
605
  query: z.ZodObject<{
@@ -765,6 +765,7 @@ export declare const AXIOM_DASHBOARD_CHART_SCHEMA: z.ZodDiscriminatedUnion<[z.Zo
765
765
  options: z.ZodOptional<z.ZodJSONSchema>;
766
766
  query: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodOptional<z.ZodCustom<import("@automate.ax/codec").Encodable, import("@automate.ax/codec").Encodable>>>>;
767
767
  selectType: z.ZodEnum<{
768
+ apl: "apl";
768
769
  query: "query";
769
770
  list: "list";
770
771
  }>;
@@ -785,6 +786,7 @@ export declare const AXIOM_DASHBOARD_CHART_SCHEMA: z.ZodDiscriminatedUnion<[z.Zo
785
786
  name: z.ZodOptional<z.ZodString>;
786
787
  sectionId: z.ZodOptional<z.ZodUUID>;
787
788
  }, z.core.$catchall<z.ZodOptional<z.ZodCustom<import("@automate.ax/codec").Encodable, import("@automate.ax/codec").Encodable>>>>], "type">;
789
+ export declare const AXIOM_DASHBOARD_VERSION_SCHEMA: z.ZodString;
788
790
  export declare const AXIOM_DASHBOARD_DOCUMENT_SCHEMA: z.ZodObject<{
789
791
  against: z.ZodOptional<z.ZodEnum<{
790
792
  "": "";
@@ -968,6 +970,7 @@ export declare const AXIOM_DASHBOARD_DOCUMENT_SCHEMA: z.ZodObject<{
968
970
  options: z.ZodOptional<z.ZodJSONSchema>;
969
971
  query: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodOptional<z.ZodCustom<import("@automate.ax/codec").Encodable, import("@automate.ax/codec").Encodable>>>>;
970
972
  selectType: z.ZodEnum<{
973
+ apl: "apl";
971
974
  query: "query";
972
975
  list: "list";
973
976
  }>;
@@ -1200,6 +1203,7 @@ export declare const AXIOM_DASHBOARD_RESOURCE_SCHEMA: z.ZodObject<{
1200
1203
  options: z.ZodOptional<z.ZodJSONSchema>;
1201
1204
  query: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodOptional<z.ZodCustom<import("@automate.ax/codec").Encodable, import("@automate.ax/codec").Encodable>>>>;
1202
1205
  selectType: z.ZodEnum<{
1206
+ apl: "apl";
1203
1207
  query: "query";
1204
1208
  list: "list";
1205
1209
  }>;
@@ -1250,7 +1254,7 @@ export declare const AXIOM_DASHBOARD_RESOURCE_SCHEMA: z.ZodObject<{
1250
1254
  uid: z.ZodString;
1251
1255
  updatedAt: z.ZodString;
1252
1256
  updatedBy: z.ZodString;
1253
- version: z.ZodNumber;
1257
+ version: z.ZodString;
1254
1258
  }, z.core.$catchall<z.ZodOptional<z.ZodCustom<import("@automate.ax/codec").Encodable, import("@automate.ax/codec").Encodable>>>>;
1255
1259
  export declare const AXIOM_DASHBOARD_WRITE_SCHEMA: z.ZodObject<{
1256
1260
  dashboard: z.ZodObject<{
@@ -1439,6 +1443,7 @@ export declare const AXIOM_DASHBOARD_WRITE_SCHEMA: z.ZodObject<{
1439
1443
  options: z.ZodOptional<z.ZodJSONSchema>;
1440
1444
  query: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodOptional<z.ZodCustom<import("@automate.ax/codec").Encodable, import("@automate.ax/codec").Encodable>>>>;
1441
1445
  selectType: z.ZodEnum<{
1446
+ apl: "apl";
1442
1447
  query: "query";
1443
1448
  list: "list";
1444
1449
  }>;
@@ -1489,7 +1494,7 @@ export declare const AXIOM_DASHBOARD_WRITE_SCHEMA: z.ZodObject<{
1489
1494
  uid: z.ZodString;
1490
1495
  updatedAt: z.ZodString;
1491
1496
  updatedBy: z.ZodString;
1492
- version: z.ZodNumber;
1497
+ version: z.ZodString;
1493
1498
  }, z.core.$catchall<z.ZodOptional<z.ZodCustom<import("@automate.ax/codec").Encodable, import("@automate.ax/codec").Encodable>>>>;
1494
1499
  overwritten: z.ZodOptional<z.ZodBoolean>;
1495
1500
  status: z.ZodEnum<{
@@ -246,14 +246,19 @@ export const AXIOM_MONITOR_SCHEMA = z
246
246
  .refine(({ aplQuery, mplQuery }) => Boolean(aplQuery) !== Boolean(mplQuery), {
247
247
  message: "Provide exactly one of aplQuery or mplQuery.",
248
248
  });
249
- export const AXIOM_MONITOR_WITH_ID_SCHEMA = AXIOM_MONITOR_SCHEMA.and(z
249
+ export const AXIOM_MONITOR_WITH_ID_SCHEMA = z.preprocess((value) => typeof value === "object" &&
250
+ value !== null &&
251
+ "notifierIds" in value &&
252
+ value.notifierIds === null
253
+ ? { ...value, notifierIds: [] }
254
+ : value, AXIOM_MONITOR_SCHEMA.and(z
250
255
  .object({
251
256
  createdAt: z.string().optional(),
252
257
  createdBy: z.string().optional(),
253
258
  id: AXIOM_ID_SCHEMA,
254
259
  updatedAt: z.string().optional(),
255
260
  })
256
- .catchall(encodableSchema));
261
+ .catchall(encodableSchema)));
257
262
  export const AXIOM_ALERT_HISTORY_SCHEMA = z.object({
258
263
  checkId: AXIOM_ID_SCHEMA,
259
264
  name: z.string(),
@@ -317,9 +322,27 @@ export const AXIOM_SAVED_QUERY_SCHEMA = z.object({
317
322
  query: AXIOM_APL_REQUEST_SCHEMA,
318
323
  who: z.string(),
319
324
  });
320
- export const AXIOM_SAVED_QUERY_WITH_ID_SCHEMA = AXIOM_SAVED_QUERY_SCHEMA.extend({
321
- id: AXIOM_ID_SCHEMA,
322
- });
325
+ export const AXIOM_SAVED_QUERY_WITH_ID_SCHEMA = z.preprocess((value) => {
326
+ if (typeof value !== "object" ||
327
+ value === null ||
328
+ !("query" in value) ||
329
+ typeof value.query !== "object" ||
330
+ value.query === null) {
331
+ return value;
332
+ }
333
+ return {
334
+ ...value,
335
+ query: {
336
+ ...value.query,
337
+ ...("defaultOrder" in value.query && value.query.defaultOrder === null
338
+ ? { defaultOrder: [] }
339
+ : {}),
340
+ ...("libraries" in value.query && value.query.libraries === null
341
+ ? { libraries: [] }
342
+ : {}),
343
+ },
344
+ };
345
+ }, AXIOM_SAVED_QUERY_SCHEMA.extend({ id: AXIOM_ID_SCHEMA }));
323
346
  const AXIOM_CHART_QUERY_SCHEMA = z
324
347
  .object({
325
348
  apl: z.string().trim().min(1).optional(),
@@ -368,7 +391,7 @@ const AXIOM_SMART_FILTER_SCHEMA = z.discriminatedUnion("type", [
368
391
  ...AXIOM_SMART_FILTER_BASE_FIELDS,
369
392
  options: z.json().optional(),
370
393
  query: z.record(z.string(), encodableSchema).optional(),
371
- selectType: z.enum(["list", "query"]),
394
+ selectType: z.enum(["apl", "list", "query"]),
372
395
  type: z.literal("select"),
373
396
  })
374
397
  .catchall(encodableSchema),
@@ -490,6 +513,15 @@ export const AXIOM_DASHBOARD_CHART_SCHEMA = z.discriminatedUnion("type", [
490
513
  })
491
514
  .catchall(encodableSchema),
492
515
  ]);
516
+ const AXIOM_DASHBOARD_TIME_SCHEMA = z
517
+ .string()
518
+ .min(1)
519
+ .max(100)
520
+ .refine((value) => value === "qr-now" ||
521
+ /^qr-now-[1-9]\d*[a-z]+$/i.test(value) ||
522
+ /^\d+$/.test(value) ||
523
+ Number.isFinite(Date.parse(value)), { message: "Use qr-now, qr-now-{duration}, a timestamp, or a date." });
524
+ export const AXIOM_DASHBOARD_VERSION_SCHEMA = z.string().regex(/^[1-9]\d*$/);
493
525
  export const AXIOM_DASHBOARD_DOCUMENT_SCHEMA = z.object({
494
526
  against: z
495
527
  .enum([
@@ -539,8 +571,8 @@ export const AXIOM_DASHBOARD_DOCUMENT_SCHEMA = z.object({
539
571
  })
540
572
  .array()
541
573
  .optional(),
542
- timeWindowEnd: z.string().min(1).max(100),
543
- timeWindowStart: z.string().min(1).max(100),
574
+ timeWindowEnd: AXIOM_DASHBOARD_TIME_SCHEMA,
575
+ timeWindowStart: AXIOM_DASHBOARD_TIME_SCHEMA,
544
576
  uid: AXIOM_ID_SCHEMA.optional(),
545
577
  });
546
578
  export const AXIOM_DASHBOARD_RESOURCE_SCHEMA = z
@@ -552,7 +584,7 @@ export const AXIOM_DASHBOARD_RESOURCE_SCHEMA = z
552
584
  uid: AXIOM_ID_SCHEMA,
553
585
  updatedAt: z.string(),
554
586
  updatedBy: z.string(),
555
- version: z.number().int().positive(),
587
+ version: AXIOM_DASHBOARD_VERSION_SCHEMA,
556
588
  })
557
589
  .catchall(encodableSchema);
558
590
  export const AXIOM_DASHBOARD_WRITE_SCHEMA = z.object({
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@automate.ax/integration-contracts",
3
- "version": "0.130.3",
3
+ "version": "0.130.4",
4
4
  "description": "Shared integration payload contracts and provider primitives for Automate.ax.",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -59,7 +59,7 @@
59
59
  }
60
60
  },
61
61
  "dependencies": {
62
- "@automate.ax/codec": "0.130.3",
62
+ "@automate.ax/codec": "0.130.4",
63
63
  "@cfworker/json-schema": "^4.1.1",
64
64
  "@googleapis/calendar": "^15.0.0",
65
65
  "@googleapis/forms": "^6.0.1",
@@ -70,6 +70,7 @@
70
70
  "@octokit/rest": "^22.0.1",
71
71
  "convex": "^1.45.0",
72
72
  "html-to-text": "^10.0.0",
73
+ "json-with-bigint": "^3.5.10",
73
74
  "nodemailer": "^9.0.3",
74
75
  "postal-mime": "^2.7.5",
75
76
  "stripe": "^22.1.0",
package/src/axiom/api.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  import { encodableSchema, type Encodable } from "@automate.ax/codec"
2
+ import { JSONParse, JSONStringify } from "json-with-bigint"
2
3
  import * as z from "zod"
3
4
 
4
5
  const AXIOM_API_ORIGIN = "https://api.axiom.co"
@@ -14,6 +15,7 @@ export interface AxiomRequestOptions<TSchema extends z.ZodType> {
14
15
  body?: Encodable
15
16
  headers?: Record<string, string>
16
17
  method?: "DELETE" | "GET" | "PATCH" | "POST" | "PUT"
18
+ numericStringFields?: readonly string[]
17
19
  query?: Record<string, boolean | number | string | undefined>
18
20
  responseSchema: TSchema
19
21
  version?: "v1" | "v2"
@@ -111,7 +113,7 @@ export function getAxiomApi(
111
113
  body:
112
114
  options.body === undefined
113
115
  ? undefined
114
- : JSON.stringify(encodableSchema.parse(options.body)),
116
+ : serializeRequestBody(options.body, options.numericStringFields),
115
117
  headers: {
116
118
  Accept: "application/json",
117
119
  Authorization: `Bearer ${apiKey}`,
@@ -205,12 +207,73 @@ function confinedUrl(origin: string, version: "v1" | "v2", path: string) {
205
207
  function parseResponse(text: string): Encodable {
206
208
  if (!text) return null
207
209
  try {
208
- return encodableSchema.parse(JSON.parse(text))
210
+ return encodableSchema.parse(normalizeBigInts(JSONParse(text) as unknown))
209
211
  } catch {
210
212
  return { response: text }
211
213
  }
212
214
  }
213
215
 
216
+ /**
217
+ * Serializes selected decimal strings as lossless JSON integers.
218
+ *
219
+ * @param body - Encodable request body.
220
+ * @param numericStringFields - Field names to emit as JSON integers.
221
+ */
222
+ function serializeRequestBody(
223
+ body: Encodable,
224
+ numericStringFields: readonly string[] | undefined,
225
+ ) {
226
+ const parsed = encodableSchema.parse(body)
227
+ if (!numericStringFields?.length) return JSON.stringify(parsed)
228
+ return JSONStringify(
229
+ mapTopLevelNumericStringFields(parsed, new Set(numericStringFields)),
230
+ )
231
+ }
232
+
233
+ /**
234
+ * Converts selected top-level fields from decimal strings to bigint wire
235
+ * values.
236
+ *
237
+ * @param value - Encodable value to convert.
238
+ * @param numericStringFields - Field names to convert.
239
+ */
240
+ function mapTopLevelNumericStringFields(
241
+ value: Encodable,
242
+ numericStringFields: ReadonlySet<string>,
243
+ ): unknown {
244
+ if (!isPlainObject(value)) return value
245
+ return Object.fromEntries(
246
+ Object.entries(value).map(([key, item]) => [
247
+ key,
248
+ numericStringFields.has(key) &&
249
+ typeof item === "string" &&
250
+ /^-?\d+$/.test(item)
251
+ ? BigInt(item)
252
+ : item,
253
+ ]),
254
+ )
255
+ }
256
+
257
+ /**
258
+ * Converts losslessly parsed bigint values to encodable decimal strings.
259
+ *
260
+ * @param value - Parsed JSON value.
261
+ */
262
+ function normalizeBigInts(value: unknown): unknown {
263
+ if (typeof value === "bigint") return value.toString()
264
+ if (Array.isArray(value)) return value.map(normalizeBigInts)
265
+ if (
266
+ typeof value !== "object" ||
267
+ value === null ||
268
+ Object.getPrototypeOf(value) !== Object.prototype
269
+ ) {
270
+ return value
271
+ }
272
+ return Object.fromEntries(
273
+ Object.entries(value).map(([key, item]) => [key, normalizeBigInts(item)]),
274
+ )
275
+ }
276
+
214
277
  /**
215
278
  * Parses a finite numeric response header.
216
279
  *
@@ -267,15 +267,24 @@ export const AXIOM_MONITOR_SCHEMA = z
267
267
  .refine(({ aplQuery, mplQuery }) => Boolean(aplQuery) !== Boolean(mplQuery), {
268
268
  message: "Provide exactly one of aplQuery or mplQuery.",
269
269
  })
270
- export const AXIOM_MONITOR_WITH_ID_SCHEMA = AXIOM_MONITOR_SCHEMA.and(
271
- z
272
- .object({
273
- createdAt: z.string().optional(),
274
- createdBy: z.string().optional(),
275
- id: AXIOM_ID_SCHEMA,
276
- updatedAt: z.string().optional(),
277
- })
278
- .catchall(encodableSchema),
270
+ export const AXIOM_MONITOR_WITH_ID_SCHEMA = z.preprocess(
271
+ (value) =>
272
+ typeof value === "object" &&
273
+ value !== null &&
274
+ "notifierIds" in value &&
275
+ value.notifierIds === null
276
+ ? { ...value, notifierIds: [] }
277
+ : value,
278
+ AXIOM_MONITOR_SCHEMA.and(
279
+ z
280
+ .object({
281
+ createdAt: z.string().optional(),
282
+ createdBy: z.string().optional(),
283
+ id: AXIOM_ID_SCHEMA,
284
+ updatedAt: z.string().optional(),
285
+ })
286
+ .catchall(encodableSchema),
287
+ ),
279
288
  )
280
289
 
281
290
  export const AXIOM_ALERT_HISTORY_SCHEMA = z.object({
@@ -344,10 +353,31 @@ export const AXIOM_SAVED_QUERY_SCHEMA = z.object({
344
353
  query: AXIOM_APL_REQUEST_SCHEMA,
345
354
  who: z.string(),
346
355
  })
347
- export const AXIOM_SAVED_QUERY_WITH_ID_SCHEMA = AXIOM_SAVED_QUERY_SCHEMA.extend(
348
- {
349
- id: AXIOM_ID_SCHEMA,
356
+ export const AXIOM_SAVED_QUERY_WITH_ID_SCHEMA = z.preprocess(
357
+ (value) => {
358
+ if (
359
+ typeof value !== "object" ||
360
+ value === null ||
361
+ !("query" in value) ||
362
+ typeof value.query !== "object" ||
363
+ value.query === null
364
+ ) {
365
+ return value
366
+ }
367
+ return {
368
+ ...value,
369
+ query: {
370
+ ...value.query,
371
+ ...("defaultOrder" in value.query && value.query.defaultOrder === null
372
+ ? { defaultOrder: [] }
373
+ : {}),
374
+ ...("libraries" in value.query && value.query.libraries === null
375
+ ? { libraries: [] }
376
+ : {}),
377
+ },
378
+ }
350
379
  },
380
+ AXIOM_SAVED_QUERY_SCHEMA.extend({ id: AXIOM_ID_SCHEMA }),
351
381
  )
352
382
 
353
383
  const AXIOM_CHART_QUERY_SCHEMA = z
@@ -398,7 +428,7 @@ const AXIOM_SMART_FILTER_SCHEMA = z.discriminatedUnion("type", [
398
428
  ...AXIOM_SMART_FILTER_BASE_FIELDS,
399
429
  options: z.json().optional(),
400
430
  query: z.record(z.string(), encodableSchema).optional(),
401
- selectType: z.enum(["list", "query"]),
431
+ selectType: z.enum(["apl", "list", "query"]),
402
432
  type: z.literal("select"),
403
433
  })
404
434
  .catchall(encodableSchema),
@@ -521,6 +551,19 @@ export const AXIOM_DASHBOARD_CHART_SCHEMA = z.discriminatedUnion("type", [
521
551
  })
522
552
  .catchall(encodableSchema),
523
553
  ])
554
+ const AXIOM_DASHBOARD_TIME_SCHEMA = z
555
+ .string()
556
+ .min(1)
557
+ .max(100)
558
+ .refine(
559
+ (value) =>
560
+ value === "qr-now" ||
561
+ /^qr-now-[1-9]\d*[a-z]+$/i.test(value) ||
562
+ /^\d+$/.test(value) ||
563
+ Number.isFinite(Date.parse(value)),
564
+ { message: "Use qr-now, qr-now-{duration}, a timestamp, or a date." },
565
+ )
566
+ export const AXIOM_DASHBOARD_VERSION_SCHEMA = z.string().regex(/^[1-9]\d*$/)
524
567
  export const AXIOM_DASHBOARD_DOCUMENT_SCHEMA = z.object({
525
568
  against: z
526
569
  .enum([
@@ -570,8 +613,8 @@ export const AXIOM_DASHBOARD_DOCUMENT_SCHEMA = z.object({
570
613
  })
571
614
  .array()
572
615
  .optional(),
573
- timeWindowEnd: z.string().min(1).max(100),
574
- timeWindowStart: z.string().min(1).max(100),
616
+ timeWindowEnd: AXIOM_DASHBOARD_TIME_SCHEMA,
617
+ timeWindowStart: AXIOM_DASHBOARD_TIME_SCHEMA,
575
618
  uid: AXIOM_ID_SCHEMA.optional(),
576
619
  })
577
620
 
@@ -584,7 +627,7 @@ export const AXIOM_DASHBOARD_RESOURCE_SCHEMA = z
584
627
  uid: AXIOM_ID_SCHEMA,
585
628
  updatedAt: z.string(),
586
629
  updatedBy: z.string(),
587
- version: z.number().int().positive(),
630
+ version: AXIOM_DASHBOARD_VERSION_SCHEMA,
588
631
  })
589
632
  .catchall(encodableSchema)
590
633
  export const AXIOM_DASHBOARD_WRITE_SCHEMA = z.object({