@hyperscale0/udl 1.0.0 → 1.0.124
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/CHANGELOG.md +5 -216
- package/LICENSE.md +356 -0
- package/NOTICE.md +8 -0
- package/README.md +14 -106
- package/dist/canonical.d.ts.map +1 -1
- package/dist/canonical.js +1 -29
- package/dist/canonical.js.map +1 -1
- package/dist/diagnostics.d.ts +13 -165
- package/dist/diagnostics.d.ts.map +1 -1
- package/dist/diagnostics.js +33 -157
- package/dist/diagnostics.js.map +1 -1
- package/dist/field-value.d.ts +5 -0
- package/dist/field-value.d.ts.map +1 -0
- package/dist/field-value.js +85 -0
- package/dist/field-value.js.map +1 -0
- package/dist/finance.d.ts +10 -53
- package/dist/finance.d.ts.map +1 -1
- package/dist/finance.js +252 -536
- package/dist/finance.js.map +1 -1
- package/dist/index.d.ts +9 -13
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +9 -9
- package/dist/index.js.map +1 -1
- package/dist/json.d.ts +2 -0
- package/dist/json.d.ts.map +1 -0
- package/dist/json.js +30 -0
- package/dist/json.js.map +1 -0
- package/dist/limits.d.ts +3 -28
- package/dist/limits.d.ts.map +1 -1
- package/dist/limits.js +5 -31
- package/dist/limits.js.map +1 -1
- package/dist/object-contract.d.ts +140 -0
- package/dist/object-contract.d.ts.map +1 -0
- package/dist/object-contract.js +314 -0
- package/dist/object-contract.js.map +1 -0
- package/dist/object-semantics-schema.d.ts +5710 -0
- package/dist/object-semantics-schema.d.ts.map +1 -0
- package/dist/object-semantics-schema.js +119 -0
- package/dist/object-semantics-schema.js.map +1 -0
- package/dist/object-semantics.d.ts +6 -0
- package/dist/object-semantics.d.ts.map +1 -0
- package/dist/object-semantics.js +279 -0
- package/dist/object-semantics.js.map +1 -0
- package/dist/object-structures.d.ts +4 -0
- package/dist/object-structures.d.ts.map +1 -0
- package/dist/object-structures.js +134 -0
- package/dist/object-structures.js.map +1 -0
- package/dist/reporting-validation.d.ts +8 -0
- package/dist/reporting-validation.d.ts.map +1 -0
- package/dist/reporting-validation.js +252 -0
- package/dist/reporting-validation.js.map +1 -0
- package/dist/reporting.d.ts +477 -0
- package/dist/reporting.d.ts.map +1 -0
- package/dist/reporting.js +169 -0
- package/dist/reporting.js.map +1 -0
- package/dist/schema.d.ts +5572 -2710
- package/dist/schema.d.ts.map +1 -1
- package/dist/schema.js +444 -1121
- package/dist/schema.js.map +1 -1
- package/dist/validation.d.ts +10 -73
- package/dist/validation.d.ts.map +1 -1
- package/dist/validation.js +1109 -2569
- package/dist/validation.js.map +1 -1
- package/docs/assets/brand/manifest.json +30 -0
- package/docs/assets/brand/udl-horizontal-white.svg +1 -0
- package/docs/assets/brand/udl-horizontal.svg +1 -0
- package/docs/assets/brand/udl-stacked-white.svg +1 -0
- package/docs/assets/brand/udl-stacked.svg +1 -0
- package/docs/assets/udl.svg +11 -0
- package/package.json +13 -22
- package/spec/README.md +300 -172
- package/spec/cars.udl.json +249 -0
- package/spec/udl.schema.json +3066 -2242
- package/src/canonical.ts +1 -35
- package/src/diagnostics.ts +76 -209
- package/src/field-value.ts +87 -0
- package/src/finance.ts +327 -832
- package/src/index.ts +18 -95
- package/src/json.ts +34 -0
- package/src/limits.ts +5 -31
- package/src/object-contract.ts +559 -0
- package/src/object-semantics-schema.ts +148 -0
- package/src/object-semantics.ts +378 -0
- package/src/object-structures.ts +255 -0
- package/src/reporting-validation.ts +383 -0
- package/src/reporting.ts +178 -0
- package/src/schema.ts +510 -1277
- package/src/validation.ts +1630 -4545
- package/LICENSE +0 -661
- package/LICENSING.md +0 -51
- package/TRADEMARKS.md +0 -35
- package/conformance/README.md +0 -82
- package/conformance/evolution/action-contract.expected.json +0 -10
- package/conformance/evolution/action-contract.live.udl +0 -44
- package/conformance/evolution/action-contract.next.udl +0 -45
- package/conformance/evolution/product-identity.expected.json +0 -10
- package/conformance/evolution/product-identity.live.udl +0 -55
- package/conformance/evolution/product-identity.next.udl +0 -55
- package/conformance/evolution/version-required.expected.json +0 -10
- package/conformance/evolution/version-required.live.udl +0 -55
- package/conformance/evolution/version-required.next.udl +0 -58
- package/conformance/invalid/action-without-transition.expected.json +0 -10
- package/conformance/invalid/action-without-transition.udl +0 -60
- package/conformance/invalid/agent-description-too-long.expected.json +0 -10
- package/conformance/invalid/agent-description-too-long.udl +0 -57
- package/conformance/invalid/blank-title.expected.json +0 -10
- package/conformance/invalid/blank-title.udl +0 -54
- package/conformance/invalid/composition-dial-duplicate-key.expected.json +0 -10
- package/conformance/invalid/composition-dial-duplicate-key.udl +0 -73
- package/conformance/invalid/depth-budget.expected.json +0 -10
- package/conformance/invalid/depth-budget.udl +0 -49
- package/conformance/invalid/duplicate-subject.expected.json +0 -10
- package/conformance/invalid/duplicate-subject.udl +0 -230
- package/conformance/invalid/forged-effects.expected.json +0 -10
- package/conformance/invalid/forged-effects.udl +0 -76
- package/conformance/invalid/format-version.expected.json +0 -10
- package/conformance/invalid/format-version.udl +0 -54
- package/conformance/invalid/instrument-id-not-snake-case.expected.json +0 -10
- package/conformance/invalid/instrument-id-not-snake-case.udl +0 -54
- package/conformance/invalid/invalid-aggregate-gate-shape.expected.json +0 -10
- package/conformance/invalid/invalid-aggregate-gate-shape.udl +0 -1819
- package/conformance/invalid/invalid-check-duration.expected.json +0 -10
- package/conformance/invalid/invalid-check-duration.udl +0 -219
- package/conformance/invalid/invalid-dial-anchor.expected.json +0 -10
- package/conformance/invalid/invalid-dial-anchor.udl +0 -219
- package/conformance/invalid/invalid-exception-parent-ref.expected.json +0 -10
- package/conformance/invalid/invalid-exception-parent-ref.udl +0 -2487
- package/conformance/invalid/invalid-exposure-shape.expected.json +0 -10
- package/conformance/invalid/invalid-exposure-shape.udl +0 -1819
- package/conformance/invalid/invalid-remainder.expected.json +0 -10
- package/conformance/invalid/invalid-remainder.udl +0 -220
- package/conformance/invalid/invalid-schema-keyword.expected.json +0 -10
- package/conformance/invalid/invalid-schema-keyword.udl +0 -220
- package/conformance/invalid/invalid-utf8.expected.json +0 -10
- package/conformance/invalid/invalid-utf8.udl +0 -1
- package/conformance/invalid/malformed-json.expected.json +0 -10
- package/conformance/invalid/malformed-json.udl +0 -1
- package/conformance/invalid/missing-create-action.expected.json +0 -10
- package/conformance/invalid/missing-create-action.udl +0 -48
- package/conformance/invalid/missing-exception-amount-field.expected.json +0 -10
- package/conformance/invalid/missing-exception-amount-field.udl +0 -2487
- package/conformance/invalid/missing-exception-contract.expected.json +0 -14
- package/conformance/invalid/missing-exception-contract.udl +0 -2523
- package/conformance/invalid/missing-exception-reason-field.expected.json +0 -10
- package/conformance/invalid/missing-exception-reason-field.udl +0 -2487
- package/conformance/invalid/not-an-object.expected.json +0 -10
- package/conformance/invalid/not-an-object.udl +0 -1
- package/conformance/invalid/payout-reconcile-not-a-bank-debit.expected.json +0 -10
- package/conformance/invalid/payout-reconcile-not-a-bank-debit.udl +0 -259
- package/conformance/invalid/quote-freeze-set-incomplete.expected.json +0 -10
- package/conformance/invalid/quote-freeze-set-incomplete.udl +0 -261
- package/conformance/invalid/quote-named-reference-gate.expected.json +0 -10
- package/conformance/invalid/quote-named-reference-gate.udl +0 -50
- package/conformance/invalid/reconcile-named-reference-gate.expected.json +0 -10
- package/conformance/invalid/reconcile-named-reference-gate.udl +0 -50
- package/conformance/invalid/unknown-key.expected.json +0 -10
- package/conformance/invalid/unknown-key.udl +0 -55
- package/conformance/invalid/unknown-reference-gate-field.expected.json +0 -10
- package/conformance/invalid/unknown-reference-gate-field.udl +0 -1819
- package/conformance/invalid/unknown-required-field.expected.json +0 -10
- package/conformance/invalid/unknown-required-field.udl +0 -220
- package/conformance/invalid/unreachable-state.expected.json +0 -10
- package/conformance/invalid/unreachable-state.udl +0 -55
- package/conformance/invalid/wrong-exception-amount-field.expected.json +0 -10
- package/conformance/invalid/wrong-exception-amount-field.udl +0 -2487
- package/conformance/invalid/wrong-exception-reason-field.expected.json +0 -10
- package/conformance/invalid/wrong-exception-reason-field.udl +0 -2487
- package/conformance/valid/agent-description.expected.json +0 -6
- package/conformance/valid/agent-description.udl +0 -66
- package/conformance/valid/cards.expected.json +0 -6
- package/conformance/valid/cards.udl +0 -1579
- package/conformance/valid/commerce-escrow.expected.json +0 -6
- package/conformance/valid/commerce-escrow.udl +0 -1512
- package/conformance/valid/compiled-crowdfunding.expected.json +0 -6
- package/conformance/valid/compiled-crowdfunding.udl +0 -1843
- package/conformance/valid/compiled-watch-club.expected.json +0 -6
- package/conformance/valid/compiled-watch-club.udl +0 -2486
- package/conformance/valid/complete-contract.expected.json +0 -6
- package/conformance/valid/complete-contract.udl +0 -218
- package/conformance/valid/effect-signatures.expected.json +0 -6
- package/conformance/valid/effect-signatures.udl +0 -75
- package/conformance/valid/hand-edited.expected.json +0 -6
- package/conformance/valid/hand-edited.udl +0 -1
- package/conformance/valid/insured-car-marketplace.expected.json +0 -6
- package/conformance/valid/insured-car-marketplace.udl +0 -1050
- package/conformance/valid/insured-travel.expected.json +0 -6
- package/conformance/valid/insured-travel.udl +0 -3469
- package/conformance/valid/minimal.expected.json +0 -6
- package/conformance/valid/minimal.udl +0 -54
- package/conformance/valid/protection.expected.json +0 -6
- package/conformance/valid/protection.udl +0 -1551
- package/conformance/valid/string-escaping.expected.json +0 -6
- package/conformance/valid/string-escaping.udl +0 -54
- package/dist/check-profiles.d.ts +0 -57
- package/dist/check-profiles.d.ts.map +0 -1
- package/dist/check-profiles.js +0 -62
- package/dist/check-profiles.js.map +0 -1
- package/dist/cli.d.ts +0 -3
- package/dist/cli.d.ts.map +0 -1
- package/dist/cli.js +0 -184
- package/dist/cli.js.map +0 -1
- package/dist/effects.d.ts +0 -41
- package/dist/effects.d.ts.map +0 -1
- package/dist/effects.js +0 -110
- package/dist/effects.js.map +0 -1
- package/dist/evolution.d.ts +0 -120
- package/dist/evolution.d.ts.map +0 -1
- package/dist/evolution.js +0 -567
- package/dist/evolution.js.map +0 -1
- package/dist/parser.d.ts +0 -4
- package/dist/parser.d.ts.map +0 -1
- package/dist/parser.js +0 -44
- package/dist/parser.js.map +0 -1
- package/docs/README.md +0 -14
- package/docs/guide/01-a-document.md +0 -37
- package/docs/guide/02-money-steps.md +0 -23
- package/docs/guide/03-laws.md +0 -18
- package/docs/guide/04-fees-and-remainder.md +0 -15
- package/docs/guide/05-checks-updates-dials.md +0 -7
- package/docs/guide/06-effects.md +0 -11
- package/docs/guide/07-evolution.md +0 -11
- package/docs/guide/08-implementing.md +0 -13
- package/docs/llms-full.txt +0 -1241
- package/docs/llms.txt +0 -14
- package/docs/reference/canonical.md +0 -16
- package/docs/reference/clauses.md +0 -986
- package/docs/reference/cli.md +0 -22
- package/docs/reference/diagnostics.md +0 -32
- package/skills/udl/SKILL.md +0 -28
- package/src/check-profiles.ts +0 -80
- package/src/cli.ts +0 -196
- package/src/effects.ts +0 -163
- package/src/evolution.ts +0 -965
- package/src/parser.ts +0 -58
|
@@ -0,0 +1,559 @@
|
|
|
1
|
+
import * as z from "zod";
|
|
2
|
+
import { udlFieldValueSchema } from "./field-value.js";
|
|
3
|
+
import {
|
|
4
|
+
projectDocumentSemantics,
|
|
5
|
+
presentationLabel,
|
|
6
|
+
} from "./object-semantics.js";
|
|
7
|
+
import type { DocumentSemantics } from "./object-semantics-schema.js";
|
|
8
|
+
export * from "./object-semantics-schema.js";
|
|
9
|
+
export {
|
|
10
|
+
projectDocumentSemantics,
|
|
11
|
+
presentationLabel,
|
|
12
|
+
} from "./object-semantics.js";
|
|
13
|
+
import {
|
|
14
|
+
udlExternalIdSchema,
|
|
15
|
+
type UdlDocument,
|
|
16
|
+
type UdlObjectField,
|
|
17
|
+
type UdlObjectKind,
|
|
18
|
+
type UdlSubjectRequirement,
|
|
19
|
+
type UdlValue,
|
|
20
|
+
type UdlInstrument,
|
|
21
|
+
} from "./schema.js";
|
|
22
|
+
|
|
23
|
+
export type JsonSchemaDocument = z.core.JSONSchema.BaseSchema;
|
|
24
|
+
|
|
25
|
+
export interface ObjectKindDiscovery {
|
|
26
|
+
attachments: readonly {
|
|
27
|
+
name: string;
|
|
28
|
+
title: string;
|
|
29
|
+
instrument: string;
|
|
30
|
+
parentAttachment: string | null;
|
|
31
|
+
block: { key: string; recordPath: string; headerDigest: string } | null;
|
|
32
|
+
}[];
|
|
33
|
+
productBuildId: string;
|
|
34
|
+
digest: string;
|
|
35
|
+
creation: true;
|
|
36
|
+
kind: string;
|
|
37
|
+
title: string;
|
|
38
|
+
fields: readonly UdlObjectField[];
|
|
39
|
+
authoredFields: readonly string[];
|
|
40
|
+
columns: readonly string[];
|
|
41
|
+
filters: readonly {
|
|
42
|
+
field: string;
|
|
43
|
+
type: "text" | "enum" | "date" | "boolean" | "integer";
|
|
44
|
+
}[];
|
|
45
|
+
createSchema: JsonSchemaDocument;
|
|
46
|
+
actions: readonly ObjectActionDiscovery[];
|
|
47
|
+
}
|
|
48
|
+
export function objectKindFilters(
|
|
49
|
+
kind: UdlObjectKind,
|
|
50
|
+
): ObjectKindDiscovery["filters"] {
|
|
51
|
+
return kind.columns.flatMap((column) => {
|
|
52
|
+
const field = kind.fields.find((item) => item.name === column);
|
|
53
|
+
return field &&
|
|
54
|
+
!field.sensitive &&
|
|
55
|
+
["text", "enum", "date", "boolean", "integer"].includes(field.type)
|
|
56
|
+
? [
|
|
57
|
+
{
|
|
58
|
+
field: column,
|
|
59
|
+
type: field.type as ObjectKindDiscovery["filters"][number]["type"],
|
|
60
|
+
},
|
|
61
|
+
]
|
|
62
|
+
: [];
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
export type ObjectActionTarget =
|
|
66
|
+
| { kind: "attachment"; attachment: string }
|
|
67
|
+
| { kind: "instance"; attachment: string; instanceId: string };
|
|
68
|
+
export interface ObjectActionContext {
|
|
69
|
+
productBuildId: string;
|
|
70
|
+
digest: string;
|
|
71
|
+
target: ObjectActionTarget;
|
|
72
|
+
}
|
|
73
|
+
export interface ObjectActionDiscovery extends ObjectActionContext {
|
|
74
|
+
summary: string;
|
|
75
|
+
name: string;
|
|
76
|
+
title: string;
|
|
77
|
+
instrument: string;
|
|
78
|
+
action: string;
|
|
79
|
+
requirements: readonly UdlObjectField[];
|
|
80
|
+
requirementConditions?: Record<
|
|
81
|
+
string,
|
|
82
|
+
NonNullable<UdlSubjectRequirement["when"]>
|
|
83
|
+
>;
|
|
84
|
+
creationRequirements?: readonly UdlObjectField[];
|
|
85
|
+
creationOnlyNames?: readonly string[];
|
|
86
|
+
inputSchema: JsonSchemaDocument;
|
|
87
|
+
fieldsSchema: JsonSchemaDocument;
|
|
88
|
+
availability: ObjectActionAvailability;
|
|
89
|
+
}
|
|
90
|
+
export type ObjectActionBlockerCode =
|
|
91
|
+
| "permission_required"
|
|
92
|
+
| "state_changed"
|
|
93
|
+
| "not_due"
|
|
94
|
+
| "deadline_passed"
|
|
95
|
+
| "clock_pending"
|
|
96
|
+
| "condition_not_met"
|
|
97
|
+
| "already_used"
|
|
98
|
+
| "evidence_required"
|
|
99
|
+
| "account_unavailable"
|
|
100
|
+
| "insufficient_money"
|
|
101
|
+
| "setup_required"
|
|
102
|
+
| "invalid_input"
|
|
103
|
+
| "operation_pending";
|
|
104
|
+
export type ObjectActionAvailability =
|
|
105
|
+
| { status: "available" }
|
|
106
|
+
| {
|
|
107
|
+
status: "requires_input";
|
|
108
|
+
subjectFields: readonly string[];
|
|
109
|
+
actionInputs: readonly string[];
|
|
110
|
+
parties: readonly string[];
|
|
111
|
+
reason: string;
|
|
112
|
+
}
|
|
113
|
+
| {
|
|
114
|
+
status: "unavailable";
|
|
115
|
+
blockers: readonly {
|
|
116
|
+
code: ObjectActionBlockerCode;
|
|
117
|
+
reason: string;
|
|
118
|
+
recheckAt?: string;
|
|
119
|
+
}[];
|
|
120
|
+
}
|
|
121
|
+
| { status: "unknown"; reason: string };
|
|
122
|
+
|
|
123
|
+
export type EvidenceState =
|
|
124
|
+
| "missing"
|
|
125
|
+
| "pending"
|
|
126
|
+
| "satisfied"
|
|
127
|
+
| "refused"
|
|
128
|
+
| "stale";
|
|
129
|
+
|
|
130
|
+
export interface ObjectEvidenceSummary {
|
|
131
|
+
requirementId: string;
|
|
132
|
+
subjectId: string;
|
|
133
|
+
protectedInputDigest: string;
|
|
134
|
+
adapter: string;
|
|
135
|
+
declarationDigest: string;
|
|
136
|
+
productBuildId: string;
|
|
137
|
+
state: EvidenceState;
|
|
138
|
+
reference?: string;
|
|
139
|
+
observedAt?: string;
|
|
140
|
+
reasonCode?: string;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
export interface ObjectActionState extends ObjectActionDiscovery {
|
|
144
|
+
requiredNow: readonly string[];
|
|
145
|
+
evidence?: readonly ObjectEvidenceSummary[];
|
|
146
|
+
}
|
|
147
|
+
/** GET /v1/products/{productId}/objects. Core supplies the frozen Build identity. */
|
|
148
|
+
export type RetainedObjectKind = Pick<
|
|
149
|
+
ObjectKindDiscovery,
|
|
150
|
+
"kind" | "title" | "fields" | "authoredFields" | "columns" | "filters"
|
|
151
|
+
> & {
|
|
152
|
+
attachments: ObjectKindDiscovery["attachments"];
|
|
153
|
+
productBuildId: string;
|
|
154
|
+
digest: string;
|
|
155
|
+
creation: false;
|
|
156
|
+
};
|
|
157
|
+
export interface ObjectDiscovery {
|
|
158
|
+
semantics: DocumentSemantics;
|
|
159
|
+
navigation: readonly { kind: string; title: string; creation: boolean }[];
|
|
160
|
+
retainedKinds: readonly RetainedObjectKind[];
|
|
161
|
+
productBuildId: string;
|
|
162
|
+
digest: string;
|
|
163
|
+
kinds: readonly ObjectKindDiscovery[];
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
/** Creation accepts the full metadata union, with every value optional. */
|
|
167
|
+
export function objectCreateSchema(kind: UdlObjectKind): z.ZodObject {
|
|
168
|
+
return z.strictObject({
|
|
169
|
+
externalId: udlExternalIdSchema.optional(),
|
|
170
|
+
fields: z
|
|
171
|
+
.strictObject(
|
|
172
|
+
Object.fromEntries(
|
|
173
|
+
kind.fields.map((field) => [
|
|
174
|
+
field.name,
|
|
175
|
+
udlFieldValueSchema(field).optional(),
|
|
176
|
+
]),
|
|
177
|
+
),
|
|
178
|
+
)
|
|
179
|
+
.optional(),
|
|
180
|
+
});
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
/** Canonical UDL supplies meaning; core adds authority, instance state and readiness. */
|
|
184
|
+
export function projectObjectDiscovery(
|
|
185
|
+
document: UdlDocument,
|
|
186
|
+
build: Pick<ObjectDiscovery, "productBuildId" | "digest">,
|
|
187
|
+
): ObjectDiscovery {
|
|
188
|
+
const semantics = projectDocumentSemantics(document);
|
|
189
|
+
return {
|
|
190
|
+
...build,
|
|
191
|
+
semantics,
|
|
192
|
+
navigation: document.objects.map((kind) => ({
|
|
193
|
+
kind: kind.id,
|
|
194
|
+
title: kind.title,
|
|
195
|
+
creation: true,
|
|
196
|
+
})),
|
|
197
|
+
retainedKinds: [],
|
|
198
|
+
kinds: semantics.objects.map((kind) => ({
|
|
199
|
+
...build,
|
|
200
|
+
creation: true,
|
|
201
|
+
kind: kind.id,
|
|
202
|
+
title: kind.title,
|
|
203
|
+
fields: kind.fields,
|
|
204
|
+
authoredFields: kind.authoredFields,
|
|
205
|
+
columns: kind.columns,
|
|
206
|
+
filters: objectKindFilters(kind),
|
|
207
|
+
attachments: kind.attachments.map((attachment) => ({
|
|
208
|
+
name: attachment.name,
|
|
209
|
+
title:
|
|
210
|
+
attachment.title ??
|
|
211
|
+
document.instruments.find((item) => item.id === attachment.instrument)
|
|
212
|
+
?.title ??
|
|
213
|
+
attachment.name,
|
|
214
|
+
instrument: attachment.instrument,
|
|
215
|
+
parentAttachment: attachment.parent ?? null,
|
|
216
|
+
block: null,
|
|
217
|
+
})),
|
|
218
|
+
createSchema: z.toJSONSchema(objectCreateSchema(kind), { io: "input" }),
|
|
219
|
+
actions: document.instruments
|
|
220
|
+
.filter((instrument) => instrument.subject === kind.id)
|
|
221
|
+
.flatMap((instrument) => {
|
|
222
|
+
const createHidden =
|
|
223
|
+
!!instrument.actions.create &&
|
|
224
|
+
!instrument.actions.create.publicAction;
|
|
225
|
+
const attachmentRefListFields = instrument.fields.filter(
|
|
226
|
+
(field) =>
|
|
227
|
+
field.type === "list" &&
|
|
228
|
+
field.item === "ref" &&
|
|
229
|
+
field.targetKind !== "object",
|
|
230
|
+
);
|
|
231
|
+
return instrument.actionOrder.flatMap((name) => {
|
|
232
|
+
const action = instrument.actions[name]!;
|
|
233
|
+
if (!action.publicAction) return [];
|
|
234
|
+
const transition = instrument.lifecycle.transitions[name];
|
|
235
|
+
const canStartFromInitial = Boolean(
|
|
236
|
+
transition?.from.includes(instrument.lifecycle.initial),
|
|
237
|
+
);
|
|
238
|
+
const isCreationAction =
|
|
239
|
+
name === "create" || (createHidden && canStartFromInitial);
|
|
240
|
+
|
|
241
|
+
const rawCreateReqs: UdlSubjectRequirement[] = isCreationAction
|
|
242
|
+
? [
|
|
243
|
+
...(instrument.actions.create?.subject?.requirements ?? []),
|
|
244
|
+
...attachmentRefListFields.map((field) => ({
|
|
245
|
+
field: field as UdlObjectField,
|
|
246
|
+
})),
|
|
247
|
+
]
|
|
248
|
+
: [];
|
|
249
|
+
const actionReqs = action.subject?.requirements ?? [];
|
|
250
|
+
const actionReqNames = new Set(
|
|
251
|
+
actionReqs.map((r) => r.objectField ?? r.field.name),
|
|
252
|
+
);
|
|
253
|
+
const mergedReqs: UdlSubjectRequirement[] = actionReqs.map(
|
|
254
|
+
(requirement) => ({ ...requirement }),
|
|
255
|
+
);
|
|
256
|
+
for (const req of rawCreateReqs) {
|
|
257
|
+
const reqName = req.objectField ?? req.field.name;
|
|
258
|
+
const existing = mergedReqs.find(
|
|
259
|
+
(r) => (r.objectField ?? r.field.name) === reqName,
|
|
260
|
+
);
|
|
261
|
+
if (!existing) mergedReqs.push({ ...req });
|
|
262
|
+
else if (!req.when) delete existing.when;
|
|
263
|
+
else if (existing.when)
|
|
264
|
+
existing.when = [...existing.when, ...req.when];
|
|
265
|
+
}
|
|
266
|
+
const requirementConditions = Object.fromEntries(
|
|
267
|
+
mergedReqs.flatMap((req) =>
|
|
268
|
+
req.when ? [[req.objectField ?? req.field.name, req.when]] : [],
|
|
269
|
+
),
|
|
270
|
+
);
|
|
271
|
+
const unbound = [
|
|
272
|
+
...(action.subject?.adapters ?? []),
|
|
273
|
+
...(isCreationAction
|
|
274
|
+
? (instrument.actions.create?.subject?.adapters ?? [])
|
|
275
|
+
: []),
|
|
276
|
+
].find((adapter) => adapter.snapshot === null);
|
|
277
|
+
const seenCreation = new Set<string>();
|
|
278
|
+
const creationRequirements: UdlObjectField[] = [];
|
|
279
|
+
for (const requirement of rawCreateReqs) {
|
|
280
|
+
const name = requirement.objectField ?? requirement.field.name;
|
|
281
|
+
if (!seenCreation.has(name)) {
|
|
282
|
+
seenCreation.add(name);
|
|
283
|
+
creationRequirements.push({
|
|
284
|
+
...requirement.field,
|
|
285
|
+
name,
|
|
286
|
+
} as UdlObjectField);
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
const creationOnlyNames = creationRequirements
|
|
290
|
+
.map((field) => field.name)
|
|
291
|
+
.filter((name) => !actionReqNames.has(name));
|
|
292
|
+
return [
|
|
293
|
+
{
|
|
294
|
+
...build,
|
|
295
|
+
target: {
|
|
296
|
+
kind: "attachment" as const,
|
|
297
|
+
attachment: kind.attachments.find(
|
|
298
|
+
(attachment) => attachment.instrument === instrument.id,
|
|
299
|
+
)!.name,
|
|
300
|
+
},
|
|
301
|
+
name: action.publicAction,
|
|
302
|
+
title: action.title ?? presentationLabel(action.publicAction),
|
|
303
|
+
summary: action.summary,
|
|
304
|
+
instrument: instrument.id,
|
|
305
|
+
action: name,
|
|
306
|
+
requirements: mergedReqs.map(
|
|
307
|
+
(requirement) =>
|
|
308
|
+
({
|
|
309
|
+
...requirement.field,
|
|
310
|
+
name: requirement.objectField ?? requirement.field.name,
|
|
311
|
+
}) as UdlObjectField,
|
|
312
|
+
),
|
|
313
|
+
...(Object.keys(requirementConditions).length
|
|
314
|
+
? { requirementConditions }
|
|
315
|
+
: {}),
|
|
316
|
+
...(creationRequirements.length > 0
|
|
317
|
+
? { creationRequirements }
|
|
318
|
+
: {}),
|
|
319
|
+
...(creationRequirements.length > 0
|
|
320
|
+
? { creationOnlyNames }
|
|
321
|
+
: {}),
|
|
322
|
+
fieldsSchema: z.toJSONSchema(
|
|
323
|
+
z.strictObject(
|
|
324
|
+
Object.fromEntries(
|
|
325
|
+
mergedReqs.map((requirement) => [
|
|
326
|
+
requirement.objectField ?? requirement.field.name,
|
|
327
|
+
udlFieldValueSchema(requirement.field).optional(),
|
|
328
|
+
]),
|
|
329
|
+
),
|
|
330
|
+
),
|
|
331
|
+
{ io: "input" },
|
|
332
|
+
),
|
|
333
|
+
inputSchema: z.toJSONSchema(
|
|
334
|
+
z.strictObject(
|
|
335
|
+
Object.fromEntries(
|
|
336
|
+
action.input.map((field) => [
|
|
337
|
+
field.name,
|
|
338
|
+
field.optional
|
|
339
|
+
? udlFieldValueSchema(field).optional()
|
|
340
|
+
: udlFieldValueSchema(field),
|
|
341
|
+
]),
|
|
342
|
+
),
|
|
343
|
+
),
|
|
344
|
+
{ io: "input" },
|
|
345
|
+
),
|
|
346
|
+
availability: unbound
|
|
347
|
+
? {
|
|
348
|
+
status: "unavailable" as const,
|
|
349
|
+
blockers: [
|
|
350
|
+
{
|
|
351
|
+
code: "setup_required" as const,
|
|
352
|
+
reason:
|
|
353
|
+
"A required external check has not been set up.",
|
|
354
|
+
},
|
|
355
|
+
],
|
|
356
|
+
}
|
|
357
|
+
: { status: "available" as const },
|
|
358
|
+
},
|
|
359
|
+
];
|
|
360
|
+
});
|
|
361
|
+
}),
|
|
362
|
+
})),
|
|
363
|
+
};
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
/** Values overwritten before invocation cannot decide a guard during discovery. */
|
|
367
|
+
export function objectActionSelf(
|
|
368
|
+
instrument: UdlInstrument,
|
|
369
|
+
actionName: string,
|
|
370
|
+
fields: Readonly<Record<string, unknown>> = {},
|
|
371
|
+
): Record<string, unknown> {
|
|
372
|
+
const action = instrument.actions[actionName]!;
|
|
373
|
+
const known = {
|
|
374
|
+
...Object.fromEntries(
|
|
375
|
+
instrument.fields.flatMap((field) =>
|
|
376
|
+
"value" in field ? [[field.name, field.value]] : [],
|
|
377
|
+
),
|
|
378
|
+
),
|
|
379
|
+
...fields,
|
|
380
|
+
};
|
|
381
|
+
for (const calculation of [
|
|
382
|
+
...instrument.calculate,
|
|
383
|
+
...(action.calculate ?? []),
|
|
384
|
+
])
|
|
385
|
+
delete known[calculation.target];
|
|
386
|
+
for (const name of Object.keys(action.set ?? {})) delete known[name];
|
|
387
|
+
return known;
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
export interface ObjectActionStateOptions {
|
|
391
|
+
attached?: boolean;
|
|
392
|
+
self?: Readonly<Record<string, unknown>>;
|
|
393
|
+
input?: Readonly<Record<string, unknown>>;
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
/** Unknown invocation state remains possible; a known false guard suppresses a prompt. */
|
|
397
|
+
function requirementPossible(
|
|
398
|
+
paths: NonNullable<UdlSubjectRequirement["when"]>,
|
|
399
|
+
action: ObjectActionDiscovery,
|
|
400
|
+
fields: Readonly<Record<string, unknown>>,
|
|
401
|
+
options: ObjectActionStateOptions,
|
|
402
|
+
): boolean {
|
|
403
|
+
return paths.some((path) =>
|
|
404
|
+
path.every((condition) => {
|
|
405
|
+
const read = (value: UdlValue): unknown => {
|
|
406
|
+
if ("literal" in value) return value.literal;
|
|
407
|
+
const [root, name, ...tail] = value.field.split(".");
|
|
408
|
+
if (!name || tail.length) return undefined;
|
|
409
|
+
if (root === "subject") return fields[name];
|
|
410
|
+
if (
|
|
411
|
+
condition.instrument !== action.instrument ||
|
|
412
|
+
condition.action !== action.action
|
|
413
|
+
)
|
|
414
|
+
return undefined;
|
|
415
|
+
if (root === "self") return options.self?.[name];
|
|
416
|
+
if (root === "input") return options.input?.[name];
|
|
417
|
+
return undefined;
|
|
418
|
+
};
|
|
419
|
+
let left = read(condition.guard.left);
|
|
420
|
+
let right = read(condition.guard.right);
|
|
421
|
+
if (left === undefined || right === undefined) return true;
|
|
422
|
+
try {
|
|
423
|
+
if (condition.valueType === "money") {
|
|
424
|
+
left = BigInt(String(left));
|
|
425
|
+
right = BigInt(String(right));
|
|
426
|
+
} else if (condition.valueType === "date") {
|
|
427
|
+
left = Date.parse(String(left));
|
|
428
|
+
right = Date.parse(String(right));
|
|
429
|
+
if (!Number.isFinite(left) || !Number.isFinite(right)) return true;
|
|
430
|
+
}
|
|
431
|
+
} catch {
|
|
432
|
+
return true;
|
|
433
|
+
}
|
|
434
|
+
if (
|
|
435
|
+
typeof left !== typeof right ||
|
|
436
|
+
!["string", "number", "boolean", "bigint"].includes(typeof left)
|
|
437
|
+
)
|
|
438
|
+
return true;
|
|
439
|
+
const a = left as string | number | bigint;
|
|
440
|
+
const b = right as string | number | bigint;
|
|
441
|
+
switch (condition.guard.operator) {
|
|
442
|
+
case "==":
|
|
443
|
+
return left === right;
|
|
444
|
+
case "!=":
|
|
445
|
+
return left !== right;
|
|
446
|
+
case "<":
|
|
447
|
+
return a < b;
|
|
448
|
+
case "<=":
|
|
449
|
+
return a <= b;
|
|
450
|
+
case ">":
|
|
451
|
+
return a > b;
|
|
452
|
+
case ">=":
|
|
453
|
+
return a >= b;
|
|
454
|
+
}
|
|
455
|
+
}),
|
|
456
|
+
);
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
/** Object-specific values determine missing fields; global discovery cannot. */
|
|
460
|
+
export function objectActionState(
|
|
461
|
+
action: ObjectActionDiscovery,
|
|
462
|
+
fields: Readonly<Record<string, unknown>>,
|
|
463
|
+
options?: ObjectActionStateOptions | boolean,
|
|
464
|
+
): ObjectActionState {
|
|
465
|
+
const attached =
|
|
466
|
+
typeof options === "boolean" ? options : (options?.attached ?? false);
|
|
467
|
+
const creationFilter = new Set(action.creationOnlyNames ?? []);
|
|
468
|
+
return {
|
|
469
|
+
...action,
|
|
470
|
+
requiredNow: action.requirements
|
|
471
|
+
.filter((field) => {
|
|
472
|
+
const conditions =
|
|
473
|
+
action.requirementConditions &&
|
|
474
|
+
Object.hasOwn(action.requirementConditions, field.name)
|
|
475
|
+
? action.requirementConditions[field.name]
|
|
476
|
+
: undefined;
|
|
477
|
+
if (
|
|
478
|
+
conditions &&
|
|
479
|
+
!requirementPossible(
|
|
480
|
+
conditions,
|
|
481
|
+
action,
|
|
482
|
+
fields,
|
|
483
|
+
typeof options === "object" ? options : {},
|
|
484
|
+
)
|
|
485
|
+
)
|
|
486
|
+
return false;
|
|
487
|
+
const value = fields[field.name];
|
|
488
|
+
const optional =
|
|
489
|
+
field.optional || (attached && creationFilter.has(field.name));
|
|
490
|
+
return (
|
|
491
|
+
!(optional && value === undefined) &&
|
|
492
|
+
!udlFieldValueSchema(field).safeParse(value).success
|
|
493
|
+
);
|
|
494
|
+
})
|
|
495
|
+
.map((field) => field.name),
|
|
496
|
+
};
|
|
497
|
+
}
|
|
498
|
+
export interface SubjectRequirementIssue {
|
|
499
|
+
code:
|
|
500
|
+
| "subject_requirement_missing"
|
|
501
|
+
| "subject_field_unknown"
|
|
502
|
+
| "subject_adapter_unbound";
|
|
503
|
+
action: string;
|
|
504
|
+
field?: string;
|
|
505
|
+
origin: string;
|
|
506
|
+
message: string;
|
|
507
|
+
}
|
|
508
|
+
|
|
509
|
+
/** Check merged metadata before dispatch. Runtime guards add their active child requirements. */
|
|
510
|
+
export function validateObjectActionSubject(
|
|
511
|
+
action: ObjectActionDiscovery,
|
|
512
|
+
storedFields: Readonly<Record<string, unknown>>,
|
|
513
|
+
submittedFields: Readonly<Record<string, unknown>>,
|
|
514
|
+
options?: ObjectActionStateOptions | boolean,
|
|
515
|
+
): readonly SubjectRequirementIssue[] {
|
|
516
|
+
const origin = `${action.instrument}.${action.action}.subject`;
|
|
517
|
+
const issues: SubjectRequirementIssue[] = [];
|
|
518
|
+
if (
|
|
519
|
+
action.availability.status === "unavailable" &&
|
|
520
|
+
action.availability.blockers.some(
|
|
521
|
+
(blocker) => blocker.code === "setup_required",
|
|
522
|
+
)
|
|
523
|
+
) {
|
|
524
|
+
issues.push({
|
|
525
|
+
code: "subject_adapter_unbound",
|
|
526
|
+
action: action.name,
|
|
527
|
+
origin,
|
|
528
|
+
message: "A required external check has not been set up.",
|
|
529
|
+
});
|
|
530
|
+
}
|
|
531
|
+
const admitted = new Set(action.requirements.map((field) => field.name));
|
|
532
|
+
for (const field of Object.keys(submittedFields)) {
|
|
533
|
+
if (!admitted.has(field))
|
|
534
|
+
issues.push({
|
|
535
|
+
code: "subject_field_unknown",
|
|
536
|
+
action: action.name,
|
|
537
|
+
field,
|
|
538
|
+
origin,
|
|
539
|
+
message: `${field} is not admitted by ${action.name}`,
|
|
540
|
+
});
|
|
541
|
+
}
|
|
542
|
+
for (const field of objectActionState(
|
|
543
|
+
action,
|
|
544
|
+
{
|
|
545
|
+
...storedFields,
|
|
546
|
+
...submittedFields,
|
|
547
|
+
},
|
|
548
|
+
options,
|
|
549
|
+
).requiredNow) {
|
|
550
|
+
issues.push({
|
|
551
|
+
code: "subject_requirement_missing",
|
|
552
|
+
action: action.name,
|
|
553
|
+
field,
|
|
554
|
+
origin: `${origin}.${field}`,
|
|
555
|
+
message: `${action.name} requires a valid ${field}`,
|
|
556
|
+
});
|
|
557
|
+
}
|
|
558
|
+
return issues;
|
|
559
|
+
}
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
import * as z from "zod";
|
|
2
|
+
import {
|
|
3
|
+
udlActionSchema,
|
|
4
|
+
udlCalculationSchema,
|
|
5
|
+
udlFieldSchema,
|
|
6
|
+
udlInstrumentSchema,
|
|
7
|
+
udlObjectKindSchema,
|
|
8
|
+
udlObjectAttachmentSchema,
|
|
9
|
+
udlPartySchema,
|
|
10
|
+
udlRequirementSchema,
|
|
11
|
+
udlValueSchema,
|
|
12
|
+
udlKernelOperationSchema,
|
|
13
|
+
subjectPartyRoles,
|
|
14
|
+
} from "./schema.js";
|
|
15
|
+
|
|
16
|
+
const text = z.string();
|
|
17
|
+
export const cardinalitySchema = z.strictObject({
|
|
18
|
+
min: z.number().int().nonnegative(),
|
|
19
|
+
// null means the declarations supply no upper bound.
|
|
20
|
+
max: z.number().int().nonnegative().nullable(),
|
|
21
|
+
});
|
|
22
|
+
export const semanticOwnerSchema = z.union([
|
|
23
|
+
z.strictObject({ kind: z.literal("instrument"), instrument: text }),
|
|
24
|
+
z.strictObject({ kind: z.literal("role"), role: z.enum(subjectPartyRoles) }),
|
|
25
|
+
z.strictObject({ kind: z.literal("party"), party: text }),
|
|
26
|
+
z.strictObject({ kind: z.literal("adapter"), adapter: text }),
|
|
27
|
+
]);
|
|
28
|
+
export const semanticAccountSchema = z.strictObject({
|
|
29
|
+
path: text,
|
|
30
|
+
scope: text,
|
|
31
|
+
instrument: text,
|
|
32
|
+
field: text,
|
|
33
|
+
owner: semanticOwnerSchema,
|
|
34
|
+
book: z.enum(["cash", "claim"]),
|
|
35
|
+
key: text.optional(),
|
|
36
|
+
contra: z.boolean(),
|
|
37
|
+
});
|
|
38
|
+
export const semanticRoleSchema = z.union([
|
|
39
|
+
semanticOwnerSchema,
|
|
40
|
+
z.strictObject({ kind: z.enum(["caller", "clock"]) }),
|
|
41
|
+
z.strictObject({ kind: z.literal("parent"), instruments: z.array(text) }),
|
|
42
|
+
]);
|
|
43
|
+
export const semanticRelationshipSchema = z.strictObject({
|
|
44
|
+
kind: z.enum(["reference", "child"]),
|
|
45
|
+
via: z.enum(["field", "attachment", "invocation", "parent_actor"]),
|
|
46
|
+
name: text,
|
|
47
|
+
targetKind: z.enum(["instrument", "object"]),
|
|
48
|
+
targets: z.array(text),
|
|
49
|
+
cardinality: cardinalitySchema,
|
|
50
|
+
});
|
|
51
|
+
export const semanticMoneyEffectSchema = z.strictObject({
|
|
52
|
+
key: text,
|
|
53
|
+
operation: udlKernelOperationSchema,
|
|
54
|
+
amount: udlValueSchema.nullable(),
|
|
55
|
+
from: z.array(semanticAccountSchema),
|
|
56
|
+
to: z.array(semanticAccountSchema),
|
|
57
|
+
// Expressions describe declared effects, never a receipt or evaluated quote.
|
|
58
|
+
disposition: z.enum(["held", "paid", "released", "claim", "unresolved"]),
|
|
59
|
+
transfer: text.nullable(),
|
|
60
|
+
reservations: z.array(
|
|
61
|
+
z.strictObject({ instrument: text, action: text, key: text }),
|
|
62
|
+
),
|
|
63
|
+
});
|
|
64
|
+
export const semanticActionSchema = z.strictObject({
|
|
65
|
+
name: text,
|
|
66
|
+
alias: text.nullable(),
|
|
67
|
+
title: text,
|
|
68
|
+
actor: udlActionSchema.shape.actor,
|
|
69
|
+
roles: z.array(semanticRoleSchema),
|
|
70
|
+
from: z.array(text),
|
|
71
|
+
to: text.nullable(),
|
|
72
|
+
references: z.array(udlFieldSchema).optional(),
|
|
73
|
+
invokedBy: z
|
|
74
|
+
.array(
|
|
75
|
+
z.strictObject({
|
|
76
|
+
instrument: text,
|
|
77
|
+
action: text,
|
|
78
|
+
alias: text.nullable(),
|
|
79
|
+
invocation: udlActionSchema.shape.invoke.unwrap().element,
|
|
80
|
+
}),
|
|
81
|
+
)
|
|
82
|
+
.optional(),
|
|
83
|
+
inputs: udlActionSchema.shape.input,
|
|
84
|
+
subject: udlActionSchema.shape.subject,
|
|
85
|
+
prerequisites: udlActionSchema.shape.requires,
|
|
86
|
+
due: udlActionSchema.shape.due.unwrap().nullable(),
|
|
87
|
+
deadline: udlActionSchema.shape.deadline.unwrap().nullable(),
|
|
88
|
+
calculations: z.array(udlCalculationSchema),
|
|
89
|
+
assignments: udlActionSchema.shape.set.unwrap(),
|
|
90
|
+
moves: udlActionSchema.shape.moves,
|
|
91
|
+
moneyEffects: z.array(semanticMoneyEffectSchema),
|
|
92
|
+
invokes: udlActionSchema.shape.invoke.unwrap(),
|
|
93
|
+
});
|
|
94
|
+
export const semanticStructureSchema = z.enum([
|
|
95
|
+
"stage_and_decisions",
|
|
96
|
+
"payment_review",
|
|
97
|
+
"held_funds",
|
|
98
|
+
"reserved_payment",
|
|
99
|
+
"payment_calendar",
|
|
100
|
+
"funding_progress",
|
|
101
|
+
"cancellation_review",
|
|
102
|
+
"external_checks",
|
|
103
|
+
"report_view",
|
|
104
|
+
]);
|
|
105
|
+
export const semanticInstrumentSchema = z.strictObject({
|
|
106
|
+
id: text,
|
|
107
|
+
title: text,
|
|
108
|
+
subject: text.optional(),
|
|
109
|
+
fields: z.array(udlFieldSchema),
|
|
110
|
+
accounts: z.array(semanticAccountSchema),
|
|
111
|
+
relationships: z.array(semanticRelationshipSchema),
|
|
112
|
+
calculations: z.array(udlCalculationSchema),
|
|
113
|
+
invariants: z.array(udlRequirementSchema),
|
|
114
|
+
initialState: text,
|
|
115
|
+
lifecycle: z.strictObject({
|
|
116
|
+
initial: text,
|
|
117
|
+
states: z.array(
|
|
118
|
+
z.strictObject({ name: text, label: text, terminal: z.boolean() }),
|
|
119
|
+
),
|
|
120
|
+
cancellationActions: z.array(text),
|
|
121
|
+
}),
|
|
122
|
+
actions: z.array(semanticActionSchema),
|
|
123
|
+
reports: udlInstrumentSchema.shape.reports.unwrap(),
|
|
124
|
+
structures: z.array(semanticStructureSchema),
|
|
125
|
+
});
|
|
126
|
+
export const documentSemanticsSchema = z.strictObject({
|
|
127
|
+
currency: text,
|
|
128
|
+
parties: z.record(text, udlPartySchema),
|
|
129
|
+
objects: z.array(
|
|
130
|
+
z.strictObject({
|
|
131
|
+
...udlObjectKindSchema.shape,
|
|
132
|
+
attachments: z.array(
|
|
133
|
+
z.strictObject({
|
|
134
|
+
...udlObjectAttachmentSchema.shape,
|
|
135
|
+
cardinality: cardinalitySchema,
|
|
136
|
+
}),
|
|
137
|
+
),
|
|
138
|
+
}),
|
|
139
|
+
),
|
|
140
|
+
instruments: z.array(semanticInstrumentSchema),
|
|
141
|
+
});
|
|
142
|
+
export type DocumentSemantics = z.infer<typeof documentSemanticsSchema>;
|
|
143
|
+
export type SemanticInstrument = z.infer<typeof semanticInstrumentSchema>;
|
|
144
|
+
export type SemanticAction = z.infer<typeof semanticActionSchema>;
|
|
145
|
+
export type SemanticAccount = z.infer<typeof semanticAccountSchema>;
|
|
146
|
+
export type SemanticOwner = z.infer<typeof semanticOwnerSchema>;
|
|
147
|
+
export type SemanticRelationship = z.infer<typeof semanticRelationshipSchema>;
|
|
148
|
+
export type SemanticMoneyEffect = z.infer<typeof semanticMoneyEffectSchema>;
|