@opencrvs/toolkit 2.0.0-rc.ff04b30 → 2.0.0-rc.ff1424b

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (36) hide show
  1. package/create-countryconfig/index.js +50 -20
  2. package/create-countryconfig/package.json +12 -2
  3. package/dist/application-config/index.js +250 -97
  4. package/dist/cli.js +10 -4
  5. package/dist/commons/api/router.d.ts +107 -21
  6. package/dist/commons/application-config/index.d.ts +1 -0
  7. package/dist/commons/conditionals/conditionals.d.ts +354 -4
  8. package/dist/commons/conditionals/validate.d.ts +51 -2
  9. package/dist/commons/events/ActionConfig.d.ts +28 -2
  10. package/dist/commons/events/ActionDocument.d.ts +6 -0
  11. package/dist/commons/events/ActionInput.d.ts +42 -36
  12. package/dist/commons/events/AdvancedSearchConfig.d.ts +342 -0
  13. package/dist/commons/events/Draft.d.ts +2 -3
  14. package/dist/commons/events/EventDocument.d.ts +3 -0
  15. package/dist/commons/events/FieldConfig.d.ts +378 -50
  16. package/dist/commons/events/FieldType.d.ts +1 -0
  17. package/dist/commons/events/FieldTypeMapping.d.ts +1 -1
  18. package/dist/commons/events/FieldValue.d.ts +6 -0
  19. package/dist/commons/events/WorkqueueConfig.d.ts +5 -5
  20. package/dist/commons/events/field.d.ts +53 -1
  21. package/dist/commons/events/index.d.ts +2 -0
  22. package/dist/commons/events/state/flags.d.ts +16 -0
  23. package/dist/commons/events/state/utils.d.ts +12 -287
  24. package/dist/commons/events/utils.d.ts +12 -1
  25. package/dist/conditionals/index.js +52 -1
  26. package/dist/events/index.js +1035 -222
  27. package/dist/migrations/v2.0/checkout-upstream-files.d.ts +1 -1
  28. package/dist/migrations/v2.0/checkout-upstream-files.d.ts.map +1 -1
  29. package/dist/migrations/v2.0/checkout-upstream-files.js +1 -1
  30. package/dist/migrations/v2.0/index.js +10 -4
  31. package/dist/notification/index.js +869 -120
  32. package/dist/scopes/index.d.ts +4 -6
  33. package/dist/scopes/index.js +9 -3
  34. package/opencrvs-toolkit-2.0.0-rc.ff1424b.tgz +0 -0
  35. package/package.json +6 -2
  36. package/opencrvs-toolkit-2.0.0-rc.ff04b30.tgz +0 -0
