@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.
@@ -37,7 +37,7 @@ var NotificationStatus = /* @__PURE__ */ ((NotificationStatus2) => {
37
37
  })(NotificationStatus || {});
38
38
 
39
39
  // src/admin/notifications/notifications.admin.ts
40
- import * as admin2 from "firebase-admin";
40
+ import * as admin from "firebase-admin";
41
41
  import { Expo } from "expo-server-sdk";
42
42
 
43
43
  // src/types/appointment/index.ts
@@ -54,6 +54,21 @@ var AppointmentStatus = /* @__PURE__ */ ((AppointmentStatus2) => {
54
54
  AppointmentStatus2["RESCHEDULED_BY_CLINIC"] = "rescheduled_by_clinic";
55
55
  return AppointmentStatus2;
56
56
  })(AppointmentStatus || {});
57
+ var PaymentStatus = /* @__PURE__ */ ((PaymentStatus2) => {
58
+ PaymentStatus2["UNPAID"] = "unpaid";
59
+ PaymentStatus2["PAID"] = "paid";
60
+ PaymentStatus2["PARTIALLY_PAID"] = "partially_paid";
61
+ PaymentStatus2["REFUNDED"] = "refunded";
62
+ PaymentStatus2["NOT_APPLICABLE"] = "not_applicable";
63
+ return PaymentStatus2;
64
+ })(PaymentStatus || {});
65
+ var MediaType = /* @__PURE__ */ ((MediaType2) => {
66
+ MediaType2["BEFORE_PHOTO"] = "before_photo";
67
+ MediaType2["AFTER_PHOTO"] = "after_photo";
68
+ MediaType2["CONSENT_SCAN"] = "consent_scan";
69
+ MediaType2["OTHER_DOCUMENT"] = "other_document";
70
+ return MediaType2;
71
+ })(MediaType || {});
57
72
  var APPOINTMENTS_COLLECTION = "appointments";
58
73
 
59
74
  // src/types/documentation-templates/index.ts
@@ -72,117 +87,11 @@ var UserRole = /* @__PURE__ */ ((UserRole2) => {
72
87
  return UserRole2;
73
88
  })(UserRole || {});
74
89
 
75
- // src/utils/TimestampUtils.ts
76
- import * as admin from "firebase-admin";
77
- import { Timestamp as ClientTimestamp } from "firebase/firestore";
78
- var TimestampUtils = class {
79
- /**
80
- * Converts an admin Firestore Timestamp to a client Firestore Timestamp
81
- * @param adminTimestamp - Admin SDK Timestamp (from firebase-admin)
82
- * @returns A client SDK Timestamp (from firebase/firestore) with same seconds/nanoseconds or null if input is null
83
- */
84
- static adminToClient(adminTimestamp) {
85
- if (!adminTimestamp) return null;
86
- return new ClientTimestamp(
87
- adminTimestamp.seconds,
88
- adminTimestamp.nanoseconds
89
- );
90
- }
91
- /**
92
- * Converts a client Firestore Timestamp to an admin Firestore Timestamp
93
- * @param clientTimestamp - Client SDK Timestamp (from firebase/firestore)
94
- * @returns An admin SDK Timestamp (from firebase-admin) with same seconds/nanoseconds or null if input is null
95
- */
96
- static clientToAdmin(clientTimestamp) {
97
- if (!clientTimestamp) return null;
98
- return new admin.firestore.Timestamp(
99
- clientTimestamp.seconds,
100
- clientTimestamp.nanoseconds
101
- );
102
- }
103
- /**
104
- * Creates a client-compatible timestamp for the current time
105
- * @returns A client SDK Timestamp (from firebase/firestore) for the current time
106
- */
107
- static nowAsClient() {
108
- const now = admin.firestore.Timestamp.now();
109
- return this.adminToClient(now);
110
- }
111
- /**
112
- * Converts a Date object to a client Firestore Timestamp
113
- * @param date - JavaScript Date object
114
- * @returns A client SDK Timestamp (from firebase/firestore) or null if input is null
115
- */
116
- static dateToClientTimestamp(date) {
117
- if (!date) return null;
118
- return ClientTimestamp.fromDate(date);
119
- }
120
- /**
121
- * Converts a Date object to an admin Firestore Timestamp
122
- * @param date - JavaScript Date object
123
- * @returns An admin SDK Timestamp (from firebase-admin) or null if input is null
124
- */
125
- static dateToAdminTimestamp(date) {
126
- if (!date) return null;
127
- return admin.firestore.Timestamp.fromDate(date);
128
- }
129
- /**
130
- * Deeply converts all admin Firestore Timestamps in an object to client Firestore Timestamps
131
- * @param obj - Object that may contain admin Firestore Timestamps
132
- * @returns The same object with all admin Timestamps converted to client Timestamps
133
- */
134
- static convertObjectTimestampsAdminToClient(obj) {
135
- if (!obj || typeof obj !== "object") {
136
- return obj;
137
- }
138
- if (obj instanceof admin.firestore.Timestamp) {
139
- return this.adminToClient(obj);
140
- }
141
- if (Array.isArray(obj)) {
142
- return obj.map(
143
- (item) => this.convertObjectTimestampsAdminToClient(item)
144
- );
145
- }
146
- const result = { ...obj };
147
- for (const key in result) {
148
- if (Object.prototype.hasOwnProperty.call(result, key)) {
149
- result[key] = this.convertObjectTimestampsAdminToClient(result[key]);
150
- }
151
- }
152
- return result;
153
- }
154
- /**
155
- * Deeply converts all client Firestore Timestamps in an object to admin Firestore Timestamps
156
- * @param obj - Object that may contain client Firestore Timestamps
157
- * @returns The same object with all client Timestamps converted to admin Timestamps
158
- */
159
- static convertObjectTimestampsClientToAdmin(obj) {
160
- if (!obj || typeof obj !== "object") {
161
- return obj;
162
- }
163
- if (obj instanceof ClientTimestamp) {
164
- return this.clientToAdmin(obj);
165
- }
166
- if (Array.isArray(obj)) {
167
- return obj.map(
168
- (item) => this.convertObjectTimestampsClientToAdmin(item)
169
- );
170
- }
171
- const result = { ...obj };
172
- for (const key in result) {
173
- if (Object.prototype.hasOwnProperty.call(result, key)) {
174
- result[key] = this.convertObjectTimestampsClientToAdmin(result[key]);
175
- }
176
- }
177
- return result;
178
- }
179
- };
180
-
181
90
  // src/admin/notifications/notifications.admin.ts
182
91
  var NotificationsAdmin = class {
183
92
  constructor(firestore12) {
184
93
  this.expo = new Expo();
185
- this.db = firestore12 || admin2.firestore();
94
+ this.db = firestore12 || admin.firestore();
186
95
  }
187
96
  /**
188
97
  * Dohvata notifikaciju po ID-u
@@ -198,8 +107,8 @@ var NotificationsAdmin = class {
198
107
  const docRef = await this.db.collection("notifications").add({
199
108
  ...notification,
200
109
  status: "pending" /* PENDING */,
201
- createdAt: admin2.firestore.FieldValue.serverTimestamp(),
202
- updatedAt: admin2.firestore.FieldValue.serverTimestamp()
110
+ createdAt: admin.firestore.FieldValue.serverTimestamp(),
111
+ updatedAt: admin.firestore.FieldValue.serverTimestamp()
203
112
  });
204
113
  return docRef.id;
205
114
  }
@@ -225,10 +134,10 @@ var NotificationsAdmin = class {
225
134
  async updateNotificationStatus(notificationId, status, error) {
226
135
  const update = {
227
136
  status,
228
- updatedAt: admin2.firestore.FieldValue.serverTimestamp()
137
+ updatedAt: admin.firestore.FieldValue.serverTimestamp()
229
138
  };
230
139
  if (status === "sent" /* SENT */) {
231
- update.sentAt = admin2.firestore.FieldValue.serverTimestamp();
140
+ update.sentAt = admin.firestore.FieldValue.serverTimestamp();
232
141
  }
233
142
  if (error) {
234
143
  update.error = error;
@@ -298,7 +207,7 @@ var NotificationsAdmin = class {
298
207
  * Procesira notifikacije koje čekaju na slanje sa batch limitom
299
208
  */
300
209
  async processPendingNotifications(batchSize = 100) {
301
- const now = admin2.firestore.Timestamp.now();
210
+ const now = admin.firestore.Timestamp.now();
302
211
  const pendingNotifications = await this.db.collection("notifications").where("status", "==", "pending" /* PENDING */).where("notificationTime", "<=", now).limit(batchSize).get();
303
212
  const results = await Promise.allSettled(
304
213
  pendingNotifications.docs.map(async (doc) => {
@@ -329,7 +238,7 @@ var NotificationsAdmin = class {
329
238
  const oldNotifications = await this.db.collection("notifications").where(
330
239
  "createdAt",
331
240
  "<=",
332
- admin2.firestore.Timestamp.fromDate(cutoffDate)
241
+ admin.firestore.Timestamp.fromDate(cutoffDate)
333
242
  ).limit(batchSize).get();
334
243
  if (oldNotifications.empty) {
335
244
  break;
@@ -371,15 +280,12 @@ var NotificationsAdmin = class {
371
280
  title = "New Appointment Confirmed";
372
281
  body = `Appointment for ${appointment.procedureInfo.name} with ${appointment.patientInfo.fullName} on ${appointment.appointmentStartTime.toDate().toLocaleDateString()} is confirmed.`;
373
282
  }
374
- const adminTsNow = admin2.firestore.Timestamp.now();
375
- const clientCompatibleNotificationTime = TimestampUtils.adminToClient(
376
- adminTsNow
377
- );
283
+ const notificationTimestampForDb = admin.firestore.Timestamp.now();
378
284
  const notificationData = {
379
285
  userId: recipientUserId,
380
286
  userRole: recipientRole,
381
287
  notificationType: "appointmentStatusChange" /* APPOINTMENT_STATUS_CHANGE */,
382
- notificationTime: clientCompatibleNotificationTime,
288
+ notificationTime: notificationTimestampForDb,
383
289
  notificationTokens: recipientExpoTokens,
384
290
  title,
385
291
  body,
@@ -425,15 +331,12 @@ var NotificationsAdmin = class {
425
331
  body += ` Reason: ${appointment.cancellationReason}`;
426
332
  }
427
333
  }
428
- const adminTsNow = admin2.firestore.Timestamp.now();
429
- const clientCompatibleNotificationTime = TimestampUtils.adminToClient(
430
- adminTsNow
431
- );
334
+ const notificationTimestampForDb = admin.firestore.Timestamp.now();
432
335
  const notificationData = {
433
336
  userId: recipientUserId,
434
337
  userRole: recipientRole,
435
338
  notificationType: "appointmentCancelled" /* APPOINTMENT_CANCELLED */,
436
- notificationTime: clientCompatibleNotificationTime,
339
+ notificationTime: notificationTimestampForDb,
437
340
  notificationTokens: recipientExpoTokens,
438
341
  title,
439
342
  body,
@@ -464,15 +367,12 @@ var NotificationsAdmin = class {
464
367
  }
465
368
  const title = "Appointment Reschedule Proposed";
466
369
  const body = `Action Required: A new time has been proposed for your appointment for ${appointment.procedureInfo.name}. Please review in the app.`;
467
- const adminTsNow = admin2.firestore.Timestamp.now();
468
- const clientCompatibleNotificationTime = TimestampUtils.adminToClient(
469
- adminTsNow
470
- );
370
+ const notificationTimestampForDb = admin.firestore.Timestamp.now();
471
371
  const notificationData = {
472
372
  userId: patientUserId,
473
373
  userRole: "patient" /* PATIENT */,
474
374
  notificationType: "appointmentRescheduledProposal" /* APPOINTMENT_RESCHEDULED_PROPOSAL */,
475
- notificationTime: clientCompatibleNotificationTime,
375
+ notificationTime: notificationTimestampForDb,
476
376
  notificationTokens: patientExpoTokens,
477
377
  title,
478
378
  body,
@@ -503,16 +403,13 @@ var NotificationsAdmin = class {
503
403
  }
504
404
  const title = "Payment Updated";
505
405
  const body = `Your payment status for the appointment (${appointment.procedureInfo.name}) on ${appointment.appointmentStartTime.toDate().toLocaleDateString()} is now ${appointment.paymentStatus}.`;
506
- const adminTsNow = admin2.firestore.Timestamp.now();
507
- const clientCompatibleNotificationTime = TimestampUtils.adminToClient(
508
- adminTsNow
509
- );
406
+ const notificationTimestampForDb = admin.firestore.Timestamp.now();
510
407
  const notificationType = appointment.paymentStatus === "paid" /* PAID */ ? "paymentConfirmation" /* PAYMENT_CONFIRMATION */ : "generalMessage" /* GENERAL_MESSAGE */;
511
408
  const notificationData = {
512
409
  userId: patientUserId,
513
410
  userRole: "patient" /* PATIENT */,
514
411
  notificationType,
515
- notificationTime: clientCompatibleNotificationTime,
412
+ notificationTime: notificationTimestampForDb,
516
413
  notificationTokens: patientExpoTokens,
517
414
  title,
518
415
  body,
@@ -543,15 +440,12 @@ var NotificationsAdmin = class {
543
440
  }
544
441
  const title = "Leave a Review";
545
442
  const body = `How was your recent appointment for ${appointment.procedureInfo.name}? We'd love to hear your feedback!`;
546
- const adminTsNow = admin2.firestore.Timestamp.now();
547
- const clientCompatibleNotificationTime = TimestampUtils.adminToClient(
548
- adminTsNow
549
- );
443
+ const notificationTimestampForDb = admin.firestore.Timestamp.now();
550
444
  const notificationData = {
551
445
  userId: patientUserId,
552
446
  userRole: "patient" /* PATIENT */,
553
447
  notificationType: "reviewRequest" /* REVIEW_REQUEST */,
554
- notificationTime: clientCompatibleNotificationTime,
448
+ notificationTime: notificationTimestampForDb,
555
449
  notificationTokens: patientExpoTokens,
556
450
  title,
557
451
  body,
@@ -588,16 +482,13 @@ var NotificationsAdmin = class {
588
482
  }
589
483
  const title = "New Review Received";
590
484
  const body = `A new review has been added by ${appointment.patientInfo.fullName} for your appointment on ${appointment.appointmentStartTime.toDate().toLocaleDateString()}.`;
591
- const adminTsNow = admin2.firestore.Timestamp.now();
592
- const clientCompatibleNotificationTime = TimestampUtils.adminToClient(
593
- adminTsNow
594
- );
485
+ const notificationTimestampForDb = admin.firestore.Timestamp.now();
595
486
  const tempNotificationType = "generalMessage" /* GENERAL_MESSAGE */;
596
487
  const notificationData = {
597
488
  userId: recipientUserId,
598
489
  userRole: "practitioner" /* PRACTITIONER */,
599
490
  notificationType: tempNotificationType,
600
- notificationTime: clientCompatibleNotificationTime,
491
+ notificationTime: notificationTimestampForDb,
601
492
  notificationTokens: recipientExpoTokens,
602
493
  title,
603
494
  body,
@@ -621,6 +512,187 @@ var NotificationsAdmin = class {
621
512
  }
622
513
  };
623
514
 
515
+ // src/utils/TimestampUtils.ts
516
+ import * as admin2 from "firebase-admin";
517
+ import { Timestamp as ClientTimestamp } from "firebase/firestore";
518
+ var IS_SERVER_ENV = process.env.NODE_ENV === "production" || process.env.FUNCTIONS_EMULATOR === "true" || process.env.FIREBASE_CONFIG !== void 0;
519
+ var TimestampUtils = class {
520
+ /**
521
+ * Enables server mode where admin timestamps are preserved when saving
522
+ * to Firestore via the admin SDK
523
+ */
524
+ static enableServerMode() {
525
+ this.serverMode = true;
526
+ }
527
+ /**
528
+ * Disables server mode - use this only for client-side or mixed environments
529
+ */
530
+ static disableServerMode() {
531
+ this.serverMode = false;
532
+ }
533
+ /**
534
+ * Converts an admin Firestore Timestamp to a client Firestore Timestamp
535
+ * In server mode, returns the original admin timestamp for storage consistency
536
+ *
537
+ * @param adminTimestamp - Admin SDK Timestamp (from firebase-admin)
538
+ * @returns A client SDK Timestamp (from firebase/firestore) with same seconds/nanoseconds,
539
+ * or the original admin timestamp in server mode,
540
+ * or null if input is null
541
+ */
542
+ static adminToClient(adminTimestamp) {
543
+ if (!adminTimestamp) return null;
544
+ if (this.serverMode) {
545
+ return adminTimestamp;
546
+ }
547
+ return new ClientTimestamp(
548
+ adminTimestamp.seconds,
549
+ adminTimestamp.nanoseconds
550
+ );
551
+ }
552
+ /**
553
+ * Converts a client Firestore Timestamp to an admin Firestore Timestamp
554
+ * @param clientTimestamp - Client SDK Timestamp (from firebase/firestore)
555
+ * @returns An admin SDK Timestamp (from firebase-admin) with same seconds/nanoseconds or null if input is null
556
+ */
557
+ static clientToAdmin(clientTimestamp) {
558
+ if (!clientTimestamp) return null;
559
+ return new admin2.firestore.Timestamp(
560
+ clientTimestamp.seconds,
561
+ clientTimestamp.nanoseconds
562
+ );
563
+ }
564
+ /**
565
+ * Creates a timestamp for the current time in the appropriate format based on environment
566
+ * @returns A timestamp for the current time (admin timestamp in server mode, client in client mode)
567
+ */
568
+ static nowAsTimestamp() {
569
+ const now = admin2.firestore.Timestamp.now();
570
+ if (this.serverMode) {
571
+ return now;
572
+ }
573
+ return this.adminToClient(now);
574
+ }
575
+ /**
576
+ * @deprecated Use nowAsTimestamp() instead for better cross-environment compatibility
577
+ */
578
+ static nowAsClient() {
579
+ const now = admin2.firestore.Timestamp.now();
580
+ return this.adminToClient(now);
581
+ }
582
+ /**
583
+ * Converts a Date object to a timestamp in the appropriate format based on environment
584
+ * @param date - JavaScript Date object
585
+ * @returns A timestamp (admin timestamp in server mode, client in client mode) or null if input is null
586
+ */
587
+ static dateToTimestamp(date) {
588
+ if (!date) return null;
589
+ if (this.serverMode) {
590
+ return admin2.firestore.Timestamp.fromDate(date);
591
+ }
592
+ return ClientTimestamp.fromDate(date);
593
+ }
594
+ /**
595
+ * @deprecated Use dateToTimestamp() instead for better cross-environment compatibility
596
+ */
597
+ static dateToClientTimestamp(date) {
598
+ if (!date) return null;
599
+ return ClientTimestamp.fromDate(date);
600
+ }
601
+ /**
602
+ * @deprecated Use dateToTimestamp() instead for better cross-environment compatibility
603
+ */
604
+ static dateToAdminTimestamp(date) {
605
+ if (!date) return null;
606
+ return admin2.firestore.Timestamp.fromDate(date);
607
+ }
608
+ /**
609
+ * Gets a server timestamp field value for use in create/update operations
610
+ * Works in both admin and client environments
611
+ */
612
+ static serverTimestamp() {
613
+ if (this.serverMode) {
614
+ return admin2.firestore.FieldValue.serverTimestamp();
615
+ }
616
+ throw new Error("Server timestamp in client mode not implemented");
617
+ }
618
+ /**
619
+ * For objects with mixed timestamp types, ensures all timestamps are
620
+ * in the correct format for the current environment
621
+ */
622
+ static normalizeTimestamps(obj) {
623
+ if (!obj || typeof obj !== "object") {
624
+ return obj;
625
+ }
626
+ if (obj instanceof admin2.firestore.Timestamp) {
627
+ return this.serverMode ? obj : this.adminToClient(obj);
628
+ }
629
+ if (obj instanceof ClientTimestamp && this.serverMode) {
630
+ return this.clientToAdmin(obj);
631
+ }
632
+ if (Array.isArray(obj)) {
633
+ return obj.map((item) => this.normalizeTimestamps(item));
634
+ }
635
+ const result = { ...obj };
636
+ for (const key in result) {
637
+ if (Object.prototype.hasOwnProperty.call(result, key)) {
638
+ result[key] = this.normalizeTimestamps(result[key]);
639
+ }
640
+ }
641
+ return result;
642
+ }
643
+ /**
644
+ * @deprecated Use normalizeTimestamps() instead for better cross-environment compatibility
645
+ */
646
+ static convertObjectTimestampsAdminToClient(obj) {
647
+ if (!obj || typeof obj !== "object") {
648
+ return obj;
649
+ }
650
+ if (obj instanceof admin2.firestore.Timestamp) {
651
+ return this.adminToClient(obj);
652
+ }
653
+ if (Array.isArray(obj)) {
654
+ return obj.map(
655
+ (item) => this.convertObjectTimestampsAdminToClient(item)
656
+ );
657
+ }
658
+ const result = { ...obj };
659
+ for (const key in result) {
660
+ if (Object.prototype.hasOwnProperty.call(result, key)) {
661
+ result[key] = this.convertObjectTimestampsAdminToClient(result[key]);
662
+ }
663
+ }
664
+ return result;
665
+ }
666
+ /**
667
+ * @deprecated Use normalizeTimestamps() instead for better cross-environment compatibility
668
+ */
669
+ static convertObjectTimestampsClientToAdmin(obj) {
670
+ if (!obj || typeof obj !== "object") {
671
+ return obj;
672
+ }
673
+ if (obj instanceof ClientTimestamp) {
674
+ return this.clientToAdmin(obj);
675
+ }
676
+ if (Array.isArray(obj)) {
677
+ return obj.map(
678
+ (item) => this.convertObjectTimestampsClientToAdmin(item)
679
+ );
680
+ }
681
+ const result = { ...obj };
682
+ for (const key in result) {
683
+ if (Object.prototype.hasOwnProperty.call(result, key)) {
684
+ result[key] = this.convertObjectTimestampsClientToAdmin(result[key]);
685
+ }
686
+ }
687
+ return result;
688
+ }
689
+ };
690
+ /**
691
+ * Flag to force server mode where admin timestamps are preserved
692
+ * This should be true in Cloud Functions environments
693
+ */
694
+ TimestampUtils.serverMode = IS_SERVER_ENV;
695
+
624
696
  // src/admin/aggregation/clinic/clinic.aggregation.service.ts
625
697
  import * as admin3 from "firebase-admin";
626
698
 
@@ -2081,7 +2153,7 @@ var PatientRequirementsAdminService = class {
2081
2153
  userRole: "patient" /* PATIENT */,
2082
2154
  notificationType: "requirementInstructionDue" /* REQUIREMENT_INSTRUCTION_DUE */,
2083
2155
  notificationTime: currentInstruction.dueTime,
2084
- // This is a Firestore Timestamp
2156
+ // dueTime should be an admin.firestore.Timestamp already
2085
2157
  notificationTokens: patientExpoTokens,
2086
2158
  title: `Reminder: ${instance.requirementName}`,
2087
2159
  body: currentInstruction.instructionText,
@@ -2423,14 +2495,8 @@ var CalendarAdminService = class {
2423
2495
  const batch = this.db.batch();
2424
2496
  const serverTimestamp = admin8.firestore.FieldValue.serverTimestamp();
2425
2497
  const firestoreCompatibleEventTime = {
2426
- start: {
2427
- seconds: newEventTime.start.seconds,
2428
- nanoseconds: newEventTime.start.nanoseconds
2429
- },
2430
- end: {
2431
- seconds: newEventTime.end.seconds,
2432
- nanoseconds: newEventTime.end.nanoseconds
2433
- }
2498
+ start: TimestampUtils.clientToAdmin(newEventTime.start) || admin8.firestore.Timestamp.now(),
2499
+ end: TimestampUtils.clientToAdmin(newEventTime.end) || admin8.firestore.Timestamp.now()
2434
2500
  };
2435
2501
  if (appointment.calendarEventId) {
2436
2502
  const practitionerEventRef = this.db.doc(
@@ -3178,7 +3244,8 @@ var AppointmentAggregationService = class {
3178
3244
  status: "pendingNotification" /* PENDING_NOTIFICATION */,
3179
3245
  originalNotifyAtValue: notifyAtValue,
3180
3246
  originalTimeframeUnit: template.timeframe.unit,
3181
- updatedAt: admin10.firestore.FieldValue.serverTimestamp(),
3247
+ updatedAt: admin10.firestore.Timestamp.now(),
3248
+ // Use current server timestamp
3182
3249
  notificationId: void 0,
3183
3250
  actionTakenAt: void 0
3184
3251
  };
@@ -3288,7 +3355,8 @@ var AppointmentAggregationService = class {
3288
3355
  status: "pendingNotification" /* PENDING_NOTIFICATION */,
3289
3356
  originalNotifyAtValue: notifyAtValue,
3290
3357
  originalTimeframeUnit: template.timeframe.unit,
3291
- updatedAt: admin10.firestore.FieldValue.serverTimestamp(),
3358
+ updatedAt: admin10.firestore.Timestamp.now(),
3359
+ // Use current server timestamp
3292
3360
  notificationId: void 0,
3293
3361
  actionTakenAt: void 0
3294
3362
  };
@@ -4499,8 +4567,12 @@ var BookingAdmin = class {
4499
4567
  return events.map((event) => ({
4500
4568
  ...event,
4501
4569
  eventTime: {
4502
- start: TimestampUtils.adminToClient(event.eventTime.start),
4503
- end: TimestampUtils.adminToClient(event.eventTime.end)
4570
+ start: TimestampUtils.adminToClient(
4571
+ event.eventTime.start
4572
+ ),
4573
+ end: TimestampUtils.adminToClient(
4574
+ event.eventTime.end
4575
+ )
4504
4576
  }
4505
4577
  // Convert any other timestamps in the event if needed
4506
4578
  }));
@@ -4965,12 +5037,20 @@ var BookingAdmin = class {
4965
5037
 
4966
5038
  // src/admin/index.ts
4967
5039
  console.log("[Admin Module] Initialized and services exported.");
5040
+ TimestampUtils.enableServerMode();
4968
5041
  export {
5042
+ APPOINTMENTS_COLLECTION,
4969
5043
  AppointmentAggregationService,
5044
+ AppointmentMailingService,
4970
5045
  AppointmentStatus,
4971
5046
  BaseMailingService,
4972
5047
  BookingAdmin,
5048
+ BookingAvailabilityCalculator,
5049
+ CalendarAdminService,
4973
5050
  ClinicAggregationService,
5051
+ DocumentManagerAdminService,
5052
+ Logger,
5053
+ MediaType,
4974
5054
  NOTIFICATIONS_COLLECTION,
4975
5055
  NotificationStatus,
4976
5056
  NotificationType,
@@ -4980,6 +5060,7 @@ export {
4980
5060
  PatientInstructionStatus,
4981
5061
  PatientRequirementOverallStatus,
4982
5062
  PatientRequirementsAdminService,
5063
+ PaymentStatus,
4983
5064
  PractitionerAggregationService,
4984
5065
  PractitionerInviteMailingService,
4985
5066
  PractitionerTokenStatus,
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@blackcode_sa/metaestetics-api",
3
3
  "private": false,
4
- "version": "1.6.14",
4
+ "version": "1.6.15",
5
5
  "description": "Firebase authentication service with anonymous upgrade support",
6
6
  "main": "./dist/index.js",
7
7
  "module": "./dist/index.mjs",
@@ -565,7 +565,7 @@ export class AppointmentAggregationService {
565
565
  status: PatientInstructionStatus.PENDING_NOTIFICATION,
566
566
  originalNotifyAtValue: notifyAtValue,
567
567
  originalTimeframeUnit: template.timeframe.unit,
568
- updatedAt: admin.firestore.FieldValue.serverTimestamp() as any,
568
+ updatedAt: admin.firestore.Timestamp.now() as any, // Use current server timestamp
569
569
  notificationId: undefined,
570
570
  actionTakenAt: undefined,
571
571
  };
@@ -707,7 +707,7 @@ export class AppointmentAggregationService {
707
707
  status: PatientInstructionStatus.PENDING_NOTIFICATION,
708
708
  originalNotifyAtValue: notifyAtValue,
709
709
  originalTimeframeUnit: template.timeframe.unit,
710
- updatedAt: admin.firestore.FieldValue.serverTimestamp() as any,
710
+ updatedAt: admin.firestore.Timestamp.now() as any, // Use current server timestamp
711
711
  notificationId: undefined,
712
712
  actionTakenAt: undefined,
713
713
  } as PatientRequirementInstruction;
@@ -205,9 +205,9 @@ export class BookingAdmin {
205
205
  */
206
206
  private adminTimestampToClientTimestamp(
207
207
  timestamp: admin.firestore.Timestamp
208
- ): any {
208
+ ): FirebaseClientTimestamp {
209
209
  // Use TimestampUtils instead of custom implementation
210
- return TimestampUtils.adminToClient(timestamp);
210
+ return TimestampUtils.adminToClient(timestamp) as FirebaseClientTimestamp;
211
211
  }
212
212
 
213
213
  /**
@@ -217,8 +217,12 @@ export class BookingAdmin {
217
217
  return events.map((event) => ({
218
218
  ...event,
219
219
  eventTime: {
220
- start: TimestampUtils.adminToClient(event.eventTime.start),
221
- end: TimestampUtils.adminToClient(event.eventTime.end),
220
+ start: TimestampUtils.adminToClient(
221
+ event.eventTime.start
222
+ ) as FirebaseClientTimestamp,
223
+ end: TimestampUtils.adminToClient(
224
+ event.eventTime.end
225
+ ) as FirebaseClientTimestamp,
222
226
  },
223
227
  // Convert any other timestamps in the event if needed
224
228
  }));
@@ -10,6 +10,7 @@ import { Logger } from "../logger";
10
10
  import { PRACTITIONERS_COLLECTION } from "../../types/practitioner";
11
11
  import { PATIENTS_COLLECTION } from "../../types/patient";
12
12
  import { CLINICS_COLLECTION } from "../../types/clinic";
13
+ import { TimestampUtils } from "../../utils/TimestampUtils";
13
14
 
14
15
  /**
15
16
  * @class CalendarAdminService
@@ -103,18 +104,14 @@ export class CalendarAdminService {
103
104
  const batch = this.db.batch();
104
105
  const serverTimestamp = admin.firestore.FieldValue.serverTimestamp();
105
106
 
106
- // Convert FirebaseClientTimestamp to a plain object for Firestore admin SDK if needed,
107
- // or ensure the CalendarEventTime type is directly compatible.
108
- // Firestore admin SDK usually handles { seconds: X, nanoseconds: Y } objects correctly.
107
+ // Convert client timestamps to admin timestamps since we're in server mode
109
108
  const firestoreCompatibleEventTime = {
110
- start: {
111
- seconds: newEventTime.start.seconds,
112
- nanoseconds: newEventTime.start.nanoseconds,
113
- },
114
- end: {
115
- seconds: newEventTime.end.seconds,
116
- nanoseconds: newEventTime.end.nanoseconds,
117
- },
109
+ start:
110
+ TimestampUtils.clientToAdmin(newEventTime.start) ||
111
+ admin.firestore.Timestamp.now(),
112
+ end:
113
+ TimestampUtils.clientToAdmin(newEventTime.end) ||
114
+ admin.firestore.Timestamp.now(),
118
115
  };
119
116
 
120
117
  // TODO: Confirm paths as in updateAppointmentCalendarEventsStatus