@opencrvs/toolkit 2.0.0-rc.fe35c20 → 2.0.0-rc.fe577a4

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.
@@ -75,6 +75,7 @@ __export(events_exports, {
75
75
  CheckboxFieldValue: () => CheckboxFieldValue,
76
76
  Clause: () => Clause,
77
77
  ClientSpecificAction: () => ClientSpecificAction,
78
+ ComputedDefaultValue: () => ComputedDefaultValue,
78
79
  Conditional: () => Conditional,
79
80
  ConditionalType: () => ConditionalType,
80
81
  ConfirmableActions: () => ConfirmableActions,
@@ -200,6 +201,7 @@ __export(events_exports, {
200
201
  SelectDateRangeValue: () => SelectDateRangeValue,
201
202
  SelectOption: () => SelectOption,
202
203
  ShowConditional: () => ShowConditional,
204
+ SignatureFieldValue: () => SignatureFieldValue,
203
205
  StaticDataEntry: () => StaticDataEntry,
204
206
  StreetLevelDetailsUpdateValue: () => StreetLevelDetailsUpdateValue,
205
207
  SummaryConfig: () => SummaryConfig,
@@ -246,10 +248,12 @@ __export(events_exports, {
246
248
  applyDraftToEventIndex: () => applyDraftToEventIndex,
247
249
  areCertificateConditionsMet: () => areCertificateConditionsMet,
248
250
  areConditionsMet: () => areConditionsMet,
251
+ buildClientFunctionContext: () => buildClientFunctionContext,
249
252
  buildFormState: () => buildFormState,
250
253
  canAccessEventWithScope: () => canAccessEventWithScope,
251
254
  canAccessOtherUserWithScopes: () => canAccessOtherUserWithScopes,
252
255
  canAccessUserWithScope: () => canAccessUserWithScope,
256
+ compileClientFunction: () => compileClientFunction,
253
257
  compositeFieldTypes: () => compositeFieldTypes,
254
258
  createEmptyDraft: () => createEmptyDraft,
255
259
  createFieldConditionals: () => createFieldConditionals,
@@ -270,6 +274,7 @@ __export(events_exports, {
270
274
  defineWorkqueuesColumns: () => defineWorkqueuesColumns,
271
275
  deserializeQuery: () => deserializeQuery,
272
276
  errorMessages: () => errorMessages,
277
+ evaluate: () => evaluate,
273
278
  event: () => event,
274
279
  eventMetadataLabelMap: () => eventMetadataLabelMap,
275
280
  eventPayloadGenerator: () => eventPayloadGenerator,
@@ -316,6 +321,7 @@ __export(events_exports, {
316
321
  getAvailableActionsForEvent: () => getAvailableActionsForEvent,
317
322
  getAvailableRolesForUserUpdatePayload: () => getAvailableRolesForUserUpdatePayload,
318
323
  getCompleteActionAnnotation: () => getCompleteActionAnnotation,
324
+ getCompleteActionContent: () => getCompleteActionContent,
319
325
  getCompleteActionDeclaration: () => getCompleteActionDeclaration,
320
326
  getCurrentEventState: () => getCurrentEventState,
321
327
  getCustomActionFields: () => getCustomActionFields,
@@ -347,6 +353,7 @@ __export(events_exports, {
347
353
  isBulletListFieldType: () => isBulletListFieldType,
348
354
  isButtonFieldType: () => isButtonFieldType,
349
355
  isCheckboxFieldType: () => isCheckboxFieldType,
356
+ isCodeToEvaluate: () => isCodeToEvaluate,
350
357
  isConditionMet: () => isConditionMet,
351
358
  isCountryFieldType: () => isCountryFieldType,
352
359
  isCustomFieldType: () => isCustomFieldType,
@@ -423,11 +430,13 @@ __export(events_exports, {
423
430
  resolveDateOfEvent: () => resolveDateOfEvent,
424
431
  resolveEventCustomFlags: () => resolveEventCustomFlags,
425
432
  resolvePlaceOfEvent: () => resolvePlaceOfEvent,
433
+ runClientFunction: () => runClientFunction,
426
434
  runFieldValidations: () => runFieldValidations,
427
435
  runStructuralValidations: () => runStructuralValidations,
428
436
  safeUnion: () => safeUnion,
429
437
  status: () => status,
430
438
  timePeriodToDateRange: () => timePeriodToDateRange,
439
+ todayISO: () => todayISO,
431
440
  user: () => user,
432
441
  userCanAccessEventWithScopes: () => userCanAccessEventWithScopes,
433
442
  validate: () => validate,
@@ -702,14 +711,20 @@ var unflattenScope = (input) => {
702
711
  return { type, options };
703
712
  };
704
713
  var EncodedScope = z2.string().brand("EncodedScope");
714
+ var decodedScopeCache = /* @__PURE__ */ new Map();
705
715
  var decodeScope = (query) => {
716
+ if (decodedScopeCache.has(query)) {
717
+ return decodedScopeCache.get(query);
718
+ }
706
719
  const scope = qs.parse(query, {
707
720
  ignoreQueryPrefix: true,
708
721
  comma: true,
709
722
  allowDots: true
710
723
  });
711
724
  const unflattenedScope = unflattenScope(scope);
712
- return Scope.safeParse(unflattenedScope)?.data;
725
+ const result = Scope.safeParse(unflattenedScope)?.data;
726
+ decodedScopeCache.set(query, result);
727
+ return result;
713
728
  };
714
729
  var DEFAULT_SCOPE_OPTIONS = {
715
730
  placeOfEvent: JurisdictionFilter.enum.all,
@@ -1359,6 +1374,7 @@ var DateRangeFieldValue = z12.object({
1359
1374
  var EmailValue = z12.email();
1360
1375
  var CheckboxFieldValue = z12.boolean();
1361
1376
  var NumberFieldValue = z12.number();
1377
+ var SignatureFieldValue = FileFieldValue;
1362
1378
  var ButtonFieldValue = z12.number();
1363
1379
  var VerificationStatusValue = z12.enum([
1364
1380
  "verified",
@@ -1657,8 +1673,9 @@ var RequestedCorrectionAction = ActionBase.extend(
1657
1673
  var ApprovedCorrectionAction = ActionBase.extend(
1658
1674
  z14.object({
1659
1675
  type: z14.literal(ActionType.APPROVE_CORRECTION),
1660
- requestId: z14.string()
1676
+ requestId: z14.string(),
1661
1677
  // TODO move into 'content' property
1678
+ content: z14.object({ immediateCorrection: z14.boolean().optional() }).optional()
1662
1679
  }).shape
1663
1680
  );
1664
1681
  var RejectedCorrectionAction = ActionBase.extend(
@@ -2189,8 +2206,21 @@ var FieldReference = import_v43.default.object({
2189
2206
  $$field: FieldId.describe("Id of the field to reference"),
2190
2207
  $$subfield: import_v43.default.array(import_v43.default.string()).optional().default([]).describe(
2191
2208
  'If the FieldValue is an object, subfield can be used to refer to e.g. `["foo", "bar"]` in `{ foo: { bar: 3 } }`'
2209
+ ),
2210
+ $$code: import_v43.default.string().optional().describe(
2211
+ "Serialised client-side function body. When present the expression is evaluated rather than dereferenced."
2212
+ )
2213
+ }).describe(
2214
+ "Reference to a field value, with an optional client-side computation applied."
2215
+ );
2216
+ function isCodeToEvaluate(v) {
2217
+ return !!v && typeof v === "object" && "$$code" in v;
2218
+ }
2219
+ var ComputedDefaultValue = import_v43.default.object({
2220
+ $$code: import_v43.default.string().describe(
2221
+ "Serialised client-side function body. Receives (undefined, context) where context includes $now, $online, and system variables."
2192
2222
  )
2193
- }).describe("Reference to a field by its ID");
2223
+ }).describe("A context-only computation used as a field default value.");
2194
2224
  var ValidationConfig = import_v43.default.object({
2195
2225
  validator: Conditional.describe(
2196
2226
  "Conditional expression that must hold for the field value to be considered valid."
@@ -2231,7 +2261,7 @@ var BaseField = import_v43.default.object({
2231
2261
  "Indicates whether the field can be modified during record correction."
2232
2262
  ),
2233
2263
  value: FieldReference.or(import_v43.default.array(FieldReference)).optional().describe(
2234
- "Reference to the source field or fields. When a value is defined, it is copied from the parent field when changed. If multiple references are provided, the first truthy value is used."
2264
+ "Reference to the source field or fields. When a value is defined, it is copied from the parent field when changed. If multiple references are provided, the first truthy value is used. A FieldReference with $$code computes the value via a custom client-side function."
2235
2265
  ),
2236
2266
  analytics: import_v43.default.boolean().default(false).optional().describe(
2237
2267
  "Indicates whether the field is included in analytics. When enabled, its value becomes available in the analytics dashboard."
@@ -2245,7 +2275,7 @@ var Divider = BaseField.extend({
2245
2275
  });
2246
2276
  var TextField = BaseField.extend({
2247
2277
  type: import_v43.default.literal(FieldType.TEXT),
2248
- defaultValue: import_v43.default.union([NonEmptyTextValue, SerializedUserField]).optional(),
2278
+ defaultValue: import_v43.default.union([NonEmptyTextValue, SerializedUserField, ComputedDefaultValue]).optional(),
2249
2279
  configuration: import_v43.default.object({
2250
2280
  maxLength: import_v43.default.number().optional().describe("Maximum length of the text"),
2251
2281
  type: import_v43.default.enum(["text", "password"]).optional(),
@@ -2258,7 +2288,7 @@ var TextField = BaseField.extend({
2258
2288
  });
2259
2289
  var NumberField = BaseField.extend({
2260
2290
  type: import_v43.default.literal(FieldType.NUMBER),
2261
- defaultValue: NumberFieldValue.optional(),
2291
+ defaultValue: NumberFieldValue.or(ComputedDefaultValue).optional(),
2262
2292
  configuration: import_v43.default.object({
2263
2293
  min: import_v43.default.number().optional().describe("Minimum value"),
2264
2294
  max: import_v43.default.number().optional().describe("Maximum value"),
@@ -2271,7 +2301,7 @@ var NumberField = BaseField.extend({
2271
2301
  });
2272
2302
  var TextAreaField = BaseField.extend({
2273
2303
  type: import_v43.default.literal(FieldType.TEXTAREA),
2274
- defaultValue: NonEmptyTextValue.optional(),
2304
+ defaultValue: NonEmptyTextValue.or(ComputedDefaultValue).optional(),
2275
2305
  configuration: import_v43.default.object({
2276
2306
  maxLength: import_v43.default.number().optional().describe("Maximum length of the text"),
2277
2307
  rows: import_v43.default.number().optional().describe("Number of visible text lines"),
@@ -2305,7 +2335,7 @@ var SignatureField = BaseField.extend({
2305
2335
  signaturePromptLabel: TranslationConfig.describe(
2306
2336
  "Title of the signature modal"
2307
2337
  ),
2308
- defaultValue: FieldValue.optional(),
2338
+ defaultValue: SignatureFieldValue.or(ComputedDefaultValue).optional(),
2309
2339
  configuration: import_v43.default.object({
2310
2340
  maxFileSize: import_v43.default.number().describe("Maximum file size in bytes").default(DEFAULT_MAX_FILE_SIZE_BYTES),
2311
2341
  acceptedFileTypes: MimeType.array().optional().describe("List of allowed file formats for the signature")
@@ -2321,14 +2351,14 @@ var EmailField = BaseField.extend({
2321
2351
  configuration: import_v43.default.object({
2322
2352
  maxLength: import_v43.default.number().optional().describe("Maximum length of the text")
2323
2353
  }).default({ maxLength: 255 }).optional(),
2324
- defaultValue: NonEmptyTextValue.optional()
2354
+ defaultValue: NonEmptyTextValue.or(ComputedDefaultValue).optional()
2325
2355
  }).meta({
2326
2356
  description: "An email input field",
2327
2357
  id: "EmailField"
2328
2358
  });
2329
2359
  var DateField = BaseField.extend({
2330
2360
  type: import_v43.default.literal(FieldType.DATE),
2331
- defaultValue: SerializedNowDateTime.or(PlainDate).optional().describe("Default date value(yyyy-MM-dd)"),
2361
+ defaultValue: SerializedNowDateTime.or(PlainDate).or(ComputedDefaultValue).optional().describe("Default date value(yyyy-MM-dd)"),
2332
2362
  configuration: import_v43.default.object({
2333
2363
  notice: TranslationConfig.describe(
2334
2364
  "Text to display above the date input"
@@ -2340,7 +2370,7 @@ var DateField = BaseField.extend({
2340
2370
  });
2341
2371
  var AgeField = BaseField.extend({
2342
2372
  type: import_v43.default.literal(FieldType.AGE),
2343
- defaultValue: NumberFieldValue.optional(),
2373
+ defaultValue: NumberFieldValue.or(ComputedDefaultValue).optional(),
2344
2374
  configuration: import_v43.default.object({
2345
2375
  asOfDate: FieldReference,
2346
2376
  prefix: TranslationConfig.optional(),
@@ -2352,7 +2382,7 @@ var AgeField = BaseField.extend({
2352
2382
  });
2353
2383
  var TimeField = BaseField.extend({
2354
2384
  type: import_v43.default.literal(FieldType.TIME),
2355
- defaultValue: SerializedNowDateTime.or(TimeValue).optional().describe("Default time value (HH-mm)"),
2385
+ defaultValue: SerializedNowDateTime.or(TimeValue).or(ComputedDefaultValue).optional().describe("Default time value (HH-mm)"),
2356
2386
  configuration: import_v43.default.object({
2357
2387
  use12HourFormat: import_v43.default.boolean().optional().describe("Whether to use 12-hour format"),
2358
2388
  notice: TranslationConfig.describe(
@@ -2365,7 +2395,7 @@ var TimeField = BaseField.extend({
2365
2395
  });
2366
2396
  var DateRangeField = BaseField.extend({
2367
2397
  type: import_v43.default.literal(FieldType.DATE_RANGE),
2368
- defaultValue: DateRangeFieldValue.optional(),
2398
+ defaultValue: DateRangeFieldValue.or(ComputedDefaultValue).optional(),
2369
2399
  configuration: import_v43.default.object({
2370
2400
  notice: TranslationConfig.describe(
2371
2401
  "Text to display above the date input"
@@ -2444,7 +2474,7 @@ var PageHeader = BaseField.extend({
2444
2474
  });
2445
2475
  var File = BaseField.extend({
2446
2476
  type: import_v43.default.literal(FieldType.FILE),
2447
- defaultValue: FileFieldValue.optional(),
2477
+ defaultValue: FileFieldValue.or(ComputedDefaultValue).optional(),
2448
2478
  configuration: import_v43.default.object({
2449
2479
  maxFileSize: import_v43.default.number().describe("Maximum file size in bytes").default(DEFAULT_MAX_FILE_SIZE_BYTES),
2450
2480
  acceptedFileTypes: MimeType.array().optional().describe("List of allowed file formats for the signature"),
@@ -2471,7 +2501,7 @@ var SelectOption = import_v43.default.object({
2471
2501
  });
2472
2502
  var NumberWithUnitField = BaseField.extend({
2473
2503
  type: import_v43.default.literal(FieldType.NUMBER_WITH_UNIT),
2474
- defaultValue: NumberWithUnitFieldValue.optional(),
2504
+ defaultValue: NumberWithUnitFieldValue.or(ComputedDefaultValue).optional(),
2475
2505
  options: import_v43.default.array(SelectOption).describe("A list of options for the unit select"),
2476
2506
  configuration: import_v43.default.object({
2477
2507
  min: import_v43.default.number().optional().describe("Minimum value of the number field"),
@@ -2486,7 +2516,7 @@ var NumberWithUnitField = BaseField.extend({
2486
2516
  });
2487
2517
  var RadioGroup = BaseField.extend({
2488
2518
  type: import_v43.default.literal(FieldType.RADIO_GROUP),
2489
- defaultValue: TextValue.optional(),
2519
+ defaultValue: TextValue.or(ComputedDefaultValue).optional(),
2490
2520
  options: import_v43.default.array(SelectOption).describe("A list of options"),
2491
2521
  configuration: import_v43.default.object({
2492
2522
  styles: import_v43.default.object({
@@ -2511,7 +2541,7 @@ var BulletList = BaseField.extend({
2511
2541
  });
2512
2542
  var Select = BaseField.extend({
2513
2543
  type: import_v43.default.literal(FieldType.SELECT),
2514
- defaultValue: TextValue.optional(),
2544
+ defaultValue: TextValue.or(ComputedDefaultValue).optional(),
2515
2545
  options: import_v43.default.array(SelectOption).describe("A list of options"),
2516
2546
  noOptionsMessage: TranslationConfig.optional().describe(
2517
2547
  `
@@ -2533,7 +2563,7 @@ var SelectDateRangeOption = import_v43.default.object({
2533
2563
  });
2534
2564
  var SelectDateRangeField = BaseField.extend({
2535
2565
  type: import_v43.default.literal(FieldType.SELECT_DATE_RANGE),
2536
- defaultValue: SelectDateRangeValue.optional(),
2566
+ defaultValue: SelectDateRangeValue.or(ComputedDefaultValue).optional(),
2537
2567
  options: import_v43.default.array(SelectDateRangeOption).describe("A list of options")
2538
2568
  }).meta({
2539
2569
  description: "A date range selection field",
@@ -2550,7 +2580,7 @@ var NameField = BaseField.extend({
2550
2580
  firstname: SerializedUserField.or(NonEmptyTextValue).optional(),
2551
2581
  middlename: SerializedUserField.or(NonEmptyTextValue).optional(),
2552
2582
  surname: SerializedUserField.or(NonEmptyTextValue).optional()
2553
- }).optional(),
2583
+ }).or(ComputedDefaultValue).optional(),
2554
2584
  configuration: import_v43.default.object({
2555
2585
  name: NameConfig.default({
2556
2586
  firstname: { required: true },
@@ -2574,14 +2604,14 @@ var NameField = BaseField.extend({
2574
2604
  id: "NameField"
2575
2605
  });
2576
2606
  var PhoneField = BaseField.extend({
2577
- defaultValue: NonEmptyTextValue.optional(),
2607
+ defaultValue: NonEmptyTextValue.or(ComputedDefaultValue).optional(),
2578
2608
  type: import_v43.default.literal(FieldType.PHONE)
2579
2609
  }).meta({
2580
2610
  description: "A field for entering a phone number",
2581
2611
  id: "PhoneField"
2582
2612
  });
2583
2613
  var IdField = BaseField.extend({
2584
- defaultValue: NonEmptyTextValue.optional(),
2614
+ defaultValue: NonEmptyTextValue.or(ComputedDefaultValue).optional(),
2585
2615
  type: import_v43.default.literal(FieldType.ID)
2586
2616
  }).meta({
2587
2617
  description: "A field for entering an ID",
@@ -2589,14 +2619,14 @@ var IdField = BaseField.extend({
2589
2619
  });
2590
2620
  var Checkbox = BaseField.extend({
2591
2621
  type: import_v43.default.literal(FieldType.CHECKBOX),
2592
- defaultValue: CheckboxFieldValue.default(false)
2622
+ defaultValue: CheckboxFieldValue.or(ComputedDefaultValue).default(false)
2593
2623
  }).meta({
2594
2624
  description: "A boolean checkbox field",
2595
2625
  id: "Checkbox"
2596
2626
  });
2597
2627
  var Country = BaseField.extend({
2598
2628
  type: import_v43.default.literal(FieldType.COUNTRY),
2599
- defaultValue: NonEmptyTextValue.optional(),
2629
+ defaultValue: NonEmptyTextValue.or(ComputedDefaultValue).optional(),
2600
2630
  optionOverrides: import_v43.default.array(SelectOption.omit({ label: true })).optional().describe(
2601
2631
  "Conditionals for specific countries. Countries not listed are always shown and enabled."
2602
2632
  )
@@ -2614,7 +2644,7 @@ var AdministrativeAreas = import_v43.default.enum([
2614
2644
  ]);
2615
2645
  var AdministrativeAreaField = BaseField.extend({
2616
2646
  type: import_v43.default.literal(FieldType.ADMINISTRATIVE_AREA),
2617
- defaultValue: import_v43.default.union([NonEmptyTextValue, SerializedUserField]).optional(),
2647
+ defaultValue: import_v43.default.union([NonEmptyTextValue, SerializedUserField, ComputedDefaultValue]).optional(),
2618
2648
  configuration: import_v43.default.object({
2619
2649
  partOf: FieldReference.optional().describe("Parent location"),
2620
2650
  type: AdministrativeAreas,
@@ -2626,7 +2656,7 @@ var AdministrativeAreaField = BaseField.extend({
2626
2656
  });
2627
2657
  var LocationInput = BaseField.extend({
2628
2658
  type: import_v43.default.literal(FieldType.LOCATION),
2629
- defaultValue: import_v43.default.union([NonEmptyTextValue, SerializedUserField]).optional(),
2659
+ defaultValue: import_v43.default.union([NonEmptyTextValue, SerializedUserField, ComputedDefaultValue]).optional(),
2630
2660
  configuration: import_v43.default.object({
2631
2661
  locationTypes: import_v43.default.array(import_v43.default.string()).optional().describe("Types of the locations that are available for selection."),
2632
2662
  allowedLocations: AllowedLocations
@@ -2638,7 +2668,7 @@ var LocationInput = BaseField.extend({
2638
2668
  var FileUploadWithOptions = BaseField.extend({
2639
2669
  type: import_v43.default.literal(FieldType.FILE_WITH_OPTIONS),
2640
2670
  options: import_v43.default.array(SelectOption).describe("A list of options"),
2641
- defaultValue: FileFieldWithOptionValue.optional(),
2671
+ defaultValue: FileFieldWithOptionValue.or(ComputedDefaultValue).optional(),
2642
2672
  configuration: import_v43.default.object({
2643
2673
  maxFileSize: import_v43.default.number().describe("Maximum file size in bytes").default(DEFAULT_MAX_FILE_SIZE_BYTES),
2644
2674
  maxImageSize: import_v43.default.object({
@@ -2654,12 +2684,12 @@ var FileUploadWithOptions = BaseField.extend({
2654
2684
  });
2655
2685
  var Facility = BaseField.extend({
2656
2686
  type: import_v43.default.literal(FieldType.FACILITY),
2657
- defaultValue: NonEmptyTextValue.optional(),
2687
+ defaultValue: NonEmptyTextValue.or(ComputedDefaultValue).optional(),
2658
2688
  configuration: import_v43.default.object({ allowedLocations: AllowedLocations }).optional()
2659
2689
  }).describe("Input field for a facility");
2660
2690
  var Office = BaseField.extend({
2661
2691
  type: import_v43.default.literal(FieldType.OFFICE),
2662
- defaultValue: NonEmptyTextValue.optional(),
2692
+ defaultValue: NonEmptyTextValue.or(ComputedDefaultValue).optional(),
2663
2693
  configuration: import_v43.default.object({ allowedLocations: AllowedLocations }).optional()
2664
2694
  }).describe("Input field for an office");
2665
2695
  var DefaultAddressFieldValue = DomesticAddressFieldValue.extend({
@@ -2695,7 +2725,7 @@ var Address = BaseField.extend({
2695
2725
  ).optional(),
2696
2726
  allowedLocations: AllowedLocations
2697
2727
  }).optional(),
2698
- defaultValue: DefaultAddressFieldValue.optional()
2728
+ defaultValue: DefaultAddressFieldValue.or(ComputedDefaultValue).optional()
2699
2729
  }).meta({
2700
2730
  description: "Address input field \u2013 a combination of location and text fields",
2701
2731
  id: "Address"
@@ -2742,7 +2772,7 @@ var ButtonConfiguration = import_v43.default.object({
2742
2772
  });
2743
2773
  var ButtonField = BaseField.extend({
2744
2774
  type: import_v43.default.literal(FieldType.BUTTON),
2745
- defaultValue: ButtonFieldValue.optional(),
2775
+ defaultValue: ButtonFieldValue.or(ComputedDefaultValue).optional(),
2746
2776
  configuration: ButtonConfiguration
2747
2777
  }).meta({
2748
2778
  description: "A generic button that can be used to trigger an action",
@@ -2770,7 +2800,7 @@ var AlphaPrintButton = BaseField.extend({
2770
2800
  });
2771
2801
  var HttpField = BaseField.extend({
2772
2802
  type: import_v43.default.literal(FieldType.HTTP),
2773
- defaultValue: HttpFieldValue.optional(),
2803
+ defaultValue: HttpFieldValue.or(ComputedDefaultValue).optional(),
2774
2804
  configuration: import_v43.default.object({
2775
2805
  trigger: FieldReference.optional().describe(
2776
2806
  "Reference to the field that triggers the HTTP request when its value changes. If not provided, the HTTP request is triggered once on component mount."
@@ -2856,7 +2886,7 @@ var LinkButtonField = BaseField.extend({
2856
2886
  });
2857
2887
  var VerificationStatus = BaseField.extend({
2858
2888
  type: import_v43.default.literal(FieldType.VERIFICATION_STATUS),
2859
- defaultValue: VerificationStatusValue.optional(),
2889
+ defaultValue: VerificationStatusValue.or(ComputedDefaultValue).optional(),
2860
2890
  configuration: import_v43.default.object({
2861
2891
  status: TranslationConfig.describe("Text to display on the status pill."),
2862
2892
  description: TranslationConfig.describe(
@@ -2878,7 +2908,7 @@ var QueryParamReaderField = BaseField.extend({
2878
2908
  });
2879
2909
  var QrReaderField = BaseField.extend({
2880
2910
  type: import_v43.default.literal(FieldType.QR_READER),
2881
- defaultValue: QrReaderFieldValue.optional(),
2911
+ defaultValue: QrReaderFieldValue.or(ComputedDefaultValue).optional(),
2882
2912
  configuration: import_v43.default.object({
2883
2913
  validator: import_v43.default.any().meta({
2884
2914
  description: "JSON Schema to validate the scanned QR code data against before populating the form fields.",
@@ -2891,7 +2921,7 @@ var QrReaderField = BaseField.extend({
2891
2921
  });
2892
2922
  var IdReaderField = BaseField.extend({
2893
2923
  type: import_v43.default.literal(FieldType.ID_READER),
2894
- defaultValue: IdReaderFieldValue.optional(),
2924
+ defaultValue: IdReaderFieldValue.or(ComputedDefaultValue).optional(),
2895
2925
  methods: import_v43.default.array(
2896
2926
  import_v43.default.union([QrReaderField, LinkButtonField]).describe("Methods for reading an ID")
2897
2927
  )
@@ -3524,9 +3554,11 @@ var z30 = __toESM(require("zod/v4"));
3524
3554
  var z29 = __toESM(require("zod/v4"));
3525
3555
  function getDynamicNameValue(field3) {
3526
3556
  const nameConfiguration = field3.configuration?.name;
3557
+ const firstnameRequired = nameConfiguration?.firstname?.required ?? field3.required;
3558
+ const surnameRequired = nameConfiguration?.surname?.required ?? field3.required;
3527
3559
  return z29.object({
3528
- firstname: nameConfiguration?.firstname?.required ? NonEmptyTextValue : TextValue,
3529
- surname: nameConfiguration?.surname?.required ? NonEmptyTextValue : TextValue,
3560
+ firstname: firstnameRequired ? NonEmptyTextValue : TextValue,
3561
+ surname: surnameRequired ? NonEmptyTextValue : TextValue,
3530
3562
  middlename: nameConfiguration?.middlename?.required ? NonEmptyTextValue : TextValue.optional()
3531
3563
  });
3532
3564
  }
@@ -3909,7 +3941,37 @@ function resolveDataPath(rootData, dataPath, instancePath) {
3909
3941
  }
3910
3942
  return current;
3911
3943
  }
3944
+ function todayISO() {
3945
+ return (0, import_date_fns.formatISO)(/* @__PURE__ */ new Date(), { representation: "date" });
3946
+ }
3947
+ var compiledFunctionCache = /* @__PURE__ */ new Map();
3948
+ function compileClientFunction(code) {
3949
+ let fn = compiledFunctionCache.get(code);
3950
+ if (!fn) {
3951
+ fn = new Function(`return (${code})`)();
3952
+ compiledFunctionCache.set(code, fn);
3953
+ }
3954
+ return fn;
3955
+ }
3912
3956
  (0, import_ajv_formats.default)(ajv);
3957
+ function buildClientFunctionContext(input) {
3958
+ return {
3959
+ $form: input.form,
3960
+ $now: todayISO(),
3961
+ // eslint-disable-next-line @typescript-eslint/no-use-before-define
3962
+ $online: isOnline(),
3963
+ $user: input.validatorContext?.user,
3964
+ $event: input.validatorContext?.event,
3965
+ $leafAdminStructureLocationIds: input.validatorContext?.leafAdminStructureLocationIds ?? [],
3966
+ user: input.systemVariables?.user,
3967
+ $window: input.systemVariables?.$window,
3968
+ locations: input.locations,
3969
+ adminLevelIds: input.adminLevelIds
3970
+ };
3971
+ }
3972
+ function runClientFunction(code, data, context) {
3973
+ return compileClientFunction(code)(data, context);
3974
+ }
3913
3975
  ajv.addKeyword({
3914
3976
  keyword: "daysFromDate",
3915
3977
  type: "string",
@@ -3954,7 +4016,7 @@ ajv.addKeyword({
3954
4016
  $data: true,
3955
4017
  errors: true,
3956
4018
  // @ts-ignore -- Force type. We will move this away from AJV next. Parsing the array will take seconds and is only called by core.
3957
- validate(schema, data, _2, dataContext) {
4019
+ validate(_schema, data, _2, dataContext) {
3958
4020
  const locationIdInput = data;
3959
4021
  const locations = dataContext?.rootData.$leafAdminStructureLocationIds ?? [];
3960
4022
  return locations.some((location) => location.id === locationIdInput);
@@ -3985,6 +4047,23 @@ function isAgeValue(value) {
3985
4047
  function mergeWithBaseFormState(values, context) {
3986
4048
  return { ...context.baseFormState, ...values };
3987
4049
  }
4050
+ ajv.addKeyword({
4051
+ keyword: "customClientValidator",
4052
+ schemaType: "object",
4053
+ errors: true,
4054
+ // @ts-expect-error -- AJV's public types don't expose `rootData`. All
4055
+ // `validate()` callers build root data via `buildClientFunctionContext`,
4056
+ // so the cast holds.
4057
+ validate(schema, data, _2, dataContext) {
4058
+ return Boolean(
4059
+ runClientFunction(
4060
+ schema.code,
4061
+ data,
4062
+ dataContext?.rootData ?? buildClientFunctionContext({ form: {} })
4063
+ )
4064
+ );
4065
+ }
4066
+ });
3988
4067
  function validate(schema, data) {
3989
4068
  const validator = ajv.getSchema(schema.$id) || ajv.compile(schema);
3990
4069
  if ("$form" in data) {
@@ -4021,17 +4100,14 @@ function isOnline() {
4021
4100
  }
4022
4101
  return true;
4023
4102
  }
4024
- function isConditionMet(conditional, values, context, eventIndex) {
4025
- return validate(conditional, {
4026
- $form: mergeWithBaseFormState(values, context),
4027
- $now: (0, import_date_fns.formatISO)(/* @__PURE__ */ new Date(), { representation: "date" }),
4028
- $online: isOnline(),
4029
- $user: context.user,
4030
- $leafAdminStructureLocationIds: context.leafAdminStructureLocationIds ?? [],
4031
- $flags: eventIndex?.flags ?? [],
4032
- $status: eventIndex?.status,
4033
- $event: context.event
4034
- });
4103
+ function isConditionMet(conditional, values, context) {
4104
+ return validate(
4105
+ conditional,
4106
+ buildClientFunctionContext({
4107
+ form: mergeWithBaseFormState(values, context),
4108
+ validatorContext: context
4109
+ })
4110
+ );
4035
4111
  }
4036
4112
  function getConditionalActionsForField(field3, values) {
4037
4113
  if (!field3.conditionals) {
@@ -4039,9 +4115,9 @@ function getConditionalActionsForField(field3, values) {
4039
4115
  }
4040
4116
  return field3.conditionals.filter((conditional) => validate(conditional.conditional, values)).map((conditional) => conditional.type);
4041
4117
  }
4042
- function areConditionsMet(conditions, values, context, event2) {
4118
+ function areConditionsMet(conditions, values, context, _event) {
4043
4119
  return conditions.every(
4044
- (condition) => isConditionMet(condition.conditional, values, context, event2)
4120
+ (condition) => isConditionMet(condition.conditional, values, context)
4045
4121
  );
4046
4122
  }
4047
4123
  function isFieldConditionMet(field3, form, conditionalType, context) {
@@ -4051,14 +4127,13 @@ function isFieldConditionMet(field3, form, conditionalType, context) {
4051
4127
  if (!hasRule) {
4052
4128
  return true;
4053
4129
  }
4054
- const validConditionals = getConditionalActionsForField(field3, {
4055
- $form: mergeWithBaseFormState(form, context),
4056
- $now: (0, import_date_fns.formatISO)(/* @__PURE__ */ new Date(), { representation: "date" }),
4057
- $online: isOnline(),
4058
- $user: context.user,
4059
- $leafAdminStructureLocationIds: context.leafAdminStructureLocationIds ?? [],
4060
- $event: context.event
4061
- });
4130
+ const validConditionals = getConditionalActionsForField(
4131
+ field3,
4132
+ buildClientFunctionContext({
4133
+ form: mergeWithBaseFormState(form, context),
4134
+ validatorContext: context
4135
+ })
4136
+ );
4062
4137
  return validConditionals.includes(conditionalType);
4063
4138
  }
4064
4139
  function isFieldVisible(field3, form, context) {
@@ -4084,7 +4159,14 @@ function isActionConditionMet(actionConfig, event2, context, conditionalType) {
4084
4159
  if (!rule) {
4085
4160
  return true;
4086
4161
  }
4087
- return isConditionMet(rule.conditional, event2.declaration, context, event2);
4162
+ return validate(rule.conditional, {
4163
+ ...buildClientFunctionContext({
4164
+ form: mergeWithBaseFormState(event2.declaration, context),
4165
+ validatorContext: context
4166
+ }),
4167
+ $flags: event2.flags,
4168
+ $status: event2.status
4169
+ });
4088
4170
  }
4089
4171
  function isActionEnabled(actionConfig, event2, context) {
4090
4172
  return isActionConditionMet(
@@ -4243,19 +4325,10 @@ function runFieldValidations({
4243
4325
  if (!isFieldVisible(field3.config, form, context)) {
4244
4326
  return [];
4245
4327
  }
4246
- const conditionalParameters = {
4247
- $form: mergeWithBaseFormState(form, context),
4248
- $now: (0, import_date_fns.formatISO)(/* @__PURE__ */ new Date(), { representation: "date" }),
4249
- /**
4250
- * In real use cases, there can be hundreds of thousands of locations.
4251
- * Make sure that the context contains only the locations that are needed for validation.
4252
- * E.g. if the user is a leaf admin, only the leaf locations under their admin structure are needed.
4253
- * Loading few megabytes of locations to memory just for validation is not efficient and will choke the application.
4254
- */
4255
- $leafAdminStructureLocationIds: context.leafAdminStructureLocationIds ?? [],
4256
- $online: isOnline(),
4257
- $user: context.user
4258
- };
4328
+ const conditionalParameters = buildClientFunctionContext({
4329
+ form: mergeWithBaseFormState(form, context),
4330
+ validatorContext: context
4331
+ });
4259
4332
  if (isFieldGroupFieldType(field3)) {
4260
4333
  const subfieldErrors = buildFormState(
4261
4334
  field3.config.fields,
@@ -4739,19 +4812,32 @@ function getPendingAction(actions) {
4739
4812
  }
4740
4813
  return pendingActions[0];
4741
4814
  }
4742
- function getCompleteActionAnnotation(annotation, event2, action) {
4815
+ function getCompleteActionAnnotation(event2, action) {
4743
4816
  if (action.originalActionId) {
4744
4817
  const originalAction = event2.actions.find(
4745
4818
  ({ id }) => id === action.originalActionId
4746
4819
  );
4747
4820
  if (originalAction?.status === ActionStatus.Requested) {
4748
- return deepMerge(
4749
- deepMerge(annotation, originalAction.annotation ?? {}),
4750
- action.annotation ?? {}
4751
- );
4821
+ return deepMerge(originalAction.annotation ?? {}, action.annotation ?? {});
4752
4822
  }
4753
4823
  }
4754
- return deepMerge(annotation, action.annotation ?? {});
4824
+ return action.annotation ?? {};
4825
+ }
4826
+ function getCompleteActionContent(event2, action) {
4827
+ const currentContent = "content" in action ? action.content : void 0;
4828
+ if (!action.originalActionId) {
4829
+ return currentContent;
4830
+ }
4831
+ const originalAction = event2.actions.find(
4832
+ ({ id }) => id === action.originalActionId
4833
+ );
4834
+ if (originalAction && "content" in originalAction && originalAction.content) {
4835
+ return {
4836
+ ...originalAction.content,
4837
+ ...currentContent ?? {}
4838
+ };
4839
+ }
4840
+ return currentContent;
4755
4841
  }
4756
4842
  function getCompleteActionDeclaration(declaration, event2, action) {
4757
4843
  if (action.originalActionId) {
@@ -4771,7 +4857,7 @@ function getAcceptedActions(event2) {
4771
4857
  return event2.actions.filter(isAcceptedAction).map((action) => ({
4772
4858
  ...action,
4773
4859
  declaration: getCompleteActionDeclaration({}, event2, action),
4774
- annotation: getCompleteActionAnnotation({}, event2, action)
4860
+ annotation: getCompleteActionAnnotation(event2, action)
4775
4861
  }));
4776
4862
  }
4777
4863
  var EXCLUDED_ACTIONS = [
@@ -5409,7 +5495,54 @@ function createFieldConditionals(fieldId) {
5409
5495
  }
5410
5496
  },
5411
5497
  required: [fieldId]
5412
- })
5498
+ }),
5499
+ /**
5500
+ * Custom client-side validator. The provided function is serialised and executed
5501
+ * just-in-time on the client only. External references (e.g. lodash) are not
5502
+ * available inside the function body — all logic must be self-contained.
5503
+ *
5504
+ * @example
5505
+ * field('nid').customClientValidator((value) => {
5506
+ * // LUHN check — all logic must be inline
5507
+ * const digits = String(value).split('').map(Number)
5508
+ * // ...
5509
+ * return isValid
5510
+ * })
5511
+ */
5512
+ customClientValidator(validationFn) {
5513
+ const code = validationFn.toString();
5514
+ return defineFormConditional({
5515
+ type: "object",
5516
+ properties: wrapToPath(
5517
+ { [fieldId]: { customClientValidator: { code } } },
5518
+ this.$$subfield
5519
+ ),
5520
+ required: [fieldId]
5521
+ });
5522
+ },
5523
+ /**
5524
+ * Custom client-side evaluation. Returns a {@link FieldReference} descriptor
5525
+ * that can be used as the `value` property or a DATA component entry.
5526
+ * The function receives the referenced field's value as the first argument and
5527
+ * the full form context as the second; its return value replaces the field reference.
5528
+ * The function is serialised and executed just-in-time on the client only.
5529
+ * External references (e.g. lodash) are not available inside the function body.
5530
+ *
5531
+ * For computing a default value without referencing a specific field, use
5532
+ * `evaluate(fn)` in the `defaultValue` property instead.
5533
+ *
5534
+ * @example
5535
+ * field('a').customClientEvaluation((aValue, ctx) =>
5536
+ * Number(aValue) + Number(ctx.$form.b)
5537
+ * )
5538
+ */
5539
+ customClientEvaluation(computationFn) {
5540
+ return {
5541
+ $$code: computationFn.toString(),
5542
+ $$field: fieldId,
5543
+ $$subfield: this.$$subfield
5544
+ };
5545
+ }
5413
5546
  };
5414
5547
  }
5415
5548
 
@@ -6199,7 +6332,8 @@ var RejectCorrectionActionInput = BaseActionInput.extend(
6199
6332
  var ApproveCorrectionActionInput = BaseActionInput.extend(
6200
6333
  z38.object({
6201
6334
  requestId: z38.string(),
6202
- type: z38.literal(ActionType.APPROVE_CORRECTION).default(ActionType.APPROVE_CORRECTION)
6335
+ type: z38.literal(ActionType.APPROVE_CORRECTION).default(ActionType.APPROVE_CORRECTION),
6336
+ content: z38.object({ immediateCorrection: z38.boolean().optional() }).optional()
6203
6337
  }).shape
6204
6338
  );
6205
6339
  var ReadActionInput = BaseActionInput.extend(
@@ -6767,7 +6901,7 @@ function getActionAnnotation({
6767
6901
  const action = (0, import_lodash4.findLast)(activeActions, (a) => a.type === actionType);
6768
6902
  const actionWithCompleteAnnotation = action && {
6769
6903
  ...action,
6770
- annotation: getCompleteActionAnnotation({}, event2, action)
6904
+ annotation: getCompleteActionAnnotation(event2, action)
6771
6905
  };
6772
6906
  const matchingDraft = draft?.action.type === actionType ? draft : void 0;
6773
6907
  const sortedActions = (0, import_lodash4.orderBy)(
@@ -6839,6 +6973,9 @@ function createFieldConfig(fieldId, options) {
6839
6973
  }
6840
6974
 
6841
6975
  // ../commons/src/events/field.ts
6976
+ function evaluate(computationFn) {
6977
+ return { $$code: computationFn.toString() };
6978
+ }
6842
6979
  function field(fieldId, options = {}) {
6843
6980
  return {
6844
6981
  ...createFieldConditionals(fieldId),