@hyperscale0/udl 1.0.0-rc.1 → 1.0.123
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 -211
- 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
package/dist/schema.js
CHANGED
|
@@ -1,1171 +1,494 @@
|
|
|
1
|
-
import
|
|
2
|
-
import {
|
|
1
|
+
import * as z from "zod";
|
|
2
|
+
import { reportDefinitionSchema } from "./reporting.js";
|
|
3
|
+
import { writeJson } from "./json.js";
|
|
3
4
|
export const UDL_FORMAT_VERSION = 1;
|
|
4
|
-
|
|
5
|
-
const
|
|
6
|
-
const
|
|
7
|
-
const idPrefixPattern = /^[a-z]{2,8}$/;
|
|
8
|
-
const eventNamePattern = /^[a-z][a-z0-9_]*(?:\.[a-z][a-z0-9_]*)+$/;
|
|
9
|
-
const udlSnakeCaseSchema = z
|
|
5
|
+
/** Counts the root and every nested invocation, including selected and ranged children. */
|
|
6
|
+
export const MAX_ACTION_EXPANSION = 4096;
|
|
7
|
+
const name = z
|
|
10
8
|
.string()
|
|
11
|
-
.regex(
|
|
12
|
-
|
|
9
|
+
.regex(/^[a-z][a-zA-Z0-9_]*$/)
|
|
10
|
+
.max(80);
|
|
11
|
+
const text = z.string().min(1).max(2048);
|
|
12
|
+
const amount = z.string().regex(/^(0|[1-9][0-9]{0,17})$/);
|
|
13
|
+
const integer = z.number().int().safe();
|
|
14
|
+
const scalar = z.union([z.string(), integer, z.boolean()]);
|
|
15
|
+
const path = z
|
|
13
16
|
.string()
|
|
14
|
-
.regex(
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
export const
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
export const
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
.
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
const
|
|
33
|
-
|
|
34
|
-
.
|
|
35
|
-
const instanceValuePathSchema = z
|
|
36
|
-
.string()
|
|
37
|
-
.regex(/^(?:fields|refs)\.[a-z][A-Za-z0-9]*$/, "must name one declared fields.* or refs.* value");
|
|
38
|
-
const jsonObjectSchema = z.record(z.string(), z.json());
|
|
39
|
-
const stringMapSchema = z.record(nonEmptyTextSchema, nonEmptyTextSchema);
|
|
40
|
-
const providerFamilyIds = [
|
|
41
|
-
"accounts_ledger_first_party",
|
|
42
|
-
"identity_verification",
|
|
43
|
-
"national_identity",
|
|
44
|
-
"credit_bureau",
|
|
45
|
-
"sanctions_screening",
|
|
46
|
-
"enforcement_instrument",
|
|
47
|
-
"credit_servicing",
|
|
48
|
-
"collections_agency",
|
|
49
|
-
"settlement_ingestion",
|
|
50
|
-
"payouts",
|
|
51
|
-
"banking_or_card_issuing",
|
|
52
|
-
"insurance_carrier",
|
|
53
|
-
"insurance_claims_adjuster",
|
|
54
|
-
"air_carrier",
|
|
55
|
-
"lodging_supplier",
|
|
56
|
-
"email_or_notification",
|
|
57
|
-
];
|
|
58
|
-
export const udlProviderFamilyIdSchema = z.enum(providerFamilyIds);
|
|
59
|
-
const udlDeclaredValuePolicySchema = z.enum(["required", "optional", "none"]);
|
|
60
|
-
const udlSubjectSchema = z.strictObject({
|
|
61
|
-
declaredValue: udlDeclaredValuePolicySchema,
|
|
62
|
-
kind: udlSnakeCaseSchema,
|
|
63
|
-
schema: jsonObjectSchema,
|
|
64
|
-
title: nonEmptyTextSchema,
|
|
65
|
-
version: z.number().int().positive(),
|
|
66
|
-
});
|
|
67
|
-
const udlInstrumentSubjectSchema = z.strictObject({
|
|
68
|
-
extensible: z.boolean().optional(),
|
|
69
|
-
kinds: z.array(udlSnakeCaseSchema).min(1),
|
|
70
|
-
});
|
|
71
|
-
const udlExampleSchema = z.strictObject({
|
|
72
|
-
input: jsonObjectSchema,
|
|
73
|
-
name: nonEmptyTextSchema,
|
|
74
|
-
output: z.json().optional(),
|
|
75
|
-
});
|
|
76
|
-
const udlLifecycleTransitionSchema = z.strictObject({
|
|
77
|
-
from: z.array(udlSnakeCaseSchema).min(1),
|
|
78
|
-
to: udlSnakeCaseSchema,
|
|
79
|
-
});
|
|
80
|
-
const udlLifecycleSchema = z.strictObject({
|
|
81
|
-
initial: udlSnakeCaseSchema,
|
|
82
|
-
states: z.array(udlSnakeCaseSchema).min(1),
|
|
83
|
-
transitions: z.record(udlActionNameSchema, udlLifecycleTransitionSchema),
|
|
84
|
-
});
|
|
85
|
-
const udlUpdatePolicySchema = z.strictObject({
|
|
86
|
-
examples: z.array(udlExampleSchema).optional(),
|
|
87
|
-
fields: z.array(udlFieldNameSchema).min(1),
|
|
88
|
-
states: z.array(udlSnakeCaseSchema).min(1),
|
|
89
|
-
});
|
|
90
|
-
const udlGateSchema = z.strictObject({
|
|
91
|
-
/** Local field key <- referenced instance path; create actions only. */
|
|
92
|
-
bind: z.record(udlFieldNameSchema, fieldPathSchema).optional(),
|
|
93
|
-
field: udlFieldNameSchema,
|
|
94
|
-
/** Local instance path === referenced instance path at admission. */
|
|
95
|
-
match: z.record(fieldPathSchema, fieldPathSchema).optional(),
|
|
96
|
-
/** Opt-in over an optional reference field: absent passes, set is held to the clause. */
|
|
17
|
+
.regex(/^[a-z][a-zA-Z0-9_]*(?:\.[a-z][a-zA-Z0-9_]*)*$/)
|
|
18
|
+
.max(240);
|
|
19
|
+
const instrumentId = name.meta({ "x-udl-reference": "instrument" });
|
|
20
|
+
const objectKindId = name.meta({ "x-udl-reference": "object" });
|
|
21
|
+
export const udlPartyNameSchema = name;
|
|
22
|
+
export const udlObjectIdSchema = z.string().min(1).max(160);
|
|
23
|
+
export const udlExternalIdSchema = z.string().min(1).max(2048);
|
|
24
|
+
export const udlObjectRevisionSchema = integer.positive();
|
|
25
|
+
/** Currency belongs to the document. Accounts and amounts cannot override it. */
|
|
26
|
+
export const udlPartySchema = z.strictObject({
|
|
27
|
+
kind: z.enum(["person", "business", "staff"]),
|
|
28
|
+
role: name.optional(),
|
|
29
|
+
});
|
|
30
|
+
export const udlFamilySchema = z.strictObject({
|
|
31
|
+
module: name,
|
|
32
|
+
exportPath: path,
|
|
33
|
+
revision: integer.positive(),
|
|
34
|
+
});
|
|
35
|
+
const fieldBase = {
|
|
36
|
+
name,
|
|
37
|
+
label: text.optional(),
|
|
97
38
|
optional: z.literal(true).optional(),
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
unique: z.literal(true).optional(),
|
|
101
|
-
});
|
|
102
|
-
const udlBindingSchema = z.discriminatedUnion("from", [
|
|
103
|
-
z.strictObject({ from: z.literal("const"), value: z.string() }),
|
|
104
|
-
z.strictObject({ from: z.literal("instance"), path: fieldPathSchema }),
|
|
105
|
-
z.strictObject({ from: z.literal("input"), path: fieldPathSchema }),
|
|
106
|
-
]);
|
|
107
|
-
const udlStepOperationSchema = z.enum([
|
|
108
|
-
"account.escrow.provision",
|
|
109
|
-
"account.freeze",
|
|
110
|
-
"account.unfreeze",
|
|
111
|
-
]);
|
|
112
|
-
const udlMoveOperationSchema = z.enum([
|
|
113
|
-
"internal_transfer.create",
|
|
114
|
-
"internal_transfer.reserve",
|
|
115
|
-
"internal_transfer.post",
|
|
116
|
-
"internal_transfer.void",
|
|
117
|
-
]);
|
|
118
|
-
export const udlKernelOperationSchema = z.enum([
|
|
119
|
-
...udlStepOperationSchema.options,
|
|
120
|
-
...udlMoveOperationSchema.options,
|
|
121
|
-
]);
|
|
122
|
-
const udlStepSchema = z.strictObject({
|
|
123
|
-
bind: z.record(fieldPathSchema, udlBindingSchema),
|
|
124
|
-
capture: stringMapSchema.optional(),
|
|
125
|
-
operation: udlStepOperationSchema,
|
|
126
|
-
});
|
|
127
|
-
const udlMoveSchema = z.strictObject({
|
|
128
|
-
bind: z.record(fieldPathSchema, udlBindingSchema),
|
|
129
|
-
capture: stringMapSchema.optional(),
|
|
130
|
-
key: udlSnakeCaseSchema,
|
|
131
|
-
operation: udlMoveOperationSchema,
|
|
132
|
-
});
|
|
133
|
-
const udlDueRecurrenceSchema = z.strictObject({
|
|
134
|
-
countField: udlFieldNameSchema.optional(),
|
|
135
|
-
delinquency: z.literal("parent_policy").optional(),
|
|
136
|
-
drainAction: udlActionNameSchema.optional(),
|
|
137
|
-
period: z.union([
|
|
138
|
-
nonEmptyTextSchema,
|
|
139
|
-
z.strictObject({
|
|
140
|
-
calendar: z.enum(["gregorian", "hijri"]),
|
|
141
|
-
monthEnd: z.literal("clamp_to_last_day"),
|
|
142
|
-
months: z.number().int().positive(),
|
|
143
|
-
}),
|
|
144
|
-
]),
|
|
145
|
-
liability: z.literal("one_open").optional(),
|
|
146
|
-
untilAction: udlActionNameSchema.optional(),
|
|
147
|
-
untilField: udlFieldNameSchema.optional(),
|
|
148
|
-
});
|
|
149
|
-
const udlDueParentStatusSchema = z.strictObject({
|
|
150
|
-
instrumentId: udlSnakeCaseSchema,
|
|
151
|
-
refField: udlFieldNameSchema,
|
|
152
|
-
statuses: z.array(udlSnakeCaseSchema).min(1),
|
|
153
|
-
});
|
|
154
|
-
const udlDueSchema = z.strictObject({
|
|
155
|
-
every: udlDueRecurrenceSchema.optional(),
|
|
156
|
-
field: udlFieldNameSchema,
|
|
157
|
-
offset: nonEmptyTextSchema.optional(),
|
|
158
|
-
whenParentStatus: udlDueParentStatusSchema.optional(),
|
|
159
|
-
});
|
|
160
|
-
const udlDeadlineSchema = z.strictObject({
|
|
161
|
-
field: udlFieldNameSchema,
|
|
162
|
-
offset: nonEmptyTextSchema.optional(),
|
|
163
|
-
});
|
|
164
|
-
const udlSetsAtSchema = z.strictObject({
|
|
165
|
-
field: udlFieldNameSchema,
|
|
166
|
-
marker: z.literal(true).optional(),
|
|
167
|
-
offset: nonEmptyTextSchema,
|
|
168
|
-
});
|
|
169
|
-
const udlQuoteChargeSchema = z.strictObject({
|
|
170
|
-
bps: z.number().int().min(0).max(9_999),
|
|
171
|
-
withinOffset: nonEmptyTextSchema.optional(),
|
|
172
|
-
});
|
|
173
|
-
// A priced, expiring offer. The quoting action splits `baseField` into a charge
|
|
174
|
-
// and a net at its own clock, freezes the fields the price was read from, and
|
|
175
|
-
// stamps an expiry. Only the paired `commit` action may spend the offer, and
|
|
176
|
-
// only while it is unexpired and its frozen fields still hold.
|
|
177
|
-
const udlQuoteShape = {
|
|
178
|
-
/** Date-time whose remaining time picks the charge tier; omit for elapsed age. */
|
|
179
|
-
anchorField: udlFieldNameSchema.optional(),
|
|
180
|
-
baseField: udlFieldNameSchema,
|
|
181
|
-
chargeRef: udlFieldNameSchema,
|
|
182
|
-
charges: z.array(udlQuoteChargeSchema).min(1),
|
|
183
|
-
/** Fixed ISO-8601 duration from the quoting action, or a stored deadline. */
|
|
184
|
-
expires: z.union([
|
|
185
|
-
z.strictObject({ field: udlFieldNameSchema }),
|
|
186
|
-
z.strictObject({ offset: nonEmptyTextSchema }),
|
|
187
|
-
]),
|
|
188
|
-
fixes: z.array(udlFieldNameSchema).min(1),
|
|
189
|
-
netDestinationField: udlFieldNameSchema,
|
|
190
|
-
netRef: udlFieldNameSchema,
|
|
39
|
+
description: text.optional(),
|
|
40
|
+
sensitive: z.literal(true).optional(),
|
|
191
41
|
};
|
|
192
|
-
const
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
/**
|
|
210
|
-
* Every ref key one quote seeds: the charge and the net the author named, plus
|
|
211
|
-
* the two the machinery derives to hold the offer itself. One derivation, read
|
|
212
|
-
* by the validator, the compiler, and the runtime alike.
|
|
213
|
-
*/
|
|
214
|
-
export function quoteSeededRefKeys(quote) {
|
|
215
|
-
return [
|
|
216
|
-
quote.chargeRef,
|
|
217
|
-
quote.netRef,
|
|
218
|
-
quoteExpiresAtRefKey(quote),
|
|
219
|
-
quoteFrozenRefKey(quote),
|
|
220
|
-
];
|
|
221
|
-
}
|
|
222
|
-
const udlDecisionSchema = z.strictObject({
|
|
223
|
-
capability: udlProviderFamilyIdSchema,
|
|
224
|
-
deadlineMs: z.number().int().positive().max(15_000),
|
|
225
|
-
// A decision that never came back is not an approval. `approve` would let a
|
|
226
|
-
// document release money because a counterparty went quiet, so the grammar
|
|
227
|
-
// admits only the fail-closed answer. Every published document already
|
|
228
|
-
// writes `decline`; widening later is additive, narrowing later would not
|
|
229
|
-
// be.
|
|
230
|
-
onTimeout: z.literal("decline"),
|
|
231
|
-
});
|
|
232
|
-
const udlAggregateCheckSchema = z.discriminatedUnion("kind", [
|
|
42
|
+
const referenceField = z.strictObject({
|
|
43
|
+
...fieldBase,
|
|
44
|
+
type: z.literal("ref"),
|
|
45
|
+
targetKind: z.enum(["instrument", "object"]),
|
|
46
|
+
targetFamily: udlFamilySchema.optional(),
|
|
47
|
+
target: z.union([name, z.array(name).min(1).max(16)]),
|
|
48
|
+
});
|
|
49
|
+
const listField = z.strictObject({
|
|
50
|
+
...fieldBase,
|
|
51
|
+
type: z.literal("list"),
|
|
52
|
+
item: z.enum(["money", "date", "text", "integer", "ref"]),
|
|
53
|
+
targetKind: z.enum(["instrument", "object"]).optional(),
|
|
54
|
+
targetFamily: udlFamilySchema.optional(),
|
|
55
|
+
target: name.optional(),
|
|
56
|
+
maxItems: integer.min(1).max(366),
|
|
57
|
+
});
|
|
58
|
+
export const udlFieldSchema = z.discriminatedUnion("type", [
|
|
233
59
|
z.strictObject({
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
60
|
+
...fieldBase,
|
|
61
|
+
type: z.literal("money"),
|
|
62
|
+
value: amount.optional(),
|
|
63
|
+
minimum: amount.optional(),
|
|
64
|
+
maximum: amount.optional(),
|
|
237
65
|
}),
|
|
238
66
|
z.strictObject({
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
67
|
+
...fieldBase,
|
|
68
|
+
type: z.literal("account"),
|
|
69
|
+
owner: z.union([name, z.strictObject({ adapter: name })]),
|
|
70
|
+
key: name.optional(),
|
|
71
|
+
book: z.enum(["cash", "claim"]).default("cash"),
|
|
72
|
+
contra: z.literal(true).optional(),
|
|
73
|
+
}),
|
|
74
|
+
referenceField,
|
|
75
|
+
z.strictObject({
|
|
76
|
+
...fieldBase,
|
|
77
|
+
type: z.literal("date"),
|
|
78
|
+
value: z.iso.datetime({ offset: true }).optional(),
|
|
79
|
+
}),
|
|
80
|
+
z.strictObject({
|
|
81
|
+
...fieldBase,
|
|
82
|
+
type: z.literal("duration"),
|
|
83
|
+
value: integer.positive().optional(),
|
|
84
|
+
}),
|
|
85
|
+
z.strictObject({
|
|
86
|
+
...fieldBase,
|
|
87
|
+
type: z.literal("text"),
|
|
88
|
+
value: text.optional(),
|
|
89
|
+
minLength: integer.positive().max(2048).optional(),
|
|
90
|
+
maxLength: integer.positive().max(2048).optional(),
|
|
91
|
+
// One anchored ASCII character class and a fixed repetition. No executable patterns.
|
|
92
|
+
pattern: z
|
|
93
|
+
.string()
|
|
94
|
+
.regex(/^\^\[[A-Za-z0-9-]+\]\{[1-9][0-9]{0,3}\}\$$/)
|
|
95
|
+
.optional(),
|
|
242
96
|
}),
|
|
243
97
|
z.strictObject({
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
98
|
+
...fieldBase,
|
|
99
|
+
type: z.literal("integer"),
|
|
100
|
+
value: integer.optional(),
|
|
101
|
+
minimum: integer.optional(),
|
|
102
|
+
maximum: integer.optional(),
|
|
247
103
|
}),
|
|
248
|
-
// Siblings summed against a cap read from the LOCKED anchor row's
|
|
249
|
-
// machinery-seeded ref (never a stored field on the counted rows).
|
|
250
104
|
z.strictObject({
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
105
|
+
...fieldBase,
|
|
106
|
+
type: z.literal("percent"),
|
|
107
|
+
value: integer.min(0).max(10000).optional(),
|
|
254
108
|
}),
|
|
255
109
|
z.strictObject({
|
|
256
|
-
|
|
257
|
-
|
|
110
|
+
...fieldBase,
|
|
111
|
+
type: z.literal("boolean"),
|
|
112
|
+
value: z.boolean().optional(),
|
|
258
113
|
}),
|
|
259
|
-
z.strictObject({ kind: z.literal("all_in") }),
|
|
260
114
|
z.strictObject({
|
|
261
|
-
|
|
262
|
-
|
|
115
|
+
...fieldBase,
|
|
116
|
+
type: z.literal("enum"),
|
|
117
|
+
values: z.array(name).min(1).max(64),
|
|
118
|
+
value: name.optional(),
|
|
263
119
|
}),
|
|
120
|
+
listField,
|
|
264
121
|
]);
|
|
265
|
-
const
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
const
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
122
|
+
const [moneyField, , refField, dateField, durationField, textField, integerField, percentField, booleanField, enumField, boundedListField,] = udlFieldSchema.options;
|
|
123
|
+
export const udlObjectFieldSchema = z.discriminatedUnion("type", [
|
|
124
|
+
moneyField,
|
|
125
|
+
refField,
|
|
126
|
+
dateField,
|
|
127
|
+
durationField,
|
|
128
|
+
textField,
|
|
129
|
+
integerField,
|
|
130
|
+
percentField,
|
|
131
|
+
booleanField,
|
|
132
|
+
enumField,
|
|
133
|
+
boundedListField,
|
|
134
|
+
]);
|
|
135
|
+
/** Values are constants or resolved typed paths, never executable strings. */
|
|
136
|
+
export const udlValueSchema = z.union([
|
|
137
|
+
z.strictObject({ literal: scalar }),
|
|
138
|
+
z.strictObject({ field: path }),
|
|
139
|
+
]);
|
|
140
|
+
const value = udlValueSchema;
|
|
141
|
+
const comparisonRequirement = z.strictObject({
|
|
142
|
+
kind: z.literal("compare"),
|
|
143
|
+
left: value,
|
|
144
|
+
operator: z.enum(["==", "!=", "<", "<=", ">", ">="]),
|
|
145
|
+
right: value,
|
|
146
|
+
});
|
|
147
|
+
// Alternatives are OR; each invocation path is a conjunction of scoped guards.
|
|
148
|
+
export const udlSubjectConditionsSchema = z
|
|
149
|
+
.array(z
|
|
150
|
+
.array(z.strictObject({
|
|
151
|
+
instrument: instrumentId,
|
|
152
|
+
action: name,
|
|
153
|
+
guard: comparisonRequirement,
|
|
154
|
+
valueType: z.enum(["money", "date"]).optional(),
|
|
155
|
+
}))
|
|
156
|
+
.min(1)
|
|
157
|
+
.max(32))
|
|
158
|
+
.min(1)
|
|
159
|
+
.max(128);
|
|
160
|
+
export const udlSubjectRequirementSchema = z.strictObject({
|
|
161
|
+
field: udlObjectFieldSchema,
|
|
162
|
+
// Present only for an authored rename.
|
|
163
|
+
objectField: name.optional(),
|
|
164
|
+
when: udlSubjectConditionsSchema.optional(),
|
|
165
|
+
});
|
|
166
|
+
export const adapterSubjectSnapshotSchema = z.strictObject({
|
|
167
|
+
provider: text,
|
|
168
|
+
capability: text,
|
|
169
|
+
operation: text,
|
|
170
|
+
declarationDigest: z.string().regex(/^[a-f0-9]{64}$/),
|
|
171
|
+
requirements: z.array(udlObjectFieldSchema).max(128),
|
|
172
|
+
});
|
|
173
|
+
export const udlActionSubjectSchema = z.strictObject({
|
|
174
|
+
requirements: z.array(udlSubjectRequirementSchema).max(128),
|
|
175
|
+
adapters: z
|
|
176
|
+
.array(z.strictObject({
|
|
177
|
+
binding: name,
|
|
178
|
+
// null means unavailable, never "no requirements".
|
|
179
|
+
snapshot: adapterSubjectSnapshotSchema.nullable(),
|
|
180
|
+
renames: z.record(name, name).optional(),
|
|
181
|
+
}))
|
|
182
|
+
.max(16),
|
|
183
|
+
});
|
|
184
|
+
export const subjectPartyRoles = ["owner", "actor", "operator"];
|
|
185
|
+
export const attachmentPartyBindingSchema = z.union([
|
|
186
|
+
z.strictObject({ role: z.enum(subjectPartyRoles) }),
|
|
187
|
+
z.strictObject({ party: name }),
|
|
188
|
+
]);
|
|
189
|
+
export const udlObjectAttachmentSchema = z.strictObject({
|
|
190
|
+
name,
|
|
191
|
+
title: text.optional(),
|
|
192
|
+
parent: name.optional(),
|
|
193
|
+
instrument: instrumentId,
|
|
194
|
+
parties: z.record(name, attachmentPartyBindingSchema),
|
|
195
|
+
});
|
|
196
|
+
export const udlObjectKindSchema = z.strictObject({
|
|
197
|
+
entryActions: z.array(name).min(1).max(128).optional(),
|
|
198
|
+
id: objectKindId,
|
|
199
|
+
title: text,
|
|
200
|
+
authoredFields: z.array(name).max(256),
|
|
201
|
+
attachments: z.array(udlObjectAttachmentSchema).max(256),
|
|
202
|
+
fields: z.array(udlObjectFieldSchema).max(256),
|
|
203
|
+
columns: z.array(name).max(8),
|
|
204
|
+
});
|
|
205
|
+
const values = z.array(value).min(1).max(256);
|
|
206
|
+
const selection = z.strictObject({
|
|
207
|
+
family: udlFamilySchema.optional(),
|
|
208
|
+
instrument: z.union([instrumentId, z.array(instrumentId).min(1).max(16)]),
|
|
209
|
+
reference: name,
|
|
210
|
+
anchor: path,
|
|
211
|
+
states: z.array(name).min(1).max(64),
|
|
212
|
+
limit: integer.min(1).max(366),
|
|
213
|
+
order: z.array(path).min(1).max(4).optional(),
|
|
214
|
+
window: z
|
|
215
|
+
.strictObject({ field: name, milliseconds: integer.positive() })
|
|
216
|
+
.optional(),
|
|
217
|
+
where: z
|
|
218
|
+
.record(path, value)
|
|
219
|
+
.refine((filters) => Object.keys(filters).length <= 8, "at most eight selection filters")
|
|
220
|
+
.meta({ maxProperties: 8 })
|
|
221
|
+
.optional(),
|
|
296
222
|
});
|
|
297
|
-
/**
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
*/
|
|
305
|
-
const udlReconcileSchema = z.strictObject({
|
|
306
|
-
/** `fields.<name>` or `refs.<name>`: the money this action says will land. */
|
|
307
|
-
amount: instanceValuePathSchema,
|
|
308
|
-
/** Where the matched evidence id lands in refs. */
|
|
309
|
-
capture: udlFieldNameSchema,
|
|
310
|
-
/** The ref naming the provider-side row the evidence must cite. */
|
|
311
|
-
counterpartyRef: udlFieldNameSchema,
|
|
312
|
-
currencyField: udlFieldNameSchema,
|
|
313
|
-
direction: z.enum(["credit", "debit"]),
|
|
314
|
-
/** Exactly one source. A reconcile never reads two ledgers at once. */
|
|
315
|
-
evidence: z.enum(["movement", "provider_confirmation", "statement_line"]),
|
|
316
|
-
/**
|
|
317
|
-
* Where an expectation that never matched lands. The named child instrument
|
|
318
|
-
* carries the break, and `maxOpen` caps how many of them one instance may
|
|
319
|
-
* hold open at once, the same count measure the aggregate invariants use.
|
|
320
|
-
*/
|
|
321
|
-
exception: z.strictObject({
|
|
322
|
-
amountField: udlFieldNameSchema,
|
|
323
|
-
childInstrumentId: udlSnakeCaseSchema,
|
|
324
|
-
maxOpen: z.number().int().min(1).max(1_000),
|
|
325
|
-
reasonField: udlFieldNameSchema,
|
|
326
|
-
refField: udlFieldNameSchema,
|
|
223
|
+
/** A finite, ordered calculation graph. Every result is a declared field. */
|
|
224
|
+
export const udlCalculationSchema = z.discriminatedUnion("op", [
|
|
225
|
+
z.strictObject({
|
|
226
|
+
target: name,
|
|
227
|
+
op: z.literal("at"),
|
|
228
|
+
list: path,
|
|
229
|
+
position: value,
|
|
327
230
|
}),
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
match: z.discriminatedUnion("law", [
|
|
334
|
-
z.strictObject({ law: z.literal("exact") }),
|
|
335
|
-
z.strictObject({
|
|
336
|
-
dial: udlSnakeCaseSchema,
|
|
337
|
-
law: z.literal("tolerance"),
|
|
338
|
-
minorUnits: z.number().int().positive(),
|
|
339
|
-
}),
|
|
340
|
-
z.strictObject({ law: z.literal("window") }),
|
|
341
|
-
]),
|
|
342
|
-
/** Fixed ISO-8601 duration from the expecting action, or a stored deadline. */
|
|
343
|
-
within: z.union([
|
|
344
|
-
z.strictObject({ field: udlFieldNameSchema }),
|
|
345
|
-
z.strictObject({ offset: nonEmptyTextSchema }),
|
|
346
|
-
]),
|
|
347
|
-
});
|
|
348
|
-
const udlSignedSumSourceSchema = z.strictObject({
|
|
349
|
-
amountField: udlFieldNameSchema,
|
|
350
|
-
instrumentId: udlSnakeCaseSchema,
|
|
351
|
-
refField: udlFieldNameSchema,
|
|
352
|
-
sign: z.enum(["add", "subtract"]),
|
|
353
|
-
statuses: z.array(udlSnakeCaseSchema).min(1),
|
|
354
|
-
subtotalRef: udlFieldNameSchema,
|
|
355
|
-
});
|
|
356
|
-
const udlSignedSumSchema = z.strictObject({
|
|
357
|
-
amountRef: udlFieldNameSchema,
|
|
358
|
-
onNegative: z.literal("refuse"),
|
|
359
|
-
onZero: z.enum(["refuse", "skip_steps"]),
|
|
360
|
-
sources: z.array(udlSignedSumSourceSchema).min(1),
|
|
361
|
-
});
|
|
362
|
-
const udlDistributeSchema = z.strictObject({
|
|
363
|
-
amountRef: udlFieldNameSchema,
|
|
364
|
-
onZero: z.enum(["refuse", "skip_steps"]),
|
|
365
|
-
pool: z.strictObject({
|
|
366
|
-
from: z.literal("parent"),
|
|
367
|
-
path: fieldPathSchema,
|
|
231
|
+
z.strictObject({
|
|
232
|
+
target: name,
|
|
233
|
+
op: z.literal("aggregate"),
|
|
234
|
+
selection,
|
|
235
|
+
measure: z.union([z.literal("count"), z.strictObject({ sum: path })]),
|
|
368
236
|
}),
|
|
369
|
-
refField: udlFieldNameSchema,
|
|
370
|
-
statuses: z.array(udlSnakeCaseSchema).min(1),
|
|
371
|
-
weightField: udlFieldNameSchema,
|
|
372
|
-
});
|
|
373
|
-
const udlRemainderCollectedSchema = z.strictObject({
|
|
374
|
-
amountField: udlFieldNameSchema,
|
|
375
|
-
instrumentId: udlSnakeCaseSchema,
|
|
376
|
-
path: z.literal("refs").optional(),
|
|
377
|
-
refField: udlFieldNameSchema,
|
|
378
|
-
statuses: z.array(udlSnakeCaseSchema).min(1),
|
|
379
|
-
});
|
|
380
|
-
const udlRemainderSchema = z.strictObject({
|
|
381
|
-
accumulateRef: udlFieldNameSchema.optional(),
|
|
382
|
-
amountRef: udlFieldNameSchema,
|
|
383
|
-
collected: z.array(udlRemainderCollectedSchema).optional(),
|
|
384
|
-
inputKey: udlFieldNameSchema.optional(),
|
|
385
|
-
onZero: z.enum(["refuse", "skip_steps"]),
|
|
386
|
-
totalPath: instanceValuePathSchema,
|
|
387
|
-
});
|
|
388
|
-
const udlCheckRequirementVariants = udlCheckEvidenceProfiles.map((profile) => z.strictObject({
|
|
389
|
-
checkKind: z.literal(profile.checkKind),
|
|
390
|
-
family: z.literal(profile.family),
|
|
391
|
-
maxAge: nonEmptyTextSchema.optional(),
|
|
392
|
-
statuses: z.array(z.enum(profile.statuses)).min(1),
|
|
393
|
-
subjectField: udlFieldNameSchema,
|
|
394
|
-
}));
|
|
395
|
-
const udlCheckRequirementSchema = z.union(udlCheckRequirementVariants);
|
|
396
|
-
const udlDialSchema = z.discriminatedUnion("kind", [
|
|
397
237
|
z.strictObject({
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
238
|
+
target: name,
|
|
239
|
+
op: z.literal("ratio"),
|
|
240
|
+
amount: value,
|
|
241
|
+
numerator: value,
|
|
242
|
+
denominator: value,
|
|
243
|
+
rounding: z.literal("floor"),
|
|
244
|
+
}),
|
|
245
|
+
z.strictObject({ target: name, op: z.literal("sum"), values }),
|
|
246
|
+
z.strictObject({
|
|
247
|
+
target: name,
|
|
248
|
+
op: z.literal("subtract"),
|
|
249
|
+
base: value,
|
|
250
|
+
subtract: values,
|
|
405
251
|
}),
|
|
406
252
|
z.strictObject({
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
summary: nonEmptyTextSchema,
|
|
413
|
-
title: nonEmptyTextSchema,
|
|
253
|
+
target: name,
|
|
254
|
+
op: z.literal("rate"),
|
|
255
|
+
base: value,
|
|
256
|
+
bps: value,
|
|
257
|
+
rounding: z.literal("floor"),
|
|
414
258
|
}),
|
|
259
|
+
z.strictObject({ target: name, op: z.literal("minimum"), values }),
|
|
415
260
|
z.strictObject({
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
summary: nonEmptyTextSchema,
|
|
421
|
-
title: nonEmptyTextSchema,
|
|
261
|
+
target: name,
|
|
262
|
+
op: z.literal("multiply"),
|
|
263
|
+
amount: value,
|
|
264
|
+
units: value,
|
|
422
265
|
}),
|
|
423
266
|
z.strictObject({
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
267
|
+
target: name,
|
|
268
|
+
op: z.literal("divide"),
|
|
269
|
+
amount: value,
|
|
270
|
+
divisor: value,
|
|
271
|
+
rounding: z.literal("floor"),
|
|
272
|
+
}),
|
|
273
|
+
z.strictObject({
|
|
274
|
+
target: name,
|
|
275
|
+
op: z.literal("shift"),
|
|
276
|
+
date: value,
|
|
277
|
+
milliseconds: value,
|
|
278
|
+
direction: z.enum(["before", "after"]),
|
|
428
279
|
}),
|
|
429
280
|
]);
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
title: nonEmptyTextSchema,
|
|
444
|
-
});
|
|
445
|
-
const udlPartitionSchema = z.strictObject({
|
|
446
|
-
pieceFields: z.array(udlFieldNameSchema).min(2),
|
|
447
|
-
totalField: udlFieldNameSchema,
|
|
448
|
-
});
|
|
449
|
-
const udlDerivedAmountSchema = z.strictObject({
|
|
450
|
-
field: udlFieldNameSchema,
|
|
451
|
-
rounding: z.literal("floor"),
|
|
452
|
-
rule: z.strictObject({
|
|
453
|
-
bps: z.number().int().min(1).max(9_999),
|
|
454
|
-
kind: z.literal("percentage_of"),
|
|
281
|
+
export const udlRequirementSchema = z.discriminatedUnion("kind", [
|
|
282
|
+
z.strictObject({
|
|
283
|
+
kind: z.literal("hours"),
|
|
284
|
+
at: path,
|
|
285
|
+
start: integer.min(0).max(23),
|
|
286
|
+
end: integer.min(0).max(23),
|
|
287
|
+
timezone: text,
|
|
288
|
+
}),
|
|
289
|
+
comparisonRequirement,
|
|
290
|
+
z.strictObject({
|
|
291
|
+
kind: z.literal("state"),
|
|
292
|
+
reference: path,
|
|
293
|
+
states: z.array(name).min(1).max(64),
|
|
455
294
|
}),
|
|
456
|
-
sourceField: udlFieldNameSchema,
|
|
457
|
-
});
|
|
458
|
-
const udlFeeLeafRuleSchema = z.discriminatedUnion("kind", [
|
|
459
295
|
z.strictObject({
|
|
460
|
-
|
|
461
|
-
|
|
296
|
+
kind: z.literal("unique"),
|
|
297
|
+
namespace: name,
|
|
298
|
+
fields: z.array(path).min(1).max(8),
|
|
462
299
|
}),
|
|
463
300
|
z.strictObject({
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
301
|
+
kind: z.literal("aggregate"),
|
|
302
|
+
selection,
|
|
303
|
+
measure: z.union([z.literal("count"), z.strictObject({ sum: path })]),
|
|
304
|
+
operator: z.enum(["==", "<=", ">=", "<", ">"]),
|
|
305
|
+
value,
|
|
306
|
+
}),
|
|
307
|
+
z.strictObject({
|
|
308
|
+
kind: z.literal("evidence"),
|
|
309
|
+
instruction: path.optional(),
|
|
310
|
+
subject: path,
|
|
311
|
+
family: name,
|
|
312
|
+
check: name,
|
|
313
|
+
result: name,
|
|
314
|
+
maxAge: integer.positive(),
|
|
467
315
|
}),
|
|
468
316
|
]);
|
|
469
|
-
const
|
|
470
|
-
.
|
|
471
|
-
.
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
fromInclusive: nonNegativeDecimalIntegerSchema,
|
|
484
|
-
rule: udlFeeLeafRuleSchema,
|
|
485
|
-
toExclusive: nonNegativeDecimalIntegerSchema.optional(),
|
|
486
|
-
}))
|
|
487
|
-
.min(1)
|
|
488
|
-
.max(16),
|
|
489
|
-
}),
|
|
317
|
+
export const udlKernelOperationSchema = z.enum([
|
|
318
|
+
"internal_transfer.create",
|
|
319
|
+
"internal_transfer.reserve",
|
|
320
|
+
"internal_transfer.post",
|
|
321
|
+
"internal_transfer.void",
|
|
322
|
+
]);
|
|
323
|
+
const moveEconomics = z.strictObject({
|
|
324
|
+
purpose: z.enum([
|
|
325
|
+
"earning",
|
|
326
|
+
"principal",
|
|
327
|
+
"participant_payout",
|
|
328
|
+
"internal",
|
|
329
|
+
"prepaid_credit",
|
|
330
|
+
"pass_through",
|
|
490
331
|
]),
|
|
332
|
+
sourceParty: name,
|
|
333
|
+
reversalOf: path.optional(),
|
|
491
334
|
});
|
|
492
|
-
const
|
|
493
|
-
boundField: udlFieldNameSchema,
|
|
494
|
-
field: udlFieldNameSchema,
|
|
495
|
-
remainderAction: udlActionNameSchema,
|
|
496
|
-
});
|
|
497
|
-
const udlEffectRowSchema = z.strictObject({
|
|
498
|
-
signature: nonEmptyTextSchema,
|
|
499
|
-
source: nonEmptyTextSchema,
|
|
500
|
-
});
|
|
501
|
-
const udlNotifyEffectSchema = z.strictObject({
|
|
502
|
-
channel: udlSnakeCaseSchema,
|
|
503
|
-
role: udlSnakeCaseSchema,
|
|
504
|
-
signature: nonEmptyTextSchema,
|
|
505
|
-
source: nonEmptyTextSchema,
|
|
506
|
-
});
|
|
507
|
-
const udlEffectsShape = {
|
|
508
|
-
decides: z.array(udlEffectRowSchema).min(1).optional(),
|
|
509
|
-
holds: z.array(udlEffectRowSchema).min(1).optional(),
|
|
510
|
-
moves: z.array(udlEffectRowSchema).min(1).optional(),
|
|
511
|
-
notifies: z.array(udlNotifyEffectSchema).min(1).optional(),
|
|
512
|
-
reads: z.array(udlEffectRowSchema).min(1).optional(),
|
|
513
|
-
schedules: z.array(udlEffectRowSchema).min(1).optional(),
|
|
514
|
-
};
|
|
515
|
-
const udlEffectsSchema = z.strictObject(udlEffectsShape);
|
|
516
|
-
const udlActionShape = {
|
|
517
|
-
agentDescription: udlAgentDescriptionSchema.optional(),
|
|
518
|
-
captureInput: z.record(udlFieldNameSchema, udlFieldNameSchema).optional(),
|
|
519
|
-
/** Names the quoting action whose offer this action spends. */
|
|
520
|
-
commit: udlActionNameSchema.optional(),
|
|
521
|
-
decidedAmount: udlDecidedAmountSchema.optional(),
|
|
522
|
-
deadline: udlDeadlineSchema.optional(),
|
|
523
|
-
decision: udlDecisionSchema.optional(),
|
|
524
|
-
distribute: udlDistributeSchema.optional(),
|
|
525
|
-
description: nonEmptyTextSchema.optional(),
|
|
526
|
-
due: udlDueSchema.optional(),
|
|
527
|
-
earnable: z.boolean().optional(),
|
|
528
|
-
effects: udlEffectsSchema.optional(),
|
|
529
|
-
eventName: z.string().regex(eventNamePattern).optional(),
|
|
530
|
-
examples: z.array(udlExampleSchema).min(1).optional(),
|
|
531
|
-
input: jsonObjectSchema.optional(),
|
|
532
|
-
moves: z.array(udlMoveSchema).default([]),
|
|
533
|
-
payout: udlPayoutSchema.optional(),
|
|
534
|
-
port: udlPortSchema.optional(),
|
|
535
|
-
quote: udlQuoteSchema.optional(),
|
|
536
|
-
publicAction: udlPublicActionSchema
|
|
537
|
-
.optional()
|
|
538
|
-
.describe("Author-approved public action name; the containing action key remains the lifecycle and execution identity"),
|
|
539
|
-
principal: z.literal("user_session").optional(),
|
|
540
|
-
reconcile: z.array(udlReconcileSchema).min(1).optional(),
|
|
541
|
-
remainder: udlRemainderSchema.optional(),
|
|
542
|
-
requiresAggregate: z.array(udlAggregateConditionSchema).min(1).optional(),
|
|
543
|
-
requiresChecks: z.array(udlCheckRequirementSchema).optional(),
|
|
544
|
-
requiresDrainedAccount: z.strictObject({ path: fieldPathSchema }).optional(),
|
|
545
|
-
requiresExposure: z.array(udlExposureRequirementSchema).min(1).optional(),
|
|
546
|
-
requiresRefs: z.array(udlGateSchema).min(1).optional(),
|
|
547
|
-
sandboxFailurePoint: z.enum(["funding", "release"]).optional(),
|
|
548
|
-
setsAt: udlSetsAtSchema.optional(),
|
|
549
|
-
signedSum: udlSignedSumSchema.optional(),
|
|
550
|
-
steps: z.array(udlStepSchema),
|
|
551
|
-
summary: nonEmptyTextSchema,
|
|
552
|
-
updates: z.array(udlFieldNameSchema).min(1).optional(),
|
|
553
|
-
};
|
|
554
|
-
const udlActionSchema = z.strictObject(udlActionShape);
|
|
555
|
-
const udlAggregateBaseShape = {
|
|
556
|
-
childInstrumentId: udlSnakeCaseSchema,
|
|
557
|
-
childRefField: udlFieldNameSchema,
|
|
558
|
-
childStatuses: z.array(udlSnakeCaseSchema).min(1),
|
|
559
|
-
parentField: udlFieldNameSchema,
|
|
560
|
-
};
|
|
561
|
-
// Two measures, mutually exclusive by strictness: a sum cap over a child money
|
|
562
|
-
// field, or a count cap (optionally windowed to the rolling `days` ending at
|
|
563
|
-
// the child's own as-written date-time value).
|
|
564
|
-
const udlAggregateSchema = z.union([
|
|
335
|
+
export const udlMoveSchema = z.discriminatedUnion("operation", [
|
|
565
336
|
z.strictObject({
|
|
566
|
-
|
|
567
|
-
|
|
337
|
+
key: name,
|
|
338
|
+
operation: z.literal("internal_transfer.create"),
|
|
339
|
+
economics: moveEconomics.optional(),
|
|
340
|
+
capture: name.optional(),
|
|
341
|
+
amount: value,
|
|
342
|
+
from: path,
|
|
343
|
+
to: path,
|
|
568
344
|
}),
|
|
569
345
|
z.strictObject({
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
346
|
+
key: name,
|
|
347
|
+
operation: z.literal("internal_transfer.reserve"),
|
|
348
|
+
economics: moveEconomics.optional(),
|
|
349
|
+
boundary: z.strictObject({ adapter: name }).optional(),
|
|
350
|
+
amount: value,
|
|
351
|
+
from: path,
|
|
352
|
+
to: path,
|
|
353
|
+
capture: name,
|
|
354
|
+
}),
|
|
355
|
+
z.strictObject({
|
|
356
|
+
key: name,
|
|
357
|
+
operation: z.literal("internal_transfer.post"),
|
|
358
|
+
economics: moveEconomics.optional(),
|
|
359
|
+
capture: name.optional(),
|
|
360
|
+
transfer: path,
|
|
361
|
+
}),
|
|
362
|
+
z.strictObject({
|
|
363
|
+
key: name,
|
|
364
|
+
operation: z.literal("internal_transfer.void"),
|
|
365
|
+
economics: moveEconomics.optional(),
|
|
366
|
+
capture: name.optional(),
|
|
367
|
+
transfer: path,
|
|
578
368
|
}),
|
|
579
369
|
]);
|
|
580
|
-
const
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
.
|
|
370
|
+
const clock = z.strictObject({
|
|
371
|
+
at: path,
|
|
372
|
+
offset: integer.optional(),
|
|
373
|
+
localDay: z
|
|
374
|
+
.strictObject({
|
|
375
|
+
days: integer.min(0).max(366),
|
|
376
|
+
direction: z.enum(["before", "after"]),
|
|
377
|
+
hour: integer.min(0).max(23),
|
|
378
|
+
timezone: text,
|
|
379
|
+
})
|
|
586
380
|
.optional(),
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
.regex(idPrefixPattern, "must contain 2 to 8 lowercase letters"),
|
|
597
|
-
lifecycle: udlLifecycleSchema,
|
|
598
|
-
nav: z.array(nonEmptyTextSchema).min(1).optional(),
|
|
599
|
-
parties: z
|
|
381
|
+
});
|
|
382
|
+
export const udlActionSchema = z.strictObject({
|
|
383
|
+
allowZero: z.literal(true).optional(),
|
|
384
|
+
purpose: z.enum(["obligation", "option"]).optional(),
|
|
385
|
+
summary: text,
|
|
386
|
+
title: text.optional(),
|
|
387
|
+
publicAction: name.optional(),
|
|
388
|
+
expansionLimit: z.literal(8192).optional(),
|
|
389
|
+
reminder: z
|
|
600
390
|
.strictObject({
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
391
|
+
installment: path,
|
|
392
|
+
recipient: path,
|
|
393
|
+
dueAt: path,
|
|
394
|
+
channel: z.literal("email"),
|
|
395
|
+
template: z.literal("payment_reminder"),
|
|
396
|
+
beforeDays: integer.min(0).max(366),
|
|
397
|
+
overdueDays: integer.min(1).max(366),
|
|
398
|
+
maxPerDay: integer.min(1).max(10),
|
|
399
|
+
startHour: integer.min(0).max(23),
|
|
400
|
+
endHour: integer.min(1).max(24),
|
|
401
|
+
timezone: text,
|
|
604
402
|
})
|
|
605
403
|
.optional(),
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
linearOutputs: ["netRef"],
|
|
654
|
-
scope: "action",
|
|
655
|
-
spelling: "quote",
|
|
656
|
-
target: "quote",
|
|
657
|
-
},
|
|
658
|
-
{
|
|
659
|
-
cardinality: "one",
|
|
660
|
-
linearOutputs: ["field"],
|
|
661
|
-
scope: "action",
|
|
662
|
-
spelling: "decided amount",
|
|
663
|
-
target: "decidedAmount",
|
|
664
|
-
},
|
|
665
|
-
{
|
|
666
|
-
cardinality: "one",
|
|
667
|
-
effects: [
|
|
668
|
-
{
|
|
669
|
-
kind: "schedules",
|
|
670
|
-
per: "clause",
|
|
671
|
-
signature: { fixed: "deadline" },
|
|
672
|
-
},
|
|
673
|
-
],
|
|
674
|
-
scope: "action",
|
|
675
|
-
spelling: "deadline",
|
|
676
|
-
target: "deadline",
|
|
677
|
-
},
|
|
678
|
-
{
|
|
679
|
-
cardinality: "one",
|
|
680
|
-
effects: [
|
|
681
|
-
{
|
|
682
|
-
kind: "decides",
|
|
683
|
-
per: "clause",
|
|
684
|
-
signature: { fromField: "capability" },
|
|
685
|
-
},
|
|
686
|
-
],
|
|
687
|
-
scope: "action",
|
|
688
|
-
spelling: "decision",
|
|
689
|
-
target: "decision",
|
|
690
|
-
},
|
|
691
|
-
{
|
|
692
|
-
cardinality: "one",
|
|
693
|
-
linearOutputs: ["amountRef"],
|
|
694
|
-
scope: "action",
|
|
695
|
-
spelling: "computes distribute",
|
|
696
|
-
target: "distribute",
|
|
697
|
-
},
|
|
698
|
-
{
|
|
699
|
-
cardinality: "one",
|
|
700
|
-
scope: "action",
|
|
701
|
-
spelling: "description",
|
|
702
|
-
target: "description",
|
|
703
|
-
},
|
|
704
|
-
{
|
|
705
|
-
cardinality: "one",
|
|
706
|
-
effects: [
|
|
707
|
-
{
|
|
708
|
-
kind: "schedules",
|
|
709
|
-
per: "clause",
|
|
710
|
-
signature: { fixed: "due" },
|
|
711
|
-
},
|
|
712
|
-
],
|
|
713
|
-
scope: "action",
|
|
714
|
-
spelling: "due",
|
|
715
|
-
target: "due",
|
|
716
|
-
},
|
|
717
|
-
{
|
|
718
|
-
cardinality: "one",
|
|
719
|
-
scope: "action",
|
|
720
|
-
spelling: "earnable",
|
|
721
|
-
target: "earnable",
|
|
722
|
-
},
|
|
723
|
-
{
|
|
724
|
-
cardinality: "one",
|
|
725
|
-
scope: "action",
|
|
726
|
-
spelling: "event name",
|
|
727
|
-
target: "eventName",
|
|
728
|
-
},
|
|
729
|
-
{
|
|
730
|
-
cardinality: "many",
|
|
731
|
-
scope: "action",
|
|
732
|
-
spelling: "examples",
|
|
733
|
-
target: "examples",
|
|
734
|
-
},
|
|
735
|
-
{
|
|
736
|
-
cardinality: "one",
|
|
737
|
-
scope: "action",
|
|
738
|
-
spelling: "input",
|
|
739
|
-
target: "input",
|
|
740
|
-
},
|
|
741
|
-
{
|
|
742
|
-
cardinality: "many",
|
|
743
|
-
effects: [
|
|
744
|
-
{
|
|
745
|
-
kind: "moves",
|
|
746
|
-
per: "element",
|
|
747
|
-
signature: { movementClass: true },
|
|
748
|
-
},
|
|
749
|
-
{
|
|
750
|
-
kind: "holds",
|
|
751
|
-
per: "element",
|
|
752
|
-
signature: { fixed: "reserve" },
|
|
753
|
-
},
|
|
754
|
-
],
|
|
755
|
-
linearSink: true,
|
|
756
|
-
scope: "action",
|
|
757
|
-
spelling: "moves",
|
|
758
|
-
target: "moves",
|
|
759
|
-
},
|
|
760
|
-
{
|
|
761
|
-
cardinality: "one",
|
|
762
|
-
effects: [
|
|
763
|
-
{
|
|
764
|
-
kind: "moves",
|
|
765
|
-
per: "clause",
|
|
766
|
-
signature: { fixed: "payout.external" },
|
|
767
|
-
},
|
|
768
|
-
],
|
|
769
|
-
linearSink: true,
|
|
770
|
-
scope: "action",
|
|
771
|
-
spelling: "payout",
|
|
772
|
-
target: "payout",
|
|
773
|
-
},
|
|
774
|
-
{
|
|
775
|
-
cardinality: "one",
|
|
776
|
-
effects: [
|
|
777
|
-
{
|
|
778
|
-
kind: "decides",
|
|
779
|
-
per: "clause",
|
|
780
|
-
signature: { fixed: "tenant_port" },
|
|
781
|
-
},
|
|
782
|
-
],
|
|
783
|
-
scope: "action",
|
|
784
|
-
spelling: "port",
|
|
785
|
-
target: "port",
|
|
786
|
-
},
|
|
787
|
-
{
|
|
788
|
-
cardinality: "one",
|
|
789
|
-
scope: "action",
|
|
790
|
-
spelling: "principal",
|
|
791
|
-
target: "principal",
|
|
792
|
-
},
|
|
793
|
-
{
|
|
794
|
-
cardinality: "one",
|
|
795
|
-
scope: "action",
|
|
796
|
-
spelling: "public action",
|
|
797
|
-
target: "publicAction",
|
|
798
|
-
},
|
|
799
|
-
{
|
|
800
|
-
cardinality: "many",
|
|
801
|
-
effects: [
|
|
802
|
-
{
|
|
803
|
-
kind: "reads",
|
|
804
|
-
per: "element",
|
|
805
|
-
signature: { fixed: "reconcile" },
|
|
806
|
-
},
|
|
807
|
-
],
|
|
808
|
-
scope: "action",
|
|
809
|
-
spelling: "reconcile",
|
|
810
|
-
target: "reconcile",
|
|
811
|
-
},
|
|
812
|
-
{
|
|
813
|
-
cardinality: "one",
|
|
814
|
-
linearOutputs: ["amountRef"],
|
|
815
|
-
scope: "action",
|
|
816
|
-
spelling: "computes remainder",
|
|
817
|
-
target: "remainder",
|
|
818
|
-
},
|
|
819
|
-
{
|
|
820
|
-
cardinality: "many",
|
|
821
|
-
effects: [
|
|
822
|
-
{
|
|
823
|
-
kind: "reads",
|
|
824
|
-
per: "clause",
|
|
825
|
-
signature: { fixed: "requires_aggregate" },
|
|
826
|
-
},
|
|
827
|
-
],
|
|
828
|
-
scope: "action",
|
|
829
|
-
spelling: "requires aggregate",
|
|
830
|
-
target: "requiresAggregate",
|
|
831
|
-
},
|
|
832
|
-
{
|
|
833
|
-
cardinality: "many",
|
|
834
|
-
effects: [
|
|
835
|
-
{
|
|
836
|
-
kind: "reads",
|
|
837
|
-
per: "clause",
|
|
838
|
-
signature: { fixed: "requires_checks" },
|
|
839
|
-
},
|
|
840
|
-
],
|
|
841
|
-
scope: "action",
|
|
842
|
-
spelling: "requires checks",
|
|
843
|
-
target: "requiresChecks",
|
|
844
|
-
},
|
|
845
|
-
{
|
|
846
|
-
cardinality: "one",
|
|
847
|
-
scope: "action",
|
|
848
|
-
spelling: "requires drained",
|
|
849
|
-
target: "requiresDrainedAccount",
|
|
850
|
-
},
|
|
851
|
-
{
|
|
852
|
-
cardinality: "many",
|
|
853
|
-
scope: "action",
|
|
854
|
-
spelling: "requires exposure",
|
|
855
|
-
target: "requiresExposure",
|
|
856
|
-
},
|
|
857
|
-
{
|
|
858
|
-
cardinality: "many",
|
|
859
|
-
effects: [
|
|
860
|
-
{
|
|
861
|
-
kind: "reads",
|
|
862
|
-
per: "clause",
|
|
863
|
-
signature: { fixed: "requires_refs" },
|
|
864
|
-
},
|
|
865
|
-
],
|
|
866
|
-
scope: "action",
|
|
867
|
-
spelling: "requires refs",
|
|
868
|
-
target: "requiresRefs",
|
|
869
|
-
},
|
|
870
|
-
{
|
|
871
|
-
cardinality: "one",
|
|
872
|
-
scope: "action",
|
|
873
|
-
spelling: "sandbox failure point",
|
|
874
|
-
target: "sandboxFailurePoint",
|
|
875
|
-
},
|
|
876
|
-
{
|
|
877
|
-
cardinality: "one",
|
|
878
|
-
scope: "action",
|
|
879
|
-
spelling: "sets at",
|
|
880
|
-
target: "setsAt",
|
|
881
|
-
},
|
|
882
|
-
{
|
|
883
|
-
cardinality: "one",
|
|
884
|
-
linearOutputs: ["amountRef"],
|
|
885
|
-
scope: "action",
|
|
886
|
-
spelling: "computes signed_sum",
|
|
887
|
-
target: "signedSum",
|
|
888
|
-
},
|
|
889
|
-
{
|
|
890
|
-
cardinality: "many",
|
|
891
|
-
linearSink: true,
|
|
892
|
-
scope: "action",
|
|
893
|
-
spelling: "steps",
|
|
894
|
-
target: "steps",
|
|
895
|
-
},
|
|
896
|
-
{
|
|
897
|
-
cardinality: "one",
|
|
898
|
-
scope: "action",
|
|
899
|
-
spelling: "summary",
|
|
900
|
-
target: "summary",
|
|
901
|
-
},
|
|
902
|
-
{
|
|
903
|
-
cardinality: "many",
|
|
904
|
-
scope: "action",
|
|
905
|
-
spelling: "updates",
|
|
906
|
-
target: "updates",
|
|
907
|
-
},
|
|
908
|
-
{
|
|
909
|
-
cardinality: "many",
|
|
910
|
-
effects: [
|
|
911
|
-
{
|
|
912
|
-
kind: "notifies",
|
|
913
|
-
per: "element",
|
|
914
|
-
signature: { fromField: "channel" },
|
|
915
|
-
},
|
|
916
|
-
],
|
|
917
|
-
scope: "action",
|
|
918
|
-
spelling: "notify",
|
|
919
|
-
target: "effects.notifies",
|
|
920
|
-
},
|
|
921
|
-
{
|
|
922
|
-
cardinality: "one",
|
|
923
|
-
scope: "instrument",
|
|
924
|
-
spelling: "agent description",
|
|
925
|
-
target: "agentDescription",
|
|
926
|
-
},
|
|
927
|
-
{
|
|
928
|
-
cardinality: "many",
|
|
929
|
-
scope: "instrument",
|
|
930
|
-
spelling: "aggregate invariants",
|
|
931
|
-
target: "aggregateInvariants",
|
|
932
|
-
},
|
|
933
|
-
{
|
|
934
|
-
cardinality: "one",
|
|
935
|
-
scope: "instrument",
|
|
936
|
-
spelling: "caller parked states",
|
|
937
|
-
target: "callerParkedStates",
|
|
938
|
-
},
|
|
939
|
-
{
|
|
940
|
-
cardinality: "one",
|
|
941
|
-
scope: "instrument",
|
|
942
|
-
spelling: "description",
|
|
943
|
-
target: "description",
|
|
944
|
-
},
|
|
945
|
-
{
|
|
946
|
-
cardinality: "many",
|
|
947
|
-
scope: "instrument",
|
|
948
|
-
spelling: "dials",
|
|
949
|
-
target: "dials",
|
|
950
|
-
},
|
|
951
|
-
{
|
|
952
|
-
cardinality: "one",
|
|
953
|
-
scope: "instrument",
|
|
954
|
-
spelling: "distinct parties",
|
|
955
|
-
target: "distinctParties",
|
|
956
|
-
},
|
|
957
|
-
{
|
|
958
|
-
cardinality: "many",
|
|
959
|
-
scope: "instrument",
|
|
960
|
-
spelling: "computes derived",
|
|
961
|
-
target: "derivedAmounts",
|
|
962
|
-
},
|
|
963
|
-
{
|
|
964
|
-
cardinality: "many",
|
|
965
|
-
scope: "instrument",
|
|
966
|
-
spelling: "computes fees",
|
|
967
|
-
target: "feeRules",
|
|
968
|
-
},
|
|
969
|
-
{
|
|
970
|
-
cardinality: "one",
|
|
971
|
-
scope: "instrument",
|
|
972
|
-
spelling: "id prefix",
|
|
973
|
-
target: "idPrefix",
|
|
974
|
-
},
|
|
975
|
-
{
|
|
976
|
-
cardinality: "many",
|
|
977
|
-
scope: "instrument",
|
|
978
|
-
spelling: "nav",
|
|
979
|
-
target: "nav",
|
|
980
|
-
},
|
|
981
|
-
{
|
|
982
|
-
cardinality: "many",
|
|
983
|
-
scope: "instrument",
|
|
984
|
-
spelling: "partitions",
|
|
985
|
-
target: "partitions",
|
|
986
|
-
},
|
|
987
|
-
{
|
|
988
|
-
cardinality: "one",
|
|
989
|
-
scope: "instrument",
|
|
990
|
-
spelling: "subject",
|
|
991
|
-
target: "subject",
|
|
992
|
-
},
|
|
993
|
-
{
|
|
994
|
-
cardinality: "one",
|
|
995
|
-
scope: "instrument",
|
|
996
|
-
spelling: "summary",
|
|
997
|
-
target: "summary",
|
|
998
|
-
},
|
|
999
|
-
{
|
|
1000
|
-
cardinality: "one",
|
|
1001
|
-
scope: "instrument",
|
|
1002
|
-
spelling: "surface visibility",
|
|
1003
|
-
target: "surfaceVisibility",
|
|
1004
|
-
},
|
|
1005
|
-
{
|
|
1006
|
-
cardinality: "one",
|
|
1007
|
-
scope: "instrument",
|
|
1008
|
-
spelling: "template id",
|
|
1009
|
-
target: "templateId",
|
|
1010
|
-
},
|
|
1011
|
-
{
|
|
1012
|
-
cardinality: "one",
|
|
1013
|
-
scope: "instrument",
|
|
1014
|
-
spelling: "title",
|
|
1015
|
-
target: "title",
|
|
1016
|
-
},
|
|
1017
|
-
{
|
|
1018
|
-
cardinality: "one",
|
|
1019
|
-
scope: "instrument",
|
|
1020
|
-
spelling: "update",
|
|
1021
|
-
target: "update",
|
|
1022
|
-
},
|
|
1023
|
-
];
|
|
1024
|
-
const udlDocumentShapeSchema = z.strictObject({
|
|
1025
|
-
dials: z.array(udlCompositionDialSchema).min(1).optional(),
|
|
1026
|
-
instruments: z.array(udlInstrumentSchema).min(1),
|
|
1027
|
-
product: udlSnakeCaseSchema,
|
|
1028
|
-
subjects: z.array(udlSubjectSchema),
|
|
1029
|
-
title: nonEmptyTextSchema,
|
|
1030
|
-
udl: z.literal(UDL_FORMAT_VERSION),
|
|
1031
|
-
version: z.number().int().positive(),
|
|
404
|
+
event: text,
|
|
405
|
+
actor: z.union([
|
|
406
|
+
z.literal("caller"),
|
|
407
|
+
z.literal("clock"),
|
|
408
|
+
z.strictObject({ party: name }),
|
|
409
|
+
z.strictObject({
|
|
410
|
+
parent: z.union([instrumentId, z.array(instrumentId).min(1).max(16)]),
|
|
411
|
+
}),
|
|
412
|
+
]),
|
|
413
|
+
subject: udlActionSubjectSchema.optional(),
|
|
414
|
+
input: z.array(udlFieldSchema).max(128),
|
|
415
|
+
requires: z.array(udlRequirementSchema).max(128),
|
|
416
|
+
due: clock.optional(),
|
|
417
|
+
deadline: clock.optional(),
|
|
418
|
+
set: z.record(name, value).optional(),
|
|
419
|
+
calculate: z.array(udlCalculationSchema).max(128).optional(),
|
|
420
|
+
moves: z.array(udlMoveSchema).max(256),
|
|
421
|
+
invoke: z
|
|
422
|
+
.array(z.union([
|
|
423
|
+
z.strictObject({
|
|
424
|
+
instrument: instrumentId,
|
|
425
|
+
action: z.literal("create"),
|
|
426
|
+
input: z.record(name, value),
|
|
427
|
+
guard: comparisonRequirement.optional(),
|
|
428
|
+
range: z
|
|
429
|
+
.strictObject({
|
|
430
|
+
count: value,
|
|
431
|
+
maximum: integer.min(1).max(366),
|
|
432
|
+
bind: name,
|
|
433
|
+
})
|
|
434
|
+
.optional(),
|
|
435
|
+
}),
|
|
436
|
+
z.strictObject({
|
|
437
|
+
reference: path,
|
|
438
|
+
action: name,
|
|
439
|
+
input: z.record(name, value),
|
|
440
|
+
guard: comparisonRequirement.optional(),
|
|
441
|
+
}),
|
|
442
|
+
z.strictObject({
|
|
443
|
+
selection,
|
|
444
|
+
action: name,
|
|
445
|
+
input: z.record(name, value),
|
|
446
|
+
guard: comparisonRequirement.optional(),
|
|
447
|
+
}),
|
|
448
|
+
]))
|
|
449
|
+
.max(16)
|
|
450
|
+
.optional(),
|
|
1032
451
|
});
|
|
1033
|
-
const
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
}
|
|
1059
|
-
function declaredMoneyRefKeys(instrument) {
|
|
1060
|
-
return new Set([
|
|
1061
|
-
...Object.values(instrument.actions).flatMap((action) => [
|
|
1062
|
-
...(action.remainder
|
|
1063
|
-
? [
|
|
1064
|
-
action.remainder.amountRef,
|
|
1065
|
-
...(action.remainder.accumulateRef
|
|
1066
|
-
? [action.remainder.accumulateRef]
|
|
1067
|
-
: []),
|
|
1068
|
-
]
|
|
1069
|
-
: []),
|
|
1070
|
-
...(action.signedSum
|
|
1071
|
-
? [
|
|
1072
|
-
action.signedSum.amountRef,
|
|
1073
|
-
...action.signedSum.sources.map((source) => source.subtotalRef),
|
|
1074
|
-
]
|
|
1075
|
-
: []),
|
|
1076
|
-
...(action.distribute ? [action.distribute.amountRef] : []),
|
|
1077
|
-
...(action.quote ? [action.quote.chargeRef, action.quote.netRef] : []),
|
|
1078
|
-
]),
|
|
1079
|
-
]);
|
|
1080
|
-
}
|
|
1081
|
-
export const udlDocumentSchema = udlDocumentShapeSchema.superRefine((document, context) => {
|
|
1082
|
-
document.instruments.forEach((instrument, instrumentIndex) => {
|
|
1083
|
-
instrument.derivedAmounts?.forEach((amount, amountIndex) => {
|
|
1084
|
-
const base = [
|
|
1085
|
-
"instruments",
|
|
1086
|
-
instrumentIndex,
|
|
1087
|
-
"derivedAmounts",
|
|
1088
|
-
amountIndex,
|
|
1089
|
-
];
|
|
1090
|
-
if (!isMoneyField(instrument.fields[amount.field])) {
|
|
1091
|
-
context.addIssue({
|
|
1092
|
-
code: "custom",
|
|
1093
|
-
message: `derived amount target ${amount.field} must be a declared money field`,
|
|
1094
|
-
path: [...base, "field"],
|
|
1095
|
-
});
|
|
1096
|
-
}
|
|
1097
|
-
if (!isMoneyField(instrument.fields[amount.sourceField])) {
|
|
1098
|
-
context.addIssue({
|
|
1099
|
-
code: "custom",
|
|
1100
|
-
message: `derived amount source ${amount.sourceField} must be a declared money field`,
|
|
1101
|
-
path: [...base, "sourceField"],
|
|
1102
|
-
});
|
|
1103
|
-
}
|
|
1104
|
-
if (amount.field === amount.sourceField) {
|
|
1105
|
-
context.addIssue({
|
|
1106
|
-
code: "custom",
|
|
1107
|
-
message: "a derived amount cannot derive from itself",
|
|
1108
|
-
path: [...base, "sourceField"],
|
|
1109
|
-
});
|
|
1110
|
-
}
|
|
1111
|
-
});
|
|
1112
|
-
Object.entries(instrument.actions).forEach(([actionName, action]) => {
|
|
1113
|
-
const distribute = action.distribute;
|
|
1114
|
-
if (!distribute)
|
|
1115
|
-
return;
|
|
1116
|
-
const base = [
|
|
1117
|
-
"instruments",
|
|
1118
|
-
instrumentIndex,
|
|
1119
|
-
"actions",
|
|
1120
|
-
actionName,
|
|
1121
|
-
"distribute",
|
|
1122
|
-
];
|
|
1123
|
-
const refSchema = instrument.fields[distribute.refField];
|
|
1124
|
-
const parents = refSchema
|
|
1125
|
-
? referenceTargets(refSchema, document.instruments)
|
|
1126
|
-
: [];
|
|
1127
|
-
if (parents.length !== 1) {
|
|
1128
|
-
context.addIssue({
|
|
1129
|
-
code: "custom",
|
|
1130
|
-
message: `distribute refField ${distribute.refField} must identify exactly one parent instrument`,
|
|
1131
|
-
path: [...base, "refField"],
|
|
1132
|
-
});
|
|
1133
|
-
}
|
|
1134
|
-
if (!isMoneyField(instrument.fields[distribute.weightField])) {
|
|
1135
|
-
context.addIssue({
|
|
1136
|
-
code: "custom",
|
|
1137
|
-
message: `distribute weightField ${distribute.weightField} must be a declared money field`,
|
|
1138
|
-
path: [...base, "weightField"],
|
|
1139
|
-
});
|
|
1140
|
-
}
|
|
1141
|
-
distribute.statuses.forEach((status, statusIndex) => {
|
|
1142
|
-
if (instrument.lifecycle.states.includes(status))
|
|
1143
|
-
return;
|
|
1144
|
-
context.addIssue({
|
|
1145
|
-
code: "custom",
|
|
1146
|
-
message: `distribute status ${status} is not declared by ${instrument.id}`,
|
|
1147
|
-
path: [...base, "statuses", statusIndex],
|
|
1148
|
-
});
|
|
1149
|
-
});
|
|
1150
|
-
const parent = parents[0];
|
|
1151
|
-
if (!parent)
|
|
1152
|
-
return;
|
|
1153
|
-
const poolMatch = /^(fields|refs)\.([a-z][A-Za-z0-9]*)$/.exec(distribute.pool.path);
|
|
1154
|
-
const root = poolMatch?.[1];
|
|
1155
|
-
const key = poolMatch?.[2];
|
|
1156
|
-
const poolDeclared = root === "fields"
|
|
1157
|
-
? isMoneyField(parent.fields[key ?? ""])
|
|
1158
|
-
: root === "refs"
|
|
1159
|
-
? declaredMoneyRefKeys(parent).has(key ?? "")
|
|
1160
|
-
: false;
|
|
1161
|
-
if (!poolDeclared) {
|
|
1162
|
-
context.addIssue({
|
|
1163
|
-
code: "custom",
|
|
1164
|
-
message: `distribute pool ${distribute.pool.path} must be a declared money field or ref of ${parent.id}`,
|
|
1165
|
-
path: [...base, "pool", "path"],
|
|
1166
|
-
});
|
|
1167
|
-
}
|
|
1168
|
-
});
|
|
1169
|
-
});
|
|
452
|
+
export const udlLifecycleSchema = z.strictObject({
|
|
453
|
+
states: z.array(name).min(1).max(64),
|
|
454
|
+
labels: z.record(name, text).optional(),
|
|
455
|
+
initial: name,
|
|
456
|
+
transitions: z.record(name, z.strictObject({ from: z.array(name).min(1).max(64), to: name })),
|
|
457
|
+
});
|
|
458
|
+
export const udlInstrumentSchema = z.strictObject({
|
|
459
|
+
scope: z.literal("product").optional(),
|
|
460
|
+
reports: z.array(reportDefinitionSchema).max(16).optional(),
|
|
461
|
+
revisioned: z.literal(true).optional(),
|
|
462
|
+
family: udlFamilySchema.optional(),
|
|
463
|
+
id: instrumentId,
|
|
464
|
+
subject: objectKindId.optional(),
|
|
465
|
+
title: text,
|
|
466
|
+
summary: text,
|
|
467
|
+
fields: z.array(udlFieldSchema).max(256),
|
|
468
|
+
calculate: z.array(udlCalculationSchema).max(128),
|
|
469
|
+
lifecycle: udlLifecycleSchema,
|
|
470
|
+
actions: z.record(name, udlActionSchema),
|
|
471
|
+
actionOrder: z.array(name).min(1).max(128),
|
|
472
|
+
invariants: z.array(udlRequirementSchema).max(128).optional(),
|
|
473
|
+
examples: z
|
|
474
|
+
.array(z.strictObject({ name: text, input: z.json() }))
|
|
475
|
+
.max(16)
|
|
476
|
+
.optional(),
|
|
1170
477
|
});
|
|
478
|
+
export const udlDocumentSchema = z.strictObject({
|
|
479
|
+
udl: z.literal(UDL_FORMAT_VERSION),
|
|
480
|
+
version: integer.positive(),
|
|
481
|
+
product: name,
|
|
482
|
+
title: text,
|
|
483
|
+
currency: z.literal("SAR"),
|
|
484
|
+
parties: z.record(name, udlPartySchema),
|
|
485
|
+
objects: z.array(udlObjectKindSchema).max(256),
|
|
486
|
+
instruments: z.array(udlInstrumentSchema).max(256),
|
|
487
|
+
});
|
|
488
|
+
/** Names and display text may differ; executable constraints must match. */
|
|
489
|
+
export function sameObjectField(left, right) {
|
|
490
|
+
const signature = (field) => writeJson(Object.fromEntries(Object.entries(field).filter(([key, value]) => !["name", "label", "description", "optional"].includes(key) &&
|
|
491
|
+
value !== undefined)));
|
|
492
|
+
return signature(left) === signature(right);
|
|
493
|
+
}
|
|
1171
494
|
//# sourceMappingURL=schema.js.map
|