@opencrvs/toolkit 2.0.0-rc.fef9d21 → 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 (62) hide show
  1. package/create-countryconfig/index.js +103 -0
  2. package/create-countryconfig/package.json +21 -0
  3. package/dist/application-config/index.js +312 -130
  4. package/dist/cli.js +548 -178
  5. package/dist/commons/api/router.d.ts +3390 -241
  6. package/dist/commons/application-config/index.d.ts +17 -4
  7. package/dist/commons/conditionals/conditionals.d.ts +360 -10
  8. package/dist/commons/conditionals/validate.d.ts +52 -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 +114 -0
  12. package/dist/commons/events/AdvancedSearchConfig.d.ts +342 -0
  13. package/dist/commons/events/Draft.d.ts +4 -2
  14. package/dist/commons/events/EventDocument.d.ts +3 -0
  15. package/dist/commons/events/EventIndex.d.ts +0 -3
  16. package/dist/commons/events/EventMetadata.d.ts +0 -7
  17. package/dist/commons/events/FieldConfig.d.ts +388 -50
  18. package/dist/commons/events/FieldType.d.ts +1 -0
  19. package/dist/commons/events/FieldTypeMapping.d.ts +1 -1
  20. package/dist/commons/events/FieldValue.d.ts +6 -0
  21. package/dist/commons/events/WorkqueueConfig.d.ts +150 -150
  22. package/dist/commons/events/field.d.ts +53 -1
  23. package/dist/commons/events/index.d.ts +2 -0
  24. package/dist/commons/events/locations.d.ts +38 -1
  25. package/dist/commons/events/mocks.test.utils.d.ts +19 -0
  26. package/dist/commons/events/scopes.d.ts +24 -1
  27. package/dist/commons/events/state/flags.d.ts +16 -0
  28. package/dist/commons/events/state/index.d.ts +0 -4
  29. package/dist/commons/events/state/utils.d.ts +12 -289
  30. package/dist/commons/events/utils.d.ts +13 -2
  31. package/dist/conditionals/index.js +92 -9
  32. package/dist/events/index.js +1204 -290
  33. package/dist/migrations/v2.0/add-birth-certificate-issuance-flag.d.ts.map +1 -1
  34. package/dist/migrations/v2.0/add-birth-certificate-issuance-flag.js +60 -35
  35. package/dist/migrations/v2.0/checkout-upstream-files.d.ts +1 -1
  36. package/dist/migrations/v2.0/checkout-upstream-files.d.ts.map +1 -1
  37. package/dist/migrations/v2.0/checkout-upstream-files.js +1 -2
  38. package/dist/migrations/v2.0/delete-infrastructure-directory.d.ts +9 -1
  39. package/dist/migrations/v2.0/delete-infrastructure-directory.d.ts.map +1 -1
  40. package/dist/migrations/v2.0/delete-infrastructure-directory.js +66 -20
  41. package/dist/migrations/v2.0/fix-accept-requested-registration-function-type.d.ts +3 -0
  42. package/dist/migrations/v2.0/fix-accept-requested-registration-function-type.d.ts.map +1 -0
  43. package/dist/migrations/v2.0/fix-accept-requested-registration-function-type.js +110 -0
  44. package/dist/migrations/v2.0/index.d.ts +5 -3
  45. package/dist/migrations/v2.0/index.d.ts.map +1 -1
  46. package/dist/migrations/v2.0/index.js +546 -176
  47. package/dist/migrations/v2.0/make-built-in-validate-actions-custom.d.ts.map +1 -1
  48. package/dist/migrations/v2.0/make-built-in-validate-actions-custom.js +90 -1
  49. package/dist/migrations/v2.0/merge-infrastructure-directory.d.ts +11 -1
  50. package/dist/migrations/v2.0/merge-infrastructure-directory.d.ts.map +1 -1
  51. package/dist/migrations/v2.0/merge-infrastructure-directory.js +17 -16
  52. package/dist/migrations/v2.0/migrate-scopes.d.ts.map +1 -1
  53. package/dist/migrations/v2.0/migrate-scopes.js +54 -30
  54. package/dist/migrations/v2.0/migrate-workqueue-configs.d.ts.map +1 -1
  55. package/dist/migrations/v2.0/migrate-workqueue-configs.js +140 -59
  56. package/dist/notification/index.js +936 -162
  57. package/dist/scopes/index.d.ts +91 -16
  58. package/dist/scopes/index.js +55 -12
  59. package/opencrvs-toolkit-2.0.0-rc.ff1424b.tgz +0 -0
  60. package/package.json +6 -2
  61. package/tsconfig.tsbuildinfo +1 -1
  62. package/opencrvs-toolkit-2.0.0-rc.fef9d21.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,8 +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,
255
+ canAccessOtherUserWithScopes: () => canAccessOtherUserWithScopes,
256
+ canAccessUserWithScope: () => canAccessUserWithScope,
257
+ compileClientFunction: () => compileClientFunction,
246
258
  compositeFieldTypes: () => compositeFieldTypes,
247
259
  createEmptyDraft: () => createEmptyDraft,
248
260
  createFieldConditionals: () => createFieldConditionals,
