@blackcode_sa/metaestetics-api 1.6.14 → 1.6.15

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.
@@ -30,11 +30,18 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
30
30
  // src/admin/index.ts
31
31
  var index_exports = {};
32
32
  __export(index_exports, {
33
+ APPOINTMENTS_COLLECTION: () => APPOINTMENTS_COLLECTION,
33
34
  AppointmentAggregationService: () => AppointmentAggregationService,
35
+ AppointmentMailingService: () => AppointmentMailingService,
34
36
  AppointmentStatus: () => AppointmentStatus,
35
37
  BaseMailingService: () => BaseMailingService,
36
38
  BookingAdmin: () => BookingAdmin,
39
+ BookingAvailabilityCalculator: () => BookingAvailabilityCalculator,
40
+ CalendarAdminService: () => CalendarAdminService,
37
41
  ClinicAggregationService: () => ClinicAggregationService,
42
+ DocumentManagerAdminService: () => DocumentManagerAdminService,
43
+ Logger: () => Logger,
44
+ MediaType: () => MediaType,
38
45
  NOTIFICATIONS_COLLECTION: () => NOTIFICATIONS_COLLECTION,
39
46
  NotificationStatus: () => NotificationStatus,
40
47
  NotificationType: () => NotificationType,
@@ -44,6 +51,7 @@ __export(index_exports, {
44
51
  PatientInstructionStatus: () => PatientInstructionStatus,
45
52
  PatientRequirementOverallStatus: () => PatientRequirementOverallStatus,
46
53
  PatientRequirementsAdminService: () => PatientRequirementsAdminService,
54
+ PaymentStatus: () => PaymentStatus,
47
55
  PractitionerAggregationService: () => PractitionerAggregationService,
48
56
  PractitionerInviteMailingService: () => PractitionerInviteMailingService,
49
57
  PractitionerTokenStatus: () => PractitionerTokenStatus,
@@ -84,7 +92,7 @@ var NotificationStatus = /* @__PURE__ */ ((NotificationStatus2) => {
84
92
  })(NotificationStatus || {});
85
93
 
86
94
  // src/admin/notifications/notifications.admin.ts
87
- var admin2 = __toESM(require("firebase-admin"));
95
+ var admin = __toESM(require("firebase-admin"));
88
96
  var import_expo_server_sdk = require("expo-server-sdk");
89
97
 
90
98
  // src/types/appointment/index.ts
@@ -101,6 +109,21 @@ var AppointmentStatus = /* @__PURE__ */ ((AppointmentStatus2) => {
101
109
  AppointmentStatus2["RESCHEDULED_BY_CLINIC"] = "rescheduled_by_clinic";
102
110
  return AppointmentStatus2;
103
111
  })(AppointmentStatus || {});
112
+ var PaymentStatus = /* @__PURE__ */ ((PaymentStatus2) => {
113
+ PaymentStatus2["UNPAID"] = "unpaid";
114
+ PaymentStatus2["PAID"] = "paid";
115
+ PaymentStatus2["PARTIALLY_PAID"] = "partially_paid";
116
+ PaymentStatus2["REFUNDED"] = "refunded";
117
+ PaymentStatus2["NOT_APPLICABLE"] = "not_applicable";
118
+ return PaymentStatus2;
119
+ })(PaymentStatus || {});
120
+ var MediaType = /* @__PURE__ */ ((MediaType2) => {
121
+ MediaType2["BEFORE_PHOTO"] = "before_photo";
122
+ MediaType2["AFTER_PHOTO"] = "after_photo";
123
+ MediaType2["CONSENT_SCAN"] = "consent_scan";
124
+ MediaType2["OTHER_DOCUMENT"] = "other_document";
125
+ return MediaType2;
126
+ })(MediaType || {});
104
127
  var APPOINTMENTS_COLLECTION = "appointments";
105
128
 
106
129
  // src/types/documentation-templates/index.ts
@@ -119,117 +142,11 @@ var UserRole = /* @__PURE__ */ ((UserRole2) => {
119
142
  return UserRole2;
120
143
  })(UserRole || {});
121
144
 
122
- // src/utils/TimestampUtils.ts
123
- var admin = __toESM(require("firebase-admin"));
124
- var import_firestore = require("firebase/firestore");
125
- var TimestampUtils = class {
126
- /**
127
- * Converts an admin Firestore Timestamp to a client Firestore Timestamp
128
- * @param adminTimestamp - Admin SDK Timestamp (from firebase-admin)
129
- * @returns A client SDK Timestamp (from firebase/firestore) with same seconds/nanoseconds or null if input is null
130
- */
131
- static adminToClient(adminTimestamp) {
132
- if (!adminTimestamp) return null;
133
- return new import_firestore.Timestamp(
134
- adminTimestamp.seconds,
135
- adminTimestamp.nanoseconds
136
- );
137
- }
138
- /**
139
- * Converts a client Firestore Timestamp to an admin Firestore Timestamp
140
- * @param clientTimestamp - Client SDK Timestamp (from firebase/firestore)
141
- * @returns An admin SDK Timestamp (from firebase-admin) with same seconds/nanoseconds or null if input is null
142
- */
143
- static clientToAdmin(clientTimestamp) {
144
- if (!clientTimestamp) return null;
145
- return new admin.firestore.Timestamp(
146
- clientTimestamp.seconds,
147
- clientTimestamp.nanoseconds
148
- );
149
- }
150
- /**
151
- * Creates a client-compatible timestamp for the current time
152
- * @returns A client SDK Timestamp (from firebase/firestore) for the current time
153
- */
154
- static nowAsClient() {
155
- const now = admin.firestore.Timestamp.now();
156
- return this.adminToClient(now);
157
- }
158
- /**
159
- * Converts a Date object to a client Firestore Timestamp
160
- * @param date - JavaScript Date object
161
- * @returns A client SDK Timestamp (from firebase/firestore) or null if input is null
162
- */
163
- static dateToClientTimestamp(date) {
164
- if (!date) return null;
165
- return import_firestore.Timestamp.fromDate(date);
166
- }
167
- /**
168
- * Converts a Date object to an admin Firestore Timestamp
169
- * @param date - JavaScript Date object
170
- * @returns An admin SDK Timestamp (from firebase-admin) or null if input is null
171
- */
172
- static dateToAdminTimestamp(date) {
173
- if (!date) return null;
174
- return admin.firestore.Timestamp.fromDate(date);
175
- }
176
- /**
177
- * Deeply converts all admin Firestore Timestamps in an object to client Firestore Timestamps
178
- * @param obj - Object that may contain admin Firestore Timestamps
179
- * @returns The same object with all admin Timestamps converted to client Timestamps
180
- */
181
- static convertObjectTimestampsAdminToClient(obj) {
182
- if (!obj || typeof obj !== "object") {
183
- return obj;
184
- }
185
- if (obj instanceof admin.firestore.Timestamp) {
186
- return this.adminToClient(obj);
187
- }
188
- if (Array.isArray(obj)) {
189
- return obj.map(
190
- (item) => this.convertObjectTimestampsAdminToClient(item)
191
- );
192
- }
193
- const result = { ...obj };
194
- for (const key in result) {
195
- if (Object.prototype.hasOwnProperty.call(result, key)) {
196
- result[key] = this.convertObjectTimestampsAdminToClient(result[key]);
197
- }
198
- }
199
- return result;
200
- }
201
- /**
202
- * Deeply converts all client Firestore Timestamps in an object to admin Firestore Timestamps
203
- * @param obj - Object that may contain client Firestore Timestamps
204
- * @returns The same object with all client Timestamps converted to admin Timestamps
205
- */
206
- static convertObjectTimestampsClientToAdmin(obj) {
207
- if (!obj || typeof obj !== "object") {
208
- return obj;
209
- }
210
- if (obj instanceof import_firestore.Timestamp) {
211
- return this.clientToAdmin(obj);
212
- }
213
- if (Array.isArray(obj)) {
214
- return obj.map(
215
- (item) => this.convertObjectTimestampsClientToAdmin(item)
216
- );
217
- }
218
- const result = { ...obj };
219
- for (const key in result) {
220
- if (Object.prototype.hasOwnProperty.call(result, key)) {
221
- result[key] = this.convertObjectTimestampsClientToAdmin(result[key]);
222
- }
223
- }
224
- return result;
225
- }
226
- };
227
-
228
145
  // src/admin/notifications/notifications.admin.ts
229
146
  var NotificationsAdmin = class {
230
147
  constructor(firestore12) {
231
148
  this.expo = new import_expo_server_sdk.Expo();
232
- this.db = firestore12 || admin2.firestore();
149
+ this.db = firestore12 || admin.firestore();
233
150
  }
234
151
  /**
235
152
  * Dohvata notifikaciju po ID-u
@@ -245,8 +162,8 @@ var NotificationsAdmin = class {
245
162
  const docRef = await this.db.collection("notifications").add({
246
163
  ...notification,
247
164
  status: "pending" /* PENDING */,
248
- createdAt: admin2.firestore.FieldValue.serverTimestamp(),
249
- updatedAt: admin2.firestore.FieldValue.serverTimestamp()
165
+ createdAt: admin.firestore.FieldValue.serverTimestamp(),
166
+ updatedAt: admin.firestore.FieldValue.serverTimestamp()
250
167
  });
251
168
  return docRef.id;
252
169
  }
@@ -272,10 +189,10 @@ var NotificationsAdmin = class {
272
189
  async updateNotificationStatus(notificationId, status, error) {
273
190
  const update = {
274
191
  status,
275
- updatedAt: admin2.firestore.FieldValue.serverTimestamp()
192
+ updatedAt: admin.firestore.FieldValue.serverTimestamp()
276
193
  };
277
194
  if (status === "sent" /* SENT */) {
278
- update.sentAt = admin2.firestore.FieldValue.serverTimestamp();
195
+ update.sentAt = admin.firestore.FieldValue.serverTimestamp();
279
196
  }
280
197
  if (error) {
281
198
  update.error = error;
@@ -345,7 +262,7 @@ var NotificationsAdmin = class {
345
262
  * Procesira notifikacije koje čekaju na slanje sa batch limitom
346
263
  */
347
264
  async processPendingNotifications(batchSize = 100) {
348
- const now = admin2.firestore.Timestamp.now();
265
+ const now = admin.firestore.Timestamp.now();
349
266
  const pendingNotifications = await this.db.collection("notifications").where("status", "==", "pending" /* PENDING */).where("notificationTime", "<=", now).limit(batchSize).get();
350
267
  const results = await Promise.allSettled(
351
268
  pendingNotifications.docs.map(async (doc) => {
@@ -376,7 +293,7 @@ var NotificationsAdmin = class {
376
293
  const oldNotifications = await this.db.collection("notifications").where(
377
294
  "createdAt",
378
295
  "<=",
379
- admin2.firestore.Timestamp.fromDate(cutoffDate)
296
+ admin.firestore.Timestamp.fromDate(cutoffDate)
380
297
  ).limit(batchSize).get();
381
298
  if (oldNotifications.empty) {
382
299
  break;
@@ -418,15 +335,12 @@ var NotificationsAdmin = class {
418
335
  title = "New Appointment Confirmed";
419
336
  body = `Appointment for ${appointment.procedureInfo.name} with ${appointment.patientInfo.fullName} on ${appointment.appointmentStartTime.toDate().toLocaleDateString()} is confirmed.`;
420
337
  }
421
- const adminTsNow = admin2.firestore.Timestamp.now();
422
- const clientCompatibleNotificationTime = TimestampUtils.adminToClient(
423
- adminTsNow
424
- );
338
+ const notificationTimestampForDb = admin.firestore.Timestamp.now();
425
339
  const notificationData = {
426
340
  userId: recipientUserId,
427
341
  userRole: recipientRole,
428
342
  notificationType: "appointmentStatusChange" /* APPOINTMENT_STATUS_CHANGE */,
429
- notificationTime: clientCompatibleNotificationTime,
343
+ notificationTime: notificationTimestampForDb,
430
344
  notificationTokens: recipientExpoTokens,
431
345
  title,
432
346
  body,
@@ -472,15 +386,12 @@ var NotificationsAdmin = class {
472
386
  body += ` Reason: ${appointment.cancellationReason}`;
473
387
  }
474
388
  }
475
- const adminTsNow = admin2.firestore.Timestamp.now();
476
- const clientCompatibleNotificationTime = TimestampUtils.adminToClient(
477
- adminTsNow
478
- );
389
+ const notificationTimestampForDb = admin.firestore.Timestamp.now();
479
390
  const notificationData = {
480
391
  userId: recipientUserId,
481
392
  userRole: recipientRole,
482
393
  notificationType: "appointmentCancelled" /* APPOINTMENT_CANCELLED */,
483
- notificationTime: clientCompatibleNotificationTime,
394
+ notificationTime: notificationTimestampForDb,
484
395
  notificationTokens: recipientExpoTokens,
485
396
  title,
486
397
  body,
@@ -511,15 +422,12 @@ var NotificationsAdmin = class {
511
422
  }
512
423
  const title = "Appointment Reschedule Proposed";
513
424
  const body = `Action Required: A new time has been proposed for your appointment for ${appointment.procedureInfo.name}. Please review in the app.`;
514
- const adminTsNow = admin2.firestore.Timestamp.now();
515
- const clientCompatibleNotificationTime = TimestampUtils.adminToClient(
516
- adminTsNow
517
- );
425
+ const notificationTimestampForDb = admin.firestore.Timestamp.now();
518
426
  const notificationData = {
519
427
  userId: patientUserId,
520
428
  userRole: "patient" /* PATIENT */,
521
429
  notificationType: "appointmentRescheduledProposal" /* APPOINTMENT_RESCHEDULED_PROPOSAL */,
522
- notificationTime: clientCompatibleNotificationTime,
430
+ notificationTime: notificationTimestampForDb,
523
431
  notificationTokens: patientExpoTokens,
524
432
  title,
525
433
  body,
@@ -550,16 +458,13 @@ var NotificationsAdmin = class {
550
458
  }
551
459
  const title = "Payment Updated";
552
460
  const body = `Your payment status for the appointment (${appointment.procedureInfo.name}) on ${appointment.appointmentStartTime.toDate().toLocaleDateString()} is now ${appointment.paymentStatus}.`;
553
- const adminTsNow = admin2.firestore.Timestamp.now();
554
- const clientCompatibleNotificationTime = TimestampUtils.adminToClient(
555
- adminTsNow
556
- );
461
+ const notificationTimestampForDb = admin.firestore.Timestamp.now();
557
462
  const notificationType = appointment.paymentStatus === "paid" /* PAID */ ? "paymentConfirmation" /* PAYMENT_CONFIRMATION */ : "generalMessage" /* GENERAL_MESSAGE */;
558
463
  const notificationData = {
559
464
  userId: patientUserId,
560
465
  userRole: "patient" /* PATIENT */,
561
466
  notificationType,
562
- notificationTime: clientCompatibleNotificationTime,
467
+ notificationTime: notificationTimestampForDb,
563
468
  notificationTokens: patientExpoTokens,
564
469
  title,
565
470
  body,
@@ -590,15 +495,12 @@ var NotificationsAdmin = class {
590
495
  }
591
496
  const title = "Leave a Review";
592
497
  const body = `How was your recent appointment for ${appointment.procedureInfo.name}? We'd love to hear your feedback!`;
593
- const adminTsNow = admin2.firestore.Timestamp.now();
594
- const clientCompatibleNotificationTime = TimestampUtils.adminToClient(
595
- adminTsNow
596
- );
498
+ const notificationTimestampForDb = admin.firestore.Timestamp.now();
597
499
  const notificationData = {
598
500
  userId: patientUserId,
599
501
  userRole: "patient" /* PATIENT */,
600
502
  notificationType: "reviewRequest" /* REVIEW_REQUEST */,
601
- notificationTime: clientCompatibleNotificationTime,
503
+ notificationTime: notificationTimestampForDb,
602
504
  notificationTokens: patientExpoTokens,
603
505
  title,
604
506
  body,
@@ -635,16 +537,13 @@ var NotificationsAdmin = class {
635
537
  }
636
538
  const title = "New Review Received";
637
539
  const body = `A new review has been added by ${appointment.patientInfo.fullName} for your appointment on ${appointment.appointmentStartTime.toDate().toLocaleDateString()}.`;
638
- const adminTsNow = admin2.firestore.Timestamp.now();
639
- const clientCompatibleNotificationTime = TimestampUtils.adminToClient(
640
- adminTsNow
641
- );
540
+ const notificationTimestampForDb = admin.firestore.Timestamp.now();
642
541
  const tempNotificationType = "generalMessage" /* GENERAL_MESSAGE */;
643
542
  const notificationData = {
644
543
  userId: recipientUserId,
645
544
  userRole: "practitioner" /* PRACTITIONER */,
646
545
  notificationType: tempNotificationType,
647
- notificationTime: clientCompatibleNotificationTime,
546
+ notificationTime: notificationTimestampForDb,
648
547
  notificationTokens: recipientExpoTokens,
649
548
  title,
650
549
  body,
@@ -668,6 +567,187 @@ var NotificationsAdmin = class {
668
567
  }
669
568
  };
670
569
 
570
+ // src/utils/TimestampUtils.ts
571
+ var admin2 = __toESM(require("firebase-admin"));
572
+ var import_firestore = require("firebase/firestore");
573
+ var IS_SERVER_ENV = process.env.NODE_ENV === "production" || process.env.FUNCTIONS_EMULATOR === "true" || process.env.FIREBASE_CONFIG !== void 0;
574
+ var TimestampUtils = class {
575
+ /**
576
+ * Enables server mode where admin timestamps are preserved when saving
577
+ * to Firestore via the admin SDK
578
+ */
579
+ static enableServerMode() {
580
+ this.serverMode = true;
581
+ }
582
+ /**
583
+ * Disables server mode - use this only for client-side or mixed environments
584
+ */
585
+ static disableServerMode() {
586
+ this.serverMode = false;
587
+ }
588
+ /**
589
+ * Converts an admin Firestore Timestamp to a client Firestore Timestamp
590
+ * In server mode, returns the original admin timestamp for storage consistency
591
+ *
592
+ * @param adminTimestamp - Admin SDK Timestamp (from firebase-admin)
593
+ * @returns A client SDK Timestamp (from firebase/firestore) with same seconds/nanoseconds,
594
+ * or the original admin timestamp in server mode,
595
+ * or null if input is null
596
+ */
597
+ static adminToClient(adminTimestamp) {
598
+ if (!adminTimestamp) return null;
599
+ if (this.serverMode) {
600
+ return adminTimestamp;
601
+ }
602
+ return new import_firestore.Timestamp(
603
+ adminTimestamp.seconds,
604
+ adminTimestamp.nanoseconds
605
+ );
606
+ }
607
+ /**
608
+ * Converts a client Firestore Timestamp to an admin Firestore Timestamp
609
+ * @param clientTimestamp - Client SDK Timestamp (from firebase/firestore)
610
+ * @returns An admin SDK Timestamp (from firebase-admin) with same seconds/nanoseconds or null if input is null
611
+ */
612
+ static clientToAdmin(clientTimestamp) {
613
+ if (!clientTimestamp) return null;
614
+ return new admin2.firestore.Timestamp(
615
+ clientTimestamp.seconds,
616
+ clientTimestamp.nanoseconds
617
+ );
618
+ }
619
+ /**
620
+ * Creates a timestamp for the current time in the appropriate format based on environment
621
+ * @returns A timestamp for the current time (admin timestamp in server mode, client in client mode)
622
+ */
623
+ static nowAsTimestamp() {
624
+ const now = admin2.firestore.Timestamp.now();
625
+ if (this.serverMode) {
626
+ return now;
627
+ }
628
+ return this.adminToClient(now);
629
+ }
630
+ /**
631
+ * @deprecated Use nowAsTimestamp() instead for better cross-environment compatibility
632
+ */
633
+ static nowAsClient() {
634
+ const now = admin2.firestore.Timestamp.now();
635
+ return this.adminToClient(now);
636
+ }
637
+ /**
638
+ * Converts a Date object to a timestamp in the appropriate format based on environment
639
+ * @param date - JavaScript Date object
640
+ * @returns A timestamp (admin timestamp in server mode, client in client mode) or null if input is null
641
+ */
642
+ static dateToTimestamp(date) {
643
+ if (!date) return null;
644
+ if (this.serverMode) {
645
+ return admin2.firestore.Timestamp.fromDate(date);
646
+ }
647
+ return import_firestore.Timestamp.fromDate(date);
648
+ }
649
+ /**
650
+ * @deprecated Use dateToTimestamp() instead for better cross-environment compatibility
651
+ */
652
+ static dateToClientTimestamp(date) {
653
+ if (!date) return null;
654
+ return import_firestore.Timestamp.fromDate(date);
655
+ }
656
+ /**
657
+ * @deprecated Use dateToTimestamp() instead for better cross-environment compatibility
658
+ */
659
+ static dateToAdminTimestamp(date) {
660
+ if (!date) return null;
661
+ return admin2.firestore.Timestamp.fromDate(date);
662
+ }
663
+ /**
664
+ * Gets a server timestamp field value for use in create/update operations
665
+ * Works in both admin and client environments
666
+ */
667
+ static serverTimestamp() {
668
+ if (this.serverMode) {
669
+ return admin2.firestore.FieldValue.serverTimestamp();
670
+ }
671
+ throw new Error("Server timestamp in client mode not implemented");
672
+ }
673
+ /**
674
+ * For objects with mixed timestamp types, ensures all timestamps are
675
+ * in the correct format for the current environment
676
+ */
677
+ static normalizeTimestamps(obj) {
678
+ if (!obj || typeof obj !== "object") {
679
+ return obj;
680
+ }
681
+ if (obj instanceof admin2.firestore.Timestamp) {
682
+ return this.serverMode ? obj : this.adminToClient(obj);
683
+ }
684
+ if (obj instanceof import_firestore.Timestamp && this.serverMode) {
685
+ return this.clientToAdmin(obj);
686
+ }
687
+ if (Array.isArray(obj)) {
688
+ return obj.map((item) => this.normalizeTimestamps(item));
689
+ }
690
+ const result = { ...obj };
691
+ for (const key in result) {
692
+ if (Object.prototype.hasOwnProperty.call(result, key)) {
693
+ result[key] = this.normalizeTimestamps(result[key]);
694
+ }
695
+ }
696
+ return result;
697
+ }
698
+ /**
699
+ * @deprecated Use normalizeTimestamps() instead for better cross-environment compatibility
700
+ */
701
+ static convertObjectTimestampsAdminToClient(obj) {
702
+ if (!obj || typeof obj !== "object") {
703
+ return obj;
704
+ }
705
+ if (obj instanceof admin2.firestore.Timestamp) {
706
+ return this.adminToClient(obj);
707
+ }
708
+ if (Array.isArray(obj)) {
709
+ return obj.map(
710
+ (item) => this.convertObjectTimestampsAdminToClient(item)
711
+ );
712
+ }
713
+ const result = { ...obj };
714
+ for (const key in result) {
715
+ if (Object.prototype.hasOwnProperty.call(result, key)) {
716
+ result[key] = this.convertObjectTimestampsAdminToClient(result[key]);
717
+ }
718
+ }
719
+ return result;
720
+ }
721
+ /**
722
+ * @deprecated Use normalizeTimestamps() instead for better cross-environment compatibility
723
+ */
724
+ static convertObjectTimestampsClientToAdmin(obj) {
725
+ if (!obj || typeof obj !== "object") {
726
+ return obj;
727
+ }
728
+ if (obj instanceof import_firestore.Timestamp) {
729
+ return this.clientToAdmin(obj);
730
+ }
731
+ if (Array.isArray(obj)) {
732
+ return obj.map(
733
+ (item) => this.convertObjectTimestampsClientToAdmin(item)
734
+ );
735
+ }
736
+ const result = { ...obj };
737
+ for (const key in result) {
738
+ if (Object.prototype.hasOwnProperty.call(result, key)) {
739
+ result[key] = this.convertObjectTimestampsClientToAdmin(result[key]);
740
+ }
741
+ }
742
+ return result;
743
+ }
744
+ };
745
+ /**
746
+ * Flag to force server mode where admin timestamps are preserved
747
+ * This should be true in Cloud Functions environments
748
+ */
749
+ TimestampUtils.serverMode = IS_SERVER_ENV;
750
+
671
751
  // src/admin/aggregation/clinic/clinic.aggregation.service.ts
672
752
  var admin3 = __toESM(require("firebase-admin"));
673
753
 
@@ -2128,7 +2208,7 @@ var PatientRequirementsAdminService = class {
2128
2208
  userRole: "patient" /* PATIENT */,
2129
2209
  notificationType: "requirementInstructionDue" /* REQUIREMENT_INSTRUCTION_DUE */,
2130
2210
  notificationTime: currentInstruction.dueTime,
2131
- // This is a Firestore Timestamp
2211
+ // dueTime should be an admin.firestore.Timestamp already
2132
2212
  notificationTokens: patientExpoTokens,
2133
2213
  title: `Reminder: ${instance.requirementName}`,
2134
2214
  body: currentInstruction.instructionText,
@@ -2470,14 +2550,8 @@ var CalendarAdminService = class {
2470
2550
  const batch = this.db.batch();
2471
2551
  const serverTimestamp = admin8.firestore.FieldValue.serverTimestamp();
2472
2552
  const firestoreCompatibleEventTime = {
2473
- start: {
2474
- seconds: newEventTime.start.seconds,
2475
- nanoseconds: newEventTime.start.nanoseconds
2476
- },
2477
- end: {
2478
- seconds: newEventTime.end.seconds,
2479
- nanoseconds: newEventTime.end.nanoseconds
2480
- }
2553
+ start: TimestampUtils.clientToAdmin(newEventTime.start) || admin8.firestore.Timestamp.now(),
2554
+ end: TimestampUtils.clientToAdmin(newEventTime.end) || admin8.firestore.Timestamp.now()
2481
2555
  };
2482
2556
  if (appointment.calendarEventId) {
2483
2557
  const practitionerEventRef = this.db.doc(
@@ -3225,7 +3299,8 @@ var AppointmentAggregationService = class {
3225
3299
  status: "pendingNotification" /* PENDING_NOTIFICATION */,
3226
3300
  originalNotifyAtValue: notifyAtValue,
3227
3301
  originalTimeframeUnit: template.timeframe.unit,
3228
- updatedAt: admin10.firestore.FieldValue.serverTimestamp(),
3302
+ updatedAt: admin10.firestore.Timestamp.now(),
3303
+ // Use current server timestamp
3229
3304
  notificationId: void 0,
3230
3305
  actionTakenAt: void 0
3231
3306
  };
@@ -3335,7 +3410,8 @@ var AppointmentAggregationService = class {
3335
3410
  status: "pendingNotification" /* PENDING_NOTIFICATION */,
3336
3411
  originalNotifyAtValue: notifyAtValue,
3337
3412
  originalTimeframeUnit: template.timeframe.unit,
3338
- updatedAt: admin10.firestore.FieldValue.serverTimestamp(),
3413
+ updatedAt: admin10.firestore.Timestamp.now(),
3414
+ // Use current server timestamp
3339
3415
  notificationId: void 0,
3340
3416
  actionTakenAt: void 0
3341
3417
  };
@@ -4546,8 +4622,12 @@ var BookingAdmin = class {
4546
4622
  return events.map((event) => ({
4547
4623
  ...event,
4548
4624
  eventTime: {
4549
- start: TimestampUtils.adminToClient(event.eventTime.start),
4550
- end: TimestampUtils.adminToClient(event.eventTime.end)
4625
+ start: TimestampUtils.adminToClient(
4626
+ event.eventTime.start
4627
+ ),
4628
+ end: TimestampUtils.adminToClient(
4629
+ event.eventTime.end
4630
+ )
4551
4631
  }
4552
4632
  // Convert any other timestamps in the event if needed
4553
4633
  }));
@@ -5012,13 +5092,21 @@ var BookingAdmin = class {
5012
5092
 
5013
5093
  // src/admin/index.ts
5014
5094
  console.log("[Admin Module] Initialized and services exported.");
5095
+ TimestampUtils.enableServerMode();
5015
5096
  // Annotate the CommonJS export names for ESM import in node:
5016
5097
  0 && (module.exports = {
5098
+ APPOINTMENTS_COLLECTION,
5017
5099
  AppointmentAggregationService,
5100
+ AppointmentMailingService,
5018
5101
  AppointmentStatus,
5019
5102
  BaseMailingService,
5020
5103
  BookingAdmin,
5104
+ BookingAvailabilityCalculator,
5105
+ CalendarAdminService,
5021
5106
  ClinicAggregationService,
5107
+ DocumentManagerAdminService,
5108
+ Logger,
5109
+ MediaType,
5022
5110
  NOTIFICATIONS_COLLECTION,
5023
5111
  NotificationStatus,
5024
5112
  NotificationType,
@@ -5028,6 +5116,7 @@ console.log("[Admin Module] Initialized and services exported.");
5028
5116
  PatientInstructionStatus,
5029
5117
  PatientRequirementOverallStatus,
5030
5118
  PatientRequirementsAdminService,
5119
+ PaymentStatus,
5031
5120
  PractitionerAggregationService,
5032
5121
  PractitionerInviteMailingService,
5033
5122
  PractitionerTokenStatus,