@actuarial-ts/interchange 0.6.0 → 0.6.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.
Files changed (39) hide show
  1. package/README.md +3 -3
  2. package/dist/convert/diagnosticDefinition.d.ts +6 -5
  3. package/dist/convert/diagnosticDefinition.d.ts.map +1 -1
  4. package/dist/convert/diagnosticDefinition.js +43 -8
  5. package/dist/convert/diagnosticDefinition.js.map +1 -1
  6. package/dist/envelope.d.ts +4 -4
  7. package/dist/envelope.d.ts.map +1 -1
  8. package/dist/envelope.js +10 -6
  9. package/dist/envelope.js.map +1 -1
  10. package/dist/json.d.ts +5 -0
  11. package/dist/json.d.ts.map +1 -0
  12. package/dist/json.js +13 -0
  13. package/dist/json.js.map +1 -0
  14. package/dist/parse.d.ts.map +1 -1
  15. package/dist/parse.js +7 -2
  16. package/dist/parse.js.map +1 -1
  17. package/dist/schemas/crosscheck.d.ts +6 -6
  18. package/dist/schemas/diagnosticDefinition.d.ts +121 -49
  19. package/dist/schemas/diagnosticDefinition.d.ts.map +1 -1
  20. package/dist/schemas/diagnosticDefinition.js +6 -5
  21. package/dist/schemas/diagnosticDefinition.js.map +1 -1
  22. package/dist/schemas/record.d.ts +5 -0
  23. package/dist/schemas/record.d.ts.map +1 -0
  24. package/dist/schemas/record.js +9 -0
  25. package/dist/schemas/record.js.map +1 -0
  26. package/dist/schemas/result.d.ts +12 -12
  27. package/dist/schemas/selection.d.ts +6 -6
  28. package/dist/schemas/triangle.d.ts +89 -89
  29. package/dist/schemas/triangle.d.ts.map +1 -1
  30. package/dist/schemas/triangle.js +20 -5
  31. package/dist/schemas/triangle.js.map +1 -1
  32. package/package.json +3 -2
  33. package/src/convert/diagnosticDefinition.ts +89 -14
  34. package/src/envelope.ts +25 -8
  35. package/src/json.ts +17 -0
  36. package/src/parse.ts +7 -2
  37. package/src/schemas/diagnosticDefinition.ts +10 -9
  38. package/src/schemas/record.ts +16 -0
  39. package/src/schemas/triangle.ts +23 -5