@@ -263,6 +275,7 @@ __export(events_exports, {
263
275
  defineWorkqueuesColumns: () => defineWorkqueuesColumns,
264
276
  deserializeQuery: () => deserializeQuery,
265
277
  errorMessages: () => errorMessages,
278
+ evaluate: () => evaluate,
266
279
  event: () => event,
267
280
  eventMetadataLabelMap: () => eventMetadataLabelMap,
268
281
  eventPayloadGenerator: () => eventPayloadGenerator,
@@ -275,6 +288,7 @@ __export(events_exports, {
275
288
  findActiveDraftForEvent: () => findActiveDraftForEvent,
276
289
  findAllFields: () => findAllFields,
277
290
  findLastAssignmentAction: () => findLastAssignmentAction,
291
+ findPendingCorrectionAction: () => findPendingCorrectionAction,
278
292
  findRecordActionPages: () => findRecordActionPages,
279
293
  flag: () => flag,
280
294
  flattenFieldReference: () => flattenFieldReference,
@@ -300,13 +314,15 @@ __export(events_exports, {
300
314
  getActionConfig: () => getActionConfig,
301
315
  getActionReview: () => getActionReview,
302
316
  getActionReviewFields: () => getActionReviewFields,
317
+ getAdministrativeAreaHierarchy: () => getAdministrativeAreaHierarchy,
303
318
  getAllUniqueFields: () => getAllUniqueFields,
304
319
  getAnnotationFromDrafts: () => getAnnotationFromDrafts,
305
320
  getAssignedUserFromActions: () => getAssignedUserFromActions,
306
- getAssignedUserSignatureFromActions: () => getAssignedUserSignatureFromActions,
307
321
  getAssignmentStatus: () => getAssignmentStatus,
308
322
  getAvailableActionsForEvent: () => getAvailableActionsForEvent,
323
+ getAvailableRolesForUserUpdatePayload: () => getAvailableRolesForUserUpdatePayload,
309
324
  getCompleteActionAnnotation: () => getCompleteActionAnnotation,
325
+ getCompleteActionContent: () => getCompleteActionContent,
310
326
  getCompleteActionDeclaration: () => getCompleteActionDeclaration,
311
327
  getCurrentEventState: () => getCurrentEventState,
312
328
  getCustomActionFields: () => getCustomActionFields,
@@ -315,7 +331,9 @@ __export(events_exports, {
315
331
  getDeclarationFields: () => getDeclarationFields,
316
332
  getDeclarationPages: () => getDeclarationPages,
317
333
  getEventConfigById: () => getEventConfigById,
334
+ getEventFlags: () => getEventFlags,
318
335
  getFilePathsFromEvent: () => getFilePathsFromEvent,
336
+ getLocationHierarchy: () => getLocationHierarchy,
319
337
  getMixedPath: () => getMixedPath,
320
338
  getPendingAction: () => getPendingAction,
321
339
  getPrintCertificatePages: () => getPrintCertificatePages,
@@ -336,6 +354,7 @@ __export(events_exports, {
336
354
  isBulletListFieldType: () => isBulletListFieldType,
337
355
  isButtonFieldType: () => isButtonFieldType,
338
356
  isCheckboxFieldType: () => isCheckboxFieldType,
357
+ isCodeToEvaluate: () => isCodeToEvaluate,
339
358
  isConditionMet: () => isConditionMet,
340
359
  isCountryFieldType: () => isCountryFieldType,
341
360
  isCustomFieldType: () => isCustomFieldType,
@@ -376,6 +395,7 @@ __export(events_exports, {
376
395
  isPageVisible: () => isPageVisible,
377
396
  isParagraphFieldType: () => isParagraphFieldType,
378
397
  isPhoneFieldType: () => isPhoneFieldType,
398
+ isPotentialDuplicate: () => isPotentialDuplicate,
379
399
  isPrintButtonFieldType: () => isPrintButtonFieldType,
380
400
  isQrReaderFieldType: () => isQrReaderFieldType,
381
401
  isQueryParamReaderFieldType: () => isQueryParamReaderFieldType,
@@ -409,12 +429,15 @@ __export(events_exports, {
409
429
  plainDateToLocalDate: () => plainDateToLocalDate,
410
430
  precompileActionSchemas: () => precompileActionSchemas,
411
431
  resolveDateOfEvent: () => resolveDateOfEvent,
432
+ resolveEventCustomFlags: () => resolveEventCustomFlags,
412
433
  resolvePlaceOfEvent: () => resolvePlaceOfEvent,
434
+ runClientFunction: () => runClientFunction,
413
435
  runFieldValidations: () => runFieldValidations,
414
436
  runStructuralValidations: () => runStructuralValidations,
415
437
  safeUnion: () => safeUnion,
416
438
  status: () => status,
417
439
  timePeriodToDateRange: () => timePeriodToDateRange,
440
+ todayISO: () => todayISO,
418
441
  user: () => user,
419
442
  userCanAccessEventWithScopes: () => userCanAccessEventWithScopes,
420
443
  validate: () => validate,
@@ -489,6 +512,10 @@ var scopeByEvent = z2.preprocess(
489
512
  (val) => val === void 0 ? void 0 : [val].flat(),
490
513
  z2.array(z2.string()).optional()
491
514
  ).describe("Event type, e.g. birth, death");
515
+ var userRole = z2.preprocess(
516
+ (val) => val === void 0 ? void 0 : [val].flat(),
517
+ z2.array(z2.string()).optional()
518
+ ).describe("User role, e.g. admin, field agent");
492
519
  var scopeOptionsPlaceEvent = z2.object({
493
520
  event: scopeByEvent,
494
521
  placeOfEvent: JurisdictionFilter.optional()
@@ -512,6 +539,9 @@ var CustomActionScopeOptions = AllRecordScopeOptions.extend({
512
539
  var AccessLevelOptions = z2.object({
513
540
  accessLevel: JurisdictionFilter.optional()
514
541
  });
542
+ var AllUserScopeOptions = AccessLevelOptions.extend({
543
+ role: userRole.optional()
544
+ });
515
545
  var WorkqueueOrDashboardOptions = z2.object({
516
546
  ids: z2.preprocess(
517
547
  (val) => val === void 0 ? void 0 : [val].flat(),
@@ -521,6 +551,7 @@ var WorkqueueOrDashboardOptions = z2.object({
521
551
  var AllScopeOptions = z2.object({
522
552
  ...AllRecordScopeOptions.shape,
523
553
  ...AccessLevelOptions.shape,
554
+ ...AllUserScopeOptions.shape,
524
555
  ...WorkqueueOrDashboardOptions.shape
525
556
  });
526
557
  var ScopeOptionKey = AllScopeOptions.keyof();
@@ -593,6 +624,33 @@ var RecordScopeV2 = z2.discriminatedUnion("type", [
593
624
  ]).describe(
594
625
  "Scopes used to check user's permission to perform actions on a record."
595
626
  );
627
+ var SystemScopeType = z2.enum([
628
+ "organisation.read-locations",
629
+ "user.read",
630
+ "user.create",
631
+ "user.edit",
632
+ "user.search"
633
+ ]);
634
+ var UserScopeType = SystemScopeType.extract([
635
+ "user.read",
636
+ "user.create",
637
+ "user.edit",
638
+ "user.search"
639
+ ]);
640
+ var ScopesWithRoleOption = UserScopeType.extract(["user.edit", "user.create"]);
641
+ var UserScopeV2 = z2.discriminatedUnion("type", [
642
+ z2.object({
643
+ type: ScopesWithRoleOption,
644
+ options: AllUserScopeOptions.optional()
645
+ }),
646
+ z2.object({
647
+ type: UserScopeType.extract(["user.read", "user.search"]),
648
+ options: AccessLevelOptions.optional()
649
+ })
650
+ ]);
651
+ function scopeUsesRoleOptions(scope) {
652
+ return ScopesWithRoleOption?.options.some((opt) => opt === scope.type);
653
+ }
596
654
  function scopeUsesDeclaredOptions(scope) {
597
655
  return !ScopesWithPlaceEventOptions.options.some((opt) => opt === scope.type);
598
656
  }
@@ -625,16 +683,14 @@ var ResolvedRecordScopeV2 = z2.discriminatedUnion("type", [
625
683
  }).optional()
626
684
  })
627
685
  ]).describe("Resolved scope with location/user IDs instead of filters.");
628
- var SystemScopeType = z2.enum([
629
- "organisation.read-locations",
630
- "user.read",
631
- "user.create",
632
- "user.edit"
633
- ]);
634
686
  var Scope = z2.discriminatedUnion("type", [
635
687
  z2.object({ type: PlainScopeType }),
636
688
  ...RecordScopeV2.options,
637
- z2.object({ type: SystemScopeType, options: AccessLevelOptions.optional() }),
689
+ ...UserScopeV2.options,
690
+ z2.object({
691
+ type: z2.literal("organisation.read-locations"),
692
+ options: AccessLevelOptions.optional()
693
+ }),
638
694
  z2.object({
639
695
  type: z2.literal("workqueue"),
640
696
  options: WorkqueueOrDashboardOptions
@@ -656,18 +712,26 @@ var unflattenScope = (input) => {
656
712
  return { type, options };
657
713
  };
658
714
  var EncodedScope = z2.string().brand("EncodedScope");
659
- var decodeScope = (query) => {
660
- 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, {
661
721
  ignoreQueryPrefix: true,
662
722
  comma: true,
663
723
  allowDots: true
664
724
  });
665
725
  const unflattenedScope = unflattenScope(scope);
666
- return Scope.safeParse(unflattenedScope)?.data;
726
+ const result = Scope.safeParse(unflattenedScope)?.data;
727
+ decodedScopeCache.set(encodedScope, result);
728
+ return result;
667
729
  };
668
730
  var DEFAULT_SCOPE_OPTIONS = {
669
731
  placeOfEvent: JurisdictionFilter.enum.all,
670
- accessLevel: JurisdictionFilter.enum.all
732
+ accessLevel: JurisdictionFilter.enum.all,
733
+ registeredIn: JurisdictionFilter.enum.all,
734
+ declaredIn: JurisdictionFilter.enum.all
671
735
  };
672
736
  function getAcceptedScopesByType({
673
737
  acceptedScopes,
@@ -1040,7 +1104,10 @@ var ActionConditional = z7.discriminatedUnion("type", [
1040
1104
  ShowConditional,
1041
1105
  // Action can be shown to the user in the list but as disabled
1042
1106
  EnableConditional
1043
- ]);
1107
+ ]).meta({
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."
1110
+ });
1044
1111
  var DisplayOnReviewConditional = z7.object({
1045
1112
  type: z7.literal(ConditionalType.DISPLAY_ON_REVIEW),
1046
1113
  conditional: Conditional
@@ -1055,8 +1122,8 @@ var FieldConditional = z7.discriminatedUnion("type", [
1055
1122
  // Field output can be shown / hidden on the review page
1056
1123
  DisplayOnReviewConditional
1057
1124
  ]).meta({
1058
- description: "Field conditional configuration",
1059
- 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."
1060
1127
  });
1061
1128
 
1062
1129
  // ../commons/src/events/FieldType.ts
@@ -1153,6 +1220,11 @@ var FieldTypesToHideInReview = [
1153
1220
  FieldType.ALPHA_PRINT_BUTTON,
1154
1221
  FieldType.ALPHA_HIDDEN
1155
1222
  ];
1223
+ var HiddenFieldTypes = [
1224
+ FieldType.HTTP,
1225
+ FieldType.QUERY_PARAM_READER,
1226
+ FieldType.ALPHA_HIDDEN
1227
+ ];
1156
1228
 
1157
1229
  // ../commons/src/events/FieldValue.ts
1158
1230
  var z12 = __toESM(require("zod/v4"));
@@ -1279,7 +1351,7 @@ function plainDateToLocalDate(date) {
1279
1351
  // ../commons/src/events/FieldValue.ts
1280
1352
  var TextValue = z12.string();
1281
1353
  var HiddenFieldValue = z12.string();
1282
- var NonEmptyTextValue = TextValue.min(1);
1354
+ var NonEmptyTextValue = z12.string().trim().min(1);
1283
1355
  var DateValue = z12.iso.date().describe("Date in the format YYYY-MM-DD");
1284
1356
  var AgeValue = z12.object({
1285
1357
  age: z12.number(),
@@ -1308,6 +1380,7 @@ var DateRangeFieldValue = z12.object({
1308
1380
  var EmailValue = z12.email();
1309
1381
  var CheckboxFieldValue = z12.boolean();
1310
1382
  var NumberFieldValue = z12.number();
1383
+ var SignatureFieldValue = FileFieldValue;
1311
1384
  var ButtonFieldValue = z12.number();
1312
1385
  var VerificationStatusValue = z12.enum([
1313
1386
  "verified",
@@ -1376,28 +1449,20 @@ function schemaPriority(schema) {
1376
1449
  return idx === -1 ? 9999 : idx;
1377
1450
  }
1378
1451
  function safeUnion(schemas) {
1452
+ const sortedSchemas = [...schemas].sort(
1453
+ (a, b) => schemaPriority(a) - schemaPriority(b)
1454
+ );
1379
1455
  return z12.any().superRefine((val, ctx) => {
1380
- const successful = schemas.filter((s) => s.safeParse(val).success);
1381
- if (successful.length === 1) {
1382
- return;
1383
- }
1384
- if (successful.length === 0) {
1385
- ctx.addIssue({
1386
- code: "invalid_type",
1387
- expected: "custom",
1388
- message: "Value does not match any schema"
1389
- });
1390
- return;
1391
- }
1392
- successful.sort((a, b) => schemaPriority(a) - schemaPriority(b));
1393
- const best = successful[0];
1394
- if (!best.safeParse(val).success) {
1395
- ctx.addIssue({
1396
- expected: "custom",
1397
- code: "invalid_type",
1398
- message: "Value did not match the best schema"
1399
- });
1456
+ for (const schema of sortedSchemas) {
1457
+ if (schema.safeParse(val).success) {
1458
+ return;
1459
+ }
1400
1460
  }
1461
+ ctx.addIssue({
1462
+ code: "invalid_type",
1463
+ expected: "custom",
1464
+ message: "Value does not match any schema"
1465
+ });
1401
1466
  }).meta({
1402
1467
  description: "Value that matches exactly one of the possible schema types (TextValue, DateValue, DateRangeFieldValue). The best matching schema is chosen by priority."
1403
1468
  });
@@ -1614,8 +1679,9 @@ var RequestedCorrectionAction = ActionBase.extend(
1614
1679
  var ApprovedCorrectionAction = ActionBase.extend(
1615
1680
  z14.object({
1616
1681
  type: z14.literal(ActionType.APPROVE_CORRECTION),
1617
- requestId: z14.string()
1682
+ requestId: z14.string(),
1618
1683
  // TODO move into 'content' property
1684
+ content: z14.object({ immediateCorrection: z14.boolean().optional() }).optional()
1619
1685
  }).shape
1620
1686
  );
1621
1687
  var RejectedCorrectionAction = ActionBase.extend(
@@ -1707,6 +1773,9 @@ var FlagConfig = z15.object({
1707
1773
  "Indicates if this flag expects an action to be performed to be cleared."
1708
1774
  ),
1709
1775
  label: TranslationConfig.describe("Human readable label of the flag.")
1776
+ }).meta({
1777
+ id: "FlagConfig",
1778
+ description: "Configuration for a custom flag that can be added to or removed from records by event actions."
1710
1779
  });
1711
1780
  var ActionFlagConfig = z15.object({
1712
1781
  id: Flag,
@@ -1714,6 +1783,9 @@ var ActionFlagConfig = z15.object({
1714
1783
  conditional: Conditional.optional().describe(
1715
1784
  "When conditional is met, the operation is performed on the flag. If not provided, the operation is performed unconditionally."
1716
1785
  )
1786
+ }).meta({
1787
+ id: "ActionFlagConfig",
1788
+ description: "Add or remove operation applied to a flag when the parent action is accepted. Optionally gated by a conditional."
1717
1789
  });
1718
1790
 
1719
1791
  // ../commons/src/events/EventMetadata.ts
@@ -1735,8 +1807,7 @@ var ActionCreationMetadata = z16.object({
1735
1807
  ),
1736
1808
  createdByUserType: z16.enum(["user", "system"]).nullish().describe("Whether the user is a normal user or a system."),
1737
1809
  acceptedAt: z16.iso.datetime().describe("Timestamp when the action request was accepted."),
1738
- createdByRole: z16.string().optional().describe("Role of the user at the time of action request creation."),
1739
- createdBySignature: z16.string().nullish().describe("Signature of the user who created the action request.")
1810
+ createdByRole: z16.string().optional().describe("Role of the user at the time of action request creation.")
1740
1811
  });
1741
1812
  var RegistrationCreationMetadata = ActionCreationMetadata.extend({
1742
1813
  registrationNumber: z16.string().describe(
@@ -1764,9 +1835,6 @@ var EventMetadata = z16.object({
1764
1835
  createdAtLocation: UUID.nullish().describe(
1765
1836
  "Location of the user who created the event."
1766
1837
  ),
1767
- createdBySignature: DocumentPath.nullish().describe(
1768
- "Signature of the user who created the event."
1769
- ),
1770
1838
  updatedAtLocation: UUID.nullish().describe(
1771
1839
  "Location of the user who last changed the status."
1772
1840
  ),
@@ -2141,14 +2209,34 @@ var FieldId = import_v43.default.string().superRefine((val, ctx) => {
2141
2209
  }
2142
2210
  }).describe("Unique identifier for the field");
2143
2211
  var FieldReference = import_v43.default.object({
2144
- $$field: FieldId,
2212
+ $$field: FieldId.describe("Id of the field to reference"),
2145
2213
  $$subfield: import_v43.default.array(import_v43.default.string()).optional().default([]).describe(
2146
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."
2147
2228
  )
2148
- }).describe("Reference to a field by its ID");
2229
+ }).describe("A context-only computation used as a field default value.");
2149
2230
  var ValidationConfig = import_v43.default.object({
2150
- validator: Conditional,
2151
- 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."
2152
2240
  });
2153
2241
  var requiredSchema = import_v43.default.union([
2154
2242
  import_v43.default.boolean(),
@@ -2179,7 +2267,7 @@ var BaseField = import_v43.default.object({
2179
2267
  "Indicates whether the field can be modified during record correction."
2180
2268
  ),
2181
2269
  value: FieldReference.or(import_v43.default.array(FieldReference)).optional().describe(
2182
- "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."
2183
2271
  ),
2184
2272
  analytics: import_v43.default.boolean().default(false).optional().describe(
2185
2273
  "Indicates whether the field is included in analytics. When enabled, its value becomes available in the analytics dashboard."
@@ -2187,30 +2275,40 @@ var BaseField = import_v43.default.object({
2187
2275
  }).describe("Common properties shared across all field types.");
2188
2276
  var Divider = BaseField.extend({
2189
2277
  type: import_v43.default.literal(FieldType.DIVIDER)
2278
+ }).meta({
2279
+ description: "A horizontal line divider",
2280
+ id: "Divider"
2190
2281
  });
2191
2282
  var TextField = BaseField.extend({
2192
2283
  type: import_v43.default.literal(FieldType.TEXT),
2193
- defaultValue: import_v43.default.union([NonEmptyTextValue, SerializedUserField]).optional(),
2284
+ defaultValue: import_v43.default.union([NonEmptyTextValue, SerializedUserField, ComputedDefaultValue]).optional(),
2194
2285
  configuration: import_v43.default.object({
2195
2286
  maxLength: import_v43.default.number().optional().describe("Maximum length of the text"),
2196
2287
  type: import_v43.default.enum(["text", "password"]).optional(),
2197
2288
  prefix: TranslationConfig.optional(),
2198
2289
  postfix: TranslationConfig.optional()
2199
2290
  }).default({ type: "text" }).optional()
2200
- }).describe("Text input");
2291
+ }).meta({
2292
+ description: "A text input field",
2293
+ id: "TextField"
2294
+ });
2201
2295
  var NumberField = BaseField.extend({
2202
2296
  type: import_v43.default.literal(FieldType.NUMBER),
2203
- defaultValue: NumberFieldValue.optional(),
2297
+ defaultValue: NumberFieldValue.or(ComputedDefaultValue).optional(),
2204
2298
  configuration: import_v43.default.object({
2205
2299
  min: import_v43.default.number().optional().describe("Minimum value"),
2206
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"),
2207
2302
  prefix: TranslationConfig.optional(),
2208
2303
  postfix: TranslationConfig.optional()
2209
2304
  }).optional()
2210
- }).describe("Number input");
2305
+ }).meta({
2306
+ description: "A number input field",
2307
+ id: "NumberField"
2308
+ });
2211
2309
  var TextAreaField = BaseField.extend({
2212
2310
  type: import_v43.default.literal(FieldType.TEXTAREA),
2213
- defaultValue: NonEmptyTextValue.optional(),
2311
+ defaultValue: NonEmptyTextValue.or(ComputedDefaultValue).optional(),
2214
2312
  configuration: import_v43.default.object({
2215
2313
  maxLength: import_v43.default.number().optional().describe("Maximum length of the text"),
2216
2314
  rows: import_v43.default.number().optional().describe("Number of visible text lines"),
@@ -2218,7 +2316,10 @@ var TextAreaField = BaseField.extend({
2218
2316
  prefix: TranslationConfig.optional(),
2219
2317
  postfix: TranslationConfig.optional()
2220
2318
  }).default({ rows: 4 }).optional()
2221
- }).describe("Multiline text input");
2319
+ }).meta({
2320
+ description: "A multiline text input",
2321
+ id: "TextAreaField"
2322
+ });
2222
2323
  var ImageMimeType = import_v43.default.enum([
2223
2324
  "image/png",
2224
2325
  "image/jpg",
@@ -2241,58 +2342,76 @@ var SignatureField = BaseField.extend({
2241
2342
  signaturePromptLabel: TranslationConfig.describe(
2242
2343
  "Title of the signature modal"
2243
2344
  ),
2244
- defaultValue: FieldValue.optional(),
2345
+ defaultValue: SignatureFieldValue.or(ComputedDefaultValue).optional(),
2245
2346
  configuration: import_v43.default.object({
2246
2347
  maxFileSize: import_v43.default.number().describe("Maximum file size in bytes").default(DEFAULT_MAX_FILE_SIZE_BYTES),
2247
2348
  acceptedFileTypes: MimeType.array().optional().describe("List of allowed file formats for the signature")
2248
2349
  }).default({
2249
2350
  maxFileSize: DEFAULT_MAX_FILE_SIZE_BYTES
2250
2351
  })
2251
- }).describe("Signature input field");
2352
+ }).meta({
2353
+ description: "A signature input field",
2354
+ id: "SignatureField"
2355
+ });
2252
2356
  var EmailField = BaseField.extend({
2253
2357
  type: import_v43.default.literal(FieldType.EMAIL),
2254
2358
  configuration: import_v43.default.object({
2255
2359
  maxLength: import_v43.default.number().optional().describe("Maximum length of the text")
2256
2360
  }).default({ maxLength: 255 }).optional(),
2257
- defaultValue: NonEmptyTextValue.optional()
2361
+ defaultValue: NonEmptyTextValue.or(ComputedDefaultValue).optional()
2362
+ }).meta({
2363
+ description: "An email input field",
2364
+ id: "EmailField"
2258
2365
  });
2259
2366
  var DateField = BaseField.extend({
2260
2367
  type: import_v43.default.literal(FieldType.DATE),
2261
- 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)"),
2262
2369
  configuration: import_v43.default.object({
2263
2370
  notice: TranslationConfig.describe(
2264
2371
  "Text to display above the date input"
2265
2372
  ).optional()
2266
2373
  }).optional()
2267
- }).describe("A single date input (yyyy-MM-dd)");
2374
+ }).meta({
2375
+ description: "A date input (yyyy-MM-dd)",
2376
+ id: "DateField"
2377
+ });
2268
2378
  var AgeField = BaseField.extend({
2269
2379
  type: import_v43.default.literal(FieldType.AGE),
2270
- defaultValue: NumberFieldValue.optional(),
2380
+ defaultValue: NumberFieldValue.or(ComputedDefaultValue).optional(),
2271
2381
  configuration: import_v43.default.object({
2272
2382
  asOfDate: FieldReference,
2273
2383
  prefix: TranslationConfig.optional(),
2274
2384
  postfix: TranslationConfig.optional()
2275
2385
  })
2276
- }).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
+ });
2277
2390
  var TimeField = BaseField.extend({
2278
2391
  type: import_v43.default.literal(FieldType.TIME),
2279
- 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)"),
2280
2393
  configuration: import_v43.default.object({
2281
2394
  use12HourFormat: import_v43.default.boolean().optional().describe("Whether to use 12-hour format"),
2282
2395
  notice: TranslationConfig.describe(
2283
2396
  "Text to display above the time input"
2284
2397
  ).optional()
2285
2398
  }).optional()
2286
- }).describe("A single date input (HH-mm)");
2399
+ }).meta({
2400
+ description: "A single time input (HH-mm)",
2401
+ id: "TimeField"
2402
+ });
2287
2403
  var DateRangeField = BaseField.extend({
2288
2404
  type: import_v43.default.literal(FieldType.DATE_RANGE),
2289
- defaultValue: DateRangeFieldValue.optional(),
2405
+ defaultValue: DateRangeFieldValue.or(ComputedDefaultValue).optional(),
2290
2406
  configuration: import_v43.default.object({
2291
2407
  notice: TranslationConfig.describe(
2292
2408
  "Text to display above the date input"
2293
2409
  ).optional()
2294
2410
  }).optional()
2295
- }).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
+ });
2296
2415
  var HtmlFontVariant = import_v43.default.enum([
2297
2416
  "reg12",
2298
2417
  "reg14",
@@ -2336,21 +2455,33 @@ var ImageViewField = BaseField.extend({
2336
2455
  type: import_v43.default.literal(FieldType.IMAGE_VIEW),
2337
2456
  defaultValue: NonEmptyTextValue.optional(),
2338
2457
  configuration: ImageConfiguration
2339
- }).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
+ });
2340
2462
  var Paragraph = BaseField.extend({
2341
2463
  type: import_v43.default.literal(FieldType.PARAGRAPH),
2342
2464
  configuration: ParagraphConfiguration
2343
- }).describe("A read-only HTML <p> paragraph");
2465
+ }).meta({
2466
+ description: "A read-only HTML <p> paragraph",
2467
+ id: "Paragraph"
2468
+ });
2344
2469
  var Heading = BaseField.extend({
2345
2470
  type: import_v43.default.literal(FieldType.HEADING),
2346
2471
  configuration: HeadingConfiguration
2347
- }).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
+ });
2348
2476
  var PageHeader = BaseField.extend({
2349
2477
  type: import_v43.default.literal(FieldType.PAGE_HEADER)
2350
- }).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
+ });
2351
2482
  var File = BaseField.extend({
2352
2483
  type: import_v43.default.literal(FieldType.FILE),
2353
- defaultValue: FileFieldValue.optional(),
2484
+ defaultValue: FileFieldValue.or(ComputedDefaultValue).optional(),
2354
2485
  configuration: import_v43.default.object({
2355
2486
  maxFileSize: import_v43.default.number().describe("Maximum file size in bytes").default(DEFAULT_MAX_FILE_SIZE_BYTES),
2356
2487
  acceptedFileTypes: MimeType.array().optional().describe("List of allowed file formats for the signature"),
@@ -2366,7 +2497,10 @@ var File = BaseField.extend({
2366
2497
  }).default({
2367
2498
  maxFileSize: DEFAULT_MAX_FILE_SIZE_BYTES
2368
2499
  })
2369
- }).describe("File upload");
2500
+ }).meta({
2501
+ description: "A file upload field",
2502
+ id: "File"
2503
+ });
2370
2504
  var SelectOption = import_v43.default.object({
2371
2505
  value: import_v43.default.string().describe("The value of the option"),
2372
2506
  label: import_v43.default.union([import_v43.default.string(), TranslationConfig]).describe("The label of the option"),
@@ -2374,7 +2508,7 @@ var SelectOption = import_v43.default.object({
2374
2508
  });
2375
2509
  var NumberWithUnitField = BaseField.extend({
2376
2510
  type: import_v43.default.literal(FieldType.NUMBER_WITH_UNIT),
2377
- defaultValue: NumberWithUnitFieldValue.optional(),
2511
+ defaultValue: NumberWithUnitFieldValue.or(ComputedDefaultValue).optional(),
2378
2512
  options: import_v43.default.array(SelectOption).describe("A list of options for the unit select"),
2379
2513
  configuration: import_v43.default.object({
2380
2514
  min: import_v43.default.number().optional().describe("Minimum value of the number field"),
@@ -2383,17 +2517,23 @@ var NumberWithUnitField = BaseField.extend({
2383
2517
  "Placeholder for the number field"
2384
2518
  )
2385
2519
  }).optional()
2386
- }).describe("Number with unit input");
2520
+ }).meta({
2521
+ description: "A number with unit input field",
2522
+ id: "NumberWithUnitField"
2523
+ });
2387
2524
  var RadioGroup = BaseField.extend({
2388
2525
  type: import_v43.default.literal(FieldType.RADIO_GROUP),
2389
- defaultValue: TextValue.optional(),
2526
+ defaultValue: TextValue.or(ComputedDefaultValue).optional(),
2390
2527
  options: import_v43.default.array(SelectOption).describe("A list of options"),
2391
2528
  configuration: import_v43.default.object({
2392
2529
  styles: import_v43.default.object({
2393
2530
  size: import_v43.default.enum(["NORMAL", "LARGE"]).optional()
2394
2531
  }).optional()
2395
2532
  }).optional()
2396
- }).describe("Grouped radio options");
2533
+ }).meta({
2534
+ description: "A grouped radio button field",
2535
+ id: "RadioGroup"
2536
+ });
2397
2537
  var BulletList = BaseField.extend({
2398
2538
  type: import_v43.default.literal(FieldType.BULLET_LIST),
2399
2539
  items: import_v43.default.array(TranslationConfig).describe("A list of items"),
@@ -2402,10 +2542,13 @@ var BulletList = BaseField.extend({
2402
2542
  fontVariant: HtmlFontVariant.optional()
2403
2543
  }).optional()
2404
2544
  }).default({})
2405
- }).describe("A list of bullet points");
2545
+ }).meta({
2546
+ description: "A list of bullet points",
2547
+ id: "BulletList"
2548
+ });
2406
2549
  var Select = BaseField.extend({
2407
2550
  type: import_v43.default.literal(FieldType.SELECT),
2408
- defaultValue: TextValue.optional(),
2551
+ defaultValue: TextValue.or(ComputedDefaultValue).optional(),
2409
2552
  options: import_v43.default.array(SelectOption).describe("A list of options"),
2410
2553
  noOptionsMessage: TranslationConfig.optional().describe(
2411
2554
  `
@@ -2417,16 +2560,22 @@ var Select = BaseField.extend({
2417
2560
  { ..., defaultMessage: "'{input}' is not listed among the health facilities." }
2418
2561
  `
2419
2562
  )
2420
- }).describe("Select input");
2563
+ }).meta({
2564
+ description: "A select input field",
2565
+ id: "Select"
2566
+ });
2421
2567
  var SelectDateRangeOption = import_v43.default.object({
2422
2568
  value: SelectDateRangeValue.describe("The value of the option"),
2423
2569
  label: TranslationConfig.describe("The label of the option")
2424
2570
  });
2425
2571
  var SelectDateRangeField = BaseField.extend({
2426
2572
  type: import_v43.default.literal(FieldType.SELECT_DATE_RANGE),
2427
- defaultValue: SelectDateRangeValue.optional(),
2573
+ defaultValue: SelectDateRangeValue.or(ComputedDefaultValue).optional(),
2428
2574
  options: import_v43.default.array(SelectDateRangeOption).describe("A list of options")
2429
- }).describe("Select input with date range options");
2575
+ }).meta({
2576
+ description: "A date range selection field",
2577
+ id: "SelectDateRangeField"
2578
+ });
2430
2579
  var NameConfig = import_v43.default.object({
2431
2580
  firstname: import_v43.default.object({ required: requiredSchema, label: TranslationConfig.optional() }).optional(),
2432
2581
  middlename: import_v43.default.object({ required: requiredSchema, label: TranslationConfig.optional() }).optional(),
@@ -2438,7 +2587,7 @@ var NameField = BaseField.extend({
2438
2587
  firstname: SerializedUserField.or(NonEmptyTextValue).optional(),
2439
2588
  middlename: SerializedUserField.or(NonEmptyTextValue).optional(),
2440
2589
  surname: SerializedUserField.or(NonEmptyTextValue).optional()
2441
- }).optional(),
2590
+ }).or(ComputedDefaultValue).optional(),
2442
2591
  configuration: import_v43.default.object({
2443
2592
  name: NameConfig.default({
2444
2593
  firstname: { required: true },
@@ -2457,26 +2606,41 @@ var NameField = BaseField.extend({
2457
2606
  surname: { required: true }
2458
2607
  }
2459
2608
  }).optional()
2460
- }).describe("Name input field");
2609
+ }).meta({
2610
+ description: "A field for entering a persons name",
2611
+ id: "NameField"
2612
+ });
2461
2613
  var PhoneField = BaseField.extend({
2462
- defaultValue: NonEmptyTextValue.optional(),
2614
+ defaultValue: NonEmptyTextValue.or(ComputedDefaultValue).optional(),
2463
2615
  type: import_v43.default.literal(FieldType.PHONE)
2464
- }).describe("Phone input field");
2616
+ }).meta({
2617
+ description: "A field for entering a phone number",
2618
+ id: "PhoneField"
2619
+ });
2465
2620
  var IdField = BaseField.extend({
2466
- defaultValue: NonEmptyTextValue.optional(),
2621
+ defaultValue: NonEmptyTextValue.or(ComputedDefaultValue).optional(),
2467
2622
  type: import_v43.default.literal(FieldType.ID)
2468
- }).describe("ID input field");
2623
+ }).meta({
2624
+ description: "A field for entering an ID",
2625
+ id: "IdField"
2626
+ });
2469
2627
  var Checkbox = BaseField.extend({
2470
2628
  type: import_v43.default.literal(FieldType.CHECKBOX),
2471
- defaultValue: CheckboxFieldValue.default(false)
2472
- }).describe("Boolean checkbox field");
2629
+ defaultValue: CheckboxFieldValue.or(ComputedDefaultValue).default(false)
2630
+ }).meta({
2631
+ description: "A boolean checkbox field",
2632
+ id: "Checkbox"
2633
+ });
2473
2634
  var Country = BaseField.extend({
2474
2635
  type: import_v43.default.literal(FieldType.COUNTRY),
2475
- defaultValue: NonEmptyTextValue.optional(),
2636
+ defaultValue: NonEmptyTextValue.or(ComputedDefaultValue).optional(),
2476
2637
  optionOverrides: import_v43.default.array(SelectOption.omit({ label: true })).optional().describe(
2477
2638
  "Conditionals for specific countries. Countries not listed are always shown and enabled."
2478
2639
  )
2479
- }).describe("Country select field");
2640
+ }).meta({
2641
+ description: "A field for selecting a country",
2642
+ id: "Country"
2643
+ });
2480
2644
  var AllowedLocations = JurisdictionReference.optional().describe(
2481
2645
  "Limits which location options are selectable depending on user jurisdiction and location."
2482
2646
  );
@@ -2485,28 +2649,33 @@ var AdministrativeAreas = import_v43.default.enum([
2485
2649
  "HEALTH_FACILITY",
2486
2650
  "CRVS_OFFICE"
2487
2651
  ]);
2488
- var AdministrativeAreaConfiguration = import_v43.default.object({
2489
- partOf: FieldReference.optional().describe("Parent location"),
2490
- type: AdministrativeAreas,
2491
- allowedLocations: AllowedLocations
2492
- }).describe("Administrative area options");
2493
2652
  var AdministrativeAreaField = BaseField.extend({
2494
2653
  type: import_v43.default.literal(FieldType.ADMINISTRATIVE_AREA),
2495
- defaultValue: import_v43.default.union([NonEmptyTextValue, SerializedUserField]).optional(),
2496
- configuration: AdministrativeAreaConfiguration
2497
- }).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
+ });
2498
2664
  var LocationInput = BaseField.extend({
2499
2665
  type: import_v43.default.literal(FieldType.LOCATION),
2500
- defaultValue: import_v43.default.union([NonEmptyTextValue, SerializedUserField]).optional(),
2666
+ defaultValue: import_v43.default.union([NonEmptyTextValue, SerializedUserField, ComputedDefaultValue]).optional(),
2501
2667
  configuration: import_v43.default.object({
2502
2668
  locationTypes: import_v43.default.array(import_v43.default.string()).optional().describe("Types of the locations that are available for selection."),
2503
2669
  allowedLocations: AllowedLocations
2504
2670
  }).optional()
2505
- }).describe("Input field for a location");
2671
+ }).meta({
2672
+ description: "A field for selecting a location",
2673
+ id: "LocationInput"
2674
+ });
2506
2675
  var FileUploadWithOptions = BaseField.extend({
2507
2676
  type: import_v43.default.literal(FieldType.FILE_WITH_OPTIONS),
2508
2677
  options: import_v43.default.array(SelectOption).describe("A list of options"),
2509
- defaultValue: FileFieldWithOptionValue.optional(),
2678
+ defaultValue: FileFieldWithOptionValue.or(ComputedDefaultValue).optional(),
2510
2679
  configuration: import_v43.default.object({
2511
2680
  maxFileSize: import_v43.default.number().describe("Maximum file size in bytes").default(DEFAULT_MAX_FILE_SIZE_BYTES),
2512
2681
  maxImageSize: import_v43.default.object({
@@ -2516,15 +2685,18 @@ var FileUploadWithOptions = BaseField.extend({
2516
2685
  }).default({
2517
2686
  maxFileSize: DEFAULT_MAX_FILE_SIZE_BYTES
2518
2687
  })
2688
+ }).meta({
2689
+ description: "A field for uploading files with file type options",
2690
+ id: "FileUploadWithOptions"
2519
2691
  });
2520
2692
  var Facility = BaseField.extend({
2521
2693
  type: import_v43.default.literal(FieldType.FACILITY),
2522
- defaultValue: NonEmptyTextValue.optional(),
2694
+ defaultValue: NonEmptyTextValue.or(ComputedDefaultValue).optional(),
2523
2695
  configuration: import_v43.default.object({ allowedLocations: AllowedLocations }).optional()
2524
2696
  }).describe("Input field for a facility");
2525
2697
  var Office = BaseField.extend({
2526
2698
  type: import_v43.default.literal(FieldType.OFFICE),
2527
- defaultValue: NonEmptyTextValue.optional(),
2699
+ defaultValue: NonEmptyTextValue.or(ComputedDefaultValue).optional(),
2528
2700
  configuration: import_v43.default.object({ allowedLocations: AllowedLocations }).optional()
2529
2701
  }).describe("Input field for an office");
2530
2702
  var DefaultAddressFieldValue = DomesticAddressFieldValue.extend({
@@ -2560,8 +2732,11 @@ var Address = BaseField.extend({
2560
2732
  ).optional(),
2561
2733
  allowedLocations: AllowedLocations
2562
2734
  }).optional(),
2563
- defaultValue: DefaultAddressFieldValue.optional()
2564
- }).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
+ });
2565
2740
  var StaticDataEntry = import_v43.default.object({
2566
2741
  id: import_v43.default.string().describe("ID for the data entry."),
2567
2742
  label: TranslationConfig,
@@ -2576,7 +2751,10 @@ var DataField = BaseField.extend({
2576
2751
  subtitle: TranslationConfig.optional(),
2577
2752
  data: import_v43.default.array(DataEntry)
2578
2753
  })
2579
- }).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
+ });
2580
2758
  var ButtonSize = import_v43.default.enum(["small", "medium", "large"]);
2581
2759
  var ButtonType = import_v43.default.enum([
2582
2760
  "primary",
@@ -2601,13 +2779,19 @@ var ButtonConfiguration = import_v43.default.object({
2601
2779
  });
2602
2780
  var ButtonField = BaseField.extend({
2603
2781
  type: import_v43.default.literal(FieldType.BUTTON),
2604
- defaultValue: ButtonFieldValue.optional(),
2782
+ defaultValue: ButtonFieldValue.or(ComputedDefaultValue).optional(),
2605
2783
  configuration: ButtonConfiguration
2606
- }).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
+ });
2607
2788
  var FieldGroup = BaseField.extend({
2608
2789
  type: import_v43.default.literal(FieldType.FIELD_GROUP),
2609
2790
  // eslint-disable-next-line @typescript-eslint/no-use-before-define
2610
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"
2611
2795
  });
2612
2796
  var AlphaPrintButton = BaseField.extend({
2613
2797
  type: import_v43.default.literal(FieldType.ALPHA_PRINT_BUTTON),
@@ -2617,10 +2801,13 @@ var AlphaPrintButton = BaseField.extend({
2617
2801
  "Label for the print button"
2618
2802
  )
2619
2803
  })
2620
- }).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
+ });
2621
2808
  var HttpField = BaseField.extend({
2622
2809
  type: import_v43.default.literal(FieldType.HTTP),
2623
- defaultValue: HttpFieldValue.optional(),
2810
+ defaultValue: HttpFieldValue.or(ComputedDefaultValue).optional(),
2624
2811
  configuration: import_v43.default.object({
2625
2812
  trigger: FieldReference.optional().describe(
2626
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."
@@ -2633,20 +2820,30 @@ var HttpField = BaseField.extend({
2633
2820
  params: import_v43.default.record(import_v43.default.string(), import_v43.default.union([import_v43.default.string(), FieldReference])).optional(),
2634
2821
  timeout: import_v43.default.number().default(15e3).describe("Request timeout in milliseconds")
2635
2822
  })
2636
- }).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
+ });
2637
2827
  var AutocompleteField = BaseField.extend({
2638
2828
  type: import_v43.default.literal(FieldType.AUTOCOMPLETE),
2639
2829
  configuration: import_v43.default.object({
2640
- 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(),
2641
2833
  method: import_v43.default.enum(["GET", "POST"]).default("GET").optional(),
2642
2834
  defaultOptions: import_v43.default.array(
2643
2835
  import_v43.default.object({
2644
2836
  label: import_v43.default.string(),
2645
2837
  value: import_v43.default.string()
2646
2838
  })
2647
- ).optional()
2839
+ ).optional().describe(
2840
+ "Manual entry is supported through configuration, allowing users to provide values not currently represented in the dataset."
2841
+ )
2648
2842
  })
2649
- }).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
+ });
2650
2847
  var SearchField = HttpField.extend({
2651
2848
  type: import_v43.default.literal(FieldType.SEARCH),
2652
2849
  configuration: SearchQuery.pick({
@@ -2679,6 +2876,9 @@ var SearchField = HttpField.extend({
2679
2876
  ok: TranslationConfig.optional()
2680
2877
  }).optional()
2681
2878
  })
2879
+ }).meta({
2880
+ description: "A search input field",
2881
+ id: "SearchField"
2682
2882
  });
2683
2883
  var LinkButtonField = BaseField.extend({
2684
2884
  type: import_v43.default.literal(FieldType.LINK_BUTTON),
@@ -2687,28 +2887,35 @@ var LinkButtonField = BaseField.extend({
2687
2887
  text: TranslationConfig.describe("Text to display on the button"),
2688
2888
  icon: import_v43.default.string().optional().describe("Icon for the button. You can find icons from OpenCRVS UI-Kit.")
2689
2889
  })
2690
- }).describe("Button that opens a link");
2890
+ }).meta({
2891
+ description: "A button that opens a URL link",
2892
+ id: "LinkButtonField"
2893
+ });
2691
2894
  var VerificationStatus = BaseField.extend({
2692
2895
  type: import_v43.default.literal(FieldType.VERIFICATION_STATUS),
2693
- defaultValue: VerificationStatusValue.optional(),
2896
+ defaultValue: VerificationStatusValue.or(ComputedDefaultValue).optional(),
2694
2897
  configuration: import_v43.default.object({
2695
2898
  status: TranslationConfig.describe("Text to display on the status pill."),
2696
2899
  description: TranslationConfig.describe(
2697
2900
  "Explaining text on the banner in form."
2698
2901
  )
2699
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"
2700
2906
  });
2701
2907
  var QueryParamReaderField = BaseField.extend({
2702
2908
  type: import_v43.default.literal(FieldType.QUERY_PARAM_READER),
2703
2909
  configuration: import_v43.default.object({
2704
2910
  pickParams: import_v43.default.array(import_v43.default.string()).describe("List of query parameters to read from the URL")
2705
2911
  })
2706
- }).describe(
2707
- "A field that maps URL query params into form values and clears them afterward"
2708
- );
2912
+ }).meta({
2913
+ description: "A field that maps URL query params into form values and clears them afterward",
2914
+ id: "QueryParamReaderField"
2915
+ });
2709
2916
  var QrReaderField = BaseField.extend({
2710
2917
  type: import_v43.default.literal(FieldType.QR_READER),
2711
- defaultValue: QrReaderFieldValue.optional(),
2918
+ defaultValue: QrReaderFieldValue.or(ComputedDefaultValue).optional(),
2712
2919
  configuration: import_v43.default.object({
2713
2920
  validator: import_v43.default.any().meta({
2714
2921
  description: "JSON Schema to validate the scanned QR code data against before populating the form fields.",
@@ -2716,21 +2923,27 @@ var QrReaderField = BaseField.extend({
2716
2923
  })
2717
2924
  }).optional()
2718
2925
  }).meta({
2719
- description: "Configuration for QR code reader field, including optional JSON Schema validator.",
2926
+ description: "QR code reader field, including optional JSON Schema validator.",
2720
2927
  id: "QrReaderField"
2721
2928
  });
2722
2929
  var IdReaderField = BaseField.extend({
2723
2930
  type: import_v43.default.literal(FieldType.ID_READER),
2724
- defaultValue: IdReaderFieldValue.optional(),
2931
+ defaultValue: IdReaderFieldValue.or(ComputedDefaultValue).optional(),
2725
2932
  methods: import_v43.default.array(
2726
2933
  import_v43.default.union([QrReaderField, LinkButtonField]).describe("Methods for reading an ID")
2727
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"
2728
2938
  });
2729
2939
  var CustomField = BaseField.extend({
2730
2940
  type: import_v43.default.literal(FieldType._EXPERIMENTAL_CUSTOM),
2731
2941
  defaultValue: CustomFieldValue.optional(),
2732
2942
  src: import_v43.default.string().describe("Module source path for the custom field component"),
2733
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"
2734
2947
  });
2735
2948
  var FieldStyleVariant = import_v43.default.enum(["default", "highlighted"]);
2736
2949
  var LoaderField = BaseField.extend({
@@ -2740,22 +2953,25 @@ var LoaderField = BaseField.extend({
2740
2953
  configuration: import_v43.default.object({
2741
2954
  text: TranslationConfig.describe("Display text above the loading spinner")
2742
2955
  })
2743
- }).describe(
2744
- "A non-interactive field that indicates an in progress operation in form"
2745
- );
2956
+ }).meta({
2957
+ description: "A non-interactive field that indicates an in progress operation in form",
2958
+ id: "LoaderField"
2959
+ });
2746
2960
  var HiddenField = BaseField.extend({
2747
2961
  type: import_v43.default.literal(FieldType.ALPHA_HIDDEN),
2748
2962
  required: import_v43.default.boolean().default(false).optional(),
2749
2963
  defaultValue: TextValue.optional()
2750
- }).describe(
2751
- "A non-interactive, hidden field that only hold a value in the form"
2752
- );
2964
+ }).meta({
2965
+ description: "A non-interactive, hidden field that only hold a value in the form",
2966
+ id: "HiddenField"
2967
+ });
2753
2968
  var UserRoleField = BaseField.extend({
2754
2969
  type: import_v43.default.literal(FieldType.USER_ROLE),
2755
2970
  defaultValue: TextValue.optional()
2756
- }).describe(
2757
- "A select dropdown that is automatically populated with available user roles"
2758
- );
2971
+ }).meta({
2972
+ description: "A select dropdown that is automatically populated with available user roles",
2973
+ id: "UserRoleField"
2974
+ });
2759
2975
  var FieldConfig = import_v43.default.discriminatedUnion("type", [
2760
2976
  FieldGroup,
2761
2977
  Address,
@@ -2854,16 +3070,19 @@ var VerificationPageConfig = FormPageConfig.extend({
2854
3070
  type: z21.literal(PageTypes.enum.VERIFICATION),
2855
3071
  actions: VerificationActionConfig
2856
3072
  });
2857
- var PageConfig = z21.discriminatedUnion("type", [
2858
- FormPageConfig,
2859
- VerificationPageConfig
2860
- ]);
3073
+ var PageConfig = z21.discriminatedUnion("type", [FormPageConfig, VerificationPageConfig]).meta({
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."
3076
+ });
2861
3077
 
2862
3078
  // ../commons/src/events/FormConfig.ts
2863
3079
  var DeclarationFormConfig = z22.object({
2864
3080
  label: TranslationConfig.describe("Human readable description of the form"),
2865
3081
  pages: z22.array(FormPageConfig)
2866
- }).describe("Configuration of the declaration form.");
3082
+ }).meta({
3083
+ id: "DeclarationFormConfig",
3084
+ description: "Configuration of the declaration form."
3085
+ });
2867
3086
  var ActionFormConfig = z22.object({
2868
3087
  label: TranslationConfig.describe("Human readable description of the form"),
2869
3088
  pages: z22.array(PageConfig)
@@ -2963,6 +3182,9 @@ var DeduplicationConfig = z23.object({
2963
3182
  id: z23.string(),
2964
3183
  label: TranslationConfig,
2965
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."
2966
3188
  });
2967
3189
 
2968
3190
  // ../commons/src/events/ActionConfig.ts
@@ -3000,6 +3222,11 @@ var ReadActionConfig = ActionConfigBase.extend(
3000
3222
  conditionals: z24.never().optional().describe("Read-action can not be disabled or hidden with conditionals.")
3001
3223
  }).shape
3002
3224
  );
3225
+ var NotifyConfig = ActionConfigBase.extend(
3226
+ z24.object({
3227
+ type: z24.literal(ActionType.NOTIFY)
3228
+ }).shape
3229
+ );
3003
3230
  var DeclareConfig = DeclarationActionBase.extend(
3004
3231
  z24.object({
3005
3232
  type: z24.literal(ActionType.DECLARE),
@@ -3080,17 +3307,46 @@ var ActionConfig = z24.discriminatedUnion("type", [
3080
3307
  * OpenAPI references are defined here so our generated OpenAPI spec knows to reuse the models
3081
3308
  * and treat them as "models" instead of duplicating the data structure in each endpoint.
3082
3309
  */
3083
- ReadActionConfig.meta({ id: "ReadActionConfig" }),
3084
- DeclareConfig.meta({ id: "DeclareActionConfig" }),
3085
- RejectConfig.meta({ id: "RejectActionConfig" }),
3086
- 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
+ }),
3087
3330
  PrintCertificateActionConfig.meta({
3088
- 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."
3337
+ }),
3338
+ EditActionConfig.meta({
3339
+ id: "EditActionConfig",
3340
+ description: "Configuration for editing a record before registration."
3089
3341
  }),
3090
- RequestCorrectionConfig.meta({ id: "RequestCorrectionActionConfig" }),
3091
- EditActionConfig.meta({ id: "EditActionConfig" }),
3092
- ArchiveConfig.meta({ id: "ArchiveActionConfig" }),
3093
- CustomActionConfig.meta({ id: "CustomActionConfig" })
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
+ })
3094
3350
  ]).describe(
3095
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."
3096
3352
  ).meta({ id: "ActionConfig" });
@@ -3166,7 +3422,10 @@ var Field = BaseField2.extend({
3166
3422
  }).describe("Custom field defined for the summary view.");
3167
3423
  var SummaryConfig = z27.object({
3168
3424
  fields: z27.array(z27.union([Field, ReferenceField])).describe("Fields displayed in the event summary view.")
3169
- }).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
+ });
3170
3429
 
3171
3430
  // ../commons/src/events/AdvancedSearchConfig.ts
3172
3431
  var z28 = __toESM(require("zod/v4"));
@@ -3237,6 +3496,9 @@ var BaseField3 = z28.object({
3237
3496
  ),
3238
3497
  validations: z28.array(ValidationConfig).optional().describe(
3239
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.`
3240
3502
  )
3241
3503
  });
3242
3504
  var SearchQueryParams = z28.object({
@@ -3290,6 +3552,9 @@ var AdvancedSearchField = z28.discriminatedUnion("fieldType", [FieldConfigSchema
3290
3552
  var AdvancedSearchConfig = z28.object({
3291
3553
  title: TranslationConfig.describe("Advanced search tab title"),
3292
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()`)."
3293
3558
  });
3294
3559
 
3295
3560
  // ../commons/src/events/utils.ts
@@ -3308,9 +3573,11 @@ var z30 = __toESM(require("zod/v4"));
3308
3573
  var z29 = __toESM(require("zod/v4"));
3309
3574
  function getDynamicNameValue(field3) {
3310
3575
  const nameConfiguration = field3.configuration?.name;
3576
+ const firstnameRequired = nameConfiguration?.firstname?.required ?? field3.required;
3577
+ const surnameRequired = nameConfiguration?.surname?.required ?? field3.required;
3311
3578
  return z29.object({
3312
- firstname: nameConfiguration?.firstname?.required ? NonEmptyTextValue : TextValue,
3313
- surname: nameConfiguration?.surname?.required ? NonEmptyTextValue : TextValue,
3579
+ firstname: firstnameRequired ? NonEmptyTextValue : TextValue,
3580
+ surname: surnameRequired ? NonEmptyTextValue : TextValue,
3314
3581
  middlename: nameConfiguration?.middlename?.required ? NonEmptyTextValue : TextValue.optional()
3315
3582
  });
3316
3583
  }
@@ -3657,7 +3924,7 @@ var isHiddenFieldType = (field3) => {
3657
3924
  return field3.config.type === FieldType.ALPHA_HIDDEN;
3658
3925
  };
3659
3926
  var isNonInteractiveFieldType = (field3) => {
3660
- 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;
3661
3928
  };
3662
3929
 
3663
3930
  // ../commons/src/conditionals/validate.ts
@@ -3693,7 +3960,37 @@ function resolveDataPath(rootData, dataPath, instancePath) {
3693
3960
  }
3694
3961
  return current;
3695
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
+ }
3696
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
+ }
3697
3994
  ajv.addKeyword({
3698
3995
  keyword: "daysFromDate",
3699
3996
  type: "string",
@@ -3738,7 +4035,7 @@ ajv.addKeyword({
3738
4035
  $data: true,
3739
4036
  errors: true,
3740
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.
3741
- validate(schema, data, _2, dataContext) {
4038
+ validate(_schema, data, _2, dataContext) {
3742
4039
  const locationIdInput = data;
3743
4040
  const locations = dataContext?.rootData.$leafAdminStructureLocationIds ?? [];
3744
4041
  return locations.some((location) => location.id === locationIdInput);
@@ -3766,6 +4063,26 @@ function precompileActionSchemas(eventConfigurations) {
3766
4063
  function isAgeValue(value) {
3767
4064
  return typeof value === "object" && value !== null && "age" in value && typeof value.age === "number";
3768
4065
  }
4066
+ function mergeWithBaseFormState(values, context) {
4067
+ return { ...context.baseFormState, ...values };
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
+ });
3769
4086
  function validate(schema, data) {
3770
4087
  const validator = ajv.getSchema(schema.$id) || ajv.compile(schema);
3771
4088
  if ("$form" in data) {
@@ -3802,17 +4119,14 @@ function isOnline() {
3802
4119
  }
3803
4120
  return true;
3804
4121
  }
3805
- function isConditionMet(conditional, values, context, eventIndex) {
3806
- return validate(conditional, {
3807
- $form: values,
3808
- $now: (0, import_date_fns.formatISO)(/* @__PURE__ */ new Date(), { representation: "date" }),
3809
- $online: isOnline(),
3810
- $user: context.user,
3811
- $leafAdminStructureLocationIds: context.leafAdminStructureLocationIds ?? [],
3812
- $flags: eventIndex?.flags ?? [],
3813
- $status: eventIndex?.status,
3814
- $event: context.event
3815
- });
4122
+ function isConditionMet(conditional, values, context) {
4123
+ return validate(
4124
+ conditional,
4125
+ buildClientFunctionContext({
4126
+ form: mergeWithBaseFormState(values, context),
4127
+ validatorContext: context
4128
+ })
4129
+ );
3816
4130
  }
3817
4131
  function getConditionalActionsForField(field3, values) {
3818
4132
  if (!field3.conditionals) {
@@ -3820,9 +4134,9 @@ function getConditionalActionsForField(field3, values) {
3820
4134
  }
3821
4135
  return field3.conditionals.filter((conditional) => validate(conditional.conditional, values)).map((conditional) => conditional.type);
3822
4136
  }
3823
- function areConditionsMet(conditions, values, context, event2) {
4137
+ function areConditionsMet(conditions, values, context, _event) {
3824
4138
  return conditions.every(
3825
- (condition) => isConditionMet(condition.conditional, values, context, event2)
4139
+ (condition) => isConditionMet(condition.conditional, values, context)
3826
4140
  );
3827
4141
  }
3828
4142
  function isFieldConditionMet(field3, form, conditionalType, context) {
@@ -3832,14 +4146,13 @@ function isFieldConditionMet(field3, form, conditionalType, context) {
3832
4146
  if (!hasRule) {
3833
4147
  return true;
3834
4148
  }
3835
- const validConditionals = getConditionalActionsForField(field3, {
3836
- $form: form,
3837
- $now: (0, import_date_fns.formatISO)(/* @__PURE__ */ new Date(), { representation: "date" }),
3838
- $online: isOnline(),
3839
- $user: context.user,
3840
- $leafAdminStructureLocationIds: context.leafAdminStructureLocationIds ?? [],
3841
- $event: context.event
3842
- });
4149
+ const validConditionals = getConditionalActionsForField(
4150
+ field3,
4151
+ buildClientFunctionContext({
4152
+ form: mergeWithBaseFormState(form, context),
4153
+ validatorContext: context
4154
+ })
4155
+ );
3843
4156
  return validConditionals.includes(conditionalType);
3844
4157
  }
3845
4158
  function isFieldVisible(field3, form, context) {
@@ -3865,7 +4178,14 @@ function isActionConditionMet(actionConfig, event2, context, conditionalType) {
3865
4178
  if (!rule) {
3866
4179
  return true;
3867
4180
  }
3868
- 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
+ });
3869
4189
  }
3870
4190
  function isActionEnabled(actionConfig, event2, context) {
3871
4191
  return isActionConditionMet(
@@ -4024,19 +4344,10 @@ function runFieldValidations({
4024
4344
  if (!isFieldVisible(field3.config, form, context)) {
4025
4345
  return [];
4026
4346
  }
4027
- const conditionalParameters = {
4028
- $form: form,
4029
- $now: (0, import_date_fns.formatISO)(/* @__PURE__ */ new Date(), { representation: "date" }),
4030
- /**
4031
- * In real use cases, there can be hundreds of thousands of locations.
4032
- * Make sure that the context contains only the locations that are needed for validation.
4033
- * E.g. if the user is a leaf admin, only the leaf locations under their admin structure are needed.
4034
- * Loading few megabytes of locations to memory just for validation is not efficient and will choke the application.
4035
- */
4036
- $leafAdminStructureLocationIds: context.leafAdminStructureLocationIds ?? [],
4037
- $online: isOnline(),
4038
- $user: context.user
4039
- };
4347
+ const conditionalParameters = buildClientFunctionContext({
4348
+ form: mergeWithBaseFormState(form, context),
4349
+ validatorContext: context
4350
+ });
4040
4351
  if (isFieldGroupFieldType(field3)) {
4041
4352
  const subfieldErrors = buildFormState(
4042
4353
  field3.config.fields,
@@ -4175,13 +4486,13 @@ function getActionConfig({
4175
4486
  actionType,
4176
4487
  customActionType
4177
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
+ }
4178
4492
  return eventConfiguration.actions.find((a) => {
4179
4493
  if (a.type === ActionType.CUSTOM && customActionType) {
4180
4494
  return a.customActionType === customActionType;
4181
4495
  }
4182
- if (actionType === ActionType.NOTIFY) {
4183
- return a.type === ActionType.DECLARE;
4184
- }
4185
4496
  if (actionType === ActionType.APPROVE_CORRECTION || actionType === ActionType.REJECT_CORRECTION) {
4186
4497
  return a.type === ActionType.REQUEST_CORRECTION;
4187
4498
  }
@@ -4218,7 +4529,7 @@ var getActionAnnotationFields = (actionConfig) => {
4218
4529
  if (actionConfig.type === ActionType.CUSTOM) {
4219
4530
  return actionConfig.form;
4220
4531
  }
4221
- if ("review" in actionConfig) {
4532
+ if ("review" in actionConfig && actionConfig.review != null) {
4222
4533
  return actionConfig.review.fields;
4223
4534
  }
4224
4535
  return [];
@@ -4269,17 +4580,16 @@ function isPageVisible(page, formValues, context) {
4269
4580
  }
4270
4581
  return isConditionMet(page.conditional, formValues, context);
4271
4582
  }
4272
- function omitHiddenFields(fields, formValues, validatorContext, includeHiddenFieldsWithNullValues = false, declarationContext) {
4583
+ function omitHiddenFields(fields, formValues, validatorContext, includeHiddenFieldsWithNullValues = false) {
4273
4584
  const base = (0, import_lodash.cloneDeep)(formValues);
4274
4585
  function fn(prevVisibilityContext) {
4275
- const visibilityForm = declarationContext ? { ...declarationContext, ...prevVisibilityContext } : prevVisibilityContext;
4276
4586
  const cleaned = (0, import_lodash.omitBy)(base, (value, fieldId) => {
4277
4587
  const fieldConfig = fields.filter((f) => f.id === fieldId);
4278
4588
  if (!fieldConfig.length) {
4279
4589
  return false;
4280
4590
  }
4281
4591
  const isHidden = fieldConfig.every(
4282
- (f) => !isFieldVisible(f, visibilityForm, validatorContext)
4592
+ (f) => !isFieldVisible(f, prevVisibilityContext, validatorContext)
4283
4593
  );
4284
4594
  if (!isHidden) {
4285
4595
  return false;
@@ -4297,7 +4607,7 @@ function omitHiddenPaginatedFields(formConfig, values, validatorContext, include
4297
4607
  const visibleFields = formConfig.pages.filter((p) => isPageVisible(p, values, validatorContext)).flatMap((p) => p.fields);
4298
4608
  const hiddenFields = formConfig.pages.filter((p) => !isPageVisible(p, values, validatorContext)).flatMap((p) => p.fields);
4299
4609
  const valuesExceptHiddenPage = (0, import_lodash.omitBy)(values, (_2, fieldId) => {
4300
- return hiddenFields.some((f) => f.id === fieldId);
4610
+ return hiddenFields.some((f) => f.id === fieldId) && !visibleFields.some((f) => f.id === fieldId);
4301
4611
  });
4302
4612
  return omitHiddenFields(
4303
4613
  visibleFields,
@@ -4344,13 +4654,10 @@ function getVisibleVerificationPageIds(pages, annotation, context) {
4344
4654
  }
4345
4655
  function omitHiddenAnnotationFields(actionConfig, declaration, annotation, context) {
4346
4656
  const annotationFields = getActionAnnotationFields(actionConfig);
4347
- return omitHiddenFields(
4348
- annotationFields,
4349
- annotation,
4350
- context,
4351
- false,
4352
- declaration
4353
- );
4657
+ return omitHiddenFields(annotationFields, annotation, {
4658
+ ...context,
4659
+ baseFormState: declaration
4660
+ });
4354
4661
  }
4355
4662
  function deepMerge(currentDocument, actionDocument) {
4356
4663
  const currentDocumentClone = (0, import_lodash.cloneDeep)(currentDocument);
@@ -4524,19 +4831,32 @@ function getPendingAction(actions) {
4524
4831
  }
4525
4832
  return pendingActions[0];
4526
4833
  }
4527
- function getCompleteActionAnnotation(annotation, event2, action) {
4834
+ function getCompleteActionAnnotation(event2, action) {
4528
4835
  if (action.originalActionId) {
4529
4836
  const originalAction = event2.actions.find(
4530
4837
  ({ id }) => id === action.originalActionId
4531
4838
  );
4532
4839
  if (originalAction?.status === ActionStatus.Requested) {
4533
- return deepMerge(
4534
- deepMerge(annotation, originalAction.annotation ?? {}),
4535
- action.annotation ?? {}
4536
- );
4840
+ return deepMerge(originalAction.annotation ?? {}, action.annotation ?? {});
4537
4841
  }
4538
4842
  }
4539
- 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;
4540
4860
  }
4541
4861
  function getCompleteActionDeclaration(declaration, event2, action) {
4542
4862
  if (action.originalActionId) {
@@ -4556,7 +4876,7 @@ function getAcceptedActions(event2) {
4556
4876
  return event2.actions.filter(isAcceptedAction).map((action) => ({
4557
4877
  ...action,
4558
4878
  declaration: getCompleteActionDeclaration({}, event2, action),
4559
- annotation: getCompleteActionAnnotation({}, event2, action)
4879
+ annotation: getCompleteActionAnnotation(event2, action)
4560
4880
  }));
4561
4881
  }
4562
4882
  var EXCLUDED_ACTIONS = [
@@ -4644,6 +4964,9 @@ function not(condition) {
4644
4964
  function never2() {
4645
4965
  return not(alwaysTrue());
4646
4966
  }
4967
+ function always() {
4968
+ return defineConditional(alwaysTrue());
4969
+ }
4647
4970
  function jsonFieldPath(field3) {
4648
4971
  return [field3.$$field, ...field3.$$subfield].join("/");
4649
4972
  }
@@ -5191,7 +5514,54 @@ function createFieldConditionals(fieldId) {
5191
5514
  }
5192
5515
  },
5193
5516
  required: [fieldId]
5194
- })
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
+ }
5195
5565
  };
5196
5566
  }
5197
5567
 
@@ -5339,7 +5709,7 @@ var _EventConfigBase = z33.object({
5339
5709
  ),
5340
5710
  label: TranslationConfig.describe("Human-readable label for the event type."),
5341
5711
  actions: z33.array(ActionConfig).describe(
5342
- "Configuration of system-defined actions associated with the event."
5712
+ "Configuration of core and custom actions associated with the event."
5343
5713
  ),
5344
5714
  actionOrder: z33.array(z33.string()).optional().describe(
5345
5715
  "Order of actions in the action menu. Use either the action type for core actions or the customActionType for custom actions."
@@ -5351,7 +5721,7 @@ var _EventConfigBase = z33.object({
5351
5721
  "Configuration of fields available in the advanced search feature."
5352
5722
  ),
5353
5723
  flags: z33.array(FlagConfig).optional().default([]).describe(
5354
- "Configuration of flags associated with the actions of this event type."
5724
+ "Configuration of custom flags associated with the actions of this event type."
5355
5725
  ),
5356
5726
  analytics: z33.boolean().optional().default(true).describe(
5357
5727
  "Indicates whether the records of this event type are included in analytics"
@@ -5364,8 +5734,9 @@ var EventConfig = _EventConfigBase.superRefine((event2, ctx) => {
5364
5734
  validateActionFlags(event2, ctx);
5365
5735
  validateActionOrder(event2, ctx);
5366
5736
  }).meta({
5367
- id: "EventConfig"
5368
- }).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
+ });
5369
5740
 
5370
5741
  // ../commons/src/events/EventConfigInput.ts
5371
5742
  var defineDeclarationForm = (form) => DeclarationFormConfig.parse(form);
@@ -5588,6 +5959,9 @@ var WorkqueueColumnValue = z34.object({
5588
5959
  var WorkqueueColumn = z34.object({
5589
5960
  label: TranslationConfig,
5590
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`)."
5591
5965
  });
5592
5966
  function defineWorkqueuesColumns(workqueueColumns) {
5593
5967
  return workqueueColumns.map(
@@ -5790,18 +6164,11 @@ var WorkqueueConfigWithoutQuery = WorkqueueConfig.omit({
5790
6164
  query: true,
5791
6165
  columns: true
5792
6166
  });
5793
- var WorkqueueConfigInput = z37.object({
5794
- slug: z37.string().describe("Determines the url of the workqueue."),
5795
- name: TranslationConfig.describe(
5796
- "Title of the workflow (both in navigation and on the page)"
5797
- ),
5798
- query: CountryConfigQueryInputType,
5799
- action: z37.object({ type: WorkqueueActionType }).optional().describe(
5800
- "Workqueue call-to-action button configuration. This determines the quick action button shown on each event card and the action taken when the button is clicked."
5801
- ),
5802
- columns: z37.array(WorkqueueColumn).default(mandatoryColumns),
5803
- icon: AvailableIcons,
5804
- emptyMessage: TranslationConfig.optional()
6167
+ var WorkqueueConfigInput = WorkqueueConfig.extend({
6168
+ query: CountryConfigQueryInputType
6169
+ }).meta({
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."
5805
6172
  });
5806
6173
  function defineWorkqueue(workqueueInput) {
5807
6174
  const queryInput = workqueueInput.query;
@@ -5862,6 +6229,11 @@ var BaseActionInput = z38.object({
5862
6229
  originalActionId: UUID.optional(),
5863
6230
  // should not be part of base action.
5864
6231
  keepAssignment: z38.boolean().optional(),
6232
+ keepAssignmentIfAccepted: z38.boolean().optional(),
6233
+ keepAssignmentIfRejected: 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
+ ),
5865
6237
  // For normal users, the createdAtLocation is resolved on the backend from the user's primaryOfficeId.
5866
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.
5867
6239
  createdAtLocation: UUID.nullish().describe(
@@ -5979,7 +6351,8 @@ var RejectCorrectionActionInput = BaseActionInput.extend(
5979
6351
  var ApproveCorrectionActionInput = BaseActionInput.extend(
5980
6352
  z38.object({
5981
6353
  requestId: z38.string(),
5982
- 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()
5983
6356
  }).shape
5984
6357
  );
5985
6358
  var ReadActionInput = BaseActionInput.extend(
@@ -6041,7 +6414,7 @@ var Draft = z39.object({
6041
6414
  }).describe(
6042
6415
  "A temporary storage for an action. Stored with details of the event, creator and creation time."
6043
6416
  );
6044
- var DraftInput = BaseActionInput.extend({
6417
+ var DraftInput = BaseActionInput.omit({ waitFor: true }).extend({
6045
6418
  type: ActionTypes.exclude([ActionTypes.enum.DELETE]),
6046
6419
  status: z39.enum([
6047
6420
  ActionStatus.Requested,
@@ -6115,7 +6488,6 @@ function getDeclarationActionCreationMetadata(actionType, actions) {
6115
6488
  createdAtLocation: requestAction?.createdAtLocation ?? acceptAction.createdAtLocation,
6116
6489
  acceptedAt: acceptAction.createdAt,
6117
6490
  createdByRole: requestAction?.createdByRole ?? acceptAction.createdByRole,
6118
- createdBySignature: requestAction?.createdBySignature ?? acceptAction.createdBySignature,
6119
6491
  registrationNumber
6120
6492
  };
6121
6493
  }
@@ -6129,6 +6501,8 @@ var updateActions = ActionTypes.extract([
6129
6501
  ActionType.ARCHIVE,
6130
6502
  ActionType.PRINT_CERTIFICATE,
6131
6503
  ActionType.REQUEST_CORRECTION,
6504
+ ActionType.APPROVE_CORRECTION,
6505
+ ActionType.REJECT_CORRECTION,
6132
6506
  ActionType.CUSTOM
6133
6507
  ]);
6134
6508
  function getActionUpdateMetadata(actions) {
@@ -6143,7 +6517,7 @@ function getActionUpdateMetadata(actions) {
6143
6517
  "createdAtLocation",
6144
6518
  "createdByRole"
6145
6519
  ];
6146
- 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(
6147
6521
  (_2, action) => {
6148
6522
  if (action.originalActionId) {
6149
6523
  const originalAction = actions.find(({ id }) => id === action.originalActionId) ?? action;
@@ -6170,28 +6544,19 @@ function getLegalStatuses(actions) {
6170
6544
  // ../commons/src/events/state/flags.ts
6171
6545
  var import_lodash3 = require("lodash");
6172
6546
  var import_date_fns3 = require("date-fns");
6173
- function isEditInProgress(actions) {
6174
- return actions.at(-1)?.type === ActionType.EDIT;
6175
- }
6176
- function isCorrectionRequested(actions) {
6177
- return actions.reduce((prev, { type }) => {
6178
- if (type === ActionType.REQUEST_CORRECTION) {
6179
- return true;
6180
- }
6181
- if (type === ActionType.APPROVE_CORRECTION) {
6182
- 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;
6183
6553
  }
6184
- if (type === ActionType.REJECT_CORRECTION) {
6185
- return false;
6554
+ if (action.type === ActionType.REQUEST_CORRECTION) {
6555
+ correctionRequestAction = action;
6556
+ break;
6186
6557
  }
6187
- return prev;
6188
- }, false);
6189
- }
6190
- function isDeclarationIncomplete(actions) {
6191
- return getStatusFromActions(actions) === EventStatus.enum.NOTIFIED;
6192
- }
6193
- function isRejected(actions) {
6194
- return actions.at(-1)?.type === ActionType.REJECT;
6558
+ }
6559
+ return correctionRequestAction;
6195
6560
  }
6196
6561
  function isPotentialDuplicate(actions) {
6197
6562
  return actions.reduce((prev, { type }) => {
@@ -6220,6 +6585,88 @@ function isFlagConditionMet(conditional, form, action) {
6220
6585
  }
6221
6586
  });
6222
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
+ }
6223
6670
  function resolveEventCustomFlags(event2, eventConfiguration) {
6224
6671
  const actions = getAcceptedActions(event2).filter(({ type }) => !isMetaAction(type)).sort((a, b) => a.createdAt.localeCompare(b.createdAt));
6225
6672
  return actions.reduce((acc, action, idx) => {
@@ -6255,8 +6702,7 @@ function resolveEventCustomFlags(event2, eventConfiguration) {
6255
6702
  return (0, import_lodash3.uniq)(flags);
6256
6703
  }, []);
6257
6704
  }
6258
- function getEventFlags(event2, config) {
6259
- const sortedActions = event2.actions.filter(({ type }) => !isMetaAction(type)).sort((a, b) => a.createdAt.localeCompare(b.createdAt));
6705
+ function getActionStatusFlags(sortedActions) {
6260
6706
  const actionStatus = sortedActions.reduce(
6261
6707
  (actionStatuses, { type, status: status2 }) => ({
6262
6708
  ...actionStatuses,
@@ -6264,26 +6710,26 @@ function getEventFlags(event2, config) {
6264
6710
  }),
6265
6711
  {}
6266
6712
  );
6267
- 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]) => {
6268
6714
  const flag2 = joinValues([type, status2], ":").toLowerCase();
6269
6715
  return flag2;
6270
6716
  });
6271
- if (isCorrectionRequested(sortedActions)) {
6272
- flags.push(InherentFlags.CORRECTION_REQUESTED);
6273
- }
6274
- if (isDeclarationIncomplete(sortedActions)) {
6275
- flags.push(InherentFlags.INCOMPLETE);
6276
- }
6277
- if (isRejected(sortedActions)) {
6278
- flags.push(InherentFlags.REJECTED);
6279
- }
6280
- if (isPotentialDuplicate(sortedActions)) {
6281
- flags.push(InherentFlags.POTENTIAL_DUPLICATE);
6282
- }
6283
- if (isEditInProgress(sortedActions)) {
6284
- flags.push(InherentFlags.EDIT_IN_PROGRESS);
6285
- }
6286
- 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
+ ];
6287
6733
  }
6288
6734
 
6289
6735
  // ../commons/src/events/state/index.ts
@@ -6329,17 +6775,6 @@ function getAssignedUserFromActions(actions) {
6329
6775
  return user2;
6330
6776
  }, null);
6331
6777
  }
6332
- function getAssignedUserSignatureFromActions(actions) {
6333
- return actions.reduce((signature, action) => {
6334
- if (action.type === ActionType.ASSIGN) {
6335
- return action.createdBySignature || null;
6336
- }
6337
- if (action.type === ActionType.UNASSIGN) {
6338
- return null;
6339
- }
6340
- return signature;
6341
- }, null);
6342
- }
6343
6778
  function deepDropNulls(obj) {
6344
6779
  if (Array.isArray(obj)) {
6345
6780
  return obj.map(deepDropNulls);
@@ -6435,10 +6870,8 @@ function getCurrentEventState(event2, config) {
6435
6870
  createdBy: creationAction.createdBy,
6436
6871
  createdByUserType: creationAction.createdByUserType,
6437
6872
  createdAtLocation: creationAction.createdAtLocation,
6438
- createdBySignature: creationAction.createdBySignature,
6439
6873
  updatedAt: acceptedActionMetadata.createdAt,
6440
6874
  assignedTo: getAssignedUserFromActions(acceptedActions),
6441
- assignedToSignature: getAssignedUserSignatureFromActions(acceptedActions),
6442
6875
  updatedBy: requestActionMetadata.createdBy,
6443
6876
  updatedAtLocation: requestActionMetadata.createdAtLocation,
6444
6877
  declaration,
@@ -6531,7 +6964,7 @@ function getActionAnnotation({
6531
6964
  const action = (0, import_lodash4.findLast)(activeActions, (a) => a.type === actionType);
6532
6965
  const actionWithCompleteAnnotation = action && {
6533
6966
  ...action,
6534
- annotation: getCompleteActionAnnotation({}, event2, action)
6967
+ annotation: getCompleteActionAnnotation(event2, action)
6535
6968
  };
6536
6969
  const matchingDraft = draft?.action.type === actionType ? draft : void 0;
6537
6970
  const sortedActions = (0, import_lodash4.orderBy)(
@@ -6603,6 +7036,9 @@ function createFieldConfig(fieldId, options) {
6603
7036
  }
6604
7037
 
6605
7038
  // ../commons/src/events/field.ts
7039
+ function evaluate(computationFn) {
7040
+ return { $$code: computationFn.toString() };
7041
+ }
6606
7042
  function field(fieldId, options = {}) {
6607
7043
  return {
6608
7044
  ...createFieldConditionals(fieldId),
@@ -7296,6 +7732,11 @@ var TENNIS_CLUB_DECLARATION_REVIEW = {
7296
7732
  id: "signature.upload.modal.title",
7297
7733
  defaultMessage: "Draw signature",
7298
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
7299
7740
  }
7300
7741
  }
7301
7742
  ]
@@ -7852,6 +8293,20 @@ var tennisClubMembershipEvent = defineConfig({
7852
8293
  },
7853
8294
  review: TENNIS_CLUB_DECLARATION_REVIEW
7854
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
+ },
7855
8310
  {
7856
8311
  type: ActionType.REJECT,
7857
8312
  label: {
@@ -8094,6 +8549,17 @@ var tennisClubMembershipEvent = defineConfig({
8094
8549
  }
8095
8550
  }
8096
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
+ ],
8097
8563
  advancedSearch: [
8098
8564
  {
8099
8565
  title: {
@@ -9697,7 +10163,6 @@ var eventQueryDataGenerator = (overrides = {}, seed = 1) => {
9697
10163
  createdBy: overrides.createdBy ?? generateUuid(rng),
9698
10164
  createdAtLocation: overrides.createdAtLocation ?? generateUuid(rng),
9699
10165
  updatedAtLocation: overrides.updatedAtLocation ?? generateUuid(rng),
9700
- createdBySignature: overrides.createdBySignature ?? generateRandomSignature(rng),
9701
10166
  updatedAt: overrides.updatedAt ?? (0, import_date_fns4.addDays)(new Date(createdAt), 1).toISOString(),
9702
10167
  assignedTo: overrides.assignedTo ?? null,
9703
10168
  updatedBy: overrides.updatedBy ?? generateUuid(rng),
@@ -9853,7 +10318,7 @@ function matchesJurisdictionFilter(locationIds, filter, user2) {
9853
10318
  return locationIds.some((id) => id === user2.primaryOfficeId);
9854
10319
  }
9855
10320
  if (filter === JurisdictionFilter.enum.administrativeArea) {
9856
- return user2.administrativeAreaId === null || locationIds.some((id) => id === user2.administrativeAreaId);
10321
+ return !user2.administrativeAreaId || locationIds.some((id) => id === user2.administrativeAreaId);
9857
10322
  }
9858
10323
  return true;
9859
10324
  }
@@ -9930,11 +10395,77 @@ function canAccessEventWithScope(event2, scope, user2, customActionType) {
9930
10395
  }
9931
10396
  return true;
9932
10397
  }
10398
+ function canAccessUserWithScope({
10399
+ userToAccess,
10400
+ scope,
10401
+ user: user2
10402
+ }) {
10403
+ const opts = scope.options;
10404
+ const hasSameOffice = user2.primaryOfficeId === userToAccess.primaryOfficeId;
10405
+ if (opts?.accessLevel === JurisdictionFilter.enum.location && !hasSameOffice) {
10406
+ return false;
10407
+ }
10408
+ const hasAdministrativeAreaInHierarchy = userToAccess.administrativeHierarchy.some(
10409
+ (id) => user2.administrativeAreaId === id
10410
+ ) || !user2.administrativeAreaId;
10411
+ if (opts?.accessLevel === JurisdictionFilter.enum.administrativeArea && !hasAdministrativeAreaInHierarchy) {
10412
+ return false;
10413
+ }
10414
+ if (scopeUsesRoleOptions(scope)) {
10415
+ const { options } = scope;
10416
+ if (options?.role && !options.role.includes(userToAccess.role)) {
10417
+ return false;
10418
+ }
10419
+ }
10420
+ return true;
10421
+ }
10422
+ function canAccessOtherUserWithScopes({
10423
+ scopes,
10424
+ userToAccess,
10425
+ user: user2
10426
+ }) {
10427
+ return scopes.some(
10428
+ (scope) => canAccessUserWithScope({ userToAccess, scope, user: user2 })
10429
+ );
10430
+ }
9933
10431
  function userCanAccessEventWithScopes(event2, scopes, user2, customActionType) {
9934
10432
  return scopes.some(
9935
10433
  (scope) => canAccessEventWithScope(event2, scope, user2, customActionType)
9936
10434
  );
9937
10435
  }
10436
+ function getAdministrativeAreaHierarchy(administrativeAreaId, administrativeAreas) {
10437
+ const collectedLocations = [];
10438
+ const parsedAdministrativeAreaId = administrativeAreaId && UUID.safeParse(administrativeAreaId).data;
10439
+ let current = parsedAdministrativeAreaId ? administrativeAreas.get(parsedAdministrativeAreaId) : null;
10440
+ while (current) {
10441
+ collectedLocations.push(current);
10442
+ if (!current.parentId) {
10443
+ break;
10444
+ }
10445
+ const parentId = current.parentId;
10446
+ current = administrativeAreas.get(parentId);
10447
+ }
10448
+ return collectedLocations;
10449
+ }
10450
+ function getLocationHierarchy(selectedId, context) {
10451
+ const { administrativeAreas, locations } = context;
10452
+ const loc = locations.get(selectedId);
10453
+ if (loc) {
10454
+ if (loc.administrativeAreaId) {
10455
+ const hierarchy2 = getAdministrativeAreaHierarchy(
10456
+ loc.administrativeAreaId,
10457
+ administrativeAreas
10458
+ );
10459
+ return [...hierarchy2.reverse().map((area) => area.id), loc.id];
10460
+ }
10461
+ return [loc.id];
10462
+ }
10463
+ const hierarchy = getAdministrativeAreaHierarchy(
10464
+ selectedId,
10465
+ administrativeAreas
10466
+ );
10467
+ return hierarchy.reverse().map((area) => area.id);
10468
+ }
9938
10469
 
9939
10470
  // ../commons/src/events/scopes.ts
9940
10471
  var ACTION_SCOPE_MAP = {
@@ -10009,6 +10540,25 @@ function isActionInScope({
10009
10540
  );
10010
10541
  return canAccess;
10011
10542
  }
10543
+ function getAvailableRolesForUserUpdatePayload({
10544
+ allRoles,
10545
+ userLocation,
10546
+ acceptedScopes,
10547
+ userRequesting
10548
+ }) {
10549
+ const availableRoles = allRoles.filter((role) => {
10550
+ const canAccess = canAccessOtherUserWithScopes({
10551
+ userToAccess: {
10552
+ ...userLocation,
10553
+ role
10554
+ },
10555
+ user: userRequesting,
10556
+ scopes: acceptedScopes
10557
+ });
10558
+ return canAccess;
10559
+ });
10560
+ return availableRoles;
10561
+ }
10012
10562
 
10013
10563
  // ../commons/src/events/serializers/user/deserializer.ts
10014
10564
  function userDeserializer(serializedUserField, user2) {
@@ -10163,18 +10713,19 @@ var ACTION_FILTERS = {
10163
10713
  function filterActionsByFlags(actions, flags) {
10164
10714
  return actions.filter((action) => ACTION_FILTERS[action]?.(flags) ?? true);
10165
10715
  }
10716
+ var REJECTED_ACTIONS = [
10717
+ ActionType.READ,
10718
+ ActionType.NOTIFY,
10719
+ ActionType.CUSTOM,
10720
+ ActionType.EDIT,
10721
+ ActionType.ARCHIVE
10722
+ ];
10166
10723
  function getAvailableActionsWithoutFlagFilters(status2, flags) {
10167
10724
  if (flags.includes(InherentFlags.EDIT_IN_PROGRESS)) {
10168
10725
  return [ActionType.NOTIFY, ActionType.DECLARE, ActionType.REGISTER];
10169
10726
  }
10170
- if (flags.includes(InherentFlags.REJECTED)) {
10171
- return [
10172
- ActionType.READ,
10173
- ActionType.NOTIFY,
10174
- ActionType.CUSTOM,
10175
- ActionType.EDIT,
10176
- ActionType.ARCHIVE
10177
- ];
10727
+ if (flags.includes(InherentFlags.REJECTED) && status2 !== EventStatus.enum.ARCHIVED) {
10728
+ return REJECTED_ACTIONS;
10178
10729
  }
10179
10730
  return AVAILABLE_ACTIONS_BY_EVENT_STATUS[status2];
10180
10731
  }
@@ -10211,3 +10762,366 @@ function getFilePathsFromEvent(event2) {
10211
10762
  });
10212
10763
  return (0, import_lodash7.uniq)(filepaths);
10213
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
+ );