@@ -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,
@@ -150,6 +151,7 @@ __export(events_exports, {
150
151
  FormPageConfig: () => FormPageConfig,
151
152
  Fuzzy: () => Fuzzy,
152
153
  GeographicalArea: () => GeographicalArea,
154
+ HiddenFieldTypes: () => HiddenFieldTypes,
153
155
  HiddenFieldValue: () => HiddenFieldValue,
154
156
  HttpFieldUpdateValue: () => HttpFieldUpdateValue,
155
157
  HttpFieldValue: () => HttpFieldValue,
@@ -200,6 +202,7 @@ __export(events_exports, {
200
202
  SelectDateRangeValue: () => SelectDateRangeValue,
201
203
  SelectOption: () => SelectOption,
202
204
  ShowConditional: () => ShowConditional,
205
+ SignatureFieldValue: () => SignatureFieldValue,
203
206
  StaticDataEntry: () => StaticDataEntry,
204
207
  StreetLevelDetailsUpdateValue: () => StreetLevelDetailsUpdateValue,
205
208
  SummaryConfig: () => SummaryConfig,
@@ -213,6 +216,10 @@ __export(events_exports, {
213
216
  UUID: () => UUID,
214
217
  UnassignActionInput: () => UnassignActionInput,
215
218
  UserAuditRecordInput: () => UserAuditRecordInput,
219
+ V2_DEFAULT_MOCK_ADMINISTRATIVE_AREAS: () => V2_DEFAULT_MOCK_ADMINISTRATIVE_AREAS,
220
+ V2_DEFAULT_MOCK_ADMINISTRATIVE_AREAS_MAP: () => V2_DEFAULT_MOCK_ADMINISTRATIVE_AREAS_MAP,
221
+ V2_DEFAULT_MOCK_LOCATIONS: () => V2_DEFAULT_MOCK_LOCATIONS,
222
+ V2_DEFAULT_MOCK_LOCATIONS_MAP: () => V2_DEFAULT_MOCK_LOCATIONS_MAP,
216
223
  ValidationConfig: () => ValidationConfig,
217
224
  VerificationActionConfig: () => VerificationActionConfig,
218
225
  VerificationPageConfig: () => VerificationPageConfig,
@@ -234,6 +241,7 @@ __export(events_exports, {
234
241
  ageToDate: () => ageToDate,
235
242
  aggregateActionAnnotations: () => aggregateActionAnnotations,
236
243
  aggregateActionDeclarations: () => aggregateActionDeclarations,
244
+ always: () => always,
237
245
  alwaysTrue: () => alwaysTrue,
238
246
  and: () => and,
239
247
  annotationActions: () => annotationActions,
@@ -241,10 +249,12 @@ __export(events_exports, {
241
249
  applyDraftToEventIndex: () => applyDraftToEventIndex,
242
250
  areCertificateConditionsMet: () => areCertificateConditionsMet,
243
251
  areConditionsMet: () => areConditionsMet,
252
+ buildClientFunctionContext: () => buildClientFunctionContext,
244
253
  buildFormState: () => buildFormState,
245
254
  canAccessEventWithScope: () => canAccessEventWithScope,
246
255
  canAccessOtherUserWithScopes: () => canAccessOtherUserWithScopes,
247
256
  canAccessUserWithScope: () => canAccessUserWithScope,
257
+ compileClientFunction: () => compileClientFunction,
248
258
  compositeFieldTypes: () => compositeFieldTypes,
249
259
  createEmptyDraft: () => createEmptyDraft,
250
260
  createFieldConditionals: () => createFieldConditionals,
@@ -265,6 +275,7 @@ __export(events_exports, {
265
275
  defineWorkqueuesColumns: () => defineWorkqueuesColumns,
266
276
  deserializeQuery: () => deserializeQuery,
267
277
  errorMessages: () => errorMessages,
278
+ evaluate: () => evaluate,
268
279
  event: () => event,
269
280
  eventMetadataLabelMap: () => eventMetadataLabelMap,
270
281
  eventPayloadGenerator: () => eventPayloadGenerator,
@@ -277,6 +288,7 @@ __export(events_exports, {
277
288
  findActiveDraftForEvent: () => findActiveDraftForEvent,
278
289
  findAllFields: () => findAllFields,
279
290
  findLastAssignmentAction: () => findLastAssignmentAction,
291
+ findPendingCorrectionAction: () => findPendingCorrectionAction,
280
292
  findRecordActionPages: () => findRecordActionPages,
281
293
  flag: () => flag,
282
294
  flattenFieldReference: () => flattenFieldReference,
@@ -310,6 +322,7 @@ __export(events_exports, {
310
322
  getAvailableActionsForEvent: () => getAvailableActionsForEvent,
311
323
  getAvailableRolesForUserUpdatePayload: () => getAvailableRolesForUserUpdatePayload,
312
324
  getCompleteActionAnnotation: () => getCompleteActionAnnotation,
325
+ getCompleteActionContent: () => getCompleteActionContent,
313
326
  getCompleteActionDeclaration: () => getCompleteActionDeclaration,
314
327
  getCurrentEventState: () => getCurrentEventState,
315
328
  getCustomActionFields: () => getCustomActionFields,
@@ -318,6 +331,7 @@ __export(events_exports, {
318
331
  getDeclarationFields: () => getDeclarationFields,
319
332
  getDeclarationPages: () => getDeclarationPages,
320
333
  getEventConfigById: () => getEventConfigById,
334
+ getEventFlags: () => getEventFlags,
321
335
  getFilePathsFromEvent: () => getFilePathsFromEvent,
322
336
  getLocationHierarchy: () => getLocationHierarchy,
323
337
  getMixedPath: () => getMixedPath,
@@ -340,6 +354,7 @@ __export(events_exports, {
340
354
  isBulletListFieldType: () => isBulletListFieldType,
341
355
  isButtonFieldType: () => isButtonFieldType,
342
356
  isCheckboxFieldType: () => isCheckboxFieldType,
357
+ isCodeToEvaluate: () => isCodeToEvaluate,
343
358
  isConditionMet: () => isConditionMet,
344
359
  isCountryFieldType: () => isCountryFieldType,
345
360
  isCustomFieldType: () => isCustomFieldType,
@@ -380,6 +395,7 @@ __export(events_exports, {
380
395
  isPageVisible: () => isPageVisible,
381
396
  isParagraphFieldType: () => isParagraphFieldType,
382
397
  isPhoneFieldType: () => isPhoneFieldType,
398
+ isPotentialDuplicate: () => isPotentialDuplicate,
383
399
  isPrintButtonFieldType: () => isPrintButtonFieldType,
384
400
  isQrReaderFieldType: () => isQrReaderFieldType,
385
401
  isQueryParamReaderFieldType: () => isQueryParamReaderFieldType,
@@ -413,12 +429,15 @@ __export(events_exports, {
413
429
  plainDateToLocalDate: () => plainDateToLocalDate,
414
430
  precompileActionSchemas: () => precompileActionSchemas,
415
431
  resolveDateOfEvent: () => resolveDateOfEvent,
432
+ resolveEventCustomFlags: () => resolveEventCustomFlags,
416
433
  resolvePlaceOfEvent: () => resolvePlaceOfEvent,
434
+ runClientFunction: () => runClientFunction,
417
435
  runFieldValidations: () => runFieldValidations,
418
436
  runStructuralValidations: () => runStructuralValidations,
419
437
  safeUnion: () => safeUnion,
420
438
  status: () => status,
421
439
  timePeriodToDateRange: () => timePeriodToDateRange,
440
+ todayISO: () => todayISO,
422
441
  user: () => user,
423
442
  userCanAccessEventWithScopes: () => userCanAccessEventWithScopes,
424
443
  validate: () => validate,
@@ -693,14 +712,20 @@ var unflattenScope = (input) => {
693
712
  return { type, options };
694
713
  };
695
714
  var EncodedScope = z2.string().brand("EncodedScope");
696
- var decodeScope = (query) => {
697
- const scope = qs.parse(query, {
715
+ var decodedScopeCache = /* @__PURE__ */ new Map();
716
+ var decodeScope = (encodedScope) => {
717
+ if (decodedScopeCache.has(encodedScope)) {
718
+ return decodedScopeCache.get(encodedScope);
719
+ }
720
+ const scope = qs.parse(encodedScope, {
698
721
  ignoreQueryPrefix: true,
699
722
  comma: true,
700
723
  allowDots: true
701
724
  });
702
725
  const unflattenedScope = unflattenScope(scope);
703
- return Scope.safeParse(unflattenedScope)?.data;
726
+ const result = Scope.safeParse(unflattenedScope)?.data;
727
+ decodedScopeCache.set(encodedScope, result);
728
+ return result;
704
729
  };
705
730
  var DEFAULT_SCOPE_OPTIONS = {
706
731
  placeOfEvent: JurisdictionFilter.enum.all,
@@ -1080,8 +1105,8 @@ var ActionConditional = z7.discriminatedUnion("type", [
1080
1105
  // Action can be shown to the user in the list but as disabled
1081
1106
  EnableConditional
1082
1107
  ]).meta({
1083
- description: "Action conditional configuration",
1084
- id: "ActionConditional"
1108
+ id: "ActionConditional",
1109
+ description: "Conditional gating whether an action is shown (SHOW) or enabled (ENABLE). When omitted from an action, the action is shown and enabled for everyone."
1085
1110
  });
1086
1111
  var DisplayOnReviewConditional = z7.object({
1087
1112
  type: z7.literal(ConditionalType.DISPLAY_ON_REVIEW),
@@ -1097,8 +1122,8 @@ var FieldConditional = z7.discriminatedUnion("type", [
1097
1122
  // Field output can be shown / hidden on the review page
1098
1123
  DisplayOnReviewConditional
1099
1124
  ]).meta({
1100
- description: "Field conditional configuration",
1101
- id: "FieldConditional"
1125
+ id: "FieldConditional",
1126
+ description: "Conditional gating whether a form field is shown (SHOW), enabled (ENABLE), or displayed on the review page (DISPLAY_ON_REVIEW). When omitted, the field is shown and enabled for everyone, and is displayed on review whenever it has a value."
1102
1127
  });
1103
1128
 
1104
1129
  // ../commons/src/events/FieldType.ts
@@ -1195,6 +1220,11 @@ var FieldTypesToHideInReview = [
1195
1220
  FieldType.ALPHA_PRINT_BUTTON,
1196
1221
  FieldType.ALPHA_HIDDEN
1197
1222
  ];
1223
+ var HiddenFieldTypes = [
1224
+ FieldType.HTTP,
1225
+ FieldType.QUERY_PARAM_READER,
1226
+ FieldType.ALPHA_HIDDEN
1227
+ ];
1198
1228
 
1199
1229
  // ../commons/src/events/FieldValue.ts
1200
1230
  var z12 = __toESM(require("zod/v4"));
@@ -1321,7 +1351,7 @@ function plainDateToLocalDate(date) {
1321
1351
  // ../commons/src/events/FieldValue.ts
1322
1352
  var TextValue = z12.string();
1323
1353
  var HiddenFieldValue = z12.string();
1324
- var NonEmptyTextValue = TextValue.min(1);
1354
+ var NonEmptyTextValue = z12.string().trim().min(1);
1325
1355
  var DateValue = z12.iso.date().describe("Date in the format YYYY-MM-DD");
1326
1356
  var AgeValue = z12.object({
1327
1357
  age: z12.number(),
@@ -1350,6 +1380,7 @@ var DateRangeFieldValue = z12.object({
1350
1380
  var EmailValue = z12.email();
1351
1381
  var CheckboxFieldValue = z12.boolean();
1352
1382
  var NumberFieldValue = z12.number();
1383
+ var SignatureFieldValue = FileFieldValue;
1353
1384
  var ButtonFieldValue = z12.number();
1354
1385
  var VerificationStatusValue = z12.enum([
1355
1386
  "verified",
@@ -1648,8 +1679,9 @@ var RequestedCorrectionAction = ActionBase.extend(
1648
1679
  var ApprovedCorrectionAction = ActionBase.extend(
1649
1680
  z14.object({
1650
1681
  type: z14.literal(ActionType.APPROVE_CORRECTION),
1651
- requestId: z14.string()
1682
+ requestId: z14.string(),
1652
1683
  // TODO move into 'content' property
1684
+ content: z14.object({ immediateCorrection: z14.boolean().optional() }).optional()
1653
1685
  }).shape
1654
1686
  );
1655
1687
  var RejectedCorrectionAction = ActionBase.extend(
@@ -1742,8 +1774,8 @@ var FlagConfig = z15.object({
1742
1774
  ),
1743
1775
  label: TranslationConfig.describe("Human readable label of the flag.")
1744
1776
  }).meta({
1745
- description: "Flag configuration",
1746
- id: "FlagConfig"
1777
+ id: "FlagConfig",
1778
+ description: "Configuration for a custom flag that can be added to or removed from records by event actions."
1747
1779
  });
1748
1780
  var ActionFlagConfig = z15.object({
1749
1781
  id: Flag,
@@ -1752,8 +1784,8 @@ var ActionFlagConfig = z15.object({
1752
1784
  "When conditional is met, the operation is performed on the flag. If not provided, the operation is performed unconditionally."
1753
1785
  )
1754
1786
  }).meta({
1755
- description: "Action flag configuration",
1756
- id: "ActionFlagConfig"
1787
+ id: "ActionFlagConfig",
1788
+ description: "Add or remove operation applied to a flag when the parent action is accepted. Optionally gated by a conditional."
1757
1789
  });
1758
1790
 
1759
1791
  // ../commons/src/events/EventMetadata.ts
@@ -2180,11 +2212,31 @@ var FieldReference = import_v43.default.object({
2180
2212
  $$field: FieldId.describe("Id of the field to reference"),
2181
2213
  $$subfield: import_v43.default.array(import_v43.default.string()).optional().default([]).describe(
2182
2214
  'If the FieldValue is an object, subfield can be used to refer to e.g. `["foo", "bar"]` in `{ foo: { bar: 3 } }`'
2215
+ ),
2216
+ $$code: import_v43.default.string().optional().describe(
2217
+ "Serialised client-side function body. When present the expression is evaluated rather than dereferenced."
2218
+ )
2219
+ }).describe(
2220
+ "Reference to a field value, with an optional client-side computation applied."
2221
+ );
2222
+ function isCodeToEvaluate(v) {
2223
+ return !!v && typeof v === "object" && "$$code" in v;
2224
+ }
2225
+ var ComputedDefaultValue = import_v43.default.object({
2226
+ $$code: import_v43.default.string().describe(
2227
+ "Serialised client-side function body. Receives (undefined, context) where context includes $now, $online, and system variables."
2183
2228
  )
2184
- }).describe("Reference to a field by its ID");
2229
+ }).describe("A context-only computation used as a field default value.");
2185
2230
  var ValidationConfig = import_v43.default.object({
2186
- validator: Conditional,
2187
- message: TranslationConfig
2231
+ validator: Conditional.describe(
2232
+ "Conditional expression that must hold for the field value to be considered valid."
2233
+ ),
2234
+ message: TranslationConfig.describe(
2235
+ "Error message displayed when the validator does not hold."
2236
+ )
2237
+ }).meta({
2238
+ id: "ValidationConfig",
2239
+ description: "Validation rule applied to a form field. The validator is a conditional expression that must hold for the field value to be considered valid."
2188
2240
  });
2189
2241
  var requiredSchema = import_v43.default.union([
2190
2242
  import_v43.default.boolean(),
@@ -2215,7 +2267,7 @@ var BaseField = import_v43.default.object({
2215
2267
  "Indicates whether the field can be modified during record correction."
2216
2268
  ),
2217
2269
  value: FieldReference.or(import_v43.default.array(FieldReference)).optional().describe(
2218
- "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."
2270
+ "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."
2219
2271
  ),
2220
2272
  analytics: import_v43.default.boolean().default(false).optional().describe(
2221
2273
  "Indicates whether the field is included in analytics. When enabled, its value becomes available in the analytics dashboard."
@@ -2223,30 +2275,40 @@ var BaseField = import_v43.default.object({
2223
2275
  }).describe("Common properties shared across all field types.");
2224
2276
  var Divider = BaseField.extend({
2225
2277
  type: import_v43.default.literal(FieldType.DIVIDER)
2278
+ }).meta({
2279
+ description: "A horizontal line divider",
2280
+ id: "Divider"
2226
2281
  });
2227
2282
  var TextField = BaseField.extend({
2228
2283
  type: import_v43.default.literal(FieldType.TEXT),
2229
- defaultValue: import_v43.default.union([NonEmptyTextValue, SerializedUserField]).optional(),
2284
+ defaultValue: import_v43.default.union([NonEmptyTextValue, SerializedUserField, ComputedDefaultValue]).optional(),
2230
2285
  configuration: import_v43.default.object({
2231
2286
  maxLength: import_v43.default.number().optional().describe("Maximum length of the text"),
2232
2287
  type: import_v43.default.enum(["text", "password"]).optional(),
2233
2288
  prefix: TranslationConfig.optional(),
2234
2289
  postfix: TranslationConfig.optional()
2235
2290
  }).default({ type: "text" }).optional()
2236
- }).describe("Text input");
2291
+ }).meta({
2292
+ description: "A text input field",
2293
+ id: "TextField"
2294
+ });
2237
2295
  var NumberField = BaseField.extend({
2238
2296
  type: import_v43.default.literal(FieldType.NUMBER),
2239
- defaultValue: NumberFieldValue.optional(),
2297
+ defaultValue: NumberFieldValue.or(ComputedDefaultValue).optional(),
2240
2298
  configuration: import_v43.default.object({
2241
2299
  min: import_v43.default.number().optional().describe("Minimum value"),
2242
2300
  max: import_v43.default.number().optional().describe("Maximum value"),
2301
+ integer: import_v43.default.boolean().optional().describe("When true, only whole numbers are allowed"),
2243
2302
  prefix: TranslationConfig.optional(),
2244
2303
  postfix: TranslationConfig.optional()
2245
2304
  }).optional()
2246
- }).describe("Number input");
2305
+ }).meta({
2306
+ description: "A number input field",
2307
+ id: "NumberField"
2308
+ });
2247
2309
  var TextAreaField = BaseField.extend({
2248
2310
  type: import_v43.default.literal(FieldType.TEXTAREA),
2249
- defaultValue: NonEmptyTextValue.optional(),
2311
+ defaultValue: NonEmptyTextValue.or(ComputedDefaultValue).optional(),
2250
2312
  configuration: import_v43.default.object({
2251
2313
  maxLength: import_v43.default.number().optional().describe("Maximum length of the text"),
2252
2314
  rows: import_v43.default.number().optional().describe("Number of visible text lines"),
@@ -2254,7 +2316,10 @@ var TextAreaField = BaseField.extend({
2254
2316
  prefix: TranslationConfig.optional(),
2255
2317
  postfix: TranslationConfig.optional()
2256
2318
  }).default({ rows: 4 }).optional()
2257
- }).describe("Multiline text input");
2319
+ }).meta({
2320
+ description: "A multiline text input",
2321
+ id: "TextAreaField"
2322
+ });
2258
2323
  var ImageMimeType = import_v43.default.enum([
2259
2324
  "image/png",
2260
2325
  "image/jpg",
@@ -2277,58 +2342,76 @@ var SignatureField = BaseField.extend({
2277
2342
  signaturePromptLabel: TranslationConfig.describe(
2278
2343
  "Title of the signature modal"
2279
2344
  ),
2280
- defaultValue: FieldValue.optional(),
2345
+ defaultValue: SignatureFieldValue.or(ComputedDefaultValue).optional(),
2281
2346
  configuration: import_v43.default.object({
2282
2347
  maxFileSize: import_v43.default.number().describe("Maximum file size in bytes").default(DEFAULT_MAX_FILE_SIZE_BYTES),
2283
2348
  acceptedFileTypes: MimeType.array().optional().describe("List of allowed file formats for the signature")
2284
2349
  }).default({
2285
2350
  maxFileSize: DEFAULT_MAX_FILE_SIZE_BYTES
2286
2351
  })
2287
- }).describe("Signature input field");
2352
+ }).meta({
2353
+ description: "A signature input field",
2354
+ id: "SignatureField"
2355
+ });
2288
2356
  var EmailField = BaseField.extend({
2289
2357
  type: import_v43.default.literal(FieldType.EMAIL),
2290
2358
  configuration: import_v43.default.object({
2291
2359
  maxLength: import_v43.default.number().optional().describe("Maximum length of the text")
2292
2360
  }).default({ maxLength: 255 }).optional(),
2293
- defaultValue: NonEmptyTextValue.optional()
2361
+ defaultValue: NonEmptyTextValue.or(ComputedDefaultValue).optional()
2362
+ }).meta({
2363
+ description: "An email input field",
2364
+ id: "EmailField"
2294
2365
  });
2295
2366
  var DateField = BaseField.extend({
2296
2367
  type: import_v43.default.literal(FieldType.DATE),
2297
- defaultValue: SerializedNowDateTime.or(PlainDate).optional().describe("Default date value(yyyy-MM-dd)"),
2368
+ defaultValue: SerializedNowDateTime.or(PlainDate).or(ComputedDefaultValue).optional().describe("Default date value(yyyy-MM-dd)"),
2298
2369
  configuration: import_v43.default.object({
2299
2370
  notice: TranslationConfig.describe(
2300
2371
  "Text to display above the date input"
2301
2372
  ).optional()
2302
2373
  }).optional()
2303
- }).describe("A single date input (yyyy-MM-dd)");
2374
+ }).meta({
2375
+ description: "A date input (yyyy-MM-dd)",
2376
+ id: "DateField"
2377
+ });
2304
2378
  var AgeField = BaseField.extend({
2305
2379
  type: import_v43.default.literal(FieldType.AGE),
2306
- defaultValue: NumberFieldValue.optional(),
2380
+ defaultValue: NumberFieldValue.or(ComputedDefaultValue).optional(),
2307
2381
  configuration: import_v43.default.object({
2308
2382
  asOfDate: FieldReference,
2309
2383
  prefix: TranslationConfig.optional(),
2310
2384
  postfix: TranslationConfig.optional()
2311
2385
  })
2312
- }).describe("An age input field which uses the current date as the asOfDate");
2386
+ }).meta({
2387
+ description: "An age input field which uses the current date as the asOfDate",
2388
+ id: "AgeField"
2389
+ });
2313
2390
  var TimeField = BaseField.extend({
2314
2391
  type: import_v43.default.literal(FieldType.TIME),
2315
- defaultValue: SerializedNowDateTime.or(TimeValue).optional().describe("Default time value (HH-mm)"),
2392
+ defaultValue: SerializedNowDateTime.or(TimeValue).or(ComputedDefaultValue).optional().describe("Default time value (HH-mm)"),
2316
2393
  configuration: import_v43.default.object({
2317
2394
  use12HourFormat: import_v43.default.boolean().optional().describe("Whether to use 12-hour format"),
2318
2395
  notice: TranslationConfig.describe(
2319
2396
  "Text to display above the time input"
2320
2397
  ).optional()
2321
2398
  }).optional()
2322
- }).describe("A single date input (HH-mm)");
2399
+ }).meta({
2400
+ description: "A single time input (HH-mm)",
2401
+ id: "TimeField"
2402
+ });
2323
2403
  var DateRangeField = BaseField.extend({
2324
2404
  type: import_v43.default.literal(FieldType.DATE_RANGE),
2325
- defaultValue: DateRangeFieldValue.optional(),
2405
+ defaultValue: DateRangeFieldValue.or(ComputedDefaultValue).optional(),
2326
2406
  configuration: import_v43.default.object({
2327
2407
  notice: TranslationConfig.describe(
2328
2408
  "Text to display above the date input"
2329
2409
  ).optional()
2330
2410
  }).optional()
2331
- }).describe("A date range input ({ start: yyyy-MM-dd, end: yyyy-MM-dd })");
2411
+ }).meta({
2412
+ description: "A date range input ({ start: yyyy-MM-dd, end: yyyy-MM-dd })",
2413
+ id: "DateRangeField"
2414
+ });
2332
2415
  var HtmlFontVariant = import_v43.default.enum([
2333
2416
  "reg12",
2334
2417
  "reg14",
@@ -2372,21 +2455,33 @@ var ImageViewField = BaseField.extend({
2372
2455
  type: import_v43.default.literal(FieldType.IMAGE_VIEW),
2373
2456
  defaultValue: NonEmptyTextValue.optional(),
2374
2457
  configuration: ImageConfiguration
2375
- }).describe("A read-only image component for form pages");
2458
+ }).meta({
2459
+ description: "A read-only image component for form pages",
2460
+ id: "ImageViewField"
2461
+ });
2376
2462
  var Paragraph = BaseField.extend({
2377
2463
  type: import_v43.default.literal(FieldType.PARAGRAPH),
2378
2464
  configuration: ParagraphConfiguration
2379
- }).describe("A read-only HTML <p> paragraph");
2465
+ }).meta({
2466
+ description: "A read-only HTML <p> paragraph",
2467
+ id: "Paragraph"
2468
+ });
2380
2469
  var Heading = BaseField.extend({
2381
2470
  type: import_v43.default.literal(FieldType.HEADING),
2382
2471
  configuration: HeadingConfiguration
2383
- }).describe("A read-only heading component for form pages");
2472
+ }).meta({
2473
+ description: "A read-only heading component for form pages",
2474
+ id: "Heading"
2475
+ });
2384
2476
  var PageHeader = BaseField.extend({
2385
2477
  type: import_v43.default.literal(FieldType.PAGE_HEADER)
2386
- }).describe("A read-only header component for form pages");
2478
+ }).meta({
2479
+ description: "A read-only header component for form pages",
2480
+ id: "PageHeader"
2481
+ });
2387
2482
  var File = BaseField.extend({
2388
2483
  type: import_v43.default.literal(FieldType.FILE),
2389
- defaultValue: FileFieldValue.optional(),
2484
+ defaultValue: FileFieldValue.or(ComputedDefaultValue).optional(),
2390
2485
  configuration: import_v43.default.object({
2391
2486
  maxFileSize: import_v43.default.number().describe("Maximum file size in bytes").default(DEFAULT_MAX_FILE_SIZE_BYTES),
2392
2487
  acceptedFileTypes: MimeType.array().optional().describe("List of allowed file formats for the signature"),
@@ -2402,7 +2497,10 @@ var File = BaseField.extend({
2402
2497
  }).default({
2403
2498
  maxFileSize: DEFAULT_MAX_FILE_SIZE_BYTES
2404
2499
  })
2405
- }).describe("File upload");
2500
+ }).meta({
2501
+ description: "A file upload field",
2502
+ id: "File"
2503
+ });
2406
2504
  var SelectOption = import_v43.default.object({
2407
2505
  value: import_v43.default.string().describe("The value of the option"),
2408
2506
  label: import_v43.default.union([import_v43.default.string(), TranslationConfig]).describe("The label of the option"),
@@ -2410,7 +2508,7 @@ var SelectOption = import_v43.default.object({
2410
2508
  });
2411
2509
  var NumberWithUnitField = BaseField.extend({
2412
2510
  type: import_v43.default.literal(FieldType.NUMBER_WITH_UNIT),
2413
- defaultValue: NumberWithUnitFieldValue.optional(),
2511
+ defaultValue: NumberWithUnitFieldValue.or(ComputedDefaultValue).optional(),
2414
2512
  options: import_v43.default.array(SelectOption).describe("A list of options for the unit select"),
2415
2513
  configuration: import_v43.default.object({
2416
2514
  min: import_v43.default.number().optional().describe("Minimum value of the number field"),
@@ -2419,17 +2517,23 @@ var NumberWithUnitField = BaseField.extend({
2419
2517
  "Placeholder for the number field"
2420
2518
  )
2421
2519
  }).optional()
2422
- }).describe("Number with unit input");
2520
+ }).meta({
2521
+ description: "A number with unit input field",
2522
+ id: "NumberWithUnitField"
2523
+ });
2423
2524
  var RadioGroup = BaseField.extend({
2424
2525
  type: import_v43.default.literal(FieldType.RADIO_GROUP),
2425
- defaultValue: TextValue.optional(),
2526
+ defaultValue: TextValue.or(ComputedDefaultValue).optional(),
2426
2527
  options: import_v43.default.array(SelectOption).describe("A list of options"),
2427
2528
  configuration: import_v43.default.object({
2428
2529
  styles: import_v43.default.object({
2429
2530
  size: import_v43.default.enum(["NORMAL", "LARGE"]).optional()
2430
2531
  }).optional()
2431
2532
  }).optional()
2432
- }).describe("Grouped radio options");
2533
+ }).meta({
2534
+ description: "A grouped radio button field",
2535
+ id: "RadioGroup"
2536
+ });
2433
2537
  var BulletList = BaseField.extend({
2434
2538
  type: import_v43.default.literal(FieldType.BULLET_LIST),
2435
2539
  items: import_v43.default.array(TranslationConfig).describe("A list of items"),
@@ -2438,10 +2542,13 @@ var BulletList = BaseField.extend({
2438
2542
  fontVariant: HtmlFontVariant.optional()
2439
2543
  }).optional()
2440
2544
  }).default({})
2441
- }).describe("A list of bullet points");
2545
+ }).meta({
2546
+ description: "A list of bullet points",
2547
+ id: "BulletList"
2548
+ });
2442
2549
  var Select = BaseField.extend({
2443
2550
  type: import_v43.default.literal(FieldType.SELECT),
2444
- defaultValue: TextValue.optional(),
2551
+ defaultValue: TextValue.or(ComputedDefaultValue).optional(),
2445
2552
  options: import_v43.default.array(SelectOption).describe("A list of options"),
2446
2553
  noOptionsMessage: TranslationConfig.optional().describe(
2447
2554
  `
@@ -2453,16 +2560,22 @@ var Select = BaseField.extend({
2453
2560
  { ..., defaultMessage: "'{input}' is not listed among the health facilities." }
2454
2561
  `
2455
2562
  )
2456
- }).describe("Select input");
2563
+ }).meta({
2564
+ description: "A select input field",
2565
+ id: "Select"
2566
+ });
2457
2567
  var SelectDateRangeOption = import_v43.default.object({
2458
2568
  value: SelectDateRangeValue.describe("The value of the option"),
2459
2569
  label: TranslationConfig.describe("The label of the option")
2460
2570
  });
2461
2571
  var SelectDateRangeField = BaseField.extend({
2462
2572
  type: import_v43.default.literal(FieldType.SELECT_DATE_RANGE),
2463
- defaultValue: SelectDateRangeValue.optional(),
2573
+ defaultValue: SelectDateRangeValue.or(ComputedDefaultValue).optional(),
2464
2574
  options: import_v43.default.array(SelectDateRangeOption).describe("A list of options")
2465
- }).describe("Select input with date range options");
2575
+ }).meta({
2576
+ description: "A date range selection field",
2577
+ id: "SelectDateRangeField"
2578
+ });
2466
2579
  var NameConfig = import_v43.default.object({
2467
2580
  firstname: import_v43.default.object({ required: requiredSchema, label: TranslationConfig.optional() }).optional(),
2468
2581
  middlename: import_v43.default.object({ required: requiredSchema, label: TranslationConfig.optional() }).optional(),
@@ -2474,7 +2587,7 @@ var NameField = BaseField.extend({
2474
2587
  firstname: SerializedUserField.or(NonEmptyTextValue).optional(),
2475
2588
  middlename: SerializedUserField.or(NonEmptyTextValue).optional(),
2476
2589
  surname: SerializedUserField.or(NonEmptyTextValue).optional()
2477
- }).optional(),
2590
+ }).or(ComputedDefaultValue).optional(),
2478
2591
  configuration: import_v43.default.object({
2479
2592
  name: NameConfig.default({
2480
2593
  firstname: { required: true },
@@ -2493,26 +2606,41 @@ var NameField = BaseField.extend({
2493
2606
  surname: { required: true }
2494
2607
  }
2495
2608
  }).optional()
2496
- }).describe("Name input field");
2609
+ }).meta({
2610
+ description: "A field for entering a persons name",
2611
+ id: "NameField"
2612
+ });
2497
2613
  var PhoneField = BaseField.extend({
2498
- defaultValue: NonEmptyTextValue.optional(),
2614
+ defaultValue: NonEmptyTextValue.or(ComputedDefaultValue).optional(),
2499
2615
  type: import_v43.default.literal(FieldType.PHONE)
2500
- }).describe("Phone input field");
2616
+ }).meta({
2617
+ description: "A field for entering a phone number",
2618
+ id: "PhoneField"
2619
+ });
2501
2620
  var IdField = BaseField.extend({
2502
- defaultValue: NonEmptyTextValue.optional(),
2621
+ defaultValue: NonEmptyTextValue.or(ComputedDefaultValue).optional(),
2503
2622
  type: import_v43.default.literal(FieldType.ID)
2504
- }).describe("ID input field");
2623
+ }).meta({
2624
+ description: "A field for entering an ID",
2625
+ id: "IdField"
2626
+ });
2505
2627
  var Checkbox = BaseField.extend({
2506
2628
  type: import_v43.default.literal(FieldType.CHECKBOX),
2507
- defaultValue: CheckboxFieldValue.default(false)
2508
- }).describe("Boolean checkbox field");
2629
+ defaultValue: CheckboxFieldValue.or(ComputedDefaultValue).default(false)
2630
+ }).meta({
2631
+ description: "A boolean checkbox field",
2632
+ id: "Checkbox"
2633
+ });
2509
2634
  var Country = BaseField.extend({
2510
2635
  type: import_v43.default.literal(FieldType.COUNTRY),
2511
- defaultValue: NonEmptyTextValue.optional(),
2636
+ defaultValue: NonEmptyTextValue.or(ComputedDefaultValue).optional(),
2512
2637
  optionOverrides: import_v43.default.array(SelectOption.omit({ label: true })).optional().describe(
2513
2638
  "Conditionals for specific countries. Countries not listed are always shown and enabled."
2514
2639
  )
2515
- }).describe("Country select field");
2640
+ }).meta({
2641
+ description: "A field for selecting a country",
2642
+ id: "Country"
2643
+ });
2516
2644
  var AllowedLocations = JurisdictionReference.optional().describe(
2517
2645
  "Limits which location options are selectable depending on user jurisdiction and location."
2518
2646
  );
@@ -2521,28 +2649,33 @@ var AdministrativeAreas = import_v43.default.enum([
2521
2649
  "HEALTH_FACILITY",
2522
2650
  "CRVS_OFFICE"
2523
2651
  ]);
2524
- var AdministrativeAreaConfiguration = import_v43.default.object({
2525
- partOf: FieldReference.optional().describe("Parent location"),
2526
- type: AdministrativeAreas,
2527
- allowedLocations: AllowedLocations
2528
- }).describe("Administrative area options");
2529
2652
  var AdministrativeAreaField = BaseField.extend({
2530
2653
  type: import_v43.default.literal(FieldType.ADMINISTRATIVE_AREA),
2531
- defaultValue: import_v43.default.union([NonEmptyTextValue, SerializedUserField]).optional(),
2532
- configuration: AdministrativeAreaConfiguration
2533
- }).describe("Administrative area input field e.g. facility, office");
2654
+ defaultValue: import_v43.default.union([NonEmptyTextValue, SerializedUserField, ComputedDefaultValue]).optional(),
2655
+ configuration: import_v43.default.object({
2656
+ partOf: FieldReference.optional().describe("Parent location"),
2657
+ type: AdministrativeAreas,
2658
+ allowedLocations: AllowedLocations
2659
+ }).describe("Administrative area options")
2660
+ }).meta({
2661
+ description: "Administrative area input field",
2662
+ id: "AdministrativeAreaField"
2663
+ });
2534
2664
  var LocationInput = BaseField.extend({
2535
2665
  type: import_v43.default.literal(FieldType.LOCATION),
2536
- defaultValue: import_v43.default.union([NonEmptyTextValue, SerializedUserField]).optional(),
2666
+ defaultValue: import_v43.default.union([NonEmptyTextValue, SerializedUserField, ComputedDefaultValue]).optional(),
2537
2667
  configuration: import_v43.default.object({
2538
2668
  locationTypes: import_v43.default.array(import_v43.default.string()).optional().describe("Types of the locations that are available for selection."),
2539
2669
  allowedLocations: AllowedLocations
2540
2670
  }).optional()
2541
- }).describe("Input field for a location");
2671
+ }).meta({
2672
+ description: "A field for selecting a location",
2673
+ id: "LocationInput"
2674
+ });
2542
2675
  var FileUploadWithOptions = BaseField.extend({
2543
2676
  type: import_v43.default.literal(FieldType.FILE_WITH_OPTIONS),
2544
2677
  options: import_v43.default.array(SelectOption).describe("A list of options"),
2545
- defaultValue: FileFieldWithOptionValue.optional(),
2678
+ defaultValue: FileFieldWithOptionValue.or(ComputedDefaultValue).optional(),
2546
2679
  configuration: import_v43.default.object({
2547
2680
  maxFileSize: import_v43.default.number().describe("Maximum file size in bytes").default(DEFAULT_MAX_FILE_SIZE_BYTES),
2548
2681
  maxImageSize: import_v43.default.object({
@@ -2552,15 +2685,18 @@ var FileUploadWithOptions = BaseField.extend({
2552
2685
  }).default({
2553
2686
  maxFileSize: DEFAULT_MAX_FILE_SIZE_BYTES
2554
2687
  })
2688
+ }).meta({
2689
+ description: "A field for uploading files with file type options",
2690
+ id: "FileUploadWithOptions"
2555
2691
  });
2556
2692
  var Facility = BaseField.extend({
2557
2693
  type: import_v43.default.literal(FieldType.FACILITY),
2558
- defaultValue: NonEmptyTextValue.optional(),
2694
+ defaultValue: NonEmptyTextValue.or(ComputedDefaultValue).optional(),
2559
2695
  configuration: import_v43.default.object({ allowedLocations: AllowedLocations }).optional()
2560
2696
  }).describe("Input field for a facility");
2561
2697
  var Office = BaseField.extend({
2562
2698
  type: import_v43.default.literal(FieldType.OFFICE),
2563
- defaultValue: NonEmptyTextValue.optional(),
2699
+ defaultValue: NonEmptyTextValue.or(ComputedDefaultValue).optional(),
2564
2700
  configuration: import_v43.default.object({ allowedLocations: AllowedLocations }).optional()
2565
2701
  }).describe("Input field for an office");
2566
2702
  var DefaultAddressFieldValue = DomesticAddressFieldValue.extend({
@@ -2596,8 +2732,11 @@ var Address = BaseField.extend({
2596
2732
  ).optional(),
2597
2733
  allowedLocations: AllowedLocations
2598
2734
  }).optional(),
2599
- defaultValue: DefaultAddressFieldValue.optional()
2600
- }).describe("Address input field \u2013 a combination of location and text fields");
2735
+ defaultValue: DefaultAddressFieldValue.or(ComputedDefaultValue).optional()
2736
+ }).meta({
2737
+ description: "Address input field \u2013 a combination of location and text fields",
2738
+ id: "Address"
2739
+ });
2601
2740
  var StaticDataEntry = import_v43.default.object({
2602
2741
  id: import_v43.default.string().describe("ID for the data entry."),
2603
2742
  label: TranslationConfig,
@@ -2612,7 +2751,10 @@ var DataField = BaseField.extend({
2612
2751
  subtitle: TranslationConfig.optional(),
2613
2752
  data: import_v43.default.array(DataEntry)
2614
2753
  })
2615
- }).describe("Data field for displaying read-only data");
2754
+ }).meta({
2755
+ description: "A field for displaying a table of read-only data",
2756
+ id: "DataField"
2757
+ });
2616
2758
  var ButtonSize = import_v43.default.enum(["small", "medium", "large"]);