@@ -1 +1 @@
1
- {"version":3,"file":"triangle.js","sourceRoot":"","sources":["../../src/schemas/triangle.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"triangle.js","sourceRoot":"","sources":["../../src/schemas/triangle.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@actuarial-ts/interchange",
3
- "version": "0.6.0",
3
+ "version": "0.6.1",
4
4
  "description": "Language-neutral actuarial-interchange documents for triangles, selections, results, studies, bundles, crosschecks, and portable diagnostic definitions across TypeScript, Python, and R.",
5
5
  "license": "Apache-2.0",
6
6
  "type": "module",
@@ -50,10 +50,11 @@
50
50
  "test:watch": "vitest",
51
51
  "typecheck": "tsc --noEmit",
52
52
  "prepack": "tsc -p tsconfig.build.json",
53
+ "prepublishOnly": "node ../../tools/release/verify-release-attestation.mjs @actuarial-ts/interchange",
53
54
  "emit-schema": "npm run build && node --experimental-strip-types scripts/emit-schema.ts"
54
55
  },
55
56
  "dependencies": {
56
- "@actuarial-ts/core": "^0.6.0",
57
+ "@actuarial-ts/core": "^0.6.1",
57
58
  "zod": "^3.25.76"
58
59
  },
59
60
  "devDependencies": {
@@ -3,11 +3,21 @@ import {
3
3
  assertCompiledDiagnosticDefinition,
4
4
  canonicalJson,
5
5
  compileDiagnosticDefinition,
6
+ isDiagnosticPlainRecord,
6
7
  type CompiledDiagnosticDefinition,
7
8
  } from "@actuarial-ts/core";
8
- import { DEFAULT_GENERATOR, INTERCHANGE_SPEC_VERSION, stampIntegrity, type GeneratorStamp } from "../envelope.js";
9
+ import {
10
+ DEFAULT_GENERATOR,
11
+ INTERCHANGE_SPEC_VERSION,
12
+ stampIntegrity,
13
+ type GeneratorStamp,
14
+ } from "../envelope.js";
9
15
  import { parseDocument, type ParseDocumentOptions } from "../parse.js";
10
- import type { DiagnosticDefinitionDoc } from "../schemas/diagnosticDefinition.js";
16
+ import { snapshotInterchangeJson } from "../json.js";
17
+ import {
18
+ diagnosticDefinitionDocSchema,
19
+ type DiagnosticDefinitionDoc,
20
+ } from "../schemas/diagnosticDefinition.js";
11
21
 
12
22
  export interface DiagnosticDefinitionToDocOptions {
13
23
  createdAt: string;
@@ -15,17 +25,39 @@ export interface DiagnosticDefinitionToDocOptions {
15
25
  extensions?: Record<string, unknown>;
16
26
  }
17
27
 
28
+ export interface DocToDiagnosticDefinitionResult {
29
+ readonly definition: CompiledDiagnosticDefinition;
30
+ readonly warnings: readonly string[];
31
+ }
32
+
18
33
  export function diagnosticDefinitionToDoc(
19
34
  compiled: CompiledDiagnosticDefinition,
20
35
  options: DiagnosticDefinitionToDocOptions,
21
36
  ): DiagnosticDefinitionDoc {
22
37
  assertCompiledDiagnosticDefinition(compiled);
23
- return stampIntegrity<DiagnosticDefinitionDoc>({
38
+ if (!isDiagnosticPlainRecord(options))
39
+ throw new ReservingError(
40
+ "BAD_INTERCHANGE",
41
+ "Diagnostic document options must be a plain object at $.options",
42
+ );
43
+ for (const key of Object.keys(options))
44
+ if (!["createdAt", "generator", "extensions"].includes(key))
45
+ throw new ReservingError(
46
+ "BAD_INTERCHANGE",
47
+ `Unknown diagnostic document option at $.options.${key}`,
48
+ );
49
+ const ownedOptions = snapshotInterchangeJson(options);
50
+ const candidate = stampIntegrity<DiagnosticDefinitionDoc>({
24
51
  interchangeVersion: INTERCHANGE_SPEC_VERSION,
25
52
  kind: "diagnostic-definition",
26
- generator: options.generator ?? DEFAULT_GENERATOR,
27
- createdAt: options.createdAt,
28
- ...(options.extensions === undefined ? {} : { extensions: options.extensions }),
53
+ generator:
54
+ ownedOptions.generator === undefined
55
+ ? DEFAULT_GENERATOR
56
+ : ownedOptions.generator,
57
+ createdAt: ownedOptions.createdAt,
58
+ ...(ownedOptions.extensions === undefined
59
+ ? {}
60
+ : { extensions: ownedOptions.extensions }),
29
61
  diagnosticDefinition: {
30
62
  definition: compiled.definition,
31
63
  identities: {
@@ -36,26 +68,63 @@ export function diagnosticDefinitionToDoc(
36
68
  },
37
69
  },
38
70
  });
71
+ const parsed = diagnosticDefinitionDocSchema.safeParse(candidate);
72
+ if (!parsed.success) {
73
+ const issue = parsed.error.issues[0];
74
+ const path = issue?.path.length ? ` at $.${issue.path.join(".")}` : "";
75
+ throw new ReservingError(
76
+ "BAD_INTERCHANGE",
77
+ `Invalid diagnostic-definition document${path}: ${issue?.message ?? "schema validation failed"}`,
78
+ );
79
+ }
80
+ return deepFreeze(snapshotInterchangeJson(candidate));
81
+ }
82
+
83
+ function deepFreeze<T>(value: T): T {
84
+ if (value !== null && typeof value === "object" && !Object.isFrozen(value)) {
85
+ for (const child of Object.values(value as Record<string, unknown>))
86
+ deepFreeze(child);
87
+ Object.freeze(value);
88
+ }
89
+ return value;
39
90
  }
40
91
 
41
- function sameRecord(left: Readonly<Record<string, string>>, right: Readonly<Record<string, string>>): boolean {
92
+ function sameRecord(
93
+ left: Readonly<Record<string, string>>,
94
+ right: Readonly<Record<string, string>>,
95
+ ): boolean {
42
96
  const leftKeys = Object.keys(left).sort();
43
97
  const rightKeys = Object.keys(right).sort();
44
- return leftKeys.length === rightKeys.length && leftKeys.every((key, index) =>
45
- key === rightKeys[index] && left[key] === right[key],
98
+ return (
99
+ leftKeys.length === rightKeys.length &&
100
+ leftKeys.every(
101
+ (key, index) => key === rightKeys[index] && left[key] === right[key],
102
+ )
46
103
  );
47
104
  }
48
105
 
49
106
  export function docToDiagnosticDefinition(
50
107
  value: unknown,
51
108
  options?: ParseDocumentOptions,
52
- ): { definition: CompiledDiagnosticDefinition; warnings: readonly string[] } {
109
+ ): DocToDiagnosticDefinitionResult {
53
110
  const parsed = parseDocument(value, options);
54
111
  if (parsed.doc.kind !== "diagnostic-definition") {
55
- throw new ReservingError("BAD_INTERCHANGE", `Expected kind "diagnostic-definition"; got kind "${parsed.doc.kind}"`);
112
+ throw new ReservingError(
113
+ "BAD_INTERCHANGE",
114
+ `Expected kind "diagnostic-definition"; got kind "${parsed.doc.kind}"`,
115
+ );
56
116
  }
57
117
  const body = parsed.doc.diagnosticDefinition;
58
- const compiled = compileDiagnosticDefinition(body.definition);
118
+ let compiled: CompiledDiagnosticDefinition;
119
+ try {
120
+ compiled = compileDiagnosticDefinition(body.definition);
121
+ } catch (error) {
122
+ const message = error instanceof Error ? error.message : String(error);
123
+ throw new ReservingError(
124
+ "BAD_INTERCHANGE",
125
+ `Diagnostic definition contains unsupported executable vocabulary: ${message}`,
126
+ );
127
+ }
59
128
  if (canonicalJson(body.definition) !== canonicalJson(compiled.definition)) {
60
129
  throw new ReservingError(
61
130
  "BAD_INTERCHANGE",
@@ -67,9 +136,15 @@ export function docToDiagnosticDefinition(
67
136
  identities.algorithm !== "fnv1a64-jcs-v1" ||
68
137
  identities.definition !== compiled.definitionIntegrity ||
69
138
  !sameRecord(identities.formulaById, compiled.formulaFingerprints) ||
70
- !sameRecord(identities.calculationByInstanceId, compiled.calculationFingerprints)
139
+ !sameRecord(
140
+ identities.calculationByInstanceId,
141
+ compiled.calculationFingerprints,
142
+ )
71
143
  ) {
72
- throw new ReservingError("BAD_INTERCHANGE", "Diagnostic definition identities do not match the compiled semantic definition");
144
+ throw new ReservingError(
145
+ "BAD_INTERCHANGE",
146
+ "Diagnostic definition identities do not match the compiled semantic definition",
147
+ );
73
148
  }
74
149
  return { definition: compiled, warnings: parsed.warnings };
75
150
  }
package/src/envelope.ts CHANGED
@@ -1,5 +1,11 @@
1
- import { ReservingError, canonicalJson, fnv1a64 } from "@actuarial-ts/core";
1
+ import {
2
+ ReservingError,
3
+ canonicalJson,
4
+ fnv1a64,
5
+ isRealIsoDate,
6
+ } from "@actuarial-ts/core";
2
7
  import { z } from "zod";
8
+ import { recordSchema } from "./schemas/record.js";
3
9
 
4
10
  /**
5
11
  * The interchange document envelope (spec 3.1 / 3.5).
@@ -37,7 +43,7 @@ export const INTERCHANGE_SPEC_MAJOR = 1;
37
43
  * This package's version, stamped into `generator` by default. A sync test
38
44
  * asserts it matches package.json so it cannot silently drift.
39
45
  */
40
- export const INTERCHANGE_PACKAGE_VERSION = "0.6.0";
46
+ export const INTERCHANGE_PACKAGE_VERSION = "0.6.1";
41
47
 
42
48
  export interface GeneratorStamp {
43
49
  name: string;
@@ -45,10 +51,10 @@ export interface GeneratorStamp {
45
51
  }
46
52
 
47
53
  /** Default `generator` stamp for documents authored by this package. */
48
- export const DEFAULT_GENERATOR: GeneratorStamp = {
54
+ export const DEFAULT_GENERATOR: Readonly<GeneratorStamp> = Object.freeze({
49
55
  name: "@actuarial-ts/interchange",
50
56
  version: INTERCHANGE_PACKAGE_VERSION,
51
- };
57
+ });
52
58
 
53
59
  export const DOCUMENT_KINDS = [
54
60
  "triangle",
@@ -97,8 +103,14 @@ export function envelopeShape<K extends DocumentKind>(kind: K) {
97
103
  interchangeVersion: z.string().regex(/^\d+\.\d+\.\d+$/),
98
104
  kind: z.literal(kind),
99
105
  generator: generatorSchema,
100
- createdAt: z.string().datetime({ offset: true }),
101
- extensions: z.record(z.unknown()).optional(),
106
+ createdAt: z
107
+ .string()
108
+ .datetime({ offset: true })
109
+ .refine(
110
+ (value) => isRealIsoDate(value.slice(0, 10)),
111
+ "expected a real Gregorian timestamp",
112
+ ),
113
+ extensions: recordSchema(z.unknown()).optional(),
102
114
  integrity: integritySchema,
103
115
  };
104
116
  }
@@ -162,7 +174,8 @@ export interface IntegrityCheck {
162
174
  /** Recomputes the tag from the semantic body and compares to the stated one. */
163
175
  export function verifyIntegrity(doc: DocumentLike): IntegrityCheck {
164
176
  const expected = computeIntegrity(doc);
165
- const actual = typeof doc["integrity"] === "string" ? (doc["integrity"] as string) : null;
177
+ const actual =
178
+ typeof doc["integrity"] === "string" ? (doc["integrity"] as string) : null;
166
179
  return { ok: actual === expected, expected, actual };
167
180
  }
168
181
 
@@ -184,7 +197,11 @@ export function acceptVersion(version: unknown): ParsedVersion {
184
197
  `interchangeVersion must be a MAJOR.MINOR.PATCH string; got ${JSON.stringify(version)}`,
185
198
  );
186
199
  }
187
- const [major, minor, patch] = version.split(".").map(Number) as [number, number, number];
200
+ const [major, minor, patch] = version.split(".").map(Number) as [
201
+ number,
202
+ number,
203
+ number,
204
+ ];
188
205
  if (major !== INTERCHANGE_SPEC_MAJOR) {
189
206
  throw new ReservingError(
190
207
  "UNSUPPORTED_VERSION",
package/src/json.ts ADDED
@@ -0,0 +1,17 @@
1
+ import { ReservingError, canonicalJson } from "@actuarial-ts/core";
2
+
3
+ /** Own the complete JSON document without dropping forward-compatible keys.
4
+ * Use the generic interchange JSON contract, not the stricter diagnostic
5
+ * identifier profile: opaque JSON strings may contain escaped control codes. */
6
+ export function snapshotInterchangeJson<T>(value: T): T {
7
+ try {
8
+ return JSON.parse(canonicalJson(value)) as T;
9
+ } catch (error) {
10
+ throw new ReservingError(
11
+ "BAD_INTERCHANGE",
12
+ `An interchange document must contain only JSON values: ${
13
+ error instanceof Error ? error.message : String(error)
14
+ }`,
15
+ );
16
+ }
17
+ }
package/src/parse.ts CHANGED
@@ -14,6 +14,7 @@ import type { StudyDoc } from "./schemas/study.js";
14
14
  import type { BundleDoc } from "./schemas/bundle.js";
15
15
  import type { CrosscheckReportDoc } from "./schemas/crosscheck.js";
16
16
  import type { DiagnosticDefinitionDoc } from "./schemas/diagnosticDefinition.js";
17
+ import { snapshotInterchangeJson } from "./json.js";
17
18
 
18
19
  /**
19
20
  * `parseDocument` (spec 4.1): version-checked, schema-validated,
@@ -124,14 +125,18 @@ export function parseDocument(
124
125
  );
125
126
  }
126
127
 
127
- const parsed = schema.safeParse(raw);
128
+ const snapshot = snapshotInterchangeJson(raw);
129
+ const parsed = schema.safeParse(snapshot);
128
130
  if (!parsed.success) {
129
131
  throw new ReservingError(
130
132
  "BAD_INTERCHANGE",
131
133
  `Document of kind "${String(kind)}" failed schema validation: ${formatZodError(parsed.error)}`,
132
134
  );
133
135
  }
134
- const doc = parsed.data as InterchangeDocument;
136
+ // These wire schemas validate only: no defaults, coercions, or semantic
137
+ // transforms. Keep the owned input snapshot because Zod 3's passthrough
138
+ // object assembler otherwise drops unknown own `__proto__` properties.
139
+ const doc = snapshot as InterchangeDocument;
135
140
 
136
141
  const warnings: string[] = [];
137
142
  const integrity = verifyIntegrity(doc);
@@ -1,11 +1,12 @@
1
1
  import type { NormalizedDiagnosticDefinitionIdentity } from "@actuarial-ts/core";
2
2
  import { z } from "zod";
3
3
  import { envelopeShape, type GeneratorStamp } from "../envelope.js";
4
+ import { recordSchema } from "./record.js";
4
5
 
5
6
  const token = z.string().min(1);
6
7
  const finite = z.number().finite();
7
8
  const nullableToken = token.nullable();
8
- const attributes = z.record(z.union([z.string(), finite, z.boolean(), z.null()]));
9
+ const attributes = recordSchema(z.union([z.string(), finite, z.boolean(), z.null()]));
9
10
  const tolerance = z.object({ absolute: finite.nonnegative(), relative: finite.nonnegative() }).passthrough();
10
11
 
11
12
  export const diagnosticMeasureExpressionSchema: z.ZodTypeAny = z.lazy(() =>
@@ -122,28 +123,28 @@ export const normalizedDiagnosticDefinitionSchema = z.object({
122
123
  derivedMeasures: z.array(z.object({ id: token, outputMeasureId: token, expression: diagnosticClaimExpressionSchema }).passthrough()),
123
124
  formulas: z.array(z.object({
124
125
  id: token, version: token,
125
- roles: z.record(z.object({ kind: z.enum(["count", "amount", "exposure"]), compatibilityGroup: nullableToken, developmentSemantics: z.enum(["cumulative", "incremental", "point-in-time", "unknown"]).nullable() }).passthrough()),
126
+ roles: recordSchema(z.object({ kind: z.enum(["count", "amount", "exposure"]), compatibilityGroup: nullableToken, developmentSemantics: z.enum(["cumulative", "incremental", "point-in-time", "unknown"]).nullable() }).passthrough()),
126
127
  numerator: diagnosticRoleExpressionSchema, denominator: diagnosticRoleExpressionSchema,
127
128
  denominatorPolicy: z.literal("positive-or-null"),
128
129
  }).passthrough()),
129
130
  instances: z.array(z.object({
130
- id: token, version: token, formulaId: token, bindings: z.record(diagnosticMeasureExpressionSchema),
131
+ id: token, version: token, formulaId: token, bindings: recordSchema(diagnosticMeasureExpressionSchema),
131
132
  presentation: z.object({ displayName: z.string(), description: z.string(), displayUnit: token, scale: finite.positive(), numeratorLabel: z.string(), denominatorLabel: z.string() }).passthrough(),
132
133
  rules: z.array(z.object({ id: token, code: token, message: z.string(), severity: z.enum(["warning", "fail"]), when: z.object({ left: ruleOperand, operator, right: ruleOperand, tolerance }).passthrough() }).passthrough()),
133
134
  }).passthrough()),
134
135
  reviewRules: z.array(reviewRule), periodAxis,
135
136
  }).passthrough();
136
137
 
137
- export interface DiagnosticDefinitionIdentities {
138
+ export interface DiagnosticDefinitionIdentitySet {
138
139
  algorithm: "fnv1a64-jcs-v1";
139
- formulaById: Record<string, string>;
140
- calculationByInstanceId: Record<string, string>;
140
+ formulaById: Readonly<Record<string, string>>;
141
+ calculationByInstanceId: Readonly<Record<string, string>>;
141
142
  definition: string;
142
143
  }
143
144
 
144
145
  export interface DiagnosticDefinitionBody {
145
146
  definition: NormalizedDiagnosticDefinitionIdentity;
146
- identities: DiagnosticDefinitionIdentities;
147
+ identities: DiagnosticDefinitionIdentitySet;
147
148
  }
148
149
 
149
150
  export interface DiagnosticDefinitionDoc {
@@ -161,8 +162,8 @@ const identityTag = z.string().regex(/^fnv1a64-jcs-v1:[0-9a-f]{16}$/);
161
162
  export const diagnosticDefinitionBodySchema: z.ZodType<DiagnosticDefinitionBody> = z.object({
162
163
  definition: normalizedDiagnosticDefinitionSchema as z.ZodType<NormalizedDiagnosticDefinitionIdentity>,
163
164
  identities: z.object({
164
- algorithm: z.literal("fnv1a64-jcs-v1"), formulaById: z.record(identityTag),
165
- calculationByInstanceId: z.record(identityTag), definition: identityTag,
165
+ algorithm: z.literal("fnv1a64-jcs-v1"), formulaById: recordSchema(identityTag),
166
+ calculationByInstanceId: recordSchema(identityTag), definition: identityTag,
166
167
  }).passthrough(),
167
168
  }).passthrough();
168
169
 
@@ -0,0 +1,16 @@
1
+ import { z } from "zod";
2
+
3
+ /** Preserve ordinary own `__proto__` keys that Zod 3 otherwise drops.
4
+ * Every key is reversibly encoded while its value is schema-validated. */
5
+ export function recordSchema<T extends z.ZodTypeAny>(valueSchema: T) {
6
+ return z
7
+ .record(
8
+ z.string().transform((key) => `:${key}`),
9
+ valueSchema,
10
+ )
11
+ .transform((record): Record<string, z.output<T>> =>
12
+ Object.fromEntries(
13
+ Object.entries(record).map(([key, value]) => [key.slice(1), value]),
14
+ ),
15
+ );
16
+ }
@@ -1,3 +1,4 @@
1
+ import { isRealIsoDate } from "@actuarial-ts/core";
1
2
  import { z } from "zod";
2
3
  import { envelopeShape } from "../envelope.js";
3
4
 
@@ -29,7 +30,12 @@ export type CoreMeasure = (typeof CORE_MEASURES)[number];
29
30
 
30
31
  export const measureSchema = z.union([
31
32
  z.enum([...CORE_MEASURES, "earnedPremium"]),
32
- z.string().regex(/^custom:.+$/, 'custom measures must be namespaced as "custom:<label>"'),
33
+ z
34
+ .string()
35
+ .regex(
36
+ /^custom:.+$/,
37
+ 'custom measures must be namespaced as "custom:<label>"',
38
+ ),
33
39
  ]);
34
40
 
35
41
  export type Measure = z.infer<typeof measureSchema>;
@@ -43,7 +49,9 @@ export const originLengthMonthsSchema = z.union([
43
49
 
44
50
  export type OriginLengthMonths = z.infer<typeof originLengthMonthsSchema>;
45
51
 
46
- const isoDateSchema = z.string().regex(/^\d{4}-\d{2}-\d{2}$/, "expected an ISO yyyy-mm-dd date");
52
+ const isoDateSchema = z
53
+ .string()
54
+ .refine(isRealIsoDate, "expected a real ISO yyyy-mm-dd date");
47
55
 
48
56
  export const triangleOriginSchema = z
49
57
  .object({ label: z.string().min(1), start: isoDateSchema })
@@ -51,7 +59,11 @@ export const triangleOriginSchema = z
51
59
 
52
60
  /** Bulk-lane reference (spec 3.3). */
53
61
  export const valuesRefSchema = z
54
- .object({ format: z.literal("arrow"), path: z.string().min(1), sha256: z.string().min(1) })
62
+ .object({
63
+ format: z.literal("arrow"),
64
+ path: z.string().min(1),
65
+ sha256: z.string().min(1),
66
+ })
55
67
  .passthrough();
56
68
 
57
69
  export const triangleBodySchema = z
@@ -73,10 +85,16 @@ export const triangleBodySchema = z
73
85
  .passthrough()
74
86
  .optional(),
75
87
  units: z
76
- .object({ currency: z.string().optional(), scale: z.number().positive().optional() })
88
+ .object({
89
+ currency: z.string().optional(),
90
+ scale: z.number().positive().optional(),
91
+ })
92
+ .passthrough()
93
+ .optional(),
94
+ segment: z
95
+ .object({ labels: z.record(z.string()) })
77
96
  .passthrough()
78
97
  .optional(),
79
- segment: z.object({ labels: z.record(z.string()) }).passthrough().optional(),
80
98
  })
81
99
  .passthrough()
82
100
  .superRefine((body, ctx) => {