@opencrvs/toolkit 2.0.0-rc.fe94e41 → 2.0.0-rc.fedb8b0

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,
@@ -348,6 +353,7 @@ __export(events_exports, {
348
353
  isBulletListFieldType: () => isBulletListFieldType,
349
354
  isButtonFieldType: () => isButtonFieldType,
350
355
  isCheckboxFieldType: () => isCheckboxFieldType,
356
+ isCodeToEvaluate: () => isCodeToEvaluate,
351
357
  isConditionMet: () => isConditionMet,
352
358
  isCountryFieldType: () => isCountryFieldType,
353
359
  isCustomFieldType: () => isCustomFieldType,
@@ -424,11 +430,13 @@ __export(events_exports, {
424
430
  resolveDateOfEvent: () => resolveDateOfEvent,
425
431
  resolveEventCustomFlags: () => resolveEventCustomFlags,
426
432
  resolvePlaceOfEvent: () => resolvePlaceOfEvent,
433
+ runClientFunction: () => runClientFunction,
427
434
  runFieldValidations: () => runFieldValidations,
428
435
  runStructuralValidations: () => runStructuralValidations,
429
436
  safeUnion: () => safeUnion,
430
437
  status: () => status,
431
438
  timePeriodToDateRange: () => timePeriodToDateRange,
439
+ todayISO: () => todayISO,
432
440
  user: () => user,
433
441
  userCanAccessEventWithScopes: () => userCanAccessEventWithScopes,
434
442
  validate: () => validate,
@@ -703,14 +711,20 @@ var unflattenScope = (input) => {
703
711
  return { type, options };
704
712
  };
705
713
  var EncodedScope = z2.string().brand("EncodedScope");
706
- var decodeScope = (query) => {
707
- const scope = qs.parse(query, {
714
+ var decodedScopeCache = /* @__PURE__ */ new Map();
715
+ var decodeScope = (encodedScope) => {
716
+ if (decodedScopeCache.has(encodedScope)) {
717
+ return decodedScopeCache.get(encodedScope);
718
+ }
719
+ const scope = qs.parse(encodedScope, {
708
720
  ignoreQueryPrefix: true,
709
721
  comma: true,
710
722
  allowDots: true
711
723
  });
712
724
  const unflattenedScope = unflattenScope(scope);
713
- return Scope.safeParse(unflattenedScope)?.data;
725
+ const result = Scope.safeParse(unflattenedScope)?.data;
726
+ decodedScopeCache.set(encodedScope, result);
727
+ return result;
714
728
  };
715
729
  var DEFAULT_SCOPE_OPTIONS = {
716
730
  placeOfEvent: JurisdictionFilter.enum.all,
@@ -1331,7 +1345,7 @@ function plainDateToLocalDate(date) {
1331
1345
  // ../commons/src/events/FieldValue.ts
1332
1346
  var TextValue = z12.string();
1333
1347
  var HiddenFieldValue = z12.string();
1334
- var NonEmptyTextValue = TextValue.min(1);
1348
+ var NonEmptyTextValue = z12.string().trim().min(1);
1335
1349
  var DateValue = z12.iso.date().describe("Date in the format YYYY-MM-DD");
1336
1350
  var AgeValue = z12.object({
1337
1351
  age: z12.number(),
@@ -1360,6 +1374,7 @@ var DateRangeFieldValue = z12.object({
1360
1374
  var EmailValue = z12.email();
1361
1375
  var CheckboxFieldValue = z12.boolean();
1362
1376
  var NumberFieldValue = z12.number();
1377
+ var SignatureFieldValue = FileFieldValue;
1363
1378
  var ButtonFieldValue = z12.number();
1364
1379
  var VerificationStatusValue = z12.enum([
1365
1380
  "verified",
@@ -2191,8 +2206,21 @@ var FieldReference = import_v43.default.object({
2191
2206
  $$field: FieldId.describe("Id of the field to reference"),
2192
2207
  $$subfield: import_v43.default.array(import_v43.default.string()).optional().default([]).describe(
2193
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."
2194
2212
  )
2195
- }).describe("Reference to a field by its ID");
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."
2222
+ )
2223
+ }).describe("A context-only computation used as a field default value.");
2196
2224
  var ValidationConfig = import_v43.default.object({
2197
2225
  validator: Conditional.describe(
2198
2226
  "Conditional expression that must hold for the field value to be considered valid."
@@ -2233,7 +2261,7 @@ var BaseField = import_v43.default.object({
2233
2261
  "Indicates whether the field can be modified during record correction."
2234
2262
  ),
2235
2263
  value: FieldReference.or(import_v43.default.array(FieldReference)).optional().describe(
2236
- "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."
2237
2265
  ),
2238
2266
  analytics: import_v43.default.boolean().default(false).optional().describe(
2239
2267
  "Indicates whether the field is included in analytics. When enabled, its value becomes available in the analytics dashboard."
@@ -2247,7 +2275,7 @@ var Divider = BaseField.extend({
2247
2275
  });
2248
2276
  var TextField = BaseField.extend({
2249
2277
  type: import_v43.default.literal(FieldType.TEXT),
2250
- defaultValue: import_v43.default.union([NonEmptyTextValue, SerializedUserField]).optional(),
2278
+ defaultValue: import_v43.default.union([NonEmptyTextValue, SerializedUserField, ComputedDefaultValue]).optional(),
2251
2279
  configuration: import_v43.default.object({
2252
2280
  maxLength: import_v43.default.number().optional().describe("Maximum length of the text"),
2253
2281
  type: import_v43.default.enum(["text", "password"]).optional(),
@@ -2260,7 +2288,7 @@ var TextField = BaseField.extend({
2260
2288
  });
2261
2289
  var NumberField = BaseField.extend({
2262
2290
  type: import_v43.default.literal(FieldType.NUMBER),
2263
- defaultValue: NumberFieldValue.optional(),
2291
+ defaultValue: NumberFieldValue.or(ComputedDefaultValue).optional(),
2264
2292
  configuration: import_v43.default.object({
2265
2293
  min: import_v43.default.number().optional().describe("Minimum value"),
2266
2294
  max: import_v43.default.number().optional().describe("Maximum value"),
@@ -2273,7 +2301,7 @@ var NumberField = BaseField.extend({
2273
2301
  });
2274
2302
  var TextAreaField = BaseField.extend({
2275
2303
  type: import_v43.default.literal(FieldType.TEXTAREA),
2276
- defaultValue: NonEmptyTextValue.optional(),
2304
+ defaultValue: NonEmptyTextValue.or(ComputedDefaultValue).optional(),
2277
2305
  configuration: import_v43.default.object({
2278
2306
  maxLength: import_v43.default.number().optional().describe("Maximum length of the text"),
2279
2307
  rows: import_v43.default.number().optional().describe("Number of visible text lines"),
@@ -2307,7 +2335,7 @@ var SignatureField = BaseField.extend({
2307
2335
  signaturePromptLabel: TranslationConfig.describe(
2308
2336
  "Title of the signature modal"
2309
2337
  ),
2310
- defaultValue: FieldValue.optional(),
2338
+ defaultValue: SignatureFieldValue.or(ComputedDefaultValue).optional(),
2311
2339
  configuration: import_v43.default.object({
2312
2340
  maxFileSize: import_v43.default.number().describe("Maximum file size in bytes").default(DEFAULT_MAX_FILE_SIZE_BYTES),
2313
2341
  acceptedFileTypes: MimeType.array().optional().describe("List of allowed file formats for the signature")
@@ -2323,14 +2351,14 @@ var EmailField = BaseField.extend({
2323
2351
  configuration: import_v43.default.object({
2324
2352
  maxLength: import_v43.default.number().optional().describe("Maximum length of the text")
2325
2353
  }).default({ maxLength: 255 }).optional(),
2326
- defaultValue: NonEmptyTextValue.optional()
2354
+ defaultValue: NonEmptyTextValue.or(ComputedDefaultValue).optional()
2327
2355
  }).meta({
2328
2356
  description: "An email input field",
2329
2357
  id: "EmailField"
2330
2358
  });
2331
2359
  var DateField = BaseField.extend({
2332
2360
  type: import_v43.default.literal(FieldType.DATE),
2333
- 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)"),
2334
2362
  configuration: import_v43.default.object({
2335
2363
  notice: TranslationConfig.describe(
2336
2364
  "Text to display above the date input"
@@ -2342,7 +2370,7 @@ var DateField = BaseField.extend({
2342
2370
  });
2343
2371
  var AgeField = BaseField.extend({
2344
2372
  type: import_v43.default.literal(FieldType.AGE),
2345
- defaultValue: NumberFieldValue.optional(),
2373
+ defaultValue: NumberFieldValue.or(ComputedDefaultValue).optional(),
2346
2374
  configuration: import_v43.default.object({
2347
2375
  asOfDate: FieldReference,
2348
2376
  prefix: TranslationConfig.optional(),
@@ -2354,7 +2382,7 @@ var AgeField = BaseField.extend({
2354
2382
  });
2355
2383
  var TimeField = BaseField.extend({
2356
2384
  type: import_v43.default.literal(FieldType.TIME),
2357
- 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)"),
2358
2386
  configuration: import_v43.default.object({
2359
2387
  use12HourFormat: import_v43.default.boolean().optional().describe("Whether to use 12-hour format"),
2360
2388
  notice: TranslationConfig.describe(
@@ -2367,7 +2395,7 @@ var TimeField = BaseField.extend({
2367
2395
  });
2368
2396
  var DateRangeField = BaseField.extend({
2369
2397
  type: import_v43.default.literal(FieldType.DATE_RANGE),
2370
- defaultValue: DateRangeFieldValue.optional(),
2398
+ defaultValue: DateRangeFieldValue.or(ComputedDefaultValue).optional(),
2371
2399
  configuration: import_v43.default.object({
2372
2400
  notice: TranslationConfig.describe(
2373
2401
  "Text to display above the date input"
@@ -2446,7 +2474,7 @@ var PageHeader = BaseField.extend({
2446
2474
  });
2447
2475
  var File = BaseField.extend({
2448
2476
  type: import_v43.default.literal(FieldType.FILE),
2449
- defaultValue: FileFieldValue.optional(),
2477
+ defaultValue: FileFieldValue.or(ComputedDefaultValue).optional(),
2450
2478
  configuration: import_v43.default.object({
2451
2479
  maxFileSize: import_v43.default.number().describe("Maximum file size in bytes").default(DEFAULT_MAX_FILE_SIZE_BYTES),
2452
2480
  acceptedFileTypes: MimeType.array().optional().describe("List of allowed file formats for the signature"),
@@ -2473,7 +2501,7 @@ var SelectOption = import_v43.default.object({
2473
2501
  });
2474
2502
  var NumberWithUnitField = BaseField.extend({
2475
2503
  type: import_v43.default.literal(FieldType.NUMBER_WITH_UNIT),
2476
- defaultValue: NumberWithUnitFieldValue.optional(),
2504
+ defaultValue: NumberWithUnitFieldValue.or(ComputedDefaultValue).optional(),
2477
2505
  options: import_v43.default.array(SelectOption).describe("A list of options for the unit select"),
2478
2506
  configuration: import_v43.default.object({
2479
2507
  min: import_v43.default.number().optional().describe("Minimum value of the number field"),
@@ -2488,7 +2516,7 @@ var NumberWithUnitField = BaseField.extend({
2488
2516
  });
2489
2517
  var RadioGroup = BaseField.extend({
2490
2518
  type: import_v43.default.literal(FieldType.RADIO_GROUP),
2491
- defaultValue: TextValue.optional(),
2519
+ defaultValue: TextValue.or(ComputedDefaultValue).optional(),
2492
2520
  options: import_v43.default.array(SelectOption).describe("A list of options"),
2493
2521
  configuration: import_v43.default.object({
2494
2522
  styles: import_v43.default.object({
@@ -2513,7 +2541,7 @@ var BulletList = BaseField.extend({
2513
2541
  });
2514
2542
  var Select = BaseField.extend({
2515
2543
  type: import_v43.default.literal(FieldType.SELECT),
2516
- defaultValue: TextValue.optional(),
2544
+ defaultValue: TextValue.or(ComputedDefaultValue).optional(),
2517
2545
  options: import_v43.default.array(SelectOption).describe("A list of options"),
2518
2546
  noOptionsMessage: TranslationConfig.optional().describe(
2519
2547
  `
@@ -2535,7 +2563,7 @@ var SelectDateRangeOption = import_v43.default.object({
2535
2563
  });
2536
2564
  var SelectDateRangeField = BaseField.extend({
2537
2565
  type: import_v43.default.literal(FieldType.SELECT_DATE_RANGE),
2538
- defaultValue: SelectDateRangeValue.optional(),
2566
+ defaultValue: SelectDateRangeValue.or(ComputedDefaultValue).optional(),
2539
2567
  options: import_v43.default.array(SelectDateRangeOption).describe("A list of options")
2540
2568
  }).meta({
2541
2569
  description: "A date range selection field",
@@ -2552,7 +2580,7 @@ var NameField = BaseField.extend({
2552
2580
  firstname: SerializedUserField.or(NonEmptyTextValue).optional(),
2553
2581
  middlename: SerializedUserField.or(NonEmptyTextValue).optional(),
2554
2582
  surname: SerializedUserField.or(NonEmptyTextValue).optional()
2555
- }).optional(),
2583
+ }).or(ComputedDefaultValue).optional(),
2556
2584
  configuration: import_v43.default.object({
2557
2585
  name: NameConfig.default({
2558
2586
  firstname: { required: true },
@@ -2576,14 +2604,14 @@ var NameField = BaseField.extend({
2576
2604
  id: "NameField"
2577
2605
  });
2578
2606
  var PhoneField = BaseField.extend({
2579
- defaultValue: NonEmptyTextValue.optional(),
2607
+ defaultValue: NonEmptyTextValue.or(ComputedDefaultValue).optional(),
2580
2608
  type: import_v43.default.literal(FieldType.PHONE)
2581
2609
  }).meta({
2582
2610
  description: "A field for entering a phone number",
2583
2611
  id: "PhoneField"
2584
2612
  });
2585
2613
  var IdField = BaseField.extend({
2586
- defaultValue: NonEmptyTextValue.optional(),
2614
+ defaultValue: NonEmptyTextValue.or(ComputedDefaultValue).optional(),
2587
2615
  type: import_v43.default.literal(FieldType.ID)
2588
2616
  }).meta({
2589
2617
  description: "A field for entering an ID",
@@ -2591,14 +2619,14 @@ var IdField = BaseField.extend({
2591
2619
  });
2592
2620
  var Checkbox = BaseField.extend({
2593
2621
  type: import_v43.default.literal(FieldType.CHECKBOX),
2594
- defaultValue: CheckboxFieldValue.default(false)
2622
+ defaultValue: CheckboxFieldValue.or(ComputedDefaultValue).default(false)
2595
2623
  }).meta({
2596
2624
  description: "A boolean checkbox field",
2597
2625
  id: "Checkbox"
2598
2626
  });
2599
2627
  var Country = BaseField.extend({
2600
2628
  type: import_v43.default.literal(FieldType.COUNTRY),
2601
- defaultValue: NonEmptyTextValue.optional(),
2629
+ defaultValue: NonEmptyTextValue.or(ComputedDefaultValue).optional(),
2602
2630
  optionOverrides: import_v43.default.array(SelectOption.omit({ label: true })).optional().describe(
2603
2631
  "Conditionals for specific countries. Countries not listed are always shown and enabled."
2604
2632
  )
@@ -2616,7 +2644,7 @@ var AdministrativeAreas = import_v43.default.enum([
2616
2644
  ]);
2617
2645
  var AdministrativeAreaField = BaseField.extend({
2618
2646
  type: import_v43.default.literal(FieldType.ADMINISTRATIVE_AREA),
2619
- defaultValue: import_v43.default.union([NonEmptyTextValue, SerializedUserField]).optional(),
2647
+ defaultValue: import_v43.default.union([NonEmptyTextValue, SerializedUserField, ComputedDefaultValue]).optional(),
2620
2648
  configuration: import_v43.default.object({
2621
2649
  partOf: FieldReference.optional().describe("Parent location"),
2622
2650
  type: AdministrativeAreas,
@@ -2628,7 +2656,7 @@ var AdministrativeAreaField = BaseField.extend({
2628
2656
  });
2629
2657
  var LocationInput = BaseField.extend({
2630
2658
  type: import_v43.default.literal(FieldType.LOCATION),
2631
- defaultValue: import_v43.default.union([NonEmptyTextValue, SerializedUserField]).optional(),
2659
+ defaultValue: import_v43.default.union([NonEmptyTextValue, SerializedUserField, ComputedDefaultValue]).optional(),
2632
2660
  configuration: import_v43.default.object({
2633
2661
  locationTypes: import_v43.default.array(import_v43.default.string()).optional().describe("Types of the locations that are available for selection."),
2634
2662
  allowedLocations: AllowedLocations
@@ -2640,7 +2668,7 @@ var LocationInput = BaseField.extend({
2640
2668
  var FileUploadWithOptions = BaseField.extend({
2641
2669
  type: import_v43.default.literal(FieldType.FILE_WITH_OPTIONS),
2642
2670
  options: import_v43.default.array(SelectOption).describe("A list of options"),
2643
- defaultValue: FileFieldWithOptionValue.optional(),
2671
+ defaultValue: FileFieldWithOptionValue.or(ComputedDefaultValue).optional(),
2644
2672
  configuration: import_v43.default.object({
2645
2673
  maxFileSize: import_v43.default.number().describe("Maximum file size in bytes").default(DEFAULT_MAX_FILE_SIZE_BYTES),
2646
2674
  maxImageSize: import_v43.default.object({
@@ -2656,12 +2684,12 @@ var FileUploadWithOptions = BaseField.extend({
2656
2684
  });
2657
2685
  var Facility = BaseField.extend({
2658
2686
  type: import_v43.default.literal(FieldType.FACILITY),
2659
- defaultValue: NonEmptyTextValue.optional(),
2687
+ defaultValue: NonEmptyTextValue.or(ComputedDefaultValue).optional(),
2660
2688
  configuration: import_v43.default.object({ allowedLocations: AllowedLocations }).optional()
2661
2689
  }).describe("Input field for a facility");
2662
2690
  var Office = BaseField.extend({
2663
2691
  type: import_v43.default.literal(FieldType.OFFICE),
2664
- defaultValue: NonEmptyTextValue.optional(),
2692
+ defaultValue: NonEmptyTextValue.or(ComputedDefaultValue).optional(),
2665
2693
  configuration: import_v43.default.object({ allowedLocations: AllowedLocations }).optional()
2666
2694
  }).describe("Input field for an office");
2667
2695
  var DefaultAddressFieldValue = DomesticAddressFieldValue.extend({
@@ -2697,7 +2725,7 @@ var Address = BaseField.extend({
2697
2725
  ).optional(),
2698
2726
  allowedLocations: AllowedLocations
2699
2727
  }).optional(),
2700
- defaultValue: DefaultAddressFieldValue.optional()
2728
+ defaultValue: DefaultAddressFieldValue.or(ComputedDefaultValue).optional()
2701
2729
  }).meta({
2702
2730
  description: "Address input field \u2013 a combination of location and text fields",
2703
2731
  id: "Address"
@@ -2744,7 +2772,7 @@ var ButtonConfiguration = import_v43.default.object({
2744
2772
  });
2745
2773
  var ButtonField = BaseField.extend({
2746
2774
  type: import_v43.default.literal(FieldType.BUTTON),
2747
- defaultValue: ButtonFieldValue.optional(),
2775
+ defaultValue: ButtonFieldValue.or(ComputedDefaultValue).optional(),
2748
2776
  configuration: ButtonConfiguration
2749
2777
  }).meta({
2750
2778
  description: "A generic button that can be used to trigger an action",
@@ -2772,7 +2800,7 @@ var AlphaPrintButton = BaseField.extend({
2772
2800
  });
2773
2801
  var HttpField = BaseField.extend({
2774
2802
  type: import_v43.default.literal(FieldType.HTTP),
2775
- defaultValue: HttpFieldValue.optional(),
2803
+ defaultValue: HttpFieldValue.or(ComputedDefaultValue).optional(),
2776
2804
  configuration: import_v43.default.object({
2777
2805
  trigger: FieldReference.optional().describe(
2778
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."
@@ -2858,7 +2886,7 @@ var LinkButtonField = BaseField.extend({
2858
2886
  });
2859
2887
  var VerificationStatus = BaseField.extend({
2860
2888
  type: import_v43.default.literal(FieldType.VERIFICATION_STATUS),
2861
- defaultValue: VerificationStatusValue.optional(),
2889
+ defaultValue: VerificationStatusValue.or(ComputedDefaultValue).optional(),
2862
2890
  configuration: import_v43.default.object({
2863
2891
  status: TranslationConfig.describe("Text to display on the status pill."),
2864
2892
  description: TranslationConfig.describe(
@@ -2880,7 +2908,7 @@ var QueryParamReaderField = BaseField.extend({
2880
2908
  });
2881
2909
  var QrReaderField = BaseField.extend({
2882
2910
  type: import_v43.default.literal(FieldType.QR_READER),
2883
- defaultValue: QrReaderFieldValue.optional(),
2911
+ defaultValue: QrReaderFieldValue.or(ComputedDefaultValue).optional(),
2884
2912
  configuration: import_v43.default.object({
2885
2913
  validator: import_v43.default.any().meta({
2886
2914
  description: "JSON Schema to validate the scanned QR code data against before populating the form fields.",
@@ -2893,7 +2921,7 @@ var QrReaderField = BaseField.extend({
2893
2921
  });
2894
2922
  var IdReaderField = BaseField.extend({
2895
2923
  type: import_v43.default.literal(FieldType.ID_READER),
2896
- defaultValue: IdReaderFieldValue.optional(),
2924
+ defaultValue: IdReaderFieldValue.or(ComputedDefaultValue).optional(),
2897
2925
  methods: import_v43.default.array(
2898
2926
  import_v43.default.union([QrReaderField, LinkButtonField]).describe("Methods for reading an ID")
2899
2927
  )
@@ -3452,6 +3480,9 @@ var BaseField3 = z28.object({
3452
3480
  ),
3453
3481
  validations: z28.array(ValidationConfig).optional().describe(
3454
3482
  `Option for overriding the field validations specifically for advanced search form.`
3483
+ ),
3484
+ allowedLocations: JurisdictionReference.optional().describe(
3485
+ `Override the allowedLocations for a location field in advanced search. Use this when the declaration form's allowedLocations references a scope (e.g. record.create) that search-only users don't have \u2014 specify record.search scope instead.`
3455
3486
  )
3456
3487
  });
3457
3488
  var SearchQueryParams = z28.object({
@@ -3526,9 +3557,11 @@ var z30 = __toESM(require("zod/v4"));
3526
3557
  var z29 = __toESM(require("zod/v4"));
3527
3558
  function getDynamicNameValue(field3) {
3528
3559
  const nameConfiguration = field3.configuration?.name;
3560
+ const firstnameRequired = nameConfiguration?.firstname?.required ?? field3.required;
3561
+ const surnameRequired = nameConfiguration?.surname?.required ?? field3.required;
3529
3562
  return z29.object({
3530
- firstname: nameConfiguration?.firstname?.required ? NonEmptyTextValue : TextValue,
3531
- surname: nameConfiguration?.surname?.required ? NonEmptyTextValue : TextValue,
3563
+ firstname: firstnameRequired ? NonEmptyTextValue : TextValue,
3564
+ surname: surnameRequired ? NonEmptyTextValue : TextValue,
3532
3565
  middlename: nameConfiguration?.middlename?.required ? NonEmptyTextValue : TextValue.optional()
3533
3566
  });
3534
3567
  }
@@ -3911,7 +3944,37 @@ function resolveDataPath(rootData, dataPath, instancePath) {
3911
3944
  }
3912
3945
  return current;
3913
3946
  }
3947
+ function todayISO() {
3948
+ return (0, import_date_fns.formatISO)(/* @__PURE__ */ new Date(), { representation: "date" });
3949
+ }
3950
+ var compiledFunctionCache = /* @__PURE__ */ new Map();
3951
+ function compileClientFunction(code) {
3952
+ let fn = compiledFunctionCache.get(code);
3953
+ if (!fn) {
3954
+ fn = new Function(`return (${code})`)();
3955
+ compiledFunctionCache.set(code, fn);
3956
+ }
3957
+ return fn;
3958
+ }
3914
3959
  (0, import_ajv_formats.default)(ajv);
3960
+ function buildClientFunctionContext(input) {
3961
+ return {
3962
+ $form: input.form,
3963
+ $now: todayISO(),
3964
+ // eslint-disable-next-line @typescript-eslint/no-use-before-define
3965
+ $online: isOnline(),
3966
+ $user: input.validatorContext?.user,
3967
+ $event: input.validatorContext?.event,
3968
+ $leafAdminStructureLocationIds: input.validatorContext?.leafAdminStructureLocationIds ?? [],
3969
+ user: input.systemVariables?.user,
3970
+ $window: input.systemVariables?.$window,
3971
+ locations: input.locations,
3972
+ adminLevelIds: input.adminLevelIds
3973
+ };
3974
+ }
3975
+ function runClientFunction(code, data, context) {
3976
+ return compileClientFunction(code)(data, context);
3977
+ }
3915
3978
  ajv.addKeyword({
3916
3979
  keyword: "daysFromDate",
3917
3980
  type: "string",
@@ -3956,7 +4019,7 @@ ajv.addKeyword({
3956
4019
  $data: true,
3957
4020
  errors: true,
3958
4021
  // @ts-ignore -- Force type. We will move this away from AJV next. Parsing the array will take seconds and is only called by core.
3959
- validate(schema, data, _2, dataContext) {
4022
+ validate(_schema, data, _2, dataContext) {
3960
4023
  const locationIdInput = data;
3961
4024
  const locations = dataContext?.rootData.$leafAdminStructureLocationIds ?? [];
3962
4025
  return locations.some((location) => location.id === locationIdInput);
@@ -3987,6 +4050,23 @@ function isAgeValue(value) {
3987
4050
  function mergeWithBaseFormState(values, context) {
3988
4051
  return { ...context.baseFormState, ...values };
3989
4052
  }
4053
+ ajv.addKeyword({
4054
+ keyword: "customClientValidator",
4055
+ schemaType: "object",
4056
+ errors: true,
4057
+ // @ts-expect-error -- AJV's public types don't expose `rootData`. All
4058
+ // `validate()` callers build root data via `buildClientFunctionContext`,
4059
+ // so the cast holds.
4060
+ validate(schema, data, _2, dataContext) {
4061
+ return Boolean(
4062
+ runClientFunction(
4063
+ schema.code,
4064
+ data,
4065
+ dataContext?.rootData ?? buildClientFunctionContext({ form: {} })
4066
+ )
4067
+ );
4068
+ }
4069
+ });
3990
4070
  function validate(schema, data) {
3991
4071
  const validator = ajv.getSchema(schema.$id) || ajv.compile(schema);
3992
4072
  if ("$form" in data) {
@@ -4023,17 +4103,14 @@ function isOnline() {
4023
4103
  }
4024
4104
  return true;
4025
4105
  }
4026
- function isConditionMet(conditional, values, context, eventIndex) {
4027
- return validate(conditional, {
4028
- $form: mergeWithBaseFormState(values, context),
4029
- $now: (0, import_date_fns.formatISO)(/* @__PURE__ */ new Date(), { representation: "date" }),
4030
- $online: isOnline(),
4031
- $user: context.user,
4032
- $leafAdminStructureLocationIds: context.leafAdminStructureLocationIds ?? [],
4033
- $flags: eventIndex?.flags ?? [],
4034
- $status: eventIndex?.status,
4035
- $event: context.event
4036
- });
4106
+ function isConditionMet(conditional, values, context) {
4107
+ return validate(
4108
+ conditional,
4109
+ buildClientFunctionContext({
4110
+ form: mergeWithBaseFormState(values, context),
4111
+ validatorContext: context
4112
+ })
4113
+ );
4037
4114
  }
4038
4115
  function getConditionalActionsForField(field3, values) {
4039
4116
  if (!field3.conditionals) {
@@ -4041,9 +4118,9 @@ function getConditionalActionsForField(field3, values) {
4041
4118
  }
4042
4119
  return field3.conditionals.filter((conditional) => validate(conditional.conditional, values)).map((conditional) => conditional.type);
4043
4120
  }
4044
- function areConditionsMet(conditions, values, context, event2) {
4121
+ function areConditionsMet(conditions, values, context, _event) {
4045
4122
  return conditions.every(
4046
- (condition) => isConditionMet(condition.conditional, values, context, event2)
4123
+ (condition) => isConditionMet(condition.conditional, values, context)
4047
4124
  );
4048
4125
  }
4049
4126
  function isFieldConditionMet(field3, form, conditionalType, context) {
@@ -4053,14 +4130,13 @@ function isFieldConditionMet(field3, form, conditionalType, context) {
4053
4130
  if (!hasRule) {
4054
4131
  return true;
4055
4132
  }
4056
- const validConditionals = getConditionalActionsForField(field3, {
4057
- $form: mergeWithBaseFormState(form, context),
4058
- $now: (0, import_date_fns.formatISO)(/* @__PURE__ */ new Date(), { representation: "date" }),
4059
- $online: isOnline(),
4060
- $user: context.user,
4061
- $leafAdminStructureLocationIds: context.leafAdminStructureLocationIds ?? [],
4062
- $event: context.event
4063
- });
4133
+ const validConditionals = getConditionalActionsForField(
4134
+ field3,
4135
+ buildClientFunctionContext({
4136
+ form: mergeWithBaseFormState(form, context),
4137
+ validatorContext: context
4138
+ })
4139
+ );
4064
4140
  return validConditionals.includes(conditionalType);
4065
4141
  }
4066
4142
  function isFieldVisible(field3, form, context) {
@@ -4086,7 +4162,14 @@ function isActionConditionMet(actionConfig, event2, context, conditionalType) {
4086
4162
  if (!rule) {
4087
4163
  return true;
4088
4164
  }
4089
- return isConditionMet(rule.conditional, event2.declaration, context, event2);
4165
+ return validate(rule.conditional, {
4166
+ ...buildClientFunctionContext({
4167
+ form: mergeWithBaseFormState(event2.declaration, context),
4168
+ validatorContext: context
4169
+ }),
4170
+ $flags: event2.flags,
4171
+ $status: event2.status
4172
+ });
4090
4173
  }
4091
4174
  function isActionEnabled(actionConfig, event2, context) {
4092
4175
  return isActionConditionMet(
@@ -4245,19 +4328,10 @@ function runFieldValidations({
4245
4328
  if (!isFieldVisible(field3.config, form, context)) {
4246
4329
  return [];
4247
4330
  }
4248
- const conditionalParameters = {
4249
- $form: mergeWithBaseFormState(form, context),
4250
- $now: (0, import_date_fns.formatISO)(/* @__PURE__ */ new Date(), { representation: "date" }),
4251
- /**
4252
- * In real use cases, there can be hundreds of thousands of locations.
4253
- * Make sure that the context contains only the locations that are needed for validation.
4254
- * E.g. if the user is a leaf admin, only the leaf locations under their admin structure are needed.
4255
- * Loading few megabytes of locations to memory just for validation is not efficient and will choke the application.
4256
- */
4257
- $leafAdminStructureLocationIds: context.leafAdminStructureLocationIds ?? [],
4258
- $online: isOnline(),
4259
- $user: context.user
4260
- };
4331
+ const conditionalParameters = buildClientFunctionContext({
4332
+ form: mergeWithBaseFormState(form, context),
4333
+ validatorContext: context
4334
+ });
4261
4335
  if (isFieldGroupFieldType(field3)) {
4262
4336
  const subfieldErrors = buildFormState(
4263
4337
  field3.config.fields,
@@ -4741,19 +4815,16 @@ function getPendingAction(actions) {
4741
4815
  }
4742
4816
  return pendingActions[0];
4743
4817
  }
4744
- function getCompleteActionAnnotation(annotation, event2, action) {
4818
+ function getCompleteActionAnnotation(event2, action) {
4745
4819
  if (action.originalActionId) {
4746
4820
  const originalAction = event2.actions.find(
4747
4821
  ({ id }) => id === action.originalActionId
4748
4822
  );
4749
4823
  if (originalAction?.status === ActionStatus.Requested) {
4750
- return deepMerge(
4751
- deepMerge(annotation, originalAction.annotation ?? {}),
4752
- action.annotation ?? {}
4753
- );
4824
+ return deepMerge(originalAction.annotation ?? {}, action.annotation ?? {});
4754
4825
  }
4755
4826
  }
4756
- return deepMerge(annotation, action.annotation ?? {});
4827
+ return action.annotation ?? {};
4757
4828
  }
4758
4829
  function getCompleteActionContent(event2, action) {
4759
4830
  const currentContent = "content" in action ? action.content : void 0;
@@ -4789,7 +4860,7 @@ function getAcceptedActions(event2) {
4789
4860
  return event2.actions.filter(isAcceptedAction).map((action) => ({
4790
4861
  ...action,
4791
4862
  declaration: getCompleteActionDeclaration({}, event2, action),
4792
- annotation: getCompleteActionAnnotation({}, event2, action)
4863
+ annotation: getCompleteActionAnnotation(event2, action)
4793
4864
  }));
4794
4865
  }
4795
4866
  var EXCLUDED_ACTIONS = [
@@ -5427,7 +5498,54 @@ function createFieldConditionals(fieldId) {
5427
5498
  }
5428
5499
  },
5429
5500
  required: [fieldId]
5430
- })
5501
+ }),
5502
+ /**
5503
+ * Custom client-side validator. The provided function is serialised and executed
5504
+ * just-in-time on the client only. External references (e.g. lodash) are not
5505
+ * available inside the function body — all logic must be self-contained.
5506
+ *
5507
+ * @example
5508
+ * field('nid').customClientValidator((value) => {
5509
+ * // LUHN check — all logic must be inline
5510
+ * const digits = String(value).split('').map(Number)
5511
+ * // ...
5512
+ * return isValid
5513
+ * })
5514
+ */
5515
+ customClientValidator(validationFn) {
5516
+ const code = validationFn.toString();
5517
+ return defineFormConditional({
5518
+ type: "object",
5519
+ properties: wrapToPath(
5520
+ { [fieldId]: { customClientValidator: { code } } },
5521
+ this.$$subfield
5522
+ ),
5523
+ required: [fieldId]
5524
+ });
5525
+ },
5526
+ /**
5527
+ * Custom client-side evaluation. Returns a {@link FieldReference} descriptor
5528
+ * that can be used as the `value` property or a DATA component entry.
5529
+ * The function receives the referenced field's value as the first argument and
5530
+ * the full form context as the second; its return value replaces the field reference.
5531
+ * The function is serialised and executed just-in-time on the client only.
5532
+ * External references (e.g. lodash) are not available inside the function body.
5533
+ *
5534
+ * For computing a default value without referencing a specific field, use
5535
+ * `evaluate(fn)` in the `defaultValue` property instead.
5536
+ *
5537
+ * @example
5538
+ * field('a').customClientEvaluation((aValue, ctx) =>
5539
+ * Number(aValue) + Number(ctx.$form.b)
5540
+ * )
5541
+ */
5542
+ customClientEvaluation(computationFn) {
5543
+ return {
5544
+ $$code: computationFn.toString(),
5545
+ $$field: fieldId,
5546
+ $$subfield: this.$$subfield
5547
+ };
5548
+ }
5431
5549
  };
5432
5550
  }
5433
5551
 
@@ -6381,7 +6499,7 @@ function getActionUpdateMetadata(actions) {
6381
6499
  "createdAtLocation",
6382
6500
  "createdByRole"
6383
6501
  ];
6384
- return actions.filter(({ type }) => updateActions.safeParse(type).success).filter(({ status: status2 }) => status2 === ActionStatus.Accepted).reduce(
6502
+ return actions.filter(({ type }) => updateActions.safeParse(type).success).reduce(
6385
6503
  (_2, action) => {
6386
6504
  if (action.originalActionId) {
6387
6505
  const originalAction = actions.find(({ id }) => id === action.originalActionId) ?? action;
@@ -6786,7 +6904,7 @@ function getActionAnnotation({
6786
6904
  const action = (0, import_lodash4.findLast)(activeActions, (a) => a.type === actionType);
6787
6905
  const actionWithCompleteAnnotation = action && {
6788
6906
  ...action,
6789
- annotation: getCompleteActionAnnotation({}, event2, action)
6907
+ annotation: getCompleteActionAnnotation(event2, action)
6790
6908
  };
6791
6909
  const matchingDraft = draft?.action.type === actionType ? draft : void 0;
6792
6910
  const sortedActions = (0, import_lodash4.orderBy)(
@@ -6858,6 +6976,9 @@ function createFieldConfig(fieldId, options) {
6858
6976
  }
6859
6977
 
6860
6978
  // ../commons/src/events/field.ts
6979
+ function evaluate(computationFn) {
6980
+ return { $$code: computationFn.toString() };
6981
+ }
6861
6982
  function field(fieldId, options = {}) {
6862
6983
  return {
6863
6984
  ...createFieldConditionals(fieldId),