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

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.
@@ -2394,14 +2394,20 @@ var encodeScope = (scope) => {
2394
2394
  encode: false
2395
2395
  });
2396
2396
  };
2397
- var decodeScope = (query) => {
2398
- const scope = qs.parse(query, {
2397
+ var decodedScopeCache = /* @__PURE__ */ new Map();
2398
+ var decodeScope = (encodedScope) => {
2399
+ if (decodedScopeCache.has(encodedScope)) {
2400
+ return decodedScopeCache.get(encodedScope);
2401
+ }
2402
+ const scope = qs.parse(encodedScope, {
2399
2403
  ignoreQueryPrefix: true,
2400
2404
  comma: true,
2401
2405
  allowDots: true
2402
2406
  });
2403
2407
  const unflattenedScope = unflattenScope(scope);
2404
- return Scope2.safeParse(unflattenedScope)?.data;
2408
+ const result = Scope2.safeParse(unflattenedScope)?.data;
2409
+ decodedScopeCache.set(encodedScope, result);
2410
+ return result;
2405
2411
  };
2406
2412
  var DEFAULT_SCOPE_OPTIONS = {
2407
2413
  placeOfEvent: JurisdictionFilter.enum.all,
@@ -770,6 +770,11 @@ var FieldTypesToHideInReview = [
770
770
  FieldType.ALPHA_PRINT_BUTTON,
771
771
  FieldType.ALPHA_HIDDEN
772
772
  ];
773
+ var HiddenFieldTypes = [
774
+ FieldType.HTTP,
775
+ FieldType.QUERY_PARAM_READER,
776
+ FieldType.ALPHA_HIDDEN
777
+ ];
773
778
 
774
779
  // ../commons/src/events/FieldValue.ts
775
780
  var z12 = __toESM(require("zod/v4"));
@@ -888,7 +893,7 @@ var PlainDate = import_zod.z.string().date().brand("PlainDate").describe("Date i
888
893
  // ../commons/src/events/FieldValue.ts
889
894
  var TextValue = z12.string();
890
895
  var HiddenFieldValue = z12.string();
891
- var NonEmptyTextValue = TextValue.min(1);
896
+ var NonEmptyTextValue = z12.string().trim().min(1);
892
897
  var DateValue = z12.iso.date().describe("Date in the format YYYY-MM-DD");
893
898
  var AgeValue = z12.object({
894
899
  age: z12.number(),
@@ -917,6 +922,7 @@ var DateRangeFieldValue = z12.object({
917
922
  var EmailValue = z12.email();
918
923
  var CheckboxFieldValue = z12.boolean();
919
924
  var NumberFieldValue = z12.number();
925
+ var SignatureFieldValue = FileFieldValue;
920
926
  var ButtonFieldValue = z12.number();
921
927
  var VerificationStatusValue = z12.enum([
922
928
  "verified",
@@ -1666,8 +1672,18 @@ var FieldReference = import_v43.default.object({
1666
1672
  $$field: FieldId.describe("Id of the field to reference"),
1667
1673
  $$subfield: import_v43.default.array(import_v43.default.string()).optional().default([]).describe(
1668
1674
  'If the FieldValue is an object, subfield can be used to refer to e.g. `["foo", "bar"]` in `{ foo: { bar: 3 } }`'
1675
+ ),
1676
+ $$code: import_v43.default.string().optional().describe(
1677
+ "Serialised client-side function body. When present the expression is evaluated rather than dereferenced."
1669
1678
  )
1670
- }).describe("Reference to a field by its ID");
1679
+ }).describe(
1680
+ "Reference to a field value, with an optional client-side computation applied."
1681
+ );
1682
+ var ComputedDefaultValue = import_v43.default.object({
1683
+ $$code: import_v43.default.string().describe(
1684
+ "Serialised client-side function body. Receives (undefined, context) where context includes $now, $online, and system variables."
1685
+ )
1686
+ }).describe("A context-only computation used as a field default value.");
1671
1687
  var ValidationConfig = import_v43.default.object({
1672
1688
  validator: Conditional.describe(
1673
1689
  "Conditional expression that must hold for the field value to be considered valid."
@@ -1708,7 +1724,7 @@ var BaseField = import_v43.default.object({
1708
1724
  "Indicates whether the field can be modified during record correction."
1709
1725
  ),
1710
1726
  value: FieldReference.or(import_v43.default.array(FieldReference)).optional().describe(
1711
- "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."
1727
+ "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."
1712
1728
  ),
1713
1729
  analytics: import_v43.default.boolean().default(false).optional().describe(
1714
1730
  "Indicates whether the field is included in analytics. When enabled, its value becomes available in the analytics dashboard."
@@ -1722,7 +1738,7 @@ var Divider = BaseField.extend({
1722
1738
  });
1723
1739
  var TextField = BaseField.extend({
1724
1740
  type: import_v43.default.literal(FieldType.TEXT),
1725
- defaultValue: import_v43.default.union([NonEmptyTextValue, SerializedUserField]).optional(),
1741
+ defaultValue: import_v43.default.union([NonEmptyTextValue, SerializedUserField, ComputedDefaultValue]).optional(),
1726
1742
  configuration: import_v43.default.object({
1727
1743
  maxLength: import_v43.default.number().optional().describe("Maximum length of the text"),
1728
1744
  type: import_v43.default.enum(["text", "password"]).optional(),
@@ -1735,10 +1751,11 @@ var TextField = BaseField.extend({
1735
1751
  });
1736
1752
  var NumberField = BaseField.extend({
1737
1753
  type: import_v43.default.literal(FieldType.NUMBER),
1738
- defaultValue: NumberFieldValue.optional(),
1754
+ defaultValue: NumberFieldValue.or(ComputedDefaultValue).optional(),
1739
1755
  configuration: import_v43.default.object({
1740
1756
  min: import_v43.default.number().optional().describe("Minimum value"),
1741
1757
  max: import_v43.default.number().optional().describe("Maximum value"),
1758
+ integer: import_v43.default.boolean().optional().describe("When true, only whole numbers are allowed"),
1742
1759
  prefix: TranslationConfig.optional(),
1743
1760
  postfix: TranslationConfig.optional()
1744
1761
  }).optional()
@@ -1748,7 +1765,7 @@ var NumberField = BaseField.extend({
1748
1765
  });
1749
1766
  var TextAreaField = BaseField.extend({
1750
1767
  type: import_v43.default.literal(FieldType.TEXTAREA),
1751
- defaultValue: NonEmptyTextValue.optional(),
1768
+ defaultValue: NonEmptyTextValue.or(ComputedDefaultValue).optional(),
1752
1769
  configuration: import_v43.default.object({
1753
1770
  maxLength: import_v43.default.number().optional().describe("Maximum length of the text"),
1754
1771
  rows: import_v43.default.number().optional().describe("Number of visible text lines"),
@@ -1782,7 +1799,7 @@ var SignatureField = BaseField.extend({
1782
1799
  signaturePromptLabel: TranslationConfig.describe(
1783
1800
  "Title of the signature modal"
1784
1801
  ),
1785
- defaultValue: FieldValue.optional(),
1802
+ defaultValue: SignatureFieldValue.or(ComputedDefaultValue).optional(),
1786
1803
  configuration: import_v43.default.object({
1787
1804
  maxFileSize: import_v43.default.number().describe("Maximum file size in bytes").default(DEFAULT_MAX_FILE_SIZE_BYTES),
1788
1805
  acceptedFileTypes: MimeType.array().optional().describe("List of allowed file formats for the signature")
@@ -1798,14 +1815,14 @@ var EmailField = BaseField.extend({
1798
1815
  configuration: import_v43.default.object({
1799
1816
  maxLength: import_v43.default.number().optional().describe("Maximum length of the text")
1800
1817
  }).default({ maxLength: 255 }).optional(),
1801
- defaultValue: NonEmptyTextValue.optional()
1818
+ defaultValue: NonEmptyTextValue.or(ComputedDefaultValue).optional()
1802
1819
  }).meta({
1803
1820
  description: "An email input field",
1804
1821
  id: "EmailField"
1805
1822
  });
1806
1823
  var DateField = BaseField.extend({
1807
1824
  type: import_v43.default.literal(FieldType.DATE),
1808
- defaultValue: SerializedNowDateTime.or(PlainDate).optional().describe("Default date value(yyyy-MM-dd)"),
1825
+ defaultValue: SerializedNowDateTime.or(PlainDate).or(ComputedDefaultValue).optional().describe("Default date value(yyyy-MM-dd)"),
1809
1826
  configuration: import_v43.default.object({
1810
1827
  notice: TranslationConfig.describe(
1811
1828
  "Text to display above the date input"
@@ -1817,7 +1834,7 @@ var DateField = BaseField.extend({
1817
1834
  });
1818
1835
  var AgeField = BaseField.extend({
1819
1836
  type: import_v43.default.literal(FieldType.AGE),
1820
- defaultValue: NumberFieldValue.optional(),
1837
+ defaultValue: NumberFieldValue.or(ComputedDefaultValue).optional(),
1821
1838
  configuration: import_v43.default.object({
1822
1839
  asOfDate: FieldReference,
1823
1840
  prefix: TranslationConfig.optional(),
@@ -1829,7 +1846,7 @@ var AgeField = BaseField.extend({
1829
1846
  });
1830
1847
  var TimeField = BaseField.extend({
1831
1848
  type: import_v43.default.literal(FieldType.TIME),
1832
- defaultValue: SerializedNowDateTime.or(TimeValue).optional().describe("Default time value (HH-mm)"),
1849
+ defaultValue: SerializedNowDateTime.or(TimeValue).or(ComputedDefaultValue).optional().describe("Default time value (HH-mm)"),
1833
1850
  configuration: import_v43.default.object({
1834
1851
  use12HourFormat: import_v43.default.boolean().optional().describe("Whether to use 12-hour format"),
1835
1852
  notice: TranslationConfig.describe(
@@ -1842,7 +1859,7 @@ var TimeField = BaseField.extend({
1842
1859
  });
1843
1860
  var DateRangeField = BaseField.extend({
1844
1861
  type: import_v43.default.literal(FieldType.DATE_RANGE),
1845
- defaultValue: DateRangeFieldValue.optional(),
1862
+ defaultValue: DateRangeFieldValue.or(ComputedDefaultValue).optional(),
1846
1863
  configuration: import_v43.default.object({
1847
1864
  notice: TranslationConfig.describe(
1848
1865
  "Text to display above the date input"
@@ -1921,7 +1938,7 @@ var PageHeader = BaseField.extend({
1921
1938
  });
1922
1939
  var File = BaseField.extend({
1923
1940
  type: import_v43.default.literal(FieldType.FILE),
1924
- defaultValue: FileFieldValue.optional(),
1941
+ defaultValue: FileFieldValue.or(ComputedDefaultValue).optional(),
1925
1942
  configuration: import_v43.default.object({
1926
1943
  maxFileSize: import_v43.default.number().describe("Maximum file size in bytes").default(DEFAULT_MAX_FILE_SIZE_BYTES),
1927
1944
  acceptedFileTypes: MimeType.array().optional().describe("List of allowed file formats for the signature"),
@@ -1948,7 +1965,7 @@ var SelectOption = import_v43.default.object({
1948
1965
  });
1949
1966
  var NumberWithUnitField = BaseField.extend({
1950
1967
  type: import_v43.default.literal(FieldType.NUMBER_WITH_UNIT),
1951
- defaultValue: NumberWithUnitFieldValue.optional(),
1968
+ defaultValue: NumberWithUnitFieldValue.or(ComputedDefaultValue).optional(),
1952
1969
  options: import_v43.default.array(SelectOption).describe("A list of options for the unit select"),
1953
1970
  configuration: import_v43.default.object({
1954
1971
  min: import_v43.default.number().optional().describe("Minimum value of the number field"),
@@ -1963,7 +1980,7 @@ var NumberWithUnitField = BaseField.extend({
1963
1980
  });
1964
1981
  var RadioGroup = BaseField.extend({
1965
1982
  type: import_v43.default.literal(FieldType.RADIO_GROUP),
1966
- defaultValue: TextValue.optional(),
1983
+ defaultValue: TextValue.or(ComputedDefaultValue).optional(),
1967
1984
  options: import_v43.default.array(SelectOption).describe("A list of options"),
1968
1985
  configuration: import_v43.default.object({
1969
1986
  styles: import_v43.default.object({
@@ -1988,7 +2005,7 @@ var BulletList = BaseField.extend({
1988
2005
  });
1989
2006
  var Select = BaseField.extend({
1990
2007
  type: import_v43.default.literal(FieldType.SELECT),
1991
- defaultValue: TextValue.optional(),
2008
+ defaultValue: TextValue.or(ComputedDefaultValue).optional(),
1992
2009
  options: import_v43.default.array(SelectOption).describe("A list of options"),
1993
2010
  noOptionsMessage: TranslationConfig.optional().describe(
1994
2011
  `
@@ -2010,7 +2027,7 @@ var SelectDateRangeOption = import_v43.default.object({
2010
2027
  });
2011
2028
  var SelectDateRangeField = BaseField.extend({
2012
2029
  type: import_v43.default.literal(FieldType.SELECT_DATE_RANGE),
2013
- defaultValue: SelectDateRangeValue.optional(),
2030
+ defaultValue: SelectDateRangeValue.or(ComputedDefaultValue).optional(),
2014
2031
  options: import_v43.default.array(SelectDateRangeOption).describe("A list of options")
2015
2032
  }).meta({
2016
2033
  description: "A date range selection field",
@@ -2027,7 +2044,7 @@ var NameField = BaseField.extend({
2027
2044
  firstname: SerializedUserField.or(NonEmptyTextValue).optional(),
2028
2045
  middlename: SerializedUserField.or(NonEmptyTextValue).optional(),
2029
2046
  surname: SerializedUserField.or(NonEmptyTextValue).optional()
2030
- }).optional(),
2047
+ }).or(ComputedDefaultValue).optional(),
2031
2048
  configuration: import_v43.default.object({
2032
2049
  name: NameConfig.default({
2033
2050
  firstname: { required: true },
@@ -2051,14 +2068,14 @@ var NameField = BaseField.extend({
2051
2068
  id: "NameField"
2052
2069
  });
2053
2070
  var PhoneField = BaseField.extend({
2054
- defaultValue: NonEmptyTextValue.optional(),
2071
+ defaultValue: NonEmptyTextValue.or(ComputedDefaultValue).optional(),
2055
2072
  type: import_v43.default.literal(FieldType.PHONE)
2056
2073
  }).meta({
2057
2074
  description: "A field for entering a phone number",
2058
2075
  id: "PhoneField"
2059
2076
  });
2060
2077
  var IdField = BaseField.extend({
2061
- defaultValue: NonEmptyTextValue.optional(),
2078
+ defaultValue: NonEmptyTextValue.or(ComputedDefaultValue).optional(),
2062
2079
  type: import_v43.default.literal(FieldType.ID)
2063
2080
  }).meta({
2064
2081
  description: "A field for entering an ID",
@@ -2066,14 +2083,14 @@ var IdField = BaseField.extend({
2066
2083
  });
2067
2084
  var Checkbox = BaseField.extend({
2068
2085
  type: import_v43.default.literal(FieldType.CHECKBOX),
2069
- defaultValue: CheckboxFieldValue.default(false)
2086
+ defaultValue: CheckboxFieldValue.or(ComputedDefaultValue).default(false)
2070
2087
  }).meta({
2071
2088
  description: "A boolean checkbox field",
2072
2089
  id: "Checkbox"
2073
2090
  });
2074
2091
  var Country = BaseField.extend({
2075
2092
  type: import_v43.default.literal(FieldType.COUNTRY),
2076
- defaultValue: NonEmptyTextValue.optional(),
2093
+ defaultValue: NonEmptyTextValue.or(ComputedDefaultValue).optional(),
2077
2094
  optionOverrides: import_v43.default.array(SelectOption.omit({ label: true })).optional().describe(
2078
2095
  "Conditionals for specific countries. Countries not listed are always shown and enabled."
2079
2096
  )
@@ -2091,7 +2108,7 @@ var AdministrativeAreas = import_v43.default.enum([
2091
2108
  ]);
2092
2109
  var AdministrativeAreaField = BaseField.extend({
2093
2110
  type: import_v43.default.literal(FieldType.ADMINISTRATIVE_AREA),
2094
- defaultValue: import_v43.default.union([NonEmptyTextValue, SerializedUserField]).optional(),
2111
+ defaultValue: import_v43.default.union([NonEmptyTextValue, SerializedUserField, ComputedDefaultValue]).optional(),
2095
2112
  configuration: import_v43.default.object({
2096
2113
  partOf: FieldReference.optional().describe("Parent location"),
2097
2114
  type: AdministrativeAreas,
@@ -2103,7 +2120,7 @@ var AdministrativeAreaField = BaseField.extend({
2103
2120
  });
2104
2121
  var LocationInput = BaseField.extend({
2105
2122
  type: import_v43.default.literal(FieldType.LOCATION),
2106
- defaultValue: import_v43.default.union([NonEmptyTextValue, SerializedUserField]).optional(),
2123
+ defaultValue: import_v43.default.union([NonEmptyTextValue, SerializedUserField, ComputedDefaultValue]).optional(),
2107
2124
  configuration: import_v43.default.object({
2108
2125
  locationTypes: import_v43.default.array(import_v43.default.string()).optional().describe("Types of the locations that are available for selection."),
2109
2126
  allowedLocations: AllowedLocations
@@ -2115,7 +2132,7 @@ var LocationInput = BaseField.extend({
2115
2132
  var FileUploadWithOptions = BaseField.extend({
2116
2133
  type: import_v43.default.literal(FieldType.FILE_WITH_OPTIONS),
2117
2134
  options: import_v43.default.array(SelectOption).describe("A list of options"),
2118
- defaultValue: FileFieldWithOptionValue.optional(),
2135
+ defaultValue: FileFieldWithOptionValue.or(ComputedDefaultValue).optional(),
2119
2136
  configuration: import_v43.default.object({
2120
2137
  maxFileSize: import_v43.default.number().describe("Maximum file size in bytes").default(DEFAULT_MAX_FILE_SIZE_BYTES),
2121
2138
  maxImageSize: import_v43.default.object({
@@ -2131,12 +2148,12 @@ var FileUploadWithOptions = BaseField.extend({
2131
2148
  });
2132
2149
  var Facility = BaseField.extend({
2133
2150
  type: import_v43.default.literal(FieldType.FACILITY),
2134
- defaultValue: NonEmptyTextValue.optional(),
2151
+ defaultValue: NonEmptyTextValue.or(ComputedDefaultValue).optional(),
2135
2152
  configuration: import_v43.default.object({ allowedLocations: AllowedLocations }).optional()
2136
2153
  }).describe("Input field for a facility");
2137
2154
  var Office = BaseField.extend({
2138
2155
  type: import_v43.default.literal(FieldType.OFFICE),
2139
- defaultValue: NonEmptyTextValue.optional(),
2156
+ defaultValue: NonEmptyTextValue.or(ComputedDefaultValue).optional(),
2140
2157
  configuration: import_v43.default.object({ allowedLocations: AllowedLocations }).optional()
2141
2158
  }).describe("Input field for an office");
2142
2159
  var DefaultAddressFieldValue = DomesticAddressFieldValue.extend({
@@ -2172,7 +2189,7 @@ var Address = BaseField.extend({
2172
2189
  ).optional(),
2173
2190
  allowedLocations: AllowedLocations
2174
2191
  }).optional(),
2175
- defaultValue: DefaultAddressFieldValue.optional()
2192
+ defaultValue: DefaultAddressFieldValue.or(ComputedDefaultValue).optional()
2176
2193
  }).meta({
2177
2194
  description: "Address input field \u2013 a combination of location and text fields",
2178
2195
  id: "Address"
@@ -2219,7 +2236,7 @@ var ButtonConfiguration = import_v43.default.object({
2219
2236
  });
2220
2237
  var ButtonField = BaseField.extend({
2221
2238
  type: import_v43.default.literal(FieldType.BUTTON),
2222
- defaultValue: ButtonFieldValue.optional(),
2239
+ defaultValue: ButtonFieldValue.or(ComputedDefaultValue).optional(),
2223
2240
  configuration: ButtonConfiguration
2224
2241
  }).meta({
2225
2242
  description: "A generic button that can be used to trigger an action",
@@ -2247,7 +2264,7 @@ var AlphaPrintButton = BaseField.extend({
2247
2264
  });
2248
2265
  var HttpField = BaseField.extend({
2249
2266
  type: import_v43.default.literal(FieldType.HTTP),
2250
- defaultValue: HttpFieldValue.optional(),
2267
+ defaultValue: HttpFieldValue.or(ComputedDefaultValue).optional(),
2251
2268
  configuration: import_v43.default.object({
2252
2269
  trigger: FieldReference.optional().describe(
2253
2270
  "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."
@@ -2333,7 +2350,7 @@ var LinkButtonField = BaseField.extend({
2333
2350
  });
2334
2351
  var VerificationStatus = BaseField.extend({
2335
2352
  type: import_v43.default.literal(FieldType.VERIFICATION_STATUS),
2336
- defaultValue: VerificationStatusValue.optional(),
2353
+ defaultValue: VerificationStatusValue.or(ComputedDefaultValue).optional(),
2337
2354
  configuration: import_v43.default.object({
2338
2355
  status: TranslationConfig.describe("Text to display on the status pill."),
2339
2356
  description: TranslationConfig.describe(
@@ -2355,7 +2372,7 @@ var QueryParamReaderField = BaseField.extend({
2355
2372
  });
2356
2373
  var QrReaderField = BaseField.extend({
2357
2374
  type: import_v43.default.literal(FieldType.QR_READER),
2358
- defaultValue: QrReaderFieldValue.optional(),
2375
+ defaultValue: QrReaderFieldValue.or(ComputedDefaultValue).optional(),
2359
2376
  configuration: import_v43.default.object({
2360
2377
  validator: import_v43.default.any().meta({
2361
2378
  description: "JSON Schema to validate the scanned QR code data against before populating the form fields.",
@@ -2368,7 +2385,7 @@ var QrReaderField = BaseField.extend({
2368
2385
  });
2369
2386
  var IdReaderField = BaseField.extend({
2370
2387
  type: import_v43.default.literal(FieldType.ID_READER),
2371
- defaultValue: IdReaderFieldValue.optional(),
2388
+ defaultValue: IdReaderFieldValue.or(ComputedDefaultValue).optional(),
2372
2389
  methods: import_v43.default.array(
2373
2390
  import_v43.default.union([QrReaderField, LinkButtonField]).describe("Methods for reading an ID")
2374
2391
  )
@@ -2662,6 +2679,14 @@ var ReadActionConfig = ActionConfigBase.extend(
2662
2679
  conditionals: z24.never().optional().describe("Read-action can not be disabled or hidden with conditionals.")
2663
2680
  }).shape
2664
2681
  );
2682
+ var NotifyConfig = DeclarationActionBase.extend(
2683
+ z24.object({
2684
+ type: z24.literal(ActionType.NOTIFY),
2685
+ review: DeclarationReviewConfig.describe(
2686
+ "Configuration of the review page fields."
2687
+ ).optional()
2688
+ }).shape
2689
+ );
2665
2690
  var DeclareConfig = DeclarationActionBase.extend(
2666
2691
  z24.object({
2667
2692
  type: z24.literal(ActionType.DECLARE),
@@ -2746,9 +2771,13 @@ var ActionConfig = z24.discriminatedUnion("type", [
2746
2771
  id: "ReadActionConfig",
2747
2772
  description: "Configuration for the read action \u2014 defines the record-tab content displayed on the event overview page."
2748
2773
  }),
2774
+ NotifyConfig.meta({
2775
+ id: "NotifyActionConfig",
2776
+ description: "Configuration for the notify action. When present, NOTIFY uses this config independently from DECLARE. When absent, NOTIFY falls back to the DeclareActionConfig."
2777
+ }),
2749
2778
  DeclareConfig.meta({
2750
2779
  id: "DeclareActionConfig",
2751
- description: "Configuration for the declare action. Includes review-page fields. Shared with the notify action (ActionType.NOTIFY)."
2780
+ description: "Configuration for the declare action. Includes review-page fields. NOTIFY falls back to this config when no dedicated NotifyActionConfig is provided."
2752
2781
  }),
2753
2782
  RejectConfig.meta({
2754
2783
  id: "RejectActionConfig",
@@ -2927,6 +2956,9 @@ var BaseField3 = z28.object({
2927
2956
  ),
2928
2957
  validations: z28.array(ValidationConfig).optional().describe(
2929
2958
  `Option for overriding the field validations specifically for advanced search form.`
2959
+ ),
2960
+ allowedLocations: JurisdictionReference.optional().describe(
2961
+ `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.`
2930
2962
  )
2931
2963
  });
2932
2964
  var SearchQueryParams = z28.object({
@@ -3033,7 +3065,37 @@ function resolveDataPath(rootData, dataPath, instancePath) {
3033
3065
  }
3034
3066
  return current;
3035
3067
  }
3068
+ function todayISO() {
3069
+ return (0, import_date_fns.formatISO)(/* @__PURE__ */ new Date(), { representation: "date" });
3070
+ }
3071
+ var compiledFunctionCache = /* @__PURE__ */ new Map();
3072
+ function compileClientFunction(code) {
3073
+ let fn = compiledFunctionCache.get(code);
3074
+ if (!fn) {
3075
+ fn = new Function(`return (${code})`)();
3076
+ compiledFunctionCache.set(code, fn);
3077
+ }
3078
+ return fn;
3079
+ }
3036
3080
  (0, import_ajv_formats.default)(ajv);
3081
+ function buildClientFunctionContext(input) {
3082
+ return {
3083
+ $form: input.form,
3084
+ $now: todayISO(),
3085
+ // eslint-disable-next-line @typescript-eslint/no-use-before-define
3086
+ $online: isOnline(),
3087
+ $user: input.validatorContext?.user,
3088
+ $event: input.validatorContext?.event,
3089
+ $leafAdminStructureLocationIds: input.validatorContext?.leafAdminStructureLocationIds ?? [],
3090
+ user: input.systemVariables?.user,
3091
+ $window: input.systemVariables?.$window,
3092
+ locations: input.locations,
3093
+ adminLevelIds: input.adminLevelIds
3094
+ };
3095
+ }
3096
+ function runClientFunction(code, data, context) {
3097
+ return compileClientFunction(code)(data, context);
3098
+ }
3037
3099
  ajv.addKeyword({
3038
3100
  keyword: "daysFromDate",
3039
3101
  type: "string",
@@ -3078,12 +3140,35 @@ ajv.addKeyword({
3078
3140
  $data: true,
3079
3141
  errors: true,
3080
3142
  // @ts-ignore -- Force type. We will move this away from AJV next. Parsing the array will take seconds and is only called by core.
3081
- validate(schema, data, _2, dataContext) {
3143
+ validate(_schema, data, _2, dataContext) {
3082
3144
  const locationIdInput = data;
3083
3145
  const locations = dataContext?.rootData.$leafAdminStructureLocationIds ?? [];
3084
3146
  return locations.some((location) => location.id === locationIdInput);
3085
3147
  }
3086
3148
  });
3149
+ ajv.addKeyword({
3150
+ keyword: "customClientValidator",
3151
+ schemaType: "object",
3152
+ errors: true,
3153
+ // @ts-expect-error -- AJV's public types don't expose `rootData`. All
3154
+ // `validate()` callers build root data via `buildClientFunctionContext`,
3155
+ // so the cast holds.
3156
+ validate(schema, data, _2, dataContext) {
3157
+ return Boolean(
3158
+ runClientFunction(
3159
+ schema.code,
3160
+ data,
3161
+ dataContext?.rootData ?? buildClientFunctionContext({ form: {} })
3162
+ )
3163
+ );
3164
+ }
3165
+ });
3166
+ function isOnline() {
3167
+ if (typeof window !== "undefined" && typeof navigator !== "undefined") {
3168
+ return navigator.onLine;
3169
+ }
3170
+ return true;
3171
+ }
3087
3172
 
3088
3173
  // ../commons/src/utils.ts
3089
3174
  var z32 = __toESM(require("zod/v4"));
@@ -3126,7 +3211,7 @@ var getActionAnnotationFields = (actionConfig) => {
3126
3211
  if (actionConfig.type === ActionType.CUSTOM) {
3127
3212
  return actionConfig.form;
3128
3213
  }
3129
- if ("review" in actionConfig) {
3214
+ if ("review" in actionConfig && actionConfig.review != null) {
3130
3215
  return actionConfig.review.fields;
3131
3216
  }
3132
3217
  return [];
@@ -3702,7 +3787,54 @@ function createFieldConditionals(fieldId) {
3702
3787
  }
3703
3788
  },
3704
3789
  required: [fieldId]
3705
- })
3790
+ }),
3791
+ /**
3792
+ * Custom client-side validator. The provided function is serialised and executed
3793
+ * just-in-time on the client only. External references (e.g. lodash) are not
3794
+ * available inside the function body — all logic must be self-contained.
3795
+ *
3796
+ * @example
3797
+ * field('nid').customClientValidator((value) => {
3798
+ * // LUHN check — all logic must be inline
3799
+ * const digits = String(value).split('').map(Number)
3800
+ * // ...
3801
+ * return isValid
3802
+ * })
3803
+ */
3804
+ customClientValidator(validationFn) {
3805
+ const code = validationFn.toString();
3806
+ return defineFormConditional({
3807
+ type: "object",
3808
+ properties: wrapToPath(
3809
+ { [fieldId]: { customClientValidator: { code } } },
3810
+ this.$$subfield
3811
+ ),
3812
+ required: [fieldId]
3813
+ });
3814
+ },
3815
+ /**
3816
+ * Custom client-side evaluation. Returns a {@link FieldReference} descriptor
3817
+ * that can be used as the `value` property or a DATA component entry.
3818
+ * The function receives the referenced field's value as the first argument and
3819
+ * the full form context as the second; its return value replaces the field reference.
3820
+ * The function is serialised and executed just-in-time on the client only.
3821
+ * External references (e.g. lodash) are not available inside the function body.
3822
+ *
3823
+ * For computing a default value without referencing a specific field, use
3824
+ * `evaluate(fn)` in the `defaultValue` property instead.
3825
+ *
3826
+ * @example
3827
+ * field('a').customClientEvaluation((aValue, ctx) =>
3828
+ * Number(aValue) + Number(ctx.$form.b)
3829
+ * )
3830
+ */
3831
+ customClientEvaluation(computationFn) {
3832
+ return {
3833
+ $$code: computationFn.toString(),
3834
+ $$field: fieldId,
3835
+ $$subfield: this.$$subfield
3836
+ };
3837
+ }
3706
3838
  };
3707
3839
  }
3708
3840
 
@@ -4583,12 +4715,53 @@ var updateActions = ActionTypes.extract([
4583
4715
  ActionType.ARCHIVE,
4584
4716
  ActionType.PRINT_CERTIFICATE,
4585
4717
  ActionType.REQUEST_CORRECTION,
4718
+ ActionType.APPROVE_CORRECTION,
4719
+ ActionType.REJECT_CORRECTION,
4586
4720
  ActionType.CUSTOM
4587
4721
  ]);
4588
4722
 
4589
4723
  // ../commons/src/events/state/flags.ts
4590
4724
  var import_lodash3 = require("lodash");
4591
4725
  var import_date_fns3 = require("date-fns");
4726
+ var INHERENT_FLAG_RULES = [
4727
+ {
4728
+ flag: InherentFlags.CORRECTION_REQUESTED,
4729
+ setOn: [ActionType.REQUEST_CORRECTION],
4730
+ resetOn: [ActionType.APPROVE_CORRECTION, ActionType.REJECT_CORRECTION]
4731
+ },
4732
+ {
4733
+ // INCOMPLETE mirrors the NOTIFIED status: set by NOTIFY, cleared by any
4734
+ // other status-changing action (see getStatusFromActions).
4735
+ flag: InherentFlags.INCOMPLETE,
4736
+ setOn: [ActionType.NOTIFY],
4737
+ resetOn: [
4738
+ ActionType.CREATE,
4739
+ ActionType.DECLARE,
4740
+ ActionType.REGISTER,
4741
+ ActionType.ARCHIVE
4742
+ ]
4743
+ },
4744
+ {
4745
+ flag: InherentFlags.REJECTED,
4746
+ setOn: [ActionType.REJECT],
4747
+ resetOn: [
4748
+ ActionType.NOTIFY,
4749
+ ActionType.DECLARE,
4750
+ ActionType.EDIT,
4751
+ ActionType.REGISTER
4752
+ ]
4753
+ },
4754
+ {
4755
+ flag: InherentFlags.POTENTIAL_DUPLICATE,
4756
+ setOn: [ActionType.DUPLICATE_DETECTED],
4757
+ resetOn: [ActionType.MARK_AS_DUPLICATE, ActionType.MARK_AS_NOT_DUPLICATE]
4758
+ },
4759
+ {
4760
+ flag: InherentFlags.EDIT_IN_PROGRESS,
4761
+ setOn: [ActionType.EDIT],
4762
+ resetOnAnyOtherAction: true
4763
+ }
4764
+ ];
4592
4765
 
4593
4766
  // ../commons/src/events/defineConfig.ts
4594
4767
  var IGNORED_EVENT_TYPES = [
@@ -5334,6 +5507,11 @@ var TENNIS_CLUB_DECLARATION_REVIEW = {
5334
5507
  id: "signature.upload.modal.title",
5335
5508
  defaultMessage: "Draw signature",
5336
5509
  description: "Title for the modal to draw signature"
5510
+ },
5511
+ // Zod applies the schema default at parse time, but this fixture bypasses
5512
+ // parsing — GeneratedInputField accesses configuration.maxFileSize directly.
5513
+ configuration: {
5514
+ maxFileSize: 5 * 1024 * 1024
5337
5515
  }
5338
5516
  }
5339
5517
  ]
@@ -7127,6 +7305,13 @@ var ACTION_FILTERS = {
7127
7305
  [ActionType.UNASSIGN]: (flags) => !flags.some((flag) => flag.endsWith(":requested")),
7128
7306
  [ActionType.CUSTOM]: (flags) => !flags.some((flag) => flag.endsWith(":requested"))
7129
7307
  };
7308
+ var REJECTED_ACTIONS = [
7309
+ ActionType.READ,
7310
+ ActionType.NOTIFY,
7311
+ ActionType.CUSTOM,
7312
+ ActionType.EDIT,
7313
+ ActionType.ARCHIVE
7314
+ ];
7130
7315
 
7131
7316
  // ../commons/src/events/FileUtils.ts
7132
7317
  var import_lodash7 = require("lodash");
@@ -580,14 +580,12 @@ export type EncodedScope = z.infer<typeof EncodedScope>;
580
580
  */
581
581
  export declare const encodeScope: (scope: Scope) => EncodedScope;
582
582
  /**
583
- * Converts a scope object into an encoded query string representation.
583
+ * Converts an encoded scope string into a scope object.
584
584
  *
585
- * @TODO scope param could be defined as EncodedScope instead of string.
586
- *
587
- * @param scope - The scope object to encode.
588
- * @returns The encoded scope as a branded string (`EncodedScope`).
585
+ * @param scope - The encoded scope string to decode.
586
+ * @returns The decoded scope object.
589
587
  */
590
- export declare const decodeScope: (query: EncodedScope) => {
588
+ export declare const decodeScope: (encodedScope: EncodedScope) => {
591
589
  type: "record.create" | "record.declare" | "record.notify";
592
590
  options?: {
593
591
  event?: string[] | undefined;
@@ -354,14 +354,20 @@ var encodeScope = (scope) => {
354
354
  encode: false
355
355
  });
356
356
  };
357
- var decodeScope = (query) => {
358
- const scope = qs.parse(query, {
357
+ var decodedScopeCache = /* @__PURE__ */ new Map();
358
+ var decodeScope = (encodedScope) => {
359
+ if (decodedScopeCache.has(encodedScope)) {
360
+ return decodedScopeCache.get(encodedScope);
361
+ }
362
+ const scope = qs.parse(encodedScope, {
359
363
  ignoreQueryPrefix: true,
360
364
  comma: true,
361
365
  allowDots: true
362
366
  });
363
367
  const unflattenedScope = unflattenScope(scope);
364
- return Scope2.safeParse(unflattenedScope)?.data;
368
+ const result = Scope2.safeParse(unflattenedScope)?.data;
369
+ decodedScopeCache.set(encodedScope, result);
370
+ return result;
365
371
  };
366
372
  var DEFAULT_SCOPE_OPTIONS = {
367
373
  placeOfEvent: JurisdictionFilter.enum.all,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@opencrvs/toolkit",
3
- "version": "2.0.0-rc.fe94e41",
3
+ "version": "2.0.0-rc.fea498b",
4
4
  "description": "OpenCRVS toolkit for building country configurations",
5
5
  "license": "MPL-2.0",
6
6
  "bin": {