2617
2759
  var ButtonType = import_v43.default.enum([
2618
2760
  "primary",
@@ -2637,13 +2779,19 @@ var ButtonConfiguration = import_v43.default.object({
2637
2779
  });
2638
2780
  var ButtonField = BaseField.extend({
2639
2781
  type: import_v43.default.literal(FieldType.BUTTON),
2640
- defaultValue: ButtonFieldValue.optional(),
2782
+ defaultValue: ButtonFieldValue.or(ComputedDefaultValue).optional(),
2641
2783
  configuration: ButtonConfiguration
2642
- }).describe("Generic button without any built-in functionality");
2784
+ }).meta({
2785
+ description: "A generic button that can be used to trigger an action",
2786
+ id: "ButtonField"
2787
+ });
2643
2788
  var FieldGroup = BaseField.extend({
2644
2789
  type: import_v43.default.literal(FieldType.FIELD_GROUP),
2645
2790
  // eslint-disable-next-line @typescript-eslint/no-use-before-define
2646
2791
  fields: import_v43.default.lazy(() => import_v43.default.array(FieldConfig))
2792
+ }).meta({
2793
+ description: "A group of fields that are displayed together",
2794
+ id: "FieldGroup"
2647
2795
  });
2648
2796
  var AlphaPrintButton = BaseField.extend({
2649
2797
  type: import_v43.default.literal(FieldType.ALPHA_PRINT_BUTTON),
@@ -2653,10 +2801,13 @@ var AlphaPrintButton = BaseField.extend({
2653
2801
  "Label for the print button"
2654
2802
  )
2655
2803
  })
2656
- }).describe("Print button field for printing certificates");
2804
+ }).meta({
2805
+ description: "An experimental print button field for printing certificates during the declaration process",
2806
+ id: "AlphaPrintButton"
2807
+ });
2657
2808
  var HttpField = BaseField.extend({
2658
2809
  type: import_v43.default.literal(FieldType.HTTP),
2659
- defaultValue: HttpFieldValue.optional(),
2810
+ defaultValue: HttpFieldValue.or(ComputedDefaultValue).optional(),
2660
2811
  configuration: import_v43.default.object({
2661
2812
  trigger: FieldReference.optional().describe(
2662
2813
  "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."
@@ -2669,20 +2820,30 @@ var HttpField = BaseField.extend({
2669
2820
  params: import_v43.default.record(import_v43.default.string(), import_v43.default.union([import_v43.default.string(), FieldReference])).optional(),
2670
2821
  timeout: import_v43.default.number().default(15e3).describe("Request timeout in milliseconds")
2671
2822
  })
2672
- }).describe("HTTP request function triggered by a button click or other event");
2823
+ }).meta({
2824
+ description: "Makes a background HTTP request to an external service and stores the response so other fields can use it. Has no visible UI \u2014 pair with LOADER to show request status.",
2825
+ id: "HttpField"
2826
+ });
2673
2827
  var AutocompleteField = BaseField.extend({
2674
2828
  type: import_v43.default.literal(FieldType.AUTOCOMPLETE),
2675
2829
  configuration: import_v43.default.object({
2676
- url: import_v43.default.string().describe("URL to fetch autocomplete suggestions from").optional(),
2830
+ url: import_v43.default.string().describe(
2831
+ "URL to fetch autocomplete suggestions from. This should be a country config server endpoint."
2832
+ ).optional(),
2677
2833
  method: import_v43.default.enum(["GET", "POST"]).default("GET").optional(),
2678
2834
  defaultOptions: import_v43.default.array(
2679
2835
  import_v43.default.object({
2680
2836
  label: import_v43.default.string(),
2681
2837
  value: import_v43.default.string()
2682
2838
  })
2683
- ).optional()
2839
+ ).optional().describe(
2840
+ "Manual entry is supported through configuration, allowing users to provide values not currently represented in the dataset."
2841
+ )
2684
2842
  })
2685
- }).describe("Autocomplete input field");
2843
+ }).meta({
2844
+ description: "Generic autocomplete component designed for use with large dictionary-based datasets. The component supports dynamic retrieval of options from configurable data sources and is intended for datasets that may contain tens or hundreds of thousands of records.",
2845
+ id: "AutocompleteField"
2846
+ });
2686
2847
  var SearchField = HttpField.extend({
2687
2848
  type: import_v43.default.literal(FieldType.SEARCH),
2688
2849
  configuration: SearchQuery.pick({
@@ -2715,6 +2876,9 @@ var SearchField = HttpField.extend({
2715
2876
  ok: TranslationConfig.optional()
2716
2877
  }).optional()
2717
2878
  })
2879
+ }).meta({
2880
+ description: "A search input field",
2881
+ id: "SearchField"
2718
2882
  });
