@hyperscale0/udl 3.1.0 → 4.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (53) hide show
  1. package/CHANGELOG.md +8 -0
  2. package/README.md +1 -1
  3. package/dist/diagnostics.d.ts +1 -1
  4. package/dist/diagnostics.d.ts.map +1 -1
  5. package/dist/diagnostics.js +13 -1
  6. package/dist/diagnostics.js.map +1 -1
  7. package/dist/evolution.d.ts.map +1 -1
  8. package/dist/evolution.js +5 -0
  9. package/dist/evolution.js.map +1 -1
  10. package/dist/finance.js +2 -1
  11. package/dist/finance.js.map +1 -1
  12. package/dist/index.d.ts +4 -1
  13. package/dist/index.d.ts.map +1 -1
  14. package/dist/index.js +4 -1
  15. package/dist/index.js.map +1 -1
  16. package/dist/instrument-references.d.ts.map +1 -1
  17. package/dist/instrument-references.js +21 -1
  18. package/dist/instrument-references.js.map +1 -1
  19. package/dist/object-contract.d.ts +157 -0
  20. package/dist/object-contract.d.ts.map +1 -0
  21. package/dist/object-contract.js +306 -0
  22. package/dist/object-contract.js.map +1 -0
  23. package/dist/reporting-validation.d.ts +8 -0
  24. package/dist/reporting-validation.d.ts.map +1 -0
  25. package/dist/reporting-validation.js +245 -0
  26. package/dist/reporting-validation.js.map +1 -0
  27. package/dist/reporting.d.ts +478 -0
  28. package/dist/reporting.d.ts.map +1 -0
  29. package/dist/reporting.js +170 -0
  30. package/dist/reporting.js.map +1 -0
  31. package/dist/schema.d.ts +2933 -24
  32. package/dist/schema.d.ts.map +1 -1
  33. package/dist/schema.js +163 -23
  34. package/dist/schema.js.map +1 -1
  35. package/dist/validation.d.ts +5 -2
  36. package/dist/validation.d.ts.map +1 -1
  37. package/dist/validation.js +495 -124
  38. package/dist/validation.js.map +1 -1
  39. package/docs/README.md +87 -9
  40. package/package.json +4 -4
  41. package/spec/README.md +87 -9
  42. package/spec/{darb.udl.json → cars.udl.json} +7 -7
  43. package/spec/udl.schema.json +2969 -4558
  44. package/src/diagnostics.ts +33 -1
  45. package/src/evolution.ts +8 -0
  46. package/src/finance.ts +1 -1
  47. package/src/index.ts +9 -0
  48. package/src/instrument-references.ts +25 -1
  49. package/src/object-contract.ts +498 -0
  50. package/src/reporting-validation.ts +381 -0
  51. package/src/reporting.ts +179 -0
  52. package/src/schema.ts +219 -23
  53. package/src/validation.ts +765 -136
package/src/schema.ts CHANGED
@@ -1,6 +1,9 @@
1
1
  import * as z from "zod";
2
+ import { reportDefinitionSchema } from "./reporting.js";
2
3
 
3
- export const UDL_FORMAT_VERSION = 3 as const;
4
+ export const UDL_FORMAT_VERSION = 4 as const;
5
+ /** Counts the root and every nested invocation, including selected and ranged children. */
6
+ export const MAX_ACTION_EXPANSION = 4096;
4
7
  const name = z
5
8
  .string()
6
9
  .regex(/^[a-z][a-zA-Z0-9_]*$/)
@@ -14,6 +17,13 @@ const path = z
14
17
  .regex(/^[a-z][a-zA-Z0-9_]*(?:\.[a-z][a-zA-Z0-9_]*)*$/)
15
18
  .max(240);
16
19
  const instrumentId = name.meta({ "x-udl-reference": "instrument" });
20
+ const objectKindId = name.meta({ "x-udl-reference": "object" });
21
+
22
+ export const udlPartyNameSchema = name;
23
+
24
+ export const udlObjectIdSchema = z.string().min(1).max(160);
25
+ export const udlExternalIdSchema = z.string().min(1).max(2048);
26
+ export const udlObjectRevisionSchema = integer.positive();
17
27
 
18
28
  /** Currency belongs to the document. Accounts and amounts cannot override it. */
19
29
  export const udlPartySchema = z.strictObject({
@@ -21,11 +31,37 @@ export const udlPartySchema = z.strictObject({
21
31
  role: name.optional(),
22
32
  });
23
33
 
34
+ export const udlFamilySchema = z.strictObject({
35
+ module: name,
36
+ exportPath: path,
37
+ revision: integer.positive(),
38
+ });
39
+
24
40
  const fieldBase = {
25
41
  name,
26
42
  optional: z.literal(true).optional(),
27
43
  description: text.optional(),
44
+ sensitive: z.literal(true).optional(),
28
45
  };
46
+
47
+ const referenceField = z.strictObject({
48
+ ...fieldBase,
49
+ type: z.literal("ref"),
50
+ targetKind: z.enum(["instrument", "object"]),
51
+ targetFamily: udlFamilySchema.optional(),
52
+ target: z.union([name, z.array(name).min(1).max(16)]),
53
+ });
54
+
55
+ const listField = z.strictObject({
56
+ ...fieldBase,
57
+ type: z.literal("list"),
58
+ item: z.enum(["money", "date", "text", "integer", "ref"]),
59
+ targetKind: z.enum(["instrument", "object"]).optional(),
60
+ targetFamily: udlFamilySchema.optional(),
61
+ target: name.optional(),
62
+ maxItems: integer.min(1).max(366),
63
+ });
64
+
29
65
  export const udlFieldSchema = z.discriminatedUnion("type", [
30
66
  z.strictObject({
31
67
  ...fieldBase,
@@ -41,13 +77,8 @@ export const udlFieldSchema = z.discriminatedUnion("type", [
41
77
  key: name.optional(),
42
78
  book: z.enum(["cash", "claim"]).default("cash"),
43
79
  contra: z.literal(true).optional(),
44
- external: z.literal(true).optional(),
45
- }),
46
- z.strictObject({
47
- ...fieldBase,
48
- type: z.literal("ref"),
49
- target: z.union([instrumentId, z.array(instrumentId).min(1).max(16)]),
50
80
  }),
81
+ referenceField,
51
82
  z.strictObject({
52
83
  ...fieldBase,
53
84
  type: z.literal("date"),
@@ -62,7 +93,13 @@ export const udlFieldSchema = z.discriminatedUnion("type", [
62
93
  ...fieldBase,
63
94
  type: z.literal("text"),
64
95
  value: text.optional(),
96
+ minLength: integer.positive().max(2048).optional(),
65
97
  maxLength: integer.positive().max(2048).optional(),
98
+ // One anchored ASCII character class and a fixed repetition. No executable patterns.
99
+ pattern: z
100
+ .string()
101
+ .regex(/^\^\[[A-Za-z0-9-]+\]\{[1-9][0-9]{0,3}\}\$$/)
102
+ .optional(),
66
103
  }),
67
104
  z.strictObject({
68
105
  ...fieldBase,
@@ -87,14 +124,88 @@ export const udlFieldSchema = z.discriminatedUnion("type", [
87
124
  values: z.array(name).min(1).max(64),
88
125
  value: name.optional(),
89
126
  }),
90
- z.strictObject({
91
- ...fieldBase,
92
- type: z.literal("list"),
93
- item: z.enum(["money", "date", "text", "integer", "ref"]),
94
- target: instrumentId.optional(),
95
- maxItems: integer.min(1).max(366),
96
- }),
127
+ listField,
128
+ ]);
129
+
130
+ const [
131
+ moneyField,
132
+ ,
133
+ refField,
134
+ dateField,
135
+ durationField,
136
+ textField,
137
+ integerField,
138
+ percentField,
139
+ booleanField,
140
+ enumField,
141
+ boundedListField,
142
+ ] = udlFieldSchema.options;
143
+
144
+ export const udlObjectFieldSchema = z.discriminatedUnion("type", [
145
+ moneyField,
146
+ refField,
147
+ dateField,
148
+ durationField,
149
+ textField,
150
+ integerField,
151
+ percentField,
152
+ booleanField,
153
+ enumField,
154
+ boundedListField,
155
+ ]);
156
+
157
+ export const udlSubjectRequirementSchema = z.strictObject({
158
+ field: udlObjectFieldSchema,
159
+ // Present only for an authored rename.
160
+ objectField: name.optional(),
161
+ });
162
+
163
+ export const adapterSubjectSnapshotSchema = z.strictObject({
164
+ provider: text,
165
+ capability: text,
166
+ operation: text,
167
+ declarationDigest: z.string().regex(/^[a-f0-9]{64}$/),
168
+ requirements: z.array(udlObjectFieldSchema).max(128),
169
+ });
170
+
171
+ export const udlActionSubjectSchema = z.strictObject({
172
+ requirements: z.array(udlSubjectRequirementSchema).max(128),
173
+ adapters: z
174
+ .array(
175
+ z.strictObject({
176
+ binding: name,
177
+ // null means unavailable, never "no requirements".
178
+ snapshot: adapterSubjectSnapshotSchema.nullable(),
179
+ renames: z.record(name, name).optional(),
180
+ }),
181
+ )
182
+ .max(16),
183
+ });
184
+
185
+ export const subjectPartyRoles = ["owner", "actor", "operator"] as const;
186
+ export const attachmentPartyBindingSchema = z.union([
187
+ z.strictObject({ role: z.enum(subjectPartyRoles) }),
188
+ z.strictObject({ party: name }),
97
189
  ]);
190
+ export type AttachmentPartyBinding = z.infer<
191
+ typeof attachmentPartyBindingSchema
192
+ >;
193
+ export const udlObjectAttachmentSchema = z.strictObject({
194
+ name,
195
+ instrument: instrumentId,
196
+ parties: z.record(name, attachmentPartyBindingSchema),
197
+ });
198
+ export type SubjectPartyRole = (typeof subjectPartyRoles)[number];
199
+ export type UdlObjectAttachment = z.infer<typeof udlObjectAttachmentSchema>;
200
+
201
+ export const udlObjectKindSchema = z.strictObject({
202
+ id: objectKindId,
203
+ title: text,
204
+ authoredFields: z.array(name).max(256),
205
+ attachments: z.array(udlObjectAttachmentSchema).max(256),
206
+ fields: z.array(udlObjectFieldSchema).max(256),
207
+ columns: z.array(name).max(8),
208
+ });
98
209
 
99
210
  /** Values are constants or resolved typed paths, never executable strings. */
100
211
  export const udlValueSchema = z.union([
@@ -105,6 +216,7 @@ const value = udlValueSchema;
105
216
  const values = z.array(value).min(1).max(256);
106
217
 
107
218
  const selection = z.strictObject({
219
+ family: udlFamilySchema.optional(),
108
220
  instrument: z.union([instrumentId, z.array(instrumentId).min(1).max(16)]),
109
221
  reference: name,
110
222
  anchor: path,
@@ -183,6 +295,13 @@ export const udlCalculationSchema = z.discriminatedUnion("op", [
183
295
  }),
184
296
  ]);
185
297
 
298
+ const comparisonRequirement = z.strictObject({
299
+ kind: z.literal("compare"),
300
+ left: value,
301
+ operator: z.enum(["==", "!=", "<", "<=", ">", ">="]),
302
+ right: value,
303
+ });
304
+
186
305
  export const udlRequirementSchema = z.discriminatedUnion("kind", [
187
306
  z.strictObject({
188
307
  kind: z.literal("hours"),
@@ -191,12 +310,7 @@ export const udlRequirementSchema = z.discriminatedUnion("kind", [
191
310
  end: integer.min(0).max(23),
192
311
  timezone: text,
193
312
  }),
194
- z.strictObject({
195
- kind: z.literal("compare"),
196
- left: value,
197
- operator: z.enum(["==", "!=", "<", "<=", ">", ">="]),
198
- right: value,
199
- }),
313
+ comparisonRequirement,
200
314
  z.strictObject({
201
315
  kind: z.literal("state"),
202
316
  reference: path,
@@ -220,9 +334,12 @@ export const udlRequirementSchema = z.discriminatedUnion("kind", [
220
334
  party: name,
221
335
  action: name.optional(),
222
336
  decision: z.enum(["approved", "declined"]),
337
+ differentFromInitiator: z.literal(true).optional(),
338
+ protectedRequest: path.default("self"),
223
339
  }),
224
340
  z.strictObject({
225
341
  kind: z.literal("evidence"),
342
+ instruction: path.optional(),
226
343
  subject: path,
227
344
  family: name,
228
345
  check: name,
@@ -249,6 +366,7 @@ export const udlMoveSchema = z.discriminatedUnion("operation", [
249
366
  z.strictObject({
250
367
  key: name,
251
368
  operation: z.literal("internal_transfer.reserve"),
369
+ boundary: z.strictObject({ adapter: name }).optional(),
252
370
  amount: value,
253
371
  from: path,
254
372
  to: path,
@@ -267,17 +385,48 @@ export const udlMoveSchema = z.discriminatedUnion("operation", [
267
385
  transfer: path,
268
386
  }),
269
387
  ]);
270
- const clock = z.strictObject({ at: path, offset: integer.optional() });
388
+ const clock = z.strictObject({
389
+ at: path,
390
+ offset: integer.optional(),
391
+ localDay: z
392
+ .strictObject({
393
+ days: integer.min(0).max(366),
394
+ direction: z.enum(["before", "after"]),
395
+ hour: integer.min(0).max(23),
396
+ timezone: text,
397
+ })
398
+ .optional(),
399
+ });
271
400
  export const udlActionSchema = z.strictObject({
272
401
  summary: text,
273
402
  publicAction: name.optional(),
403
+ expansionLimit: z.literal(8192).optional(),
404
+ humanApproval: z.literal("distinct_member").optional(),
405
+ reminder: z
406
+ .strictObject({
407
+ installment: path,
408
+ recipient: path,
409
+ dueAt: path,
410
+ channel: z.literal("email"),
411
+ template: z.literal("payment_reminder"),
412
+ beforeDays: integer.min(0).max(366),
413
+ overdueDays: integer.min(1).max(366),
414
+ maxPerDay: integer.min(1).max(10),
415
+ startHour: integer.min(0).max(23),
416
+ endHour: integer.min(1).max(24),
417
+ timezone: text,
418
+ })
419
+ .optional(),
274
420
  event: text,
275
421
  actor: z.union([
276
422
  z.literal("caller"),
277
423
  z.literal("clock"),
278
424
  z.strictObject({ party: name }),
279
- z.strictObject({ parent: instrumentId }),
425
+ z.strictObject({
426
+ parent: z.union([instrumentId, z.array(instrumentId).min(1).max(16)]),
427
+ }),
280
428
  ]),
429
+ subject: udlActionSubjectSchema.optional(),
281
430
  input: z.array(udlFieldSchema).max(128),
282
431
  requires: z.array(udlRequirementSchema).max(128),
283
432
  due: clock.optional(),
@@ -292,16 +441,26 @@ export const udlActionSchema = z.strictObject({
292
441
  instrument: instrumentId,
293
442
  action: z.literal("create"),
294
443
  input: z.record(name, value),
444
+ guard: comparisonRequirement.optional(),
445
+ range: z
446
+ .strictObject({
447
+ count: value,
448
+ maximum: integer.min(1).max(366),
449
+ bind: name,
450
+ })
451
+ .optional(),
295
452
  }),
296
453
  z.strictObject({
297
454
  reference: path,
298
455
  action: name,
299
456
  input: z.record(name, value),
457
+ guard: comparisonRequirement.optional(),
300
458
  }),
301
459
  z.strictObject({
302
460
  selection,
303
461
  action: name,
304
462
  input: z.record(name, value),
463
+ guard: comparisonRequirement.optional(),
305
464
  }),
306
465
  ]),
307
466
  )
@@ -309,6 +468,7 @@ export const udlActionSchema = z.strictObject({
309
468
  .optional(),
310
469
  approval: z
311
470
  .strictObject({
471
+ protectedRequest: path.default("self"),
312
472
  target: path,
313
473
  action: name,
314
474
  party: name,
@@ -327,7 +487,11 @@ export const udlLifecycleSchema = z.strictObject({
327
487
  ),
328
488
  });
329
489
  export const udlInstrumentSchema = z.strictObject({
490
+ reports: z.array(reportDefinitionSchema).max(16).optional(),
491
+ revisioned: z.literal(true).optional(),
492
+ family: udlFamilySchema.optional(),
330
493
  id: instrumentId,
494
+ subject: objectKindId.optional(),
331
495
  title: text,
332
496
  summary: text,
333
497
  fields: z.array(udlFieldSchema).max(256),
@@ -348,9 +512,11 @@ export const udlDocumentSchema = z.strictObject({
348
512
  title: text,
349
513
  currency: z.literal("SAR"),
350
514
  parties: z.record(name, udlPartySchema),
351
- instruments: z.array(udlInstrumentSchema).min(1).max(256),
515
+ objects: z.array(udlObjectKindSchema).max(256),
516
+ instruments: z.array(udlInstrumentSchema).max(256),
352
517
  });
353
518
 
519
+ export type UdlFamily = z.infer<typeof udlFamilySchema>;
354
520
  export type UdlDocument = z.infer<typeof udlDocumentSchema>;
355
521
  export type UdlInstrument = z.infer<typeof udlInstrumentSchema>;
356
522
  export type UdlField = z.infer<typeof udlFieldSchema>;
@@ -364,3 +530,33 @@ export type UdlLifecycle = z.infer<typeof udlLifecycleSchema>;
364
530
  export type UdlKernelOperation = z.infer<typeof udlKernelOperationSchema>;
365
531
 
366
532
  export type UdlSelection = z.infer<typeof selection>;
533
+
534
+ export type UdlObjectField = z.infer<typeof udlObjectFieldSchema>;
535
+ export type UdlObjectKind = z.infer<typeof udlObjectKindSchema>;
536
+ export type UdlActionSubject = z.infer<typeof udlActionSubjectSchema>;
537
+ export type UdlSubjectRequirement = z.infer<typeof udlSubjectRequirementSchema>;
538
+ export type UdlAdapterSubjectSnapshot = z.infer<
539
+ typeof adapterSubjectSnapshotSchema
540
+ >;
541
+
542
+ /** Names and display text may differ; executable constraints must match. */
543
+ export function sameObjectField(
544
+ left: UdlObjectField,
545
+ right: UdlObjectField,
546
+ ): boolean {
547
+ const signature = (field: UdlObjectField) =>
548
+ JSON.stringify(
549
+ Object.fromEntries(
550
+ Object.entries(field)
551
+ .filter(
552
+ ([key, value]) =>
553
+ !["name", "description", "optional"].includes(key) &&
554
+ value !== undefined,
555
+ )
556
+ .sort(([left], [right]) =>
557
+ left < right ? -1 : left > right ? 1 : 0,
558
+ ),
559
+ ),
560
+ );
561
+ return signature(left) === signature(right);
562
+ }