2719
2883
  var LinkButtonField = BaseField.extend({
2720
2884
  type: import_v43.default.literal(FieldType.LINK_BUTTON),
@@ -2723,28 +2887,35 @@ var LinkButtonField = BaseField.extend({
2723
2887
  text: TranslationConfig.describe("Text to display on the button"),
2724
2888
  icon: import_v43.default.string().optional().describe("Icon for the button. You can find icons from OpenCRVS UI-Kit.")
2725
2889
  })
2726
- }).describe("Button that opens a link");
2890
+ }).meta({
2891
+ description: "A button that opens a URL link",
2892
+ id: "LinkButtonField"
2893
+ });
2727
2894
  var VerificationStatus = BaseField.extend({
2728
2895
  type: import_v43.default.literal(FieldType.VERIFICATION_STATUS),
2729
- defaultValue: VerificationStatusValue.optional(),
2896
+ defaultValue: VerificationStatusValue.or(ComputedDefaultValue).optional(),
2730
2897
  configuration: import_v43.default.object({
2731
2898
  status: TranslationConfig.describe("Text to display on the status pill."),
2732
2899
  description: TranslationConfig.describe(
2733
2900
  "Explaining text on the banner in form."
2734
2901
  )
2735
2902
  })
2903
+ }).meta({
2904
+ description: "Displays a verification state (e.g. ID verified / pending). Often paired with ID_READER \u2014 it can read its value off an ID_READER rather than holding its own.",
2905
+ id: "VerificationStatus"
2736
2906
  });
2737
2907
  var QueryParamReaderField = BaseField.extend({
2738
2908
  type: import_v43.default.literal(FieldType.QUERY_PARAM_READER),
2739
2909
  configuration: import_v43.default.object({
2740
2910
  pickParams: import_v43.default.array(import_v43.default.string()).describe("List of query parameters to read from the URL")
2741
2911
  })
2742
- }).describe(
2743
- "A field that maps URL query params into form values and clears them afterward"
2744
- );
2912
+ }).meta({
2913
+ description: "A field that maps URL query params into form values and clears them afterward",
2914
+ id: "QueryParamReaderField"
2915
+ });
2745
2916
  var QrReaderField = BaseField.extend({
2746
2917
  type: import_v43.default.literal(FieldType.QR_READER),
2747
- defaultValue: QrReaderFieldValue.optional(),
2918
+ defaultValue: QrReaderFieldValue.or(ComputedDefaultValue).optional(),
2748
2919
  configuration: import_v43.default.object({
2749
2920
  validator: import_v43.default.any().meta({
2750
2921
  description: "JSON Schema to validate the scanned QR code data against before populating the form fields.",
@@ -2752,21 +2923,27 @@ var QrReaderField = BaseField.extend({
2752
2923
  })
2753
2924
  }).optional()
2754
2925
  }).meta({
2755
- description: "Configuration for QR code reader field, including optional JSON Schema validator.",
2926
+ description: "QR code reader field, including optional JSON Schema validator.",
2756
2927
  id: "QrReaderField"
2757
2928
  });
2758
2929
  var IdReaderField = BaseField.extend({
2759
2930
  type: import_v43.default.literal(FieldType.ID_READER),
2760
- defaultValue: IdReaderFieldValue.optional(),
2931
+ defaultValue: IdReaderFieldValue.or(ComputedDefaultValue).optional(),
2761
2932
  methods: import_v43.default.array(
2762
2933
  import_v43.default.union([QrReaderField, LinkButtonField]).describe("Methods for reading an ID")
2763
2934
  )
2935
+ }).meta({
2936
+ description: "A wrapper around nested form fields, specifically QR_READER and LINK_BUTTON. It can hold the QR_READERs value.",
2937
+ id: "IdReaderField"
2764
2938
  });
2765
2939
  var CustomField = BaseField.extend({
2766
2940
  type: import_v43.default.literal(FieldType._EXPERIMENTAL_CUSTOM),
2767
2941
  defaultValue: CustomFieldValue.optional(),
2768
2942
  src: import_v43.default.string().describe("Module source path for the custom field component"),
2769
2943
  configuration: import_v43.default.unknown().optional()
2944
+ }).meta({
2945
+ description: "An expiremental custom field that is defined by a module source path",
2946
+ id: "CustomField"
2770
2947
  });
2771
2948
  var FieldStyleVariant = import_v43.default.enum(["default", "highlighted"]);
2772
2949
  var LoaderField = BaseField.extend({
@@ -2776,22 +2953,25 @@ var LoaderField = BaseField.extend({
2776
2953
  configuration: import_v43.default.object({
2777
2954
  text: TranslationConfig.describe("Display text above the loading spinner")
2778
2955
  })
2779
- }).describe(
2780
- "A non-interactive field that indicates an in progress operation in form"
2781
- );
2956
+ }).meta({
2957
+ description: "A non-interactive field that indicates an in progress operation in form",
2958
+ id: "LoaderField"
2959
+ });
2782
2960
  var HiddenField = BaseField.extend({
2783
2961
  type: import_v43.default.literal(FieldType.ALPHA_HIDDEN),
2784
2962
  required: import_v43.default.boolean().default(false).optional(),
2785
2963
  defaultValue: TextValue.optional()
2786
- }).describe(
2787
- "A non-interactive, hidden field that only hold a value in the form"
2788
- );
2964
+ }).meta({
2965
+ description: "A non-interactive, hidden field that only hold a value in the form",
2966
+ id: "HiddenField"
2967
+ });
2789
2968
  var UserRoleField = BaseField.extend({
2790
2969
  type: import_v43.default.literal(FieldType.USER_ROLE),
2791
2970
  defaultValue: TextValue.optional()
2792
- }).describe(
2793
- "A select dropdown that is automatically populated with available user roles"
2794
- );
2971
+ }).meta({
2972
+ description: "A select dropdown that is automatically populated with available user roles",
2973
+ id: "UserRoleField"
2974
+ });
2795
2975
  var FieldConfig = import_v43.default.discriminatedUnion("type", [
2796
2976
  FieldGroup,
2797
2977
  Address,
@@ -2891,15 +3071,18 @@ var VerificationPageConfig = FormPageConfig.extend({
2891
3071
  actions: VerificationActionConfig
2892
3072
  });
2893
3073
  var PageConfig = z21.discriminatedUnion("type", [FormPageConfig, VerificationPageConfig]).meta({
2894
- description: "Page configuration",
2895
- id: "PageConfig"
3074
+ id: "PageConfig",
3075
+ description: "Configuration for a single page in a form. Either a form page with fields and a continue button, or a verification page with verify/cancel options."
2896
3076
  });
2897
3077
 
2898
3078
  // ../commons/src/events/FormConfig.ts
2899
3079
  var DeclarationFormConfig = z22.object({
2900
3080
  label: TranslationConfig.describe("Human readable description of the form"),
2901
3081
  pages: z22.array(FormPageConfig)
2902
- }).describe("Configuration of the declaration form.");
3082
+ }).meta({
3083
+ id: "DeclarationFormConfig",
3084
+ description: "Configuration of the declaration form."
3085
+ });
2903
3086
  var ActionFormConfig = z22.object({
2904
3087
  label: TranslationConfig.describe("Human readable description of the form"),
2905
3088
  pages: z22.array(PageConfig)
@@ -2999,6 +3182,9 @@ var DeduplicationConfig = z23.object({
2999
3182
  id: z23.string(),
3000
3183
  label: TranslationConfig,
3001
3184
  query: Clause
3185
+ }).meta({
3186
+ id: "DeduplicationConfig",
3187
+ description: "Configuration for duplicate detection on a declare or register action. The query is built from fuzzy / strict / date-range matchers combined with and/or/not."
3002
3188
  });
3003
3189
 
3004
3190
  // ../commons/src/events/ActionConfig.ts
@@ -3036,6 +3222,11 @@ var ReadActionConfig = ActionConfigBase.extend(
3036
3222
  conditionals: z24.never().optional().describe("Read-action can not be disabled or hidden with conditionals.")
3037
3223
  }).shape
3038
3224
  );
3225
+ var NotifyConfig = ActionConfigBase.extend(
3226
+ z24.object({
3227
+ type: z24.literal(ActionType.NOTIFY)
3228
+ }).shape
3229
+ );
3039
3230
  var DeclareConfig = DeclarationActionBase.extend(
3040
3231
  z24.object({
3041
3232
  type: z24.literal(ActionType.DECLARE),
@@ -3116,17 +3307,46 @@ var ActionConfig = z24.discriminatedUnion("type", [
3116
3307
  * OpenAPI references are defined here so our generated OpenAPI spec knows to reuse the models
3117
3308
  * and treat them as "models" instead of duplicating the data structure in each endpoint.
3118
3309
  */
3119
- ReadActionConfig.meta({ id: "ReadActionConfig" }),
3120
- DeclareConfig.meta({ id: "DeclareActionConfig" }),
3121
- RejectConfig.meta({ id: "RejectActionConfig" }),
3122
- RegisterConfig.meta({ id: "RegisterActionConfig" }),
3310
+ ReadActionConfig.meta({
3311
+ id: "ReadActionConfig",
3312
+ description: "Configuration for the read action \u2014 defines the record-tab content displayed on the event overview page."
3313
+ }),
3314
+ NotifyConfig.meta({
3315
+ id: "NotifyActionConfig",
3316
+ description: "Configuration for the notify action. When present, NOTIFY uses this config independently from DECLARE. When absent, NOTIFY falls back to the DeclareActionConfig."
3317
+ }),
3318
+ DeclareConfig.meta({
3319
+ id: "DeclareActionConfig",
3320
+ description: "Configuration for the declare action. Includes review-page fields. NOTIFY falls back to this config when no dedicated NotifyActionConfig is provided."
3321
+ }),
3322
+ RejectConfig.meta({
3323
+ id: "RejectActionConfig",
3324
+ description: "Configuration for rejecting a record before registration."
3325
+ }),
3326
+ RegisterConfig.meta({
3327
+ id: "RegisterActionConfig",
3328
+ description: "Configuration for registering a record."
3329
+ }),
3123
3330
  PrintCertificateActionConfig.meta({
3124
- id: "PrintCertificateActionConfig"
3331
+ id: "PrintCertificateActionConfig",
3332
+ description: "Configuration for printing a certificate of a registered record."
3333
+ }),
3334
+ RequestCorrectionConfig.meta({
3335
+ id: "RequestCorrectionActionConfig",
3336
+ description: "Configuration for requesting a correction on a registered record."
3125
3337
  }),
3126
- RequestCorrectionConfig.meta({ id: "RequestCorrectionActionConfig" }),
3127
- EditActionConfig.meta({ id: "EditActionConfig" }),
3128
- ArchiveConfig.meta({ id: "ArchiveActionConfig" }),
3129
- CustomActionConfig.meta({ id: "CustomActionConfig" })
3338
+ EditActionConfig.meta({
3339
+ id: "EditActionConfig",
3340
+ description: "Configuration for editing a record before registration."
3341
+ }),
3342
+ ArchiveConfig.meta({
3343
+ id: "ArchiveActionConfig",
3344
+ description: "Configuration for archiving a record."
3345
+ }),
3346
+ CustomActionConfig.meta({
3347
+ id: "CustomActionConfig",
3348
+ description: "Configuration for a country-defined custom action. An event may include any number of these."
3349
+ })
3130
3350
  ]).describe(
3131
3351
  "Configuration of an action available for an event. Data collected depends on the action type and is accessible through the annotation property in ActionDocument."
3132
3352
  ).meta({ id: "ActionConfig" });
@@ -3202,7 +3422,10 @@ var Field = BaseField2.extend({
3202
3422
  }).describe("Custom field defined for the summary view.");
3203
3423
  var SummaryConfig = z27.object({
3204
3424
  fields: z27.array(z27.union([Field, ReferenceField])).describe("Fields displayed in the event summary view.")
3205
- }).describe("Configuration of the event summary section.");
3425
+ }).meta({
3426
+ id: "SummaryConfig",
3427
+ description: "Configuration of the event overview page. Defines which declaration fields appear in the record summary, optionally with custom labels, empty-value messages, and templated values."
3428
+ });
3206
3429
 
3207
3430
  // ../commons/src/events/AdvancedSearchConfig.ts
3208
3431
  var z28 = __toESM(require("zod/v4"));
@@ -3273,6 +3496,9 @@ var BaseField3 = z28.object({
3273
3496
  ),
3274
3497
  validations: z28.array(ValidationConfig).optional().describe(
3275
3498
  `Option for overriding the field validations specifically for advanced search form.`
3499
+ ),
3500
+ allowedLocations: JurisdictionReference.optional().describe(
3501
+ `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.`
3276
3502
  )
3277
3503
  });
3278
3504
  var SearchQueryParams = z28.object({
@@ -3326,6 +3552,9 @@ var AdvancedSearchField = z28.discriminatedUnion("fieldType", [FieldConfigSchema
3326
3552
  var AdvancedSearchConfig = z28.object({
3327
3553
  title: TranslationConfig.describe("Advanced search tab title"),
3328
3554
  fields: z28.array(AdvancedSearchField).describe("Advanced search fields within the tab.")
3555
+ }).meta({
3556
+ id: "AdvancedSearchConfig",
3557
+ description: "Configuration of one advanced search tab. Each tab has a title and a list of searchable fields \u2014 either declaration fields (via `field()`) or event metadata (via `event()`)."
3329
3558
  });
3330
3559
 
3331
3560
  // ../commons/src/events/utils.ts
@@ -3344,9 +3573,11 @@ var z30 = __toESM(require("zod/v4"));
3344
3573
  var z29 = __toESM(require("zod/v4"));
3345
3574
  function getDynamicNameValue(field3) {
3346
3575
  const nameConfiguration = field3.configuration?.name;
3576
+ const firstnameRequired = nameConfiguration?.firstname?.required ?? field3.required;
3577
+ const surnameRequired = nameConfiguration?.surname?.required ?? field3.required;
3347
3578
  return z29.object({
3348
- firstname: nameConfiguration?.firstname?.required ? NonEmptyTextValue : TextValue,
3349
- surname: nameConfiguration?.surname?.required ? NonEmptyTextValue : TextValue,
3579
+ firstname: firstnameRequired ? NonEmptyTextValue : TextValue,
3580
+ surname: surnameRequired ? NonEmptyTextValue : TextValue,
3350
3581
  middlename: nameConfiguration?.middlename?.required ? NonEmptyTextValue : TextValue.optional()
3351
3582
  });
3352
3583
  }
@@ -3693,7 +3924,7 @@ var isHiddenFieldType = (field3) => {
3693
3924
  return field3.config.type === FieldType.ALPHA_HIDDEN;
3694
3925
  };
3695
3926
  var isNonInteractiveFieldType = (field3) => {
3696
- return field3.type === FieldType.DIVIDER || field3.type === FieldType.PAGE_HEADER || field3.type === FieldType.PARAGRAPH || field3.type === FieldType.HEADING || field3.type === FieldType.BULLET_LIST || field3.type === FieldType.DATA || field3.type === FieldType.ALPHA_PRINT_BUTTON || field3.type === FieldType.HTTP || field3.type === FieldType.LINK_BUTTON || field3.type === FieldType.QUERY_PARAM_READER || field3.type === FieldType.LOADER;
3927
+ return field3.type === FieldType.DIVIDER || field3.type === FieldType.PAGE_HEADER || field3.type === FieldType.PARAGRAPH || field3.type === FieldType.HEADING || field3.type === FieldType.BULLET_LIST || field3.type === FieldType.DATA || field3.type === FieldType.ALPHA_PRINT_BUTTON || field3.type === FieldType.LINK_BUTTON || field3.type === FieldType.LOADER;
3697
3928
  };
3698
3929
 
3699
3930
  // ../commons/src/conditionals/validate.ts
@@ -3729,7 +3960,37 @@ function resolveDataPath(rootData, dataPath, instancePath) {
3729
3960
  }
3730
3961
  return current;
3731
3962
  }
3963
+ function todayISO() {
3964
+ return (0, import_date_fns.formatISO)(/* @__PURE__ */ new Date(), { representation: "date" });
3965
+ }
3966
+ var compiledFunctionCache = /* @__PURE__ */ new Map();
3967
+ function compileClientFunction(code) {
3968
+ let fn = compiledFunctionCache.get(code);
3969
+ if (!fn) {
3970
+ fn = new Function(`return (${code})`)();
3971
+ compiledFunctionCache.set(code, fn);
3972
+ }
3973
+ return fn;
3974
+ }
3732
3975
  (0, import_ajv_formats.default)(ajv);
3976
+ function buildClientFunctionContext(input) {
3977
+ return {
3978
+ $form: input.form,
3979
+ $now: todayISO(),
3980
+ // eslint-disable-next-line @typescript-eslint/no-use-before-define
3981
+ $online: isOnline(),
3982
+ $user: input.validatorContext?.user,
3983
+ $event: input.validatorContext?.event,
3984
+ $leafAdminStructureLocationIds: input.validatorContext?.leafAdminStructureLocationIds ?? [],
3985
+ user: input.systemVariables?.user,
3986
+ $window: input.systemVariables?.$window,
3987
+ locations: input.locations,
3988
+ adminLevelIds: input.adminLevelIds
3989
+ };
3990
+ }
3991
+ function runClientFunction(code, data, context) {
3992
+ return compileClientFunction(code)(data, context);
3993
+ }
3733
3994
  ajv.addKeyword({
3734
3995
  keyword: "daysFromDate",
3735
3996
  type: "string",
@@ -3774,7 +4035,7 @@ ajv.addKeyword({
3774
4035
  $data: true,
3775
4036
  errors: true,
3776
4037
  // @ts-ignore -- Force type. We will move this away from AJV next. Parsing the array will take seconds and is only called by core.
3777
- validate(schema, data, _2, dataContext) {
4038
+ validate(_schema, data, _2, dataContext) {
3778
4039
  const locationIdInput = data;
3779
4040
  const locations = dataContext?.rootData.$leafAdminStructureLocationIds ?? [];
3780
4041
  return locations.some((location) => location.id === locationIdInput);
@@ -3805,6 +4066,23 @@ function isAgeValue(value) {
3805
4066
  function mergeWithBaseFormState(values, context) {
3806
4067
  return { ...context.baseFormState, ...values };
3807
4068
  }
4069
+ ajv.addKeyword({
4070
+ keyword: "customClientValidator",
4071
+ schemaType: "object",
4072
+ errors: true,
4073
+ // @ts-expect-error -- AJV's public types don't expose `rootData`. All
4074
+ // `validate()` callers build root data via `buildClientFunctionContext`,
4075
+ // so the cast holds.
4076
+ validate(schema, data, _2, dataContext) {
4077
+ return Boolean(
4078
+ runClientFunction(
4079
+ schema.code,
4080
+ data,
4081
+ dataContext?.rootData ?? buildClientFunctionContext({ form: {} })
4082
+ )
4083
+ );
4084
+ }
4085
+ });
3808
4086
  function validate(schema, data) {
3809
4087
  const validator = ajv.getSchema(schema.$id) || ajv.compile(schema);
3810
4088
  if ("$form" in data) {
@@ -3841,17 +4119,14 @@ function isOnline() {
3841
4119
  }
3842
4120
  return true;
3843
4121
  }
3844
- function isConditionMet(conditional, values, context, eventIndex) {
3845
- return validate(conditional, {
3846
- $form: mergeWithBaseFormState(values, context),
3847
- $now: (0, import_date_fns.formatISO)(/* @__PURE__ */ new Date(), { representation: "date" }),
3848
- $online: isOnline(),
3849
- $user: context.user,
3850
- $leafAdminStructureLocationIds: context.leafAdminStructureLocationIds ?? [],
3851
- $flags: eventIndex?.flags ?? [],
3852
- $status: eventIndex?.status,
3853
- $event: context.event
3854
- });
4122
+ function isConditionMet(conditional, values, context) {
4123
+ return validate(
4124
+ conditional,
4125
+ buildClientFunctionContext({
4126
+ form: mergeWithBaseFormState(values, context),
4127
+ validatorContext: context
4128
+ })
4129
+ );
3855
4130
  }
3856
4131
  function getConditionalActionsForField(field3, values) {
3857
4132
  if (!field3.conditionals) {
@@ -3859,9 +4134,9 @@ function getConditionalActionsForField(field3, values) {
3859
4134
  }
3860
4135
  return field3.conditionals.filter((conditional) => validate(conditional.conditional, values)).map((conditional) => conditional.type);
3861
4136
  }
3862
- function areConditionsMet(conditions, values, context, event2) {
4137
+ function areConditionsMet(conditions, values, context, _event) {
3863
4138
  return conditions.every(
3864
- (condition) => isConditionMet(condition.conditional, values, context, event2)
4139
+ (condition) => isConditionMet(condition.conditional, values, context)
3865
4140
  );
3866
4141
  }
3867
4142
  function isFieldConditionMet(field3, form, conditionalType, context) {
@@ -3871,14 +4146,13 @@ function isFieldConditionMet(field3, form, conditionalType, context) {
3871
4146
  if (!hasRule) {
3872
4147
  return true;
3873
4148
  }
3874
- const validConditionals = getConditionalActionsForField(field3, {
3875
- $form: mergeWithBaseFormState(form, context),
3876
- $now: (0, import_date_fns.formatISO)(/* @__PURE__ */ new Date(), { representation: "date" }),
3877
- $online: isOnline(),
3878
- $user: context.user,
3879
- $leafAdminStructureLocationIds: context.leafAdminStructureLocationIds ?? [],
3880
- $event: context.event
3881
- });
4149
+ const validConditionals = getConditionalActionsForField(
4150
+ field3,
4151
+ buildClientFunctionContext({
4152
+ form: mergeWithBaseFormState(form, context),
4153
+ validatorContext: context
4154
+ })
4155
+ );
3882
4156
  return validConditionals.includes(conditionalType);
3883
4157
  }
3884
4158
  function isFieldVisible(field3, form, context) {
@@ -3904,7 +4178,14 @@ function isActionConditionMet(actionConfig, event2, context, conditionalType) {
3904
4178
  if (!rule) {
3905
4179
  return true;
3906
4180
  }
3907
- return isConditionMet(rule.conditional, event2.declaration, context, event2);
4181
+ return validate(rule.conditional, {
4182
+ ...buildClientFunctionContext({
4183
+ form: mergeWithBaseFormState(event2.declaration, context),
4184
+ validatorContext: context
4185
+ }),
4186
+ $flags: event2.flags,
4187
+ $status: event2.status
4188
+ });
3908
4189
  }
3909
4190
  function isActionEnabled(actionConfig, event2, context) {
3910
4191
  return isActionConditionMet(
@@ -4063,19 +4344,10 @@ function runFieldValidations({
4063
4344
  if (!isFieldVisible(field3.config, form, context)) {
4064
4345
  return [];
4065
4346
  }
4066
- const conditionalParameters = {
4067
- $form: mergeWithBaseFormState(form, context),
4068
- $now: (0, import_date_fns.formatISO)(/* @__PURE__ */ new Date(), { representation: "date" }),
4069
- /**
4070
- * In real use cases, there can be hundreds of thousands of locations.
4071
- * Make sure that the context contains only the locations that are needed for validation.
4072
- * E.g. if the user is a leaf admin, only the leaf locations under their admin structure are needed.
4073
- * Loading few megabytes of locations to memory just for validation is not efficient and will choke the application.
4074
- */
4075
- $leafAdminStructureLocationIds: context.leafAdminStructureLocationIds ?? [],
4076
- $online: isOnline(),
4077
- $user: context.user
4078
- };
4347
+ const conditionalParameters = buildClientFunctionContext({
4348
+ form: mergeWithBaseFormState(form, context),
4349
+ validatorContext: context
4350
+ });
4079
4351
  if (isFieldGroupFieldType(field3)) {
4080
4352
  const subfieldErrors = buildFormState(
4081
4353
  field3.config.fields,
@@ -4214,13 +4486,13 @@ function getActionConfig({
4214
4486
  actionType,
4215
4487
  customActionType
4216
4488
  }) {
4489
+ if (actionType === ActionType.NOTIFY) {
4490
+ return eventConfiguration.actions.find((a) => a.type === ActionType.NOTIFY) ?? eventConfiguration.actions.find((a) => a.type === ActionType.DECLARE);
4491
+ }
4217
4492
  return eventConfiguration.actions.find((a) => {
4218
4493
  if (a.type === ActionType.CUSTOM && customActionType) {
4219
4494
  return a.customActionType === customActionType;
4220
4495
  }
4221
- if (actionType === ActionType.NOTIFY) {
4222
- return a.type === ActionType.DECLARE;
4223
- }
4224
4496
  if (actionType === ActionType.APPROVE_CORRECTION || actionType === ActionType.REJECT_CORRECTION) {
4225
4497
  return a.type === ActionType.REQUEST_CORRECTION;
4226
4498
  }
@@ -4257,7 +4529,7 @@ var getActionAnnotationFields = (actionConfig) => {
4257
4529
  if (actionConfig.type === ActionType.CUSTOM) {
4258
4530
  return actionConfig.form;
4259
4531
  }
4260
- if ("review" in actionConfig) {
4532
+ if ("review" in actionConfig && actionConfig.review != null) {
4261
4533
  return actionConfig.review.fields;
4262
4534
  }
4263
4535
  return [];
@@ -4559,19 +4831,32 @@ function getPendingAction(actions) {
4559
4831
  }
4560
4832
  return pendingActions[0];
4561
4833
  }
4562
- function getCompleteActionAnnotation(annotation, event2, action) {
4834
+ function getCompleteActionAnnotation(event2, action) {
4563
4835
  if (action.originalActionId) {
4564
4836
  const originalAction = event2.actions.find(
4565
4837
  ({ id }) => id === action.originalActionId
4566
4838
  );
4567
4839
  if (originalAction?.status === ActionStatus.Requested) {
4568
- return deepMerge(
4569
- deepMerge(annotation, originalAction.annotation ?? {}),
4570
- action.annotation ?? {}
4571
- );
4840
+ return deepMerge(originalAction.annotation ?? {}, action.annotation ?? {});
4572
4841
  }
4573
4842
  }
4574
- return deepMerge(annotation, action.annotation ?? {});
4843
+ return action.annotation ?? {};
4844
+ }
4845
+ function getCompleteActionContent(event2, action) {
4846
+ const currentContent = "content" in action ? action.content : void 0;
4847
+ if (!action.originalActionId) {
4848
+ return currentContent;
4849
+ }
4850
+ const originalAction = event2.actions.find(
4851
+ ({ id }) => id === action.originalActionId
4852
+ );
4853
+ if (originalAction && "content" in originalAction && originalAction.content) {
4854
+ return {
4855
+ ...originalAction.content,
4856
+ ...currentContent ?? {}
4857
+ };
4858
+ }
4859
+ return currentContent;
4575
4860
  }
4576
4861
  function getCompleteActionDeclaration(declaration, event2, action) {
4577
4862
  if (action.originalActionId) {
@@ -4591,7 +4876,7 @@ function getAcceptedActions(event2) {
4591
4876
  return event2.actions.filter(isAcceptedAction).map((action) => ({
4592
4877
  ...action,
4593
4878
  declaration: getCompleteActionDeclaration({}, event2, action),
4594
- annotation: getCompleteActionAnnotation({}, event2, action)
4879
+ annotation: getCompleteActionAnnotation(event2, action)
4595
4880
  }));
4596
4881
  }
4597
4882
  var EXCLUDED_ACTIONS = [
@@ -4679,6 +4964,9 @@ function not(condition) {
4679
4964
  function never2() {
4680
4965
  return not(alwaysTrue());
4681
4966
  }
4967
+ function always() {
4968
+ return defineConditional(alwaysTrue());
4969
+ }
4682
4970
  function jsonFieldPath(field3) {
4683
4971
  return [field3.$$field, ...field3.$$subfield].join("/");
4684
4972
  }
@@ -5226,7 +5514,54 @@ function createFieldConditionals(fieldId) {
5226
5514
  }
5227
5515
  },
5228
5516
  required: [fieldId]
5229
- })
5517
+ }),
5518
+ /**
5519
+ * Custom client-side validator. The provided function is serialised and executed
5520
+ * just-in-time on the client only. External references (e.g. lodash) are not
5521
+ * available inside the function body — all logic must be self-contained.
5522
+ *
5523
+ * @example
5524
+ * field('nid').customClientValidator((value) => {
5525
+ * // LUHN check — all logic must be inline
5526
+ * const digits = String(value).split('').map(Number)
5527
+ * // ...
5528
+ * return isValid
5529
+ * })
5530
+ */
5531
+ customClientValidator(validationFn) {
5532
+ const code = validationFn.toString();
5533
+ return defineFormConditional({
5534
+ type: "object",
5535
+ properties: wrapToPath(
5536
+ { [fieldId]: { customClientValidator: { code } } },
5537
+ this.$$subfield
5538
+ ),
5539
+ required: [fieldId]
5540
+ });
5541
+ },
5542
+ /**
5543
+ * Custom client-side evaluation. Returns a {@link FieldReference} descriptor
5544
+ * that can be used as the `value` property or a DATA component entry.
5545
+ * The function receives the referenced field's value as the first argument and
5546
+ * the full form context as the second; its return value replaces the field reference.
5547
+ * The function is serialised and executed just-in-time on the client only.
5548
+ * External references (e.g. lodash) are not available inside the function body.
5549
+ *
5550
+ * For computing a default value without referencing a specific field, use
5551
+ * `evaluate(fn)` in the `defaultValue` property instead.
5552
+ *
5553
+ * @example
5554
+ * field('a').customClientEvaluation((aValue, ctx) =>
5555
+ * Number(aValue) + Number(ctx.$form.b)
5556
+ * )
5557
+ */
5558
+ customClientEvaluation(computationFn) {
5559
+ return {
5560
+ $$code: computationFn.toString(),
5561
+ $$field: fieldId,
5562
+ $$subfield: this.$$subfield
5563
+ };
5564
+ }
5230
5565
  };
5231
5566
  }
5232
5567
 
@@ -5399,8 +5734,9 @@ var EventConfig = _EventConfigBase.superRefine((event2, ctx) => {
5399
5734
  validateActionFlags(event2, ctx);
5400
5735
  validateActionOrder(event2, ctx);
5401
5736
  }).meta({
5402
- id: "EventConfig"
5403
- }).describe("Configuration defining an event type.");
5737
+ id: "EventConfig",
5738
+ description: "Configuration defining an event type registered in OpenCRVS (for example birth or death)."
5739
+ });
5404
5740
 
5405
5741
  // ../commons/src/events/EventConfigInput.ts
5406
5742
  var defineDeclarationForm = (form) => DeclarationFormConfig.parse(form);
@@ -5623,6 +5959,9 @@ var WorkqueueColumnValue = z34.object({
5623
5959
  var WorkqueueColumn = z34.object({
5624
5960
  label: TranslationConfig,
5625
5961
  value: WorkqueueColumnValue
5962
+ }).meta({
5963
+ id: "WorkqueueColumn",
5964
+ description: "Configuration for a single workqueue column. The value references an event metadata key (e.g. `dateOfEvent`, `status`, `trackingId`)."
5626
5965
  });
5627
5966
  function defineWorkqueuesColumns(workqueueColumns) {
5628
5967
  return workqueueColumns.map(
@@ -5828,8 +6167,8 @@ var WorkqueueConfigWithoutQuery = WorkqueueConfig.omit({
5828
6167
  var WorkqueueConfigInput = WorkqueueConfig.extend({
5829
6168
  query: CountryConfigQueryInputType
5830
6169
  }).meta({
5831
- description: "Workqueue configuration",
5832
- id: "WorkqueueConfig"
6170
+ id: "WorkqueueConfig",
6171
+ description: "Configuration for a single workqueue. Defines the filter applied to the event index, the quick-action button, the columns shown on each row, and the message rendered when the queue is empty."
5833
6172
  });
5834
6173
  function defineWorkqueue(workqueueInput) {
5835
6174
  const queryInput = workqueueInput.query;
@@ -5892,7 +6231,9 @@ var BaseActionInput = z38.object({
5892
6231
  keepAssignment: z38.boolean().optional(),
5893
6232
  keepAssignmentIfAccepted: z38.boolean().optional(),
5894
6233
  keepAssignmentIfRejected: z38.boolean().optional(),
5895
- waitFor: z38.boolean().optional(),
6234
+ waitFor: z38.boolean().default(true).describe(
6235
+ "Whether action waits for the indexing before returning. Defaults to true. Setting this to to false completes faster but might lead to stale data in the client if the client tries to read the event immediately after performing the action. Use with care."
6236
+ ),
5896
6237
  // For normal users, the createdAtLocation is resolved on the backend from the user's primaryOfficeId.
5897
6238
  // @TODO: createdAtLocation should be limited to actions that system users can perform. For normal users, it should not be part of the base action.
5898
6239
  createdAtLocation: UUID.nullish().describe(
@@ -6010,7 +6351,8 @@ var RejectCorrectionActionInput = BaseActionInput.extend(
6010
6351
  var ApproveCorrectionActionInput = BaseActionInput.extend(
6011
6352
  z38.object({
6012
6353
  requestId: z38.string(),
6013
- type: z38.literal(ActionType.APPROVE_CORRECTION).default(ActionType.APPROVE_CORRECTION)
6354
+ type: z38.literal(ActionType.APPROVE_CORRECTION).default(ActionType.APPROVE_CORRECTION),
6355
+ content: z38.object({ immediateCorrection: z38.boolean().optional() }).optional()
6014
6356
  }).shape
6015
6357
  );
6016
6358
  var ReadActionInput = BaseActionInput.extend(
@@ -6072,7 +6414,7 @@ var Draft = z39.object({
6072
6414
  }).describe(
6073
6415
  "A temporary storage for an action. Stored with details of the event, creator and creation time."
6074
6416
  );
6075
- var DraftInput = BaseActionInput.extend({
6417
+ var DraftInput = BaseActionInput.omit({ waitFor: true }).extend({
6076
6418
  type: ActionTypes.exclude([ActionTypes.enum.DELETE]),
6077
6419
  status: z39.enum([
6078
6420
  ActionStatus.Requested,
@@ -6159,6 +6501,8 @@ var updateActions = ActionTypes.extract([
6159
6501
  ActionType.ARCHIVE,
6160
6502
  ActionType.PRINT_CERTIFICATE,
6161
6503
  ActionType.REQUEST_CORRECTION,
6504
+ ActionType.APPROVE_CORRECTION,
6505
+ ActionType.REJECT_CORRECTION,
6162
6506
  ActionType.CUSTOM
6163
6507
  ]);
6164
6508
  function getActionUpdateMetadata(actions) {
@@ -6173,7 +6517,7 @@ function getActionUpdateMetadata(actions) {
6173
6517
  "createdAtLocation",
6174
6518
  "createdByRole"
6175
6519
  ];
6176
- return actions.filter(({ type }) => updateActions.safeParse(type).success).filter(({ status: status2 }) => status2 === ActionStatus.Accepted).reduce(
6520
+ return actions.filter(({ type }) => updateActions.safeParse(type).success).reduce(
6177
6521
  (_2, action) => {
6178
6522
  if (action.originalActionId) {
6179
6523
  const originalAction = actions.find(({ id }) => id === action.originalActionId) ?? action;
@@ -6200,28 +6544,19 @@ function getLegalStatuses(actions) {
6200
6544
  // ../commons/src/events/state/flags.ts
6201
6545
  var import_lodash3 = require("lodash");
6202
6546
  var import_date_fns3 = require("date-fns");
6203
- function isEditInProgress(actions) {
6204
- return actions.at(-1)?.type === ActionType.EDIT;
6205
- }
6206
- function isCorrectionRequested(actions) {
6207
- return actions.reduce((prev, { type }) => {
6208
- if (type === ActionType.REQUEST_CORRECTION) {
6209
- return true;
6210
- }
6211
- if (type === ActionType.APPROVE_CORRECTION) {
6212
- return false;
6547
+ function findPendingCorrectionAction(writeActions2) {
6548
+ let correctionRequestAction;
6549
+ for (let i = writeActions2.length - 1; i >= 0; i--) {
6550
+ const action = writeActions2[i];
6551
+ if (action.type === ActionType.APPROVE_CORRECTION || action.type === ActionType.REJECT_CORRECTION) {
6552
+ break;
6213
6553
  }
6214
- if (type === ActionType.REJECT_CORRECTION) {
6215
- return false;
6554
+ if (action.type === ActionType.REQUEST_CORRECTION) {
6555
+ correctionRequestAction = action;
6556
+ break;
6216
6557
  }
6217
- return prev;
6218
- }, false);
6219
- }
6220
- function isDeclarationIncomplete(actions) {
6221
- return getStatusFromActions(actions) === EventStatus.enum.NOTIFIED;
6222
- }
6223
- function isRejected(actions) {
6224
- return actions.at(-1)?.type === ActionType.REJECT;
6558
+ }
6559
+ return correctionRequestAction;
6225
6560
  }
6226
6561
  function isPotentialDuplicate(actions) {
6227
6562
  return actions.reduce((prev, { type }) => {
@@ -6250,6 +6585,88 @@ function isFlagConditionMet(conditional, form, action) {
6250
6585
  }
6251
6586
  });
6252
6587
  }
6588
+ function actionConfigRemovesFlag(action, flagId, actionsUpToAndIncluding, event2, eventConfiguration) {
6589
+ if (!isActionConfigType(action.type)) {
6590
+ return false;
6591
+ }
6592
+ const actionConfig = getActionConfig({
6593
+ eventConfiguration,
6594
+ actionType: action.type,
6595
+ customActionType: "customActionType" in action ? action.customActionType : void 0
6596
+ });
6597
+ const removeOperations = (actionConfig?.flags ?? []).filter(
6598
+ ({ id, operation }) => id === flagId && operation === "remove"
6599
+ );
6600
+ if (removeOperations.length === 0) {
6601
+ return false;
6602
+ }
6603
+ const eventUpToThisAction = { ...event2, actions: actionsUpToAndIncluding };
6604
+ const declaration = aggregateActionDeclarations(eventUpToThisAction);
6605
+ const annotation = aggregateActionAnnotations(eventUpToThisAction);
6606
+ const form = { ...declaration, ...annotation };
6607
+ return removeOperations.some(
6608
+ ({ conditional }) => conditional ? isFlagConditionMet(conditional, form, action) : true
6609
+ );
6610
+ }
6611
+ var INHERENT_FLAG_RULES = [
6612
+ {
6613
+ flag: InherentFlags.CORRECTION_REQUESTED,
6614
+ setOn: [ActionType.REQUEST_CORRECTION],
6615
+ resetOn: [ActionType.APPROVE_CORRECTION, ActionType.REJECT_CORRECTION]
6616
+ },
6617
+ {
6618
+ // INCOMPLETE mirrors the NOTIFIED status: set by NOTIFY, cleared by any
6619
+ // other status-changing action (see getStatusFromActions).
6620
+ flag: InherentFlags.INCOMPLETE,
6621
+ setOn: [ActionType.NOTIFY],
6622
+ resetOn: [
6623
+ ActionType.CREATE,
6624
+ ActionType.DECLARE,
6625
+ ActionType.REGISTER,
6626
+ ActionType.ARCHIVE
6627
+ ]
6628
+ },
6629
+ {
6630
+ flag: InherentFlags.REJECTED,
6631
+ setOn: [ActionType.REJECT],
6632
+ resetOn: [
6633
+ ActionType.NOTIFY,
6634
+ ActionType.DECLARE,
6635
+ ActionType.EDIT,
6636
+ ActionType.REGISTER
6637
+ ]
6638
+ },
6639
+ {
6640
+ flag: InherentFlags.POTENTIAL_DUPLICATE,
6641
+ setOn: [ActionType.DUPLICATE_DETECTED],
6642
+ resetOn: [ActionType.MARK_AS_DUPLICATE, ActionType.MARK_AS_NOT_DUPLICATE]
6643
+ },
6644
+ {
6645
+ flag: InherentFlags.EDIT_IN_PROGRESS,
6646
+ setOn: [ActionType.EDIT],
6647
+ resetOnAnyOtherAction: true
6648
+ }
6649
+ ];
6650
+ function resolveInherentFlag(rule, acceptedActions, event2, eventConfiguration) {
6651
+ return acceptedActions.reduce((present, action, idx) => {
6652
+ if (rule.setOn.includes(action.type)) {
6653
+ return true;
6654
+ }
6655
+ if (rule.resetOnAnyOtherAction || (rule.resetOn ?? []).includes(action.type)) {
6656
+ return false;
6657
+ }
6658
+ if (actionConfigRemovesFlag(
6659
+ action,
6660
+ rule.flag,
6661
+ acceptedActions.slice(0, idx + 1),
6662
+ event2,
6663
+ eventConfiguration
6664
+ )) {
6665
+ return false;
6666
+ }
6667
+ return present;
6668
+ }, false);
6669
+ }
6253
6670
  function resolveEventCustomFlags(event2, eventConfiguration) {
6254
6671
  const actions = getAcceptedActions(event2).filter(({ type }) => !isMetaAction(type)).sort((a, b) => a.createdAt.localeCompare(b.createdAt));
6255
6672
  return actions.reduce((acc, action, idx) => {
@@ -6285,8 +6702,7 @@ function resolveEventCustomFlags(event2, eventConfiguration) {
6285
6702
  return (0, import_lodash3.uniq)(flags);
6286
6703
  }, []);
6287
6704
  }
6288
- function getEventFlags(event2, config) {
6289
- const sortedActions = event2.actions.filter(({ type }) => !isMetaAction(type)).sort((a, b) => a.createdAt.localeCompare(b.createdAt));
6705
+ function getActionStatusFlags(sortedActions) {
6290
6706
  const actionStatus = sortedActions.reduce(
6291
6707
  (actionStatuses, { type, status: status2 }) => ({
6292
6708
  ...actionStatuses,
@@ -6294,26 +6710,26 @@ function getEventFlags(event2, config) {
6294
6710
  }),
6295
6711
  {}
6296
6712
  );
6297
- const flags = Object.entries(actionStatus).filter(([, status2]) => status2 !== ActionStatus.Accepted).map(([type, status2]) => {
6713
+ return Object.entries(actionStatus).filter(([, status2]) => status2 !== ActionStatus.Accepted).map(([type, status2]) => {
6298
6714
  const flag2 = joinValues([type, status2], ":").toLowerCase();
6299
6715
  return flag2;
6300
6716
  });
6301
- if (isCorrectionRequested(sortedActions)) {
6302
- flags.push(InherentFlags.CORRECTION_REQUESTED);
6303
- }
6304
- if (isDeclarationIncomplete(sortedActions)) {
6305
- flags.push(InherentFlags.INCOMPLETE);
6306
- }
6307
- if (isRejected(sortedActions)) {
6308
- flags.push(InherentFlags.REJECTED);
6309
- }
6310
- if (isPotentialDuplicate(sortedActions)) {
6311
- flags.push(InherentFlags.POTENTIAL_DUPLICATE);
6312
- }
6313
- if (isEditInProgress(sortedActions)) {
6314
- flags.push(InherentFlags.EDIT_IN_PROGRESS);
6315
- }
6316
- return [...flags, ...resolveEventCustomFlags(event2, config)];
6717
+ }
6718
+ function getInherentFlags(sortedActions, event2, eventConfiguration) {
6719
+ const acceptedActions = sortedActions.filter(
6720
+ ({ status: status2 }) => status2 === ActionStatus.Accepted
6721
+ );
6722
+ return INHERENT_FLAG_RULES.filter(
6723
+ (rule) => resolveInherentFlag(rule, acceptedActions, event2, eventConfiguration)
6724
+ ).map(({ flag: flag2 }) => flag2);
6725
+ }
6726
+ function getEventFlags(event2, config) {
6727
+ const sortedActions = event2.actions.filter(({ type }) => !isMetaAction(type)).sort((a, b) => a.createdAt.localeCompare(b.createdAt));
6728
+ return [
6729
+ ...getActionStatusFlags(sortedActions),
6730
+ ...getInherentFlags(sortedActions, event2, config),
6731
+ ...resolveEventCustomFlags(event2, config)
6732
+ ];
6317
6733
  }
6318
6734
 
6319
6735
  // ../commons/src/events/state/index.ts
@@ -6548,7 +6964,7 @@ function getActionAnnotation({
6548
6964
  const action = (0, import_lodash4.findLast)(activeActions, (a) => a.type === actionType);
6549
6965
  const actionWithCompleteAnnotation = action && {
6550
6966
  ...action,
6551
- annotation: getCompleteActionAnnotation({}, event2, action)
6967
+ annotation: getCompleteActionAnnotation(event2, action)
6552
6968
  };
6553
6969
  const matchingDraft = draft?.action.type === actionType ? draft : void 0;
6554
6970
  const sortedActions = (0, import_lodash4.orderBy)(
@@ -6620,6 +7036,9 @@ function createFieldConfig(fieldId, options) {
6620
7036
  }
6621
7037
 
6622
7038
  // ../commons/src/events/field.ts
7039
+ function evaluate(computationFn) {
7040
+ return { $$code: computationFn.toString() };
7041
+ }
6623
7042
  function field(fieldId, options = {}) {
6624
7043
  return {
6625
7044
  ...createFieldConditionals(fieldId),
@@ -7313,6 +7732,11 @@ var TENNIS_CLUB_DECLARATION_REVIEW = {
7313
7732
  id: "signature.upload.modal.title",
7314
7733
  defaultMessage: "Draw signature",
7315
7734
  description: "Title for the modal to draw signature"
7735
+ },
7736
+ // Zod applies the schema default at parse time, but this fixture bypasses
7737
+ // parsing — GeneratedInputField accesses configuration.maxFileSize directly.
7738
+ configuration: {
7739
+ maxFileSize: 5 * 1024 * 1024
7316
7740
  }
7317
7741
  }
7318
7742
  ]
@@ -7869,6 +8293,20 @@ var tennisClubMembershipEvent = defineConfig({
7869
8293
  },
7870
8294
  review: TENNIS_CLUB_DECLARATION_REVIEW
7871
8295
  },
8296
+ {
8297
+ type: ActionType.NOTIFY,
8298
+ label: {
8299
+ defaultMessage: "Notify health worker",
8300
+ description: "This is shown as the action name anywhere the user can trigger the action from",
8301
+ id: "event.tennis-club-membership.action.notify.label"
8302
+ },
8303
+ flags: [
8304
+ {
8305
+ id: "health-worker-notified",
8306
+ operation: "add"
8307
+ }
8308
+ ]
8309
+ },
7872
8310
  {
7873
8311
  type: ActionType.REJECT,
7874
8312
  label: {
@@ -8111,6 +8549,17 @@ var tennisClubMembershipEvent = defineConfig({
8111
8549
  }
8112
8550
  }
8113
8551
  ],
8552
+ flags: [
8553
+ {
8554
+ id: "health-worker-notified",
8555
+ requiresAction: false,
8556
+ label: {
8557
+ id: "event.tennis-club-membership.flag.health-worker-notified.label",
8558
+ defaultMessage: "Health worker notified",
8559
+ description: "Label for the health-worker-notified flag"
8560
+ }
8561
+ }
8562
+ ],
8114
8563
  advancedSearch: [
8115
8564
  {
8116
8565
  title: {
@@ -9869,7 +10318,7 @@ function matchesJurisdictionFilter(locationIds, filter, user2) {
9869
10318
  return locationIds.some((id) => id === user2.primaryOfficeId);
9870
10319
  }
9871
10320
  if (filter === JurisdictionFilter.enum.administrativeArea) {
9872
- return user2.administrativeAreaId === null || locationIds.some((id) => id === user2.administrativeAreaId);
10321
+ return !user2.administrativeAreaId || locationIds.some((id) => id === user2.administrativeAreaId);
9873
10322
  }
9874
10323
  return true;
9875
10324
  }
@@ -9958,7 +10407,7 @@ function canAccessUserWithScope({
9958
10407
  }
9959
10408
  const hasAdministrativeAreaInHierarchy = userToAccess.administrativeHierarchy.some(
9960
10409
  (id) => user2.administrativeAreaId === id
9961
- ) || user2.administrativeAreaId === null;
10410
+ ) || !user2.administrativeAreaId;
9962
10411
  if (opts?.accessLevel === JurisdictionFilter.enum.administrativeArea && !hasAdministrativeAreaInHierarchy) {
9963
10412
  return false;
9964
10413
  }
@@ -10264,18 +10713,19 @@ var ACTION_FILTERS = {
10264
10713
  function filterActionsByFlags(actions, flags) {
10265
10714
  return actions.filter((action) => ACTION_FILTERS[action]?.(flags) ?? true);
10266
10715
  }
10716
+ var REJECTED_ACTIONS = [
10717
+ ActionType.READ,
10718
+ ActionType.NOTIFY,
10719
+ ActionType.CUSTOM,
10720
+ ActionType.EDIT,
10721
+ ActionType.ARCHIVE
10722
+ ];
10267
10723
  function getAvailableActionsWithoutFlagFilters(status2, flags) {
10268
10724
  if (flags.includes(InherentFlags.EDIT_IN_PROGRESS)) {
10269
10725
  return [ActionType.NOTIFY, ActionType.DECLARE, ActionType.REGISTER];
10270
10726
  }
10271
- if (flags.includes(InherentFlags.REJECTED)) {
10272
- return [
10273
- ActionType.READ,
10274
- ActionType.NOTIFY,
10275
- ActionType.CUSTOM,
10276
- ActionType.EDIT,
10277
- ActionType.ARCHIVE
10278
- ];
10727
+ if (flags.includes(InherentFlags.REJECTED) && status2 !== EventStatus.enum.ARCHIVED) {
10728
+ return REJECTED_ACTIONS;
10279
10729
  }
10280
10730
  return AVAILABLE_ACTIONS_BY_EVENT_STATUS[status2];
10281
10731
  }
@@ -10312,3 +10762,366 @@ function getFilePathsFromEvent(event2) {
10312
10762
  });
10313
10763
  return (0, import_lodash7.uniq)(filepaths);
10314
10764
  }
10765
+
10766
+ // ../commons/src/events/mocks.test.utils.ts
10767
+ var V2_DEFAULT_MOCK_ADMINISTRATIVE_AREAS = [
10768
+ {
10769
+ id: "a45b982a-5c7b-4bd9-8fd8-a42d0994054c",
10770
+ name: "Central",
10771
+ parentId: null,
10772
+ validUntil: null,
10773
+ externalId: "ydyJb1RAy4U1"
10774
+ },
10775
+ {
10776
+ id: "c599b691-fd2d-45e1-abf4-d185de727fb5",
10777
+ name: "Sulaka",
10778
+ parentId: null,
10779
+ validUntil: null,
10780
+ externalId: "pQ8nGxWmZ2Q3"
10781
+ },
10782
+ {
10783
+ id: "7ef2b9c7-5e6d-49f6-ae05-656207d0fc64",
10784
+ name: "Pualula",
10785
+ parentId: null,
10786
+ validUntil: null,
10787
+ externalId: "Aq91DweLmT8k"
10788
+ },
10789
+ {
10790
+ id: "6d1a59df-988c-4021-a846-ccbc021931a7",
10791
+ name: "Chuminga",
10792
+ parentId: null,
10793
+ validUntil: null,
10794
+ externalId: "Rw0fYNh2Xk9a"
10795
+ },
10796
+ {
10797
+ id: "62a0ccb4-880d-4f30-8882-f256007dfff9",
10798
+ name: "Ibombo",
10799
+ parentId: "a45b982a-5c7b-4bd9-8fd8-a42d0994054c",
10800
+ validUntil: null,
10801
+ externalId: "k7DsP4vbN1Qe"
10802
+ },
10803
+ {
10804
+ id: "27160bbd-32d1-4625-812f-860226bfb92a",
10805
+ name: "Isango",
10806
+ parentId: "a45b982a-5c7b-4bd9-8fd8-a42d0994054c",
10807
+ validUntil: null,
10808
+ externalId: "Gm3Z9eQpHw4L"
10809
+ },
10810
+ {
10811
+ id: "967032fd-3f81-478a-826c-30cb8fe121bd",
10812
+ name: "Isamba",
10813
+ parentId: "a45b982a-5c7b-4bd9-8fd8-a42d0994054c",
10814
+ validUntil: null,
10815
+ externalId: "sT0xVu1KqJ7r"
10816
+ },
10817
+ {
10818
+ id: "89a33893-b17d-481d-a26d-6461e7ac1651",
10819
+ name: "Itambo",
10820
+ parentId: "a45b982a-5c7b-4bd9-8fd8-a42d0994054c",
10821
+ validUntil: null,
10822
+ externalId: "Nq6Bv2HpL9Te"
10823
+ },
10824
+ {
10825
+ id: "d42ab2fe-e7ed-470e-8b31-4fb27f9b8250",
10826
+ name: "Ezhi",
10827
+ parentId: "a45b982a-5c7b-4bd9-8fd8-a42d0994054c",
10828
+ validUntil: null,
10829
+ externalId: "xK8cQ0ZRy5Wd"
10830
+ },
10831
+ {
10832
+ id: "8fbd09d2-212b-47f4-beb3-5e1694931d9f",
10833
+ name: "Ilanga",
10834
+ parentId: "c599b691-fd2d-45e1-abf4-d185de727fb5",
10835
+ validUntil: null,
10836
+ externalId: "Cq4Jm1XvN8Ls"
10837
+ },
10838
+ // Villages under Ibombo (62a0ccb4-880d-4f30-8882-f256007dfff9)
10839
+ {
10840
+ id: "1d4e5f6a-7b8c-4912-8efa-345678901234",
10841
+ name: "Klow",
10842
+ parentId: "62a0ccb4-880d-4f30-8882-f256007dfff9",
10843
+ validUntil: null,
10844
+ externalId: "IkYcYBUcyY2"
10845
+ },
10846
+ {
10847
+ id: "2e5f6a7b-8c9d-4a23-8fab-456789012345",
10848
+ name: "Mbondo",
10849
+ parentId: "62a0ccb4-880d-4f30-8882-f256007dfff9",
10850
+ validUntil: null,
10851
+ externalId: "Qhvv5hvo3mY"
10852
+ },
10853
+ {
10854
+ id: "3f6a7b8c-9d0e-4b34-8abc-567890123456",
10855
+ name: "Ndara",
10856
+ parentId: "62a0ccb4-880d-4f30-8882-f256007dfff9",
10857
+ validUntil: null,
10858
+ externalId: "crXh068O9TR"
10859
+ },
10860
+ {
10861
+ id: "4a7b8c9d-0e1f-4c45-abcd-678901234567",
10862
+ name: "Olani",
10863
+ parentId: "62a0ccb4-880d-4f30-8882-f256007dfff9",
10864
+ validUntil: null,
10865
+ externalId: "r00It8Tvvp7"
10866
+ },
10867
+ {
10868
+ id: "5b8c9d0e-1f2a-4d56-bcde-789012345678",
10869
+ name: "Pemba",
10870
+ parentId: "62a0ccb4-880d-4f30-8882-f256007dfff9",
10871
+ validUntil: null,
10872
+ externalId: "ZnUWsbONIaH"
10873
+ },
10874
+ {
10875
+ id: "6c9d0e1f-2a3b-4e67-8def-890123456789",
10876
+ name: "Quanza",
10877
+ parentId: "62a0ccb4-880d-4f30-8882-f256007dfff9",
10878
+ validUntil: null,
10879
+ externalId: "fDZycvQTa7l"
10880
+ },
10881
+ {
10882
+ id: "7d0e1f2a-3b4c-4f78-8efa-901234567890",
10883
+ name: "Rivka",
10884
+ parentId: "62a0ccb4-880d-4f30-8882-f256007dfff9",
10885
+ validUntil: null,
10886
+ externalId: "KqswxCGTELa"
10887
+ },
10888
+ // Villages under Isamba (967032fd-3f81-478a-826c-30cb8fe121bd)
10889
+ {
10890
+ id: "8e1f2a3b-4c5d-4089-8fab-012345678901",
10891
+ name: "Mbula",
10892
+ parentId: "967032fd-3f81-478a-826c-30cb8fe121bd",
10893
+ validUntil: null,
10894
+ externalId: "osEbKjRc9Kg"
10895
+ },
10896
+ {
10897
+ id: "9f2a3b4c-5d6e-4190-8abf-123456789012",
10898
+ name: "Ndoki",
10899
+ parentId: "967032fd-3f81-478a-826c-30cb8fe121bd",
10900
+ validUntil: null,
10901
+ externalId: "aq4daBUAGr3"
10902
+ },
10903
+ {
10904
+ id: "0a3b4c5d-6e7f-4201-abcd-234567890123",
10905
+ name: "Tsanga",
10906
+ parentId: "967032fd-3f81-478a-826c-30cb8fe121bd",
10907
+ validUntil: null,
10908
+ externalId: "cqis6Y8trbJ"
10909
+ },
10910
+ {
10911
+ id: "1b4c5d6e-7f8a-4312-bcde-345678901234",
10912
+ name: "Waziri",
10913
+ parentId: "967032fd-3f81-478a-826c-30cb8fe121bd",
10914
+ validUntil: null,
10915
+ externalId: "LMijHPyyx6d"
10916
+ },
10917
+ {
10918
+ id: "2c5d6e7f-8a9b-4423-8def-456789012345",
10919
+ name: "Zimbi",
10920
+ parentId: "967032fd-3f81-478a-826c-30cb8fe121bd",
10921
+ validUntil: null,
10922
+ externalId: "pcQYbPuKGZ7"
10923
+ },
10924
+ // Villages under Itambo (89a33893-b17d-481d-a26d-6461e7ac1651)
10925
+ {
10926
+ id: "3d6e7f8a-9b0c-4534-8efa-567890123456",
10927
+ name: "Felani",
10928
+ parentId: "89a33893-b17d-481d-a26d-6461e7ac1651",
10929
+ validUntil: null,
10930
+ externalId: "gSqpoCGdMXp"
10931
+ },
10932
+ {
10933
+ id: "4e7f8a9b-0c1d-4645-8fab-678901234567",
10934
+ name: "Goroma",
10935
+ parentId: "89a33893-b17d-481d-a26d-6461e7ac1651",
10936
+ validUntil: null,
10937
+ externalId: "KvAAIaNqVrp"
10938
+ },
10939
+ {
10940
+ id: "5f8a9b0c-1d2e-4756-8abc-789012345678",
10941
+ name: "Halifu",
10942
+ parentId: "89a33893-b17d-481d-a26d-6461e7ac1651",
10943
+ validUntil: null,
10944
+ externalId: "qe4UnEVt1hv"
10945
+ },
10946
+ {
10947
+ id: "6a9b0c1d-2e3f-4867-abcd-890123456789",
10948
+ name: "Jabari",
10949
+ parentId: "89a33893-b17d-481d-a26d-6461e7ac1651",
10950
+ validUntil: null,
10951
+ externalId: "yHH9Nz4rLOt"
10952
+ },
10953
+ {
10954
+ id: "7b0c1d2e-3f4a-4978-bcde-901234567890",
10955
+ name: "Kifani",
10956
+ parentId: "89a33893-b17d-481d-a26d-6461e7ac1651",
10957
+ validUntil: null,
10958
+ externalId: "eSWmXIGeu1I"
10959
+ },
10960
+ {
10961
+ id: "8c1d2e3f-4a5b-4089-8def-012345678901",
10962
+ name: "Lumela",
10963
+ parentId: "89a33893-b17d-481d-a26d-6461e7ac1651",
10964
+ validUntil: null,
10965
+ externalId: "bh0b3aI1uP3"
10966
+ }
10967
+ ];
10968
+ var V2_DEFAULT_MOCK_LOCATIONS = [
10969
+ {
10970
+ id: "6f6186ce-cd5f-4a5f-810a-2d99e7c4ba12",
10971
+ name: "Central Provincial Office",
10972
+ locationType: "CRVS_OFFICE",
10973
+ administrativeAreaId: "a45b982a-5c7b-4bd9-8fd8-a42d0994054c",
10974
+ validUntil: null,
10975
+ externalId: "Xr3Df8WpK6Ys"
10976
+ },
10977
+ {
10978
+ id: "b1c2d3e4-f5a6-7890-bcde-f12345678901",
10979
+ name: "Central Health Post",
10980
+ locationType: "HEALTH_FACILITY",
10981
+ administrativeAreaId: "a45b982a-5c7b-4bd9-8fd8-a42d0994054c",
10982
+ validUntil: null
10983
+ },
10984
+ {
10985
+ id: "028d2c85-ca31-426d-b5d1-2cef545a4902",
10986
+ name: "Ibombo District Office",
10987
+ locationType: "CRVS_OFFICE",
10988
+ administrativeAreaId: "62a0ccb4-880d-4f30-8882-f256007dfff9",
10989
+ validUntil: null,
10990
+ externalId: "Sm4Nw7GrD2Vy"
10991
+ },
10992
+ {
10993
+ id: "62a0ccb4-4f30-4f30-8882-f256007dff9f",
10994
+ name: "Isamba District Office",
10995
+ locationType: "CRVS_OFFICE",
10996
+ administrativeAreaId: "967032fd-3f81-478a-826c-30cb8fe121bd",
10997
+ validUntil: null,
10998
+ externalId: "Vg1Bq5XeH9Lt"
10999
+ },
11000
+ {
11001
+ id: "954c93e1-13f7-4435-bb82-35e0e215e07d",
11002
+ name: "Isango District Office",
11003
+ locationType: "CRVS_OFFICE",
11004
+ administrativeAreaId: "27160bbd-32d1-4625-812f-860226bfb92a",
11005
+ validUntil: null,
11006
+ externalId: "Je7Lm2XqN9Vz"
11007
+ },
11008
+ {
11009
+ id: "2884f5b9-17b4-49ce-bf4d-f538228935df",
11010
+ name: "Sulaka Provincial Office",
11011
+ locationType: "CRVS_OFFICE",
11012
+ administrativeAreaId: "c599b691-fd2d-45e1-abf4-d185de727fb5",
11013
+ validUntil: null,
11014
+ externalId: "Ht2Wp9KcX5Qv"
11015
+ },
11016
+ {
11017
+ id: "030358c6-54af-44be-821b-8e4af963a49c",
11018
+ name: "Ilanga District Office",
11019
+ locationType: "CRVS_OFFICE",
11020
+ administrativeAreaId: "8fbd09d2-212b-47f4-beb3-5e1694931d9f",
11021
+ validUntil: null,
11022
+ externalId: "Yp6Ds1WqN3Xz"
11023
+ },
11024
+ {
11025
+ id: "423d000f-101b-47c0-8b86-21a908067cee",
11026
+ name: "Chamakubi Health Post",
11027
+ locationType: "HEALTH_FACILITY",
11028
+ administrativeAreaId: "62a0ccb4-880d-4f30-8882-f256007dfff9",
11029
+ validUntil: null,
11030
+ externalId: "M1nFr8LbC2Qy"
11031
+ },
11032
+ {
11033
+ id: "4d3279be-d026-420c-88f7-f0a4ae986973",
11034
+ name: "Ibombo Rural Health Centre",
11035
+ locationType: "HEALTH_FACILITY",
11036
+ administrativeAreaId: "62a0ccb4-880d-4f30-8882-f256007dfff9",
11037
+ validUntil: null,
11038
+ externalId: "bT7pV6YrW0Xc"
11039
+ },
11040
+ {
11041
+ id: "190902f4-1d77-476a-8947-41145af1db7d",
11042
+ name: "Chikobo Rural Health Centre",
11043
+ locationType: "HEALTH_FACILITY",
11044
+ administrativeAreaId: "62a0ccb4-880d-4f30-8882-f256007dfff9",
11045
+ validUntil: null,
11046
+ externalId: "zE4qPn2SgJ5d"
11047
+ },
11048
+ {
11049
+ id: "f5ecbd9b-a01e-4a65-910e-70e86ab41b71",
11050
+ name: "Chilochabalenje Health Post",
11051
+ locationType: "HEALTH_FACILITY",
11052
+ administrativeAreaId: "62a0ccb4-880d-4f30-8882-f256007dfff9",
11053
+ validUntil: null,
11054
+ externalId: "H8vDs1MqR4Uf"
11055
+ },
11056
+ {
11057
+ id: "dbfc178f-7295-4b90-b28d-111c95b03127",
11058
+ name: "Chipeso Rural Health Centre",
11059
+ locationType: "HEALTH_FACILITY",
11060
+ administrativeAreaId: "62a0ccb4-880d-4f30-8882-f256007dfff9",
11061
+ validUntil: null,
11062
+ externalId: "Qw3uZ9KfX6Lm"
11063
+ },
11064
+ {
11065
+ id: "09862bfe-c7ac-46cd-987b-668681533c80",
11066
+ name: "Chisamba Rural Health Centre",
11067
+ locationType: "HEALTH_FACILITY",
11068
+ administrativeAreaId: "62a0ccb4-880d-4f30-8882-f256007dfff9",
11069
+ validUntil: null,
11070
+ externalId: "Yr0pCg8LdM2s"
11071
+ },
11072
+ {
11073
+ id: "834ce389-e95b-4fb0-96a0-33e9ab323059",
11074
+ name: "Chitanda Rural Health Centre",
11075
+ locationType: "HEALTH_FACILITY",
11076
+ administrativeAreaId: "62a0ccb4-880d-4f30-8882-f256007dfff9",
11077
+ validUntil: null,
11078
+ externalId: "tS9gJ4PwB1Qx"
11079
+ },
11080
+ {
11081
+ id: "0431c433-6062-4a4c-aee9-25271aec61ee",
11082
+ name: "Golden Valley Rural Health Centre",
11083
+ locationType: "HEALTH_FACILITY",
11084
+ administrativeAreaId: "62a0ccb4-880d-4f30-8882-f256007dfff9",
11085
+ validUntil: null,
11086
+ externalId: "Ld7Qm3XsA8Vr"
11087
+ },
11088
+ {
11089
+ id: "bc84d0b6-7ba7-480d-a339-5d9920d90eb2",
11090
+ name: "Ipongo Rural Health Centre",
11091
+ locationType: "HEALTH_FACILITY",
11092
+ administrativeAreaId: "62a0ccb4-880d-4f30-8882-f256007dfff9",
11093
+ validUntil: null,
11094
+ externalId: "kF2sW9DmH0Bt"
11095
+ },
11096
+ {
11097
+ id: "4cf1f53b-b730-41d2-8649-dff7eeed970d",
11098
+ name: "Itumbwe Health Post",
11099
+ locationType: "HEALTH_FACILITY",
11100
+ administrativeAreaId: "62a0ccb4-880d-4f30-8882-f256007dfff9",
11101
+ validUntil: null,
11102
+ externalId: "Ue5Xb3VaC7Pq"
11103
+ },
11104
+ {
11105
+ id: "4b3676cb-9355-4942-9eb9-2ce46acaf0e0",
11106
+ name: "Kabangalala Rural Health Centre",
11107
+ locationType: "HEALTH_FACILITY",
11108
+ administrativeAreaId: "62a0ccb4-880d-4f30-8882-f256007dfff9",
11109
+ validUntil: null,
11110
+ externalId: "Pz8Kc1TqH6Jn"
11111
+ },
11112
+ // Village offices
11113
+ {
11114
+ id: "1f4a5b6c-7d8e-4312-8abc-345678901234",
11115
+ name: "Klow Village Office",
11116
+ locationType: "CRVS_OFFICE",
11117
+ administrativeAreaId: "1d4e5f6a-7b8c-4912-8efa-345678901234",
11118
+ validUntil: null,
11119
+ externalId: "PmAyxAJkxiJ"
11120
+ }
11121
+ ];
11122
+ var V2_DEFAULT_MOCK_LOCATIONS_MAP = new Map(
11123
+ V2_DEFAULT_MOCK_LOCATIONS.map((l) => [l.id, l])
11124
+ );
11125
+ var V2_DEFAULT_MOCK_ADMINISTRATIVE_AREAS_MAP = new Map(
11126
+ V2_DEFAULT_MOCK_ADMINISTRATIVE_AREAS.map((a) => [a.id, a])
11127
+ );