@blackcode_sa/metaestetics-api 1.15.9 → 1.15.13
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.
- package/dist/admin/index.d.mts +9 -0
- package/dist/admin/index.d.ts +9 -0
- package/dist/index.d.mts +15 -17
- package/dist/index.d.ts +15 -17
- package/dist/index.js +25 -36
- package/dist/index.mjs +25 -34
- package/package.json +1 -1
- package/src/config/index.ts +0 -1
- package/src/config/tiers.config.ts +13 -20
- package/src/services/appointment/appointment.service.ts +14 -0
- package/src/services/tier-enforcement.ts +8 -30
- package/src/types/clinic/index.ts +9 -0
- package/src/types/clinic/rbac.types.ts +0 -1
package/dist/admin/index.d.mts
CHANGED
|
@@ -1171,6 +1171,8 @@ interface BillingInfo {
|
|
|
1171
1171
|
currentPeriodStart: Timestamp | null;
|
|
1172
1172
|
currentPeriodEnd: Timestamp | null;
|
|
1173
1173
|
updatedAt: Timestamp;
|
|
1174
|
+
seatCount?: number;
|
|
1175
|
+
seatPriceId?: string;
|
|
1174
1176
|
}
|
|
1175
1177
|
/**
|
|
1176
1178
|
* Enum for billing transaction types
|
|
@@ -1261,6 +1263,12 @@ interface ClinicGroup {
|
|
|
1261
1263
|
completed?: boolean;
|
|
1262
1264
|
step?: number;
|
|
1263
1265
|
};
|
|
1266
|
+
featureTrials?: {
|
|
1267
|
+
analytics?: {
|
|
1268
|
+
startedAt: Timestamp;
|
|
1269
|
+
durationDays: number;
|
|
1270
|
+
};
|
|
1271
|
+
};
|
|
1264
1272
|
}
|
|
1265
1273
|
/**
|
|
1266
1274
|
* Interface for doctor information
|
|
@@ -1303,6 +1311,7 @@ interface Clinic {
|
|
|
1303
1311
|
isActive: boolean;
|
|
1304
1312
|
isVerified: boolean;
|
|
1305
1313
|
logo?: MediaResource | null;
|
|
1314
|
+
acceptingBookings?: boolean;
|
|
1306
1315
|
}
|
|
1307
1316
|
|
|
1308
1317
|
/**
|
package/dist/admin/index.d.ts
CHANGED
|
@@ -1171,6 +1171,8 @@ interface BillingInfo {
|
|
|
1171
1171
|
currentPeriodStart: Timestamp | null;
|
|
1172
1172
|
currentPeriodEnd: Timestamp | null;
|
|
1173
1173
|
updatedAt: Timestamp;
|
|
1174
|
+
seatCount?: number;
|
|
1175
|
+
seatPriceId?: string;
|
|
1174
1176
|
}
|
|
1175
1177
|
/**
|
|
1176
1178
|
* Enum for billing transaction types
|
|
@@ -1261,6 +1263,12 @@ interface ClinicGroup {
|
|
|
1261
1263
|
completed?: boolean;
|
|
1262
1264
|
step?: number;
|
|
1263
1265
|
};
|
|
1266
|
+
featureTrials?: {
|
|
1267
|
+
analytics?: {
|
|
1268
|
+
startedAt: Timestamp;
|
|
1269
|
+
durationDays: number;
|
|
1270
|
+
};
|
|
1271
|
+
};
|
|
1264
1272
|
}
|
|
1265
1273
|
/**
|
|
1266
1274
|
* Interface for doctor information
|
|
@@ -1303,6 +1311,7 @@ interface Clinic {
|
|
|
1303
1311
|
isActive: boolean;
|
|
1304
1312
|
isVerified: boolean;
|
|
1305
1313
|
logo?: MediaResource | null;
|
|
1314
|
+
acceptingBookings?: boolean;
|
|
1306
1315
|
}
|
|
1307
1316
|
|
|
1308
1317
|
/**
|
package/dist/index.d.mts
CHANGED
|
@@ -5353,7 +5353,6 @@ interface TierLimits {
|
|
|
5353
5353
|
maxProcedures: number;
|
|
5354
5354
|
maxAppointmentsPerMonth: number;
|
|
5355
5355
|
maxMessagesPerMonth: number;
|
|
5356
|
-
maxStaff: number;
|
|
5357
5356
|
maxBranches: number;
|
|
5358
5357
|
}
|
|
5359
5358
|
/**
|
|
@@ -5552,6 +5551,8 @@ interface BillingInfo {
|
|
|
5552
5551
|
currentPeriodStart: Timestamp | null;
|
|
5553
5552
|
currentPeriodEnd: Timestamp | null;
|
|
5554
5553
|
updatedAt: Timestamp;
|
|
5554
|
+
seatCount?: number;
|
|
5555
|
+
seatPriceId?: string;
|
|
5555
5556
|
}
|
|
5556
5557
|
/**
|
|
5557
5558
|
* Enum for billing transaction types
|
|
@@ -5642,6 +5643,12 @@ interface ClinicGroup {
|
|
|
5642
5643
|
completed?: boolean;
|
|
5643
5644
|
step?: number;
|
|
5644
5645
|
};
|
|
5646
|
+
featureTrials?: {
|
|
5647
|
+
analytics?: {
|
|
5648
|
+
startedAt: Timestamp;
|
|
5649
|
+
durationDays: number;
|
|
5650
|
+
};
|
|
5651
|
+
};
|
|
5645
5652
|
}
|
|
5646
5653
|
/**
|
|
5647
5654
|
* Interface for creating a clinic group
|
|
@@ -5722,6 +5729,7 @@ interface Clinic {
|
|
|
5722
5729
|
isActive: boolean;
|
|
5723
5730
|
isVerified: boolean;
|
|
5724
5731
|
logo?: MediaResource | null;
|
|
5732
|
+
acceptingBookings?: boolean;
|
|
5725
5733
|
}
|
|
5726
5734
|
/**
|
|
5727
5735
|
* Interface for creating a clinic
|
|
@@ -9756,10 +9764,6 @@ declare function enforceProcedureLimit(db: Firestore, clinicGroupId: string, cou
|
|
|
9756
9764
|
* Enforces tier limit before creating a clinic branch.
|
|
9757
9765
|
*/
|
|
9758
9766
|
declare function enforceBranchLimit(db: Firestore, clinicGroupId: string): Promise<void>;
|
|
9759
|
-
/**
|
|
9760
|
-
* Enforces tier limit before creating a staff member.
|
|
9761
|
-
*/
|
|
9762
|
-
declare function enforceStaffLimit(db: Firestore, clinicGroupId: string): Promise<void>;
|
|
9763
9767
|
/**
|
|
9764
9768
|
* Enforces tier limit before creating an appointment.
|
|
9765
9769
|
* Reads the monthly counter from clinic_groups/{id}/usage_counters/{YYYY-MM}.
|
|
@@ -9828,10 +9832,10 @@ type PermissionKey = keyof typeof PERMISSION_KEYS;
|
|
|
9828
9832
|
* All features are available on every tier — tiers differ only in usage caps.
|
|
9829
9833
|
* -1 means unlimited.
|
|
9830
9834
|
*
|
|
9831
|
-
* Confirmed by client on 2026-03-
|
|
9832
|
-
* - Free: 1 provider, 3 procedures, 3 appts/mo, 10 msgs/mo, 1
|
|
9833
|
-
* - Connect:
|
|
9834
|
-
* - Pro: unlimited everything
|
|
9835
|
+
* Confirmed by client on 2026-03-10:
|
|
9836
|
+
* - Free: 1 provider, 3 procedures, 3 appts/mo, 10 msgs/mo, 1 location
|
|
9837
|
+
* - Connect (CHF 59/mo): unlimited providers, 15 procedures, 100 appts/mo, unlimited msgs, 1 location
|
|
9838
|
+
* - Pro (CHF 149/mo): unlimited everything
|
|
9835
9839
|
*/
|
|
9836
9840
|
declare const TIER_CONFIG: Record<string, TierConfig>;
|
|
9837
9841
|
/**
|
|
@@ -9840,14 +9844,8 @@ declare const TIER_CONFIG: Record<string, TierConfig>;
|
|
|
9840
9844
|
*/
|
|
9841
9845
|
declare const DEFAULT_ROLE_PERMISSIONS: Record<ClinicRole, Record<string, boolean>>;
|
|
9842
9846
|
/**
|
|
9843
|
-
*
|
|
9844
|
-
* All paid legacy tiers map to PRO.
|
|
9845
|
-
*/
|
|
9846
|
-
declare const LEGACY_TIER_MAP: Record<string, string>;
|
|
9847
|
-
/**
|
|
9848
|
-
* Resolves the effective tier for a subscription model string,
|
|
9849
|
-
* handling legacy values.
|
|
9847
|
+
* Resolves the effective tier for a subscription model string.
|
|
9850
9848
|
*/
|
|
9851
9849
|
declare function resolveEffectiveTier(subscriptionModel: string): string;
|
|
9852
9850
|
|
|
9853
|
-
export { AESTHETIC_ANALYSIS_COLLECTION, ANALYTICS_COLLECTION, APPOINTMENTS_COLLECTION, type ASAClassification, AcquisitionSource, type AddAllergyData, type AddBlockingConditionData, type AddContraindicationData, type AddMedicationData, type AddressData, type AdminInfo, type AdminToken, AdminTokenStatus, type AestheticAnalysis, type AestheticAnalysisStatus, type Allergy, type AllergySubtype, AllergyType, type AllergyTypeWithSubtype, AnalyticsCloudService, type AnalyticsDateRange, type AnalyticsFilters, type AnalyticsMetadata, type AnalyticsPeriod, AnalyticsService, type AnesthesiaHistory, type Appointment, type AppointmentCancelledNotification, type AppointmentMediaItem, type AppointmentMetadata, type AppointmentProductMetadata, type AppointmentReminderNotification, type AppointmentRescheduledProposalNotification, type AppointmentRescheduledReminderNotification, AppointmentService, AppointmentStatus, type AppointmentStatusChangeNotification, type AppointmentTrend, type AssessmentScales, AuthService, BODY_ASSESSMENT_COLLECTION, type BaseDocumentElement, type BaseMetrics, type BaseNotification, BaseService, type BeforeAfterPerZone, type BillingInfo, type BillingPerZone, type BillingTransaction, BillingTransactionType, BillingTransactionsService, type BinaryChoiceElement, type BleedingRisk, type BleedingRiskLevel, BlockingCondition, type BodyAssessment, type BodyAssessmentStatus, type BodyCompositionData, type BodyMeasurementsData, type BodySymmetryData, type BodyZone, type BodyZoneAssessment, type Brand, BrandService, type Break, CALENDAR_COLLECTION, CANCELLATION_ANALYTICS_SUBCOLLECTION, CLINICS_COLLECTION, CLINIC_ADMINS_COLLECTION, CLINIC_ANALYTICS_SUBCOLLECTION, CLINIC_GROUPS_COLLECTION, type CalendarEvent, CalendarEventStatus, type CalendarEventTime, CalendarEventType, CalendarServiceV2, CalendarServiceV3, CalendarSyncStatus, type CancellationMetrics, type CancellationRateTrend, type CancellationReasonStats, type Category, CategoryService, CertificationLevel, CertificationSpecialty, type ClearanceStatus, type Clinic, type ClinicAdmin, ClinicAdminService, type ClinicAdminSignupData, type ClinicAnalytics, type ClinicBranchSetupData, type ClinicComparisonMetrics, type ClinicContactInfo, type ClinicGroup, ClinicGroupService, type ClinicGroupSetupData, type ClinicInfo, type ClinicLocation, ClinicPhotoTag, type ClinicReview, type ClinicReviewInfo, ClinicRole, ClinicService, type ClinicStaffMember, ClinicTag, type ClinicTags, type ClinicalFindingDetail, type ClinicalFindings, ConstantsService, type ContactPerson, Contraindication, type ContraindicationDynamic, CosmeticAllergySubtype, type CostPerPatientMetrics, type CreateAdminTokenData, type CreateAestheticAnalysisData, type CreateAppointmentData, type CreateAppointmentHttpData, type CreateAppointmentParams, type CreateBillingTransactionData, type CreateBlockingEventParams, type CreateBodyAssessmentData, type CreateCalendarEventData, type CreateClinicAdminData, type CreateClinicData, type CreateClinicGroupData, type CreateDefaultClinicGroupData, type CreateDocumentTemplateData, type CreateDraftPractitionerData, type CreateHairScalpAssessmentData, type CreateManualPatientData, type CreatePatientLocationInfoData, type CreatePatientMedicalInfoData, type CreatePatientProfileData, type CreatePatientSensitiveInfoData, type CreatePatientTokenData, type CreatePractitionerData, type CreatePractitionerInviteData, type CreatePractitionerTokenData, type CreatePreSurgicalAssessmentData, type CreateProcedureData, type CreateSkinQualityAssessmentData, type CreateSyncedCalendarData, type CreateUserData, Currency, DASHBOARD_ANALYTICS_SUBCOLLECTION, DEFAULT_MEDICAL_INFO, DEFAULT_ROLE_PERMISSIONS, DOCTOR_FORMS_SUBCOLLECTION, DOCUMENTATION_TEMPLATES_COLLECTION, type DashboardAnalytics, type DatePickerElement, type DateRange, type DigitalSignatureElement, type DoctorInfo, type DocumentElement, DocumentElementType, type DocumentTemplate, DocumentationTemplateService, type DurationTrend, type DynamicTextElement, DynamicVariable, type ElastosisGrade, type EmergencyContact, type EntityType, EnvironmentalAllergySubtype, type ExtendedProcedureInfo, ExternalCalendarService, FILLED_DOCUMENTS_COLLECTION, type FileUploadElement, type FilledDocument, type FilledDocumentFileValue, FilledDocumentService, FilledDocumentStatus, type FinalBilling, type FirebaseUser, type FitzpatrickType, FoodAllergySubtype, type FormReminderNotification, type FormSubmissionConfirmationNotification, type GamificationInfo, Gender, type GeneralMessageNotification, type GlogauClassification, type GroupedAnalyticsBase, type GroupedPatientBehaviorMetrics, type GroupedPatientRetentionMetrics, type GroupedPractitionerPerformanceMetrics, type GroupedProcedurePerformanceMetrics, type GroupedProductUsageMetrics, type GroupedRevenueMetrics, type GroupedTimeEfficiencyMetrics, type GroupingPeriod, HAIR_SCALP_ASSESSMENT_COLLECTION, type HairCharacteristics, type HairColor, type HairDensity, type HairLossPattern, type HairLossType, type HairLossZone, type HairLossZoneAssessment, type HairScalpAssessment, type HairScalpAssessmentStatus, type HairTextureGrade, type HairType, type HeadingElement, HeadingLevel, INVITE_TOKENS_COLLECTION, LEGACY_TIER_MAP, type LabResult, Language, type LinkedFormInfo, type ListElement, ListType, type LocationData, type LudwigStage, MEDIA_METADATA_COLLECTION, MediaAccessLevel, type MediaMetadata, type MediaResource, MediaService, MediaType, MedicationAllergySubtype, type MultipleChoiceElement, type MuscleDefinitionLevel, NOTIFICATIONS_COLLECTION, NO_SHOW_ANALYTICS_SUBCOLLECTION, type NextStepsRecommendation, type NoShowMetrics, type NorwoodStage, type Notification, NotificationService, NotificationStatus, NotificationType, type OverallReviewAverages, PATIENTS_COLLECTION, PATIENT_APPOINTMENTS_COLLECTION, PATIENT_LOCATION_INFO_COLLECTION, PATIENT_MEDICAL_HISTORY_COLLECTION, PATIENT_MEDICAL_INFO_COLLECTION, PATIENT_REQUIREMENTS_SUBCOLLECTION_NAME, PATIENT_SENSITIVE_INFO_COLLECTION, PERMISSION_KEYS, PRACTITIONERS_COLLECTION, PRACTITIONER_ANALYTICS_SUBCOLLECTION, PRACTITIONER_INVITES_COLLECTION, PRE_SURGICAL_ASSESSMENT_COLLECTION, PROCEDURES_COLLECTION, PROCEDURE_ANALYTICS_SUBCOLLECTION, type ParagraphElement, type PatientAnalytics, type PatientClinic, type PatientDoctor, type PatientGoals, PatientInstructionStatus, type PatientLifetimeValueMetrics, type PatientLocationInfo, type PatientMedicalInfo, type PatientProfile, type PatientProfileComplete, type PatientProfileForDoctor, type PatientProfileInfo, type PatientRequirementInstance, type PatientRequirementInstruction, PatientRequirementOverallStatus, type PatientRequirementsFilters, PatientRequirementsService, type PatientRetentionMetrics, type PatientReviewInfo, type PatientSensitiveInfo, PatientService, type PatientToken, PatientTokenStatus, type PaymentConfirmationNotification, PaymentStatus, type PaymentStatusBreakdown, type PermissionKey, type PlanDetails, type PoreSizeLevel, type PostRequirementNotification, PracticeType, type Practitioner, type PractitionerAnalytics, type PractitionerBasicInfo, type PractitionerCertification, type PractitionerClinicProcedures, type PractitionerClinicWorkingHours, type PractitionerInvite, type PractitionerInviteFilters, PractitionerInviteService, PractitionerInviteStatus, type PractitionerProfileInfo, type PractitionerReview, type PractitionerReviewInfo, PractitionerService, PractitionerStatus, type PractitionerToken, PractitionerTokenStatus, type PractitionerWorkingHours, type PreRequirementNotification, type PreSurgicalAssessment, type PreSurgicalAssessmentStatus, PricingMeasure, type Procedure, type ProcedureAnalytics, type ProcedureCategorization, type ProcedureExtendedInfo, ProcedureFamily, type ProcedureInfo, type ProcedurePopularity, type ProcedureProduct, type ProcedureProfitability, type ProcedureRecommendationNotification, type ProcedureReview, type ProcedureReviewInfo, ProcedureService, type ProcedureSummaryInfo, type Product, type ProductRevenueMetrics, ProductService, type ProductUsageByProcedure, type ProductUsageMetrics, type ProposedWorkingHours, REGISTER_TOKENS_COLLECTION, REVENUE_ANALYTICS_SUBCOLLECTION, REVIEWS_COLLECTION, type RatingScaleElement, type ReadStoredAnalyticsOptions, type RecommendedProcedure, type RequesterInfo, type Requirement, type RequirementInstructionDueNotification, type RequirementSourceProcedure, RequirementType, type RevenueMetrics, type RevenueTrend, type Review, type ReviewAnalyticsMetrics, ReviewAnalyticsService, type ReviewDetail, type ReviewMetrics, type ReviewRequestNotification, ReviewService, type ReviewTrend, type RolePermissionConfig, SKIN_QUALITY_ASSESSMENT_COLLECTION, SYNCED_CALENDARS_COLLECTION, type ScalpCondition, type ScalpRednessLevel, type ScalpScalinessLevel, type ScalpSebumLevel, type SearchAppointmentsParams, type SearchCalendarEventsParams, SearchLocationEnum, type SearchPatientsParams, type SeverityLevel, type SignatureElement, type SingleChoiceElement, type SkinCharacteristics, type SkinConditionEntry, type SkinConditionType, type SkinElasticityLevel, type SkinHydrationLevel, type SkinQualityAssessment, type SkinQualityAssessmentStatus, type SkinQualityScales, type SkinSensitivityLevel, type SkinTextureLevel, type SkinZone, type SkinZoneAssessment, type SmokingStatus, type StoredCancellationMetrics, type StoredClinicAnalytics, type StoredDashboardAnalytics, type StoredNoShowMetrics, type StoredPractitionerAnalytics, type StoredProcedureAnalytics, type StoredRevenueMetrics, type StoredTimeEfficiencyMetrics, type StripeTransactionData, type Subcategory, SubcategoryService, SubscriptionModel, SubscriptionStatus, type SurgicalSiteAssessment, type SyncedCalendar, type SyncedCalendarEvent, SyncedCalendarProvider, SyncedCalendarsService, TIER_CONFIG, TIME_EFFICIENCY_ANALYTICS_SUBCOLLECTION, type Technology, type TechnologyDocumentationTemplate, TechnologyService, type TextInputElement, type TierConfig, TierLimitError, type TierLimits, type TimeEfficiencyMetrics, type TimeSlot, TimeUnit, type TissueQualityLevel, TreatmentBenefit, type TreatmentBenefitDynamic, type TrendPeriod, USERS_COLLECTION, USER_FORMS_SUBCOLLECTION, type UpdateAestheticAnalysisData, type UpdateAllergyData, type UpdateAppointmentData, type UpdateAppointmentParams, type UpdateBlockingConditionData, type UpdateBlockingEventParams, type UpdateBodyAssessmentData, type UpdateCalendarEventData, type UpdateClinicAdminData, type UpdateClinicData, type UpdateClinicGroupData, type UpdateContraindicationData, type UpdateDocumentTemplateData, type UpdateHairScalpAssessmentData, type UpdateMedicationData, type UpdatePatientLocationInfoData, type UpdatePatientMedicalInfoData, type UpdatePatientProfileData, type UpdatePatientSensitiveInfoData, type UpdatePractitionerData, type UpdatePractitionerInviteData, type UpdatePreSurgicalAssessmentData, type UpdateProcedureData, type UpdateSkinQualityAssessmentData, type UpdateSyncedCalendarData, type UpdateVitalStatsData, type User, UserRole, UserService, type VitalStats, type WorkingHours, type ZoneItemData, type ZonePhotoUploadData, enforceAppointmentLimit, enforceBranchLimit, enforceMessageLimit, enforceProcedureLimit, enforceProviderLimit, enforceStaffLimit, getEffectiveTier, getFirebaseApp, getFirebaseAuth, getFirebaseDB, getFirebaseFunctions, getFirebaseInstance, getFirebaseStorage, initializeFirebase, resolveEffectiveTier };
|
|
9851
|
+
export { AESTHETIC_ANALYSIS_COLLECTION, ANALYTICS_COLLECTION, APPOINTMENTS_COLLECTION, type ASAClassification, AcquisitionSource, type AddAllergyData, type AddBlockingConditionData, type AddContraindicationData, type AddMedicationData, type AddressData, type AdminInfo, type AdminToken, AdminTokenStatus, type AestheticAnalysis, type AestheticAnalysisStatus, type Allergy, type AllergySubtype, AllergyType, type AllergyTypeWithSubtype, AnalyticsCloudService, type AnalyticsDateRange, type AnalyticsFilters, type AnalyticsMetadata, type AnalyticsPeriod, AnalyticsService, type AnesthesiaHistory, type Appointment, type AppointmentCancelledNotification, type AppointmentMediaItem, type AppointmentMetadata, type AppointmentProductMetadata, type AppointmentReminderNotification, type AppointmentRescheduledProposalNotification, type AppointmentRescheduledReminderNotification, AppointmentService, AppointmentStatus, type AppointmentStatusChangeNotification, type AppointmentTrend, type AssessmentScales, AuthService, BODY_ASSESSMENT_COLLECTION, type BaseDocumentElement, type BaseMetrics, type BaseNotification, BaseService, type BeforeAfterPerZone, type BillingInfo, type BillingPerZone, type BillingTransaction, BillingTransactionType, BillingTransactionsService, type BinaryChoiceElement, type BleedingRisk, type BleedingRiskLevel, BlockingCondition, type BodyAssessment, type BodyAssessmentStatus, type BodyCompositionData, type BodyMeasurementsData, type BodySymmetryData, type BodyZone, type BodyZoneAssessment, type Brand, BrandService, type Break, CALENDAR_COLLECTION, CANCELLATION_ANALYTICS_SUBCOLLECTION, CLINICS_COLLECTION, CLINIC_ADMINS_COLLECTION, CLINIC_ANALYTICS_SUBCOLLECTION, CLINIC_GROUPS_COLLECTION, type CalendarEvent, CalendarEventStatus, type CalendarEventTime, CalendarEventType, CalendarServiceV2, CalendarServiceV3, CalendarSyncStatus, type CancellationMetrics, type CancellationRateTrend, type CancellationReasonStats, type Category, CategoryService, CertificationLevel, CertificationSpecialty, type ClearanceStatus, type Clinic, type ClinicAdmin, ClinicAdminService, type ClinicAdminSignupData, type ClinicAnalytics, type ClinicBranchSetupData, type ClinicComparisonMetrics, type ClinicContactInfo, type ClinicGroup, ClinicGroupService, type ClinicGroupSetupData, type ClinicInfo, type ClinicLocation, ClinicPhotoTag, type ClinicReview, type ClinicReviewInfo, ClinicRole, ClinicService, type ClinicStaffMember, ClinicTag, type ClinicTags, type ClinicalFindingDetail, type ClinicalFindings, ConstantsService, type ContactPerson, Contraindication, type ContraindicationDynamic, CosmeticAllergySubtype, type CostPerPatientMetrics, type CreateAdminTokenData, type CreateAestheticAnalysisData, type CreateAppointmentData, type CreateAppointmentHttpData, type CreateAppointmentParams, type CreateBillingTransactionData, type CreateBlockingEventParams, type CreateBodyAssessmentData, type CreateCalendarEventData, type CreateClinicAdminData, type CreateClinicData, type CreateClinicGroupData, type CreateDefaultClinicGroupData, type CreateDocumentTemplateData, type CreateDraftPractitionerData, type CreateHairScalpAssessmentData, type CreateManualPatientData, type CreatePatientLocationInfoData, type CreatePatientMedicalInfoData, type CreatePatientProfileData, type CreatePatientSensitiveInfoData, type CreatePatientTokenData, type CreatePractitionerData, type CreatePractitionerInviteData, type CreatePractitionerTokenData, type CreatePreSurgicalAssessmentData, type CreateProcedureData, type CreateSkinQualityAssessmentData, type CreateSyncedCalendarData, type CreateUserData, Currency, DASHBOARD_ANALYTICS_SUBCOLLECTION, DEFAULT_MEDICAL_INFO, DEFAULT_ROLE_PERMISSIONS, DOCTOR_FORMS_SUBCOLLECTION, DOCUMENTATION_TEMPLATES_COLLECTION, type DashboardAnalytics, type DatePickerElement, type DateRange, type DigitalSignatureElement, type DoctorInfo, type DocumentElement, DocumentElementType, type DocumentTemplate, DocumentationTemplateService, type DurationTrend, type DynamicTextElement, DynamicVariable, type ElastosisGrade, type EmergencyContact, type EntityType, EnvironmentalAllergySubtype, type ExtendedProcedureInfo, ExternalCalendarService, FILLED_DOCUMENTS_COLLECTION, type FileUploadElement, type FilledDocument, type FilledDocumentFileValue, FilledDocumentService, FilledDocumentStatus, type FinalBilling, type FirebaseUser, type FitzpatrickType, FoodAllergySubtype, type FormReminderNotification, type FormSubmissionConfirmationNotification, type GamificationInfo, Gender, type GeneralMessageNotification, type GlogauClassification, type GroupedAnalyticsBase, type GroupedPatientBehaviorMetrics, type GroupedPatientRetentionMetrics, type GroupedPractitionerPerformanceMetrics, type GroupedProcedurePerformanceMetrics, type GroupedProductUsageMetrics, type GroupedRevenueMetrics, type GroupedTimeEfficiencyMetrics, type GroupingPeriod, HAIR_SCALP_ASSESSMENT_COLLECTION, type HairCharacteristics, type HairColor, type HairDensity, type HairLossPattern, type HairLossType, type HairLossZone, type HairLossZoneAssessment, type HairScalpAssessment, type HairScalpAssessmentStatus, type HairTextureGrade, type HairType, type HeadingElement, HeadingLevel, INVITE_TOKENS_COLLECTION, type LabResult, Language, type LinkedFormInfo, type ListElement, ListType, type LocationData, type LudwigStage, MEDIA_METADATA_COLLECTION, MediaAccessLevel, type MediaMetadata, type MediaResource, MediaService, MediaType, MedicationAllergySubtype, type MultipleChoiceElement, type MuscleDefinitionLevel, NOTIFICATIONS_COLLECTION, NO_SHOW_ANALYTICS_SUBCOLLECTION, type NextStepsRecommendation, type NoShowMetrics, type NorwoodStage, type Notification, NotificationService, NotificationStatus, NotificationType, type OverallReviewAverages, PATIENTS_COLLECTION, PATIENT_APPOINTMENTS_COLLECTION, PATIENT_LOCATION_INFO_COLLECTION, PATIENT_MEDICAL_HISTORY_COLLECTION, PATIENT_MEDICAL_INFO_COLLECTION, PATIENT_REQUIREMENTS_SUBCOLLECTION_NAME, PATIENT_SENSITIVE_INFO_COLLECTION, PERMISSION_KEYS, PRACTITIONERS_COLLECTION, PRACTITIONER_ANALYTICS_SUBCOLLECTION, PRACTITIONER_INVITES_COLLECTION, PRE_SURGICAL_ASSESSMENT_COLLECTION, PROCEDURES_COLLECTION, PROCEDURE_ANALYTICS_SUBCOLLECTION, type ParagraphElement, type PatientAnalytics, type PatientClinic, type PatientDoctor, type PatientGoals, PatientInstructionStatus, type PatientLifetimeValueMetrics, type PatientLocationInfo, type PatientMedicalInfo, type PatientProfile, type PatientProfileComplete, type PatientProfileForDoctor, type PatientProfileInfo, type PatientRequirementInstance, type PatientRequirementInstruction, PatientRequirementOverallStatus, type PatientRequirementsFilters, PatientRequirementsService, type PatientRetentionMetrics, type PatientReviewInfo, type PatientSensitiveInfo, PatientService, type PatientToken, PatientTokenStatus, type PaymentConfirmationNotification, PaymentStatus, type PaymentStatusBreakdown, type PermissionKey, type PlanDetails, type PoreSizeLevel, type PostRequirementNotification, PracticeType, type Practitioner, type PractitionerAnalytics, type PractitionerBasicInfo, type PractitionerCertification, type PractitionerClinicProcedures, type PractitionerClinicWorkingHours, type PractitionerInvite, type PractitionerInviteFilters, PractitionerInviteService, PractitionerInviteStatus, type PractitionerProfileInfo, type PractitionerReview, type PractitionerReviewInfo, PractitionerService, PractitionerStatus, type PractitionerToken, PractitionerTokenStatus, type PractitionerWorkingHours, type PreRequirementNotification, type PreSurgicalAssessment, type PreSurgicalAssessmentStatus, PricingMeasure, type Procedure, type ProcedureAnalytics, type ProcedureCategorization, type ProcedureExtendedInfo, ProcedureFamily, type ProcedureInfo, type ProcedurePopularity, type ProcedureProduct, type ProcedureProfitability, type ProcedureRecommendationNotification, type ProcedureReview, type ProcedureReviewInfo, ProcedureService, type ProcedureSummaryInfo, type Product, type ProductRevenueMetrics, ProductService, type ProductUsageByProcedure, type ProductUsageMetrics, type ProposedWorkingHours, REGISTER_TOKENS_COLLECTION, REVENUE_ANALYTICS_SUBCOLLECTION, REVIEWS_COLLECTION, type RatingScaleElement, type ReadStoredAnalyticsOptions, type RecommendedProcedure, type RequesterInfo, type Requirement, type RequirementInstructionDueNotification, type RequirementSourceProcedure, RequirementType, type RevenueMetrics, type RevenueTrend, type Review, type ReviewAnalyticsMetrics, ReviewAnalyticsService, type ReviewDetail, type ReviewMetrics, type ReviewRequestNotification, ReviewService, type ReviewTrend, type RolePermissionConfig, SKIN_QUALITY_ASSESSMENT_COLLECTION, SYNCED_CALENDARS_COLLECTION, type ScalpCondition, type ScalpRednessLevel, type ScalpScalinessLevel, type ScalpSebumLevel, type SearchAppointmentsParams, type SearchCalendarEventsParams, SearchLocationEnum, type SearchPatientsParams, type SeverityLevel, type SignatureElement, type SingleChoiceElement, type SkinCharacteristics, type SkinConditionEntry, type SkinConditionType, type SkinElasticityLevel, type SkinHydrationLevel, type SkinQualityAssessment, type SkinQualityAssessmentStatus, type SkinQualityScales, type SkinSensitivityLevel, type SkinTextureLevel, type SkinZone, type SkinZoneAssessment, type SmokingStatus, type StoredCancellationMetrics, type StoredClinicAnalytics, type StoredDashboardAnalytics, type StoredNoShowMetrics, type StoredPractitionerAnalytics, type StoredProcedureAnalytics, type StoredRevenueMetrics, type StoredTimeEfficiencyMetrics, type StripeTransactionData, type Subcategory, SubcategoryService, SubscriptionModel, SubscriptionStatus, type SurgicalSiteAssessment, type SyncedCalendar, type SyncedCalendarEvent, SyncedCalendarProvider, SyncedCalendarsService, TIER_CONFIG, TIME_EFFICIENCY_ANALYTICS_SUBCOLLECTION, type Technology, type TechnologyDocumentationTemplate, TechnologyService, type TextInputElement, type TierConfig, TierLimitError, type TierLimits, type TimeEfficiencyMetrics, type TimeSlot, TimeUnit, type TissueQualityLevel, TreatmentBenefit, type TreatmentBenefitDynamic, type TrendPeriod, USERS_COLLECTION, USER_FORMS_SUBCOLLECTION, type UpdateAestheticAnalysisData, type UpdateAllergyData, type UpdateAppointmentData, type UpdateAppointmentParams, type UpdateBlockingConditionData, type UpdateBlockingEventParams, type UpdateBodyAssessmentData, type UpdateCalendarEventData, type UpdateClinicAdminData, type UpdateClinicData, type UpdateClinicGroupData, type UpdateContraindicationData, type UpdateDocumentTemplateData, type UpdateHairScalpAssessmentData, type UpdateMedicationData, type UpdatePatientLocationInfoData, type UpdatePatientMedicalInfoData, type UpdatePatientProfileData, type UpdatePatientSensitiveInfoData, type UpdatePractitionerData, type UpdatePractitionerInviteData, type UpdatePreSurgicalAssessmentData, type UpdateProcedureData, type UpdateSkinQualityAssessmentData, type UpdateSyncedCalendarData, type UpdateVitalStatsData, type User, UserRole, UserService, type VitalStats, type WorkingHours, type ZoneItemData, type ZonePhotoUploadData, enforceAppointmentLimit, enforceBranchLimit, enforceMessageLimit, enforceProcedureLimit, enforceProviderLimit, getEffectiveTier, getFirebaseApp, getFirebaseAuth, getFirebaseDB, getFirebaseFunctions, getFirebaseInstance, getFirebaseStorage, initializeFirebase, resolveEffectiveTier };
|
package/dist/index.d.ts
CHANGED
|
@@ -5353,7 +5353,6 @@ interface TierLimits {
|
|
|
5353
5353
|
maxProcedures: number;
|
|
5354
5354
|
maxAppointmentsPerMonth: number;
|
|
5355
5355
|
maxMessagesPerMonth: number;
|
|
5356
|
-
maxStaff: number;
|
|
5357
5356
|
maxBranches: number;
|
|
5358
5357
|
}
|
|
5359
5358
|
/**
|
|
@@ -5552,6 +5551,8 @@ interface BillingInfo {
|
|
|
5552
5551
|
currentPeriodStart: Timestamp | null;
|
|
5553
5552
|
currentPeriodEnd: Timestamp | null;
|
|
5554
5553
|
updatedAt: Timestamp;
|
|
5554
|
+
seatCount?: number;
|
|
5555
|
+
seatPriceId?: string;
|
|
5555
5556
|
}
|
|
5556
5557
|
/**
|
|
5557
5558
|
* Enum for billing transaction types
|
|
@@ -5642,6 +5643,12 @@ interface ClinicGroup {
|
|
|
5642
5643
|
completed?: boolean;
|
|
5643
5644
|
step?: number;
|
|
5644
5645
|
};
|
|
5646
|
+
featureTrials?: {
|
|
5647
|
+
analytics?: {
|
|
5648
|
+
startedAt: Timestamp;
|
|
5649
|
+
durationDays: number;
|
|
5650
|
+
};
|
|
5651
|
+
};
|
|
5645
5652
|
}
|
|
5646
5653
|
/**
|
|
5647
5654
|
* Interface for creating a clinic group
|
|
@@ -5722,6 +5729,7 @@ interface Clinic {
|
|
|
5722
5729
|
isActive: boolean;
|
|
5723
5730
|
isVerified: boolean;
|
|
5724
5731
|
logo?: MediaResource | null;
|
|
5732
|
+
acceptingBookings?: boolean;
|
|
5725
5733
|
}
|
|
5726
5734
|
/**
|
|
5727
5735
|
* Interface for creating a clinic
|
|
@@ -9756,10 +9764,6 @@ declare function enforceProcedureLimit(db: Firestore, clinicGroupId: string, cou
|
|
|
9756
9764
|
* Enforces tier limit before creating a clinic branch.
|
|
9757
9765
|
*/
|
|
9758
9766
|
declare function enforceBranchLimit(db: Firestore, clinicGroupId: string): Promise<void>;
|
|
9759
|
-
/**
|
|
9760
|
-
* Enforces tier limit before creating a staff member.
|
|
9761
|
-
*/
|
|
9762
|
-
declare function enforceStaffLimit(db: Firestore, clinicGroupId: string): Promise<void>;
|
|
9763
9767
|
/**
|
|
9764
9768
|
* Enforces tier limit before creating an appointment.
|
|
9765
9769
|
* Reads the monthly counter from clinic_groups/{id}/usage_counters/{YYYY-MM}.
|
|
@@ -9828,10 +9832,10 @@ type PermissionKey = keyof typeof PERMISSION_KEYS;
|
|
|
9828
9832
|
* All features are available on every tier — tiers differ only in usage caps.
|
|
9829
9833
|
* -1 means unlimited.
|
|
9830
9834
|
*
|
|
9831
|
-
* Confirmed by client on 2026-03-
|
|
9832
|
-
* - Free: 1 provider, 3 procedures, 3 appts/mo, 10 msgs/mo, 1
|
|
9833
|
-
* - Connect:
|
|
9834
|
-
* - Pro: unlimited everything
|
|
9835
|
+
* Confirmed by client on 2026-03-10:
|
|
9836
|
+
* - Free: 1 provider, 3 procedures, 3 appts/mo, 10 msgs/mo, 1 location
|
|
9837
|
+
* - Connect (CHF 59/mo): unlimited providers, 15 procedures, 100 appts/mo, unlimited msgs, 1 location
|
|
9838
|
+
* - Pro (CHF 149/mo): unlimited everything
|
|
9835
9839
|
*/
|
|
9836
9840
|
declare const TIER_CONFIG: Record<string, TierConfig>;
|
|
9837
9841
|
/**
|
|
@@ -9840,14 +9844,8 @@ declare const TIER_CONFIG: Record<string, TierConfig>;
|
|
|
9840
9844
|
*/
|
|
9841
9845
|
declare const DEFAULT_ROLE_PERMISSIONS: Record<ClinicRole, Record<string, boolean>>;
|
|
9842
9846
|
/**
|
|
9843
|
-
*
|
|
9844
|
-
* All paid legacy tiers map to PRO.
|
|
9845
|
-
*/
|
|
9846
|
-
declare const LEGACY_TIER_MAP: Record<string, string>;
|
|
9847
|
-
/**
|
|
9848
|
-
* Resolves the effective tier for a subscription model string,
|
|
9849
|
-
* handling legacy values.
|
|
9847
|
+
* Resolves the effective tier for a subscription model string.
|
|
9850
9848
|
*/
|
|
9851
9849
|
declare function resolveEffectiveTier(subscriptionModel: string): string;
|
|
9852
9850
|
|
|
9853
|
-
export { AESTHETIC_ANALYSIS_COLLECTION, ANALYTICS_COLLECTION, APPOINTMENTS_COLLECTION, type ASAClassification, AcquisitionSource, type AddAllergyData, type AddBlockingConditionData, type AddContraindicationData, type AddMedicationData, type AddressData, type AdminInfo, type AdminToken, AdminTokenStatus, type AestheticAnalysis, type AestheticAnalysisStatus, type Allergy, type AllergySubtype, AllergyType, type AllergyTypeWithSubtype, AnalyticsCloudService, type AnalyticsDateRange, type AnalyticsFilters, type AnalyticsMetadata, type AnalyticsPeriod, AnalyticsService, type AnesthesiaHistory, type Appointment, type AppointmentCancelledNotification, type AppointmentMediaItem, type AppointmentMetadata, type AppointmentProductMetadata, type AppointmentReminderNotification, type AppointmentRescheduledProposalNotification, type AppointmentRescheduledReminderNotification, AppointmentService, AppointmentStatus, type AppointmentStatusChangeNotification, type AppointmentTrend, type AssessmentScales, AuthService, BODY_ASSESSMENT_COLLECTION, type BaseDocumentElement, type BaseMetrics, type BaseNotification, BaseService, type BeforeAfterPerZone, type BillingInfo, type BillingPerZone, type BillingTransaction, BillingTransactionType, BillingTransactionsService, type BinaryChoiceElement, type BleedingRisk, type BleedingRiskLevel, BlockingCondition, type BodyAssessment, type BodyAssessmentStatus, type BodyCompositionData, type BodyMeasurementsData, type BodySymmetryData, type BodyZone, type BodyZoneAssessment, type Brand, BrandService, type Break, CALENDAR_COLLECTION, CANCELLATION_ANALYTICS_SUBCOLLECTION, CLINICS_COLLECTION, CLINIC_ADMINS_COLLECTION, CLINIC_ANALYTICS_SUBCOLLECTION, CLINIC_GROUPS_COLLECTION, type CalendarEvent, CalendarEventStatus, type CalendarEventTime, CalendarEventType, CalendarServiceV2, CalendarServiceV3, CalendarSyncStatus, type CancellationMetrics, type CancellationRateTrend, type CancellationReasonStats, type Category, CategoryService, CertificationLevel, CertificationSpecialty, type ClearanceStatus, type Clinic, type ClinicAdmin, ClinicAdminService, type ClinicAdminSignupData, type ClinicAnalytics, type ClinicBranchSetupData, type ClinicComparisonMetrics, type ClinicContactInfo, type ClinicGroup, ClinicGroupService, type ClinicGroupSetupData, type ClinicInfo, type ClinicLocation, ClinicPhotoTag, type ClinicReview, type ClinicReviewInfo, ClinicRole, ClinicService, type ClinicStaffMember, ClinicTag, type ClinicTags, type ClinicalFindingDetail, type ClinicalFindings, ConstantsService, type ContactPerson, Contraindication, type ContraindicationDynamic, CosmeticAllergySubtype, type CostPerPatientMetrics, type CreateAdminTokenData, type CreateAestheticAnalysisData, type CreateAppointmentData, type CreateAppointmentHttpData, type CreateAppointmentParams, type CreateBillingTransactionData, type CreateBlockingEventParams, type CreateBodyAssessmentData, type CreateCalendarEventData, type CreateClinicAdminData, type CreateClinicData, type CreateClinicGroupData, type CreateDefaultClinicGroupData, type CreateDocumentTemplateData, type CreateDraftPractitionerData, type CreateHairScalpAssessmentData, type CreateManualPatientData, type CreatePatientLocationInfoData, type CreatePatientMedicalInfoData, type CreatePatientProfileData, type CreatePatientSensitiveInfoData, type CreatePatientTokenData, type CreatePractitionerData, type CreatePractitionerInviteData, type CreatePractitionerTokenData, type CreatePreSurgicalAssessmentData, type CreateProcedureData, type CreateSkinQualityAssessmentData, type CreateSyncedCalendarData, type CreateUserData, Currency, DASHBOARD_ANALYTICS_SUBCOLLECTION, DEFAULT_MEDICAL_INFO, DEFAULT_ROLE_PERMISSIONS, DOCTOR_FORMS_SUBCOLLECTION, DOCUMENTATION_TEMPLATES_COLLECTION, type DashboardAnalytics, type DatePickerElement, type DateRange, type DigitalSignatureElement, type DoctorInfo, type DocumentElement, DocumentElementType, type DocumentTemplate, DocumentationTemplateService, type DurationTrend, type DynamicTextElement, DynamicVariable, type ElastosisGrade, type EmergencyContact, type EntityType, EnvironmentalAllergySubtype, type ExtendedProcedureInfo, ExternalCalendarService, FILLED_DOCUMENTS_COLLECTION, type FileUploadElement, type FilledDocument, type FilledDocumentFileValue, FilledDocumentService, FilledDocumentStatus, type FinalBilling, type FirebaseUser, type FitzpatrickType, FoodAllergySubtype, type FormReminderNotification, type FormSubmissionConfirmationNotification, type GamificationInfo, Gender, type GeneralMessageNotification, type GlogauClassification, type GroupedAnalyticsBase, type GroupedPatientBehaviorMetrics, type GroupedPatientRetentionMetrics, type GroupedPractitionerPerformanceMetrics, type GroupedProcedurePerformanceMetrics, type GroupedProductUsageMetrics, type GroupedRevenueMetrics, type GroupedTimeEfficiencyMetrics, type GroupingPeriod, HAIR_SCALP_ASSESSMENT_COLLECTION, type HairCharacteristics, type HairColor, type HairDensity, type HairLossPattern, type HairLossType, type HairLossZone, type HairLossZoneAssessment, type HairScalpAssessment, type HairScalpAssessmentStatus, type HairTextureGrade, type HairType, type HeadingElement, HeadingLevel, INVITE_TOKENS_COLLECTION, LEGACY_TIER_MAP, type LabResult, Language, type LinkedFormInfo, type ListElement, ListType, type LocationData, type LudwigStage, MEDIA_METADATA_COLLECTION, MediaAccessLevel, type MediaMetadata, type MediaResource, MediaService, MediaType, MedicationAllergySubtype, type MultipleChoiceElement, type MuscleDefinitionLevel, NOTIFICATIONS_COLLECTION, NO_SHOW_ANALYTICS_SUBCOLLECTION, type NextStepsRecommendation, type NoShowMetrics, type NorwoodStage, type Notification, NotificationService, NotificationStatus, NotificationType, type OverallReviewAverages, PATIENTS_COLLECTION, PATIENT_APPOINTMENTS_COLLECTION, PATIENT_LOCATION_INFO_COLLECTION, PATIENT_MEDICAL_HISTORY_COLLECTION, PATIENT_MEDICAL_INFO_COLLECTION, PATIENT_REQUIREMENTS_SUBCOLLECTION_NAME, PATIENT_SENSITIVE_INFO_COLLECTION, PERMISSION_KEYS, PRACTITIONERS_COLLECTION, PRACTITIONER_ANALYTICS_SUBCOLLECTION, PRACTITIONER_INVITES_COLLECTION, PRE_SURGICAL_ASSESSMENT_COLLECTION, PROCEDURES_COLLECTION, PROCEDURE_ANALYTICS_SUBCOLLECTION, type ParagraphElement, type PatientAnalytics, type PatientClinic, type PatientDoctor, type PatientGoals, PatientInstructionStatus, type PatientLifetimeValueMetrics, type PatientLocationInfo, type PatientMedicalInfo, type PatientProfile, type PatientProfileComplete, type PatientProfileForDoctor, type PatientProfileInfo, type PatientRequirementInstance, type PatientRequirementInstruction, PatientRequirementOverallStatus, type PatientRequirementsFilters, PatientRequirementsService, type PatientRetentionMetrics, type PatientReviewInfo, type PatientSensitiveInfo, PatientService, type PatientToken, PatientTokenStatus, type PaymentConfirmationNotification, PaymentStatus, type PaymentStatusBreakdown, type PermissionKey, type PlanDetails, type PoreSizeLevel, type PostRequirementNotification, PracticeType, type Practitioner, type PractitionerAnalytics, type PractitionerBasicInfo, type PractitionerCertification, type PractitionerClinicProcedures, type PractitionerClinicWorkingHours, type PractitionerInvite, type PractitionerInviteFilters, PractitionerInviteService, PractitionerInviteStatus, type PractitionerProfileInfo, type PractitionerReview, type PractitionerReviewInfo, PractitionerService, PractitionerStatus, type PractitionerToken, PractitionerTokenStatus, type PractitionerWorkingHours, type PreRequirementNotification, type PreSurgicalAssessment, type PreSurgicalAssessmentStatus, PricingMeasure, type Procedure, type ProcedureAnalytics, type ProcedureCategorization, type ProcedureExtendedInfo, ProcedureFamily, type ProcedureInfo, type ProcedurePopularity, type ProcedureProduct, type ProcedureProfitability, type ProcedureRecommendationNotification, type ProcedureReview, type ProcedureReviewInfo, ProcedureService, type ProcedureSummaryInfo, type Product, type ProductRevenueMetrics, ProductService, type ProductUsageByProcedure, type ProductUsageMetrics, type ProposedWorkingHours, REGISTER_TOKENS_COLLECTION, REVENUE_ANALYTICS_SUBCOLLECTION, REVIEWS_COLLECTION, type RatingScaleElement, type ReadStoredAnalyticsOptions, type RecommendedProcedure, type RequesterInfo, type Requirement, type RequirementInstructionDueNotification, type RequirementSourceProcedure, RequirementType, type RevenueMetrics, type RevenueTrend, type Review, type ReviewAnalyticsMetrics, ReviewAnalyticsService, type ReviewDetail, type ReviewMetrics, type ReviewRequestNotification, ReviewService, type ReviewTrend, type RolePermissionConfig, SKIN_QUALITY_ASSESSMENT_COLLECTION, SYNCED_CALENDARS_COLLECTION, type ScalpCondition, type ScalpRednessLevel, type ScalpScalinessLevel, type ScalpSebumLevel, type SearchAppointmentsParams, type SearchCalendarEventsParams, SearchLocationEnum, type SearchPatientsParams, type SeverityLevel, type SignatureElement, type SingleChoiceElement, type SkinCharacteristics, type SkinConditionEntry, type SkinConditionType, type SkinElasticityLevel, type SkinHydrationLevel, type SkinQualityAssessment, type SkinQualityAssessmentStatus, type SkinQualityScales, type SkinSensitivityLevel, type SkinTextureLevel, type SkinZone, type SkinZoneAssessment, type SmokingStatus, type StoredCancellationMetrics, type StoredClinicAnalytics, type StoredDashboardAnalytics, type StoredNoShowMetrics, type StoredPractitionerAnalytics, type StoredProcedureAnalytics, type StoredRevenueMetrics, type StoredTimeEfficiencyMetrics, type StripeTransactionData, type Subcategory, SubcategoryService, SubscriptionModel, SubscriptionStatus, type SurgicalSiteAssessment, type SyncedCalendar, type SyncedCalendarEvent, SyncedCalendarProvider, SyncedCalendarsService, TIER_CONFIG, TIME_EFFICIENCY_ANALYTICS_SUBCOLLECTION, type Technology, type TechnologyDocumentationTemplate, TechnologyService, type TextInputElement, type TierConfig, TierLimitError, type TierLimits, type TimeEfficiencyMetrics, type TimeSlot, TimeUnit, type TissueQualityLevel, TreatmentBenefit, type TreatmentBenefitDynamic, type TrendPeriod, USERS_COLLECTION, USER_FORMS_SUBCOLLECTION, type UpdateAestheticAnalysisData, type UpdateAllergyData, type UpdateAppointmentData, type UpdateAppointmentParams, type UpdateBlockingConditionData, type UpdateBlockingEventParams, type UpdateBodyAssessmentData, type UpdateCalendarEventData, type UpdateClinicAdminData, type UpdateClinicData, type UpdateClinicGroupData, type UpdateContraindicationData, type UpdateDocumentTemplateData, type UpdateHairScalpAssessmentData, type UpdateMedicationData, type UpdatePatientLocationInfoData, type UpdatePatientMedicalInfoData, type UpdatePatientProfileData, type UpdatePatientSensitiveInfoData, type UpdatePractitionerData, type UpdatePractitionerInviteData, type UpdatePreSurgicalAssessmentData, type UpdateProcedureData, type UpdateSkinQualityAssessmentData, type UpdateSyncedCalendarData, type UpdateVitalStatsData, type User, UserRole, UserService, type VitalStats, type WorkingHours, type ZoneItemData, type ZonePhotoUploadData, enforceAppointmentLimit, enforceBranchLimit, enforceMessageLimit, enforceProcedureLimit, enforceProviderLimit, enforceStaffLimit, getEffectiveTier, getFirebaseApp, getFirebaseAuth, getFirebaseDB, getFirebaseFunctions, getFirebaseInstance, getFirebaseStorage, initializeFirebase, resolveEffectiveTier };
|
|
9851
|
+
export { AESTHETIC_ANALYSIS_COLLECTION, ANALYTICS_COLLECTION, APPOINTMENTS_COLLECTION, type ASAClassification, AcquisitionSource, type AddAllergyData, type AddBlockingConditionData, type AddContraindicationData, type AddMedicationData, type AddressData, type AdminInfo, type AdminToken, AdminTokenStatus, type AestheticAnalysis, type AestheticAnalysisStatus, type Allergy, type AllergySubtype, AllergyType, type AllergyTypeWithSubtype, AnalyticsCloudService, type AnalyticsDateRange, type AnalyticsFilters, type AnalyticsMetadata, type AnalyticsPeriod, AnalyticsService, type AnesthesiaHistory, type Appointment, type AppointmentCancelledNotification, type AppointmentMediaItem, type AppointmentMetadata, type AppointmentProductMetadata, type AppointmentReminderNotification, type AppointmentRescheduledProposalNotification, type AppointmentRescheduledReminderNotification, AppointmentService, AppointmentStatus, type AppointmentStatusChangeNotification, type AppointmentTrend, type AssessmentScales, AuthService, BODY_ASSESSMENT_COLLECTION, type BaseDocumentElement, type BaseMetrics, type BaseNotification, BaseService, type BeforeAfterPerZone, type BillingInfo, type BillingPerZone, type BillingTransaction, BillingTransactionType, BillingTransactionsService, type BinaryChoiceElement, type BleedingRisk, type BleedingRiskLevel, BlockingCondition, type BodyAssessment, type BodyAssessmentStatus, type BodyCompositionData, type BodyMeasurementsData, type BodySymmetryData, type BodyZone, type BodyZoneAssessment, type Brand, BrandService, type Break, CALENDAR_COLLECTION, CANCELLATION_ANALYTICS_SUBCOLLECTION, CLINICS_COLLECTION, CLINIC_ADMINS_COLLECTION, CLINIC_ANALYTICS_SUBCOLLECTION, CLINIC_GROUPS_COLLECTION, type CalendarEvent, CalendarEventStatus, type CalendarEventTime, CalendarEventType, CalendarServiceV2, CalendarServiceV3, CalendarSyncStatus, type CancellationMetrics, type CancellationRateTrend, type CancellationReasonStats, type Category, CategoryService, CertificationLevel, CertificationSpecialty, type ClearanceStatus, type Clinic, type ClinicAdmin, ClinicAdminService, type ClinicAdminSignupData, type ClinicAnalytics, type ClinicBranchSetupData, type ClinicComparisonMetrics, type ClinicContactInfo, type ClinicGroup, ClinicGroupService, type ClinicGroupSetupData, type ClinicInfo, type ClinicLocation, ClinicPhotoTag, type ClinicReview, type ClinicReviewInfo, ClinicRole, ClinicService, type ClinicStaffMember, ClinicTag, type ClinicTags, type ClinicalFindingDetail, type ClinicalFindings, ConstantsService, type ContactPerson, Contraindication, type ContraindicationDynamic, CosmeticAllergySubtype, type CostPerPatientMetrics, type CreateAdminTokenData, type CreateAestheticAnalysisData, type CreateAppointmentData, type CreateAppointmentHttpData, type CreateAppointmentParams, type CreateBillingTransactionData, type CreateBlockingEventParams, type CreateBodyAssessmentData, type CreateCalendarEventData, type CreateClinicAdminData, type CreateClinicData, type CreateClinicGroupData, type CreateDefaultClinicGroupData, type CreateDocumentTemplateData, type CreateDraftPractitionerData, type CreateHairScalpAssessmentData, type CreateManualPatientData, type CreatePatientLocationInfoData, type CreatePatientMedicalInfoData, type CreatePatientProfileData, type CreatePatientSensitiveInfoData, type CreatePatientTokenData, type CreatePractitionerData, type CreatePractitionerInviteData, type CreatePractitionerTokenData, type CreatePreSurgicalAssessmentData, type CreateProcedureData, type CreateSkinQualityAssessmentData, type CreateSyncedCalendarData, type CreateUserData, Currency, DASHBOARD_ANALYTICS_SUBCOLLECTION, DEFAULT_MEDICAL_INFO, DEFAULT_ROLE_PERMISSIONS, DOCTOR_FORMS_SUBCOLLECTION, DOCUMENTATION_TEMPLATES_COLLECTION, type DashboardAnalytics, type DatePickerElement, type DateRange, type DigitalSignatureElement, type DoctorInfo, type DocumentElement, DocumentElementType, type DocumentTemplate, DocumentationTemplateService, type DurationTrend, type DynamicTextElement, DynamicVariable, type ElastosisGrade, type EmergencyContact, type EntityType, EnvironmentalAllergySubtype, type ExtendedProcedureInfo, ExternalCalendarService, FILLED_DOCUMENTS_COLLECTION, type FileUploadElement, type FilledDocument, type FilledDocumentFileValue, FilledDocumentService, FilledDocumentStatus, type FinalBilling, type FirebaseUser, type FitzpatrickType, FoodAllergySubtype, type FormReminderNotification, type FormSubmissionConfirmationNotification, type GamificationInfo, Gender, type GeneralMessageNotification, type GlogauClassification, type GroupedAnalyticsBase, type GroupedPatientBehaviorMetrics, type GroupedPatientRetentionMetrics, type GroupedPractitionerPerformanceMetrics, type GroupedProcedurePerformanceMetrics, type GroupedProductUsageMetrics, type GroupedRevenueMetrics, type GroupedTimeEfficiencyMetrics, type GroupingPeriod, HAIR_SCALP_ASSESSMENT_COLLECTION, type HairCharacteristics, type HairColor, type HairDensity, type HairLossPattern, type HairLossType, type HairLossZone, type HairLossZoneAssessment, type HairScalpAssessment, type HairScalpAssessmentStatus, type HairTextureGrade, type HairType, type HeadingElement, HeadingLevel, INVITE_TOKENS_COLLECTION, type LabResult, Language, type LinkedFormInfo, type ListElement, ListType, type LocationData, type LudwigStage, MEDIA_METADATA_COLLECTION, MediaAccessLevel, type MediaMetadata, type MediaResource, MediaService, MediaType, MedicationAllergySubtype, type MultipleChoiceElement, type MuscleDefinitionLevel, NOTIFICATIONS_COLLECTION, NO_SHOW_ANALYTICS_SUBCOLLECTION, type NextStepsRecommendation, type NoShowMetrics, type NorwoodStage, type Notification, NotificationService, NotificationStatus, NotificationType, type OverallReviewAverages, PATIENTS_COLLECTION, PATIENT_APPOINTMENTS_COLLECTION, PATIENT_LOCATION_INFO_COLLECTION, PATIENT_MEDICAL_HISTORY_COLLECTION, PATIENT_MEDICAL_INFO_COLLECTION, PATIENT_REQUIREMENTS_SUBCOLLECTION_NAME, PATIENT_SENSITIVE_INFO_COLLECTION, PERMISSION_KEYS, PRACTITIONERS_COLLECTION, PRACTITIONER_ANALYTICS_SUBCOLLECTION, PRACTITIONER_INVITES_COLLECTION, PRE_SURGICAL_ASSESSMENT_COLLECTION, PROCEDURES_COLLECTION, PROCEDURE_ANALYTICS_SUBCOLLECTION, type ParagraphElement, type PatientAnalytics, type PatientClinic, type PatientDoctor, type PatientGoals, PatientInstructionStatus, type PatientLifetimeValueMetrics, type PatientLocationInfo, type PatientMedicalInfo, type PatientProfile, type PatientProfileComplete, type PatientProfileForDoctor, type PatientProfileInfo, type PatientRequirementInstance, type PatientRequirementInstruction, PatientRequirementOverallStatus, type PatientRequirementsFilters, PatientRequirementsService, type PatientRetentionMetrics, type PatientReviewInfo, type PatientSensitiveInfo, PatientService, type PatientToken, PatientTokenStatus, type PaymentConfirmationNotification, PaymentStatus, type PaymentStatusBreakdown, type PermissionKey, type PlanDetails, type PoreSizeLevel, type PostRequirementNotification, PracticeType, type Practitioner, type PractitionerAnalytics, type PractitionerBasicInfo, type PractitionerCertification, type PractitionerClinicProcedures, type PractitionerClinicWorkingHours, type PractitionerInvite, type PractitionerInviteFilters, PractitionerInviteService, PractitionerInviteStatus, type PractitionerProfileInfo, type PractitionerReview, type PractitionerReviewInfo, PractitionerService, PractitionerStatus, type PractitionerToken, PractitionerTokenStatus, type PractitionerWorkingHours, type PreRequirementNotification, type PreSurgicalAssessment, type PreSurgicalAssessmentStatus, PricingMeasure, type Procedure, type ProcedureAnalytics, type ProcedureCategorization, type ProcedureExtendedInfo, ProcedureFamily, type ProcedureInfo, type ProcedurePopularity, type ProcedureProduct, type ProcedureProfitability, type ProcedureRecommendationNotification, type ProcedureReview, type ProcedureReviewInfo, ProcedureService, type ProcedureSummaryInfo, type Product, type ProductRevenueMetrics, ProductService, type ProductUsageByProcedure, type ProductUsageMetrics, type ProposedWorkingHours, REGISTER_TOKENS_COLLECTION, REVENUE_ANALYTICS_SUBCOLLECTION, REVIEWS_COLLECTION, type RatingScaleElement, type ReadStoredAnalyticsOptions, type RecommendedProcedure, type RequesterInfo, type Requirement, type RequirementInstructionDueNotification, type RequirementSourceProcedure, RequirementType, type RevenueMetrics, type RevenueTrend, type Review, type ReviewAnalyticsMetrics, ReviewAnalyticsService, type ReviewDetail, type ReviewMetrics, type ReviewRequestNotification, ReviewService, type ReviewTrend, type RolePermissionConfig, SKIN_QUALITY_ASSESSMENT_COLLECTION, SYNCED_CALENDARS_COLLECTION, type ScalpCondition, type ScalpRednessLevel, type ScalpScalinessLevel, type ScalpSebumLevel, type SearchAppointmentsParams, type SearchCalendarEventsParams, SearchLocationEnum, type SearchPatientsParams, type SeverityLevel, type SignatureElement, type SingleChoiceElement, type SkinCharacteristics, type SkinConditionEntry, type SkinConditionType, type SkinElasticityLevel, type SkinHydrationLevel, type SkinQualityAssessment, type SkinQualityAssessmentStatus, type SkinQualityScales, type SkinSensitivityLevel, type SkinTextureLevel, type SkinZone, type SkinZoneAssessment, type SmokingStatus, type StoredCancellationMetrics, type StoredClinicAnalytics, type StoredDashboardAnalytics, type StoredNoShowMetrics, type StoredPractitionerAnalytics, type StoredProcedureAnalytics, type StoredRevenueMetrics, type StoredTimeEfficiencyMetrics, type StripeTransactionData, type Subcategory, SubcategoryService, SubscriptionModel, SubscriptionStatus, type SurgicalSiteAssessment, type SyncedCalendar, type SyncedCalendarEvent, SyncedCalendarProvider, SyncedCalendarsService, TIER_CONFIG, TIME_EFFICIENCY_ANALYTICS_SUBCOLLECTION, type Technology, type TechnologyDocumentationTemplate, TechnologyService, type TextInputElement, type TierConfig, TierLimitError, type TierLimits, type TimeEfficiencyMetrics, type TimeSlot, TimeUnit, type TissueQualityLevel, TreatmentBenefit, type TreatmentBenefitDynamic, type TrendPeriod, USERS_COLLECTION, USER_FORMS_SUBCOLLECTION, type UpdateAestheticAnalysisData, type UpdateAllergyData, type UpdateAppointmentData, type UpdateAppointmentParams, type UpdateBlockingConditionData, type UpdateBlockingEventParams, type UpdateBodyAssessmentData, type UpdateCalendarEventData, type UpdateClinicAdminData, type UpdateClinicData, type UpdateClinicGroupData, type UpdateContraindicationData, type UpdateDocumentTemplateData, type UpdateHairScalpAssessmentData, type UpdateMedicationData, type UpdatePatientLocationInfoData, type UpdatePatientMedicalInfoData, type UpdatePatientProfileData, type UpdatePatientSensitiveInfoData, type UpdatePractitionerData, type UpdatePractitionerInviteData, type UpdatePreSurgicalAssessmentData, type UpdateProcedureData, type UpdateSkinQualityAssessmentData, type UpdateSyncedCalendarData, type UpdateVitalStatsData, type User, UserRole, UserService, type VitalStats, type WorkingHours, type ZoneItemData, type ZonePhotoUploadData, enforceAppointmentLimit, enforceBranchLimit, enforceMessageLimit, enforceProcedureLimit, enforceProviderLimit, getEffectiveTier, getFirebaseApp, getFirebaseAuth, getFirebaseDB, getFirebaseFunctions, getFirebaseInstance, getFirebaseStorage, initializeFirebase, resolveEffectiveTier };
|
package/dist/index.js
CHANGED
|
@@ -89,7 +89,6 @@ __export(index_exports, {
|
|
|
89
89
|
HAIR_SCALP_ASSESSMENT_COLLECTION: () => HAIR_SCALP_ASSESSMENT_COLLECTION,
|
|
90
90
|
HeadingLevel: () => HeadingLevel,
|
|
91
91
|
INVITE_TOKENS_COLLECTION: () => INVITE_TOKENS_COLLECTION,
|
|
92
|
-
LEGACY_TIER_MAP: () => LEGACY_TIER_MAP,
|
|
93
92
|
Language: () => Language,
|
|
94
93
|
ListType: () => ListType,
|
|
95
94
|
MEDIA_METADATA_COLLECTION: () => MEDIA_METADATA_COLLECTION,
|
|
@@ -161,7 +160,6 @@ __export(index_exports, {
|
|
|
161
160
|
enforceMessageLimit: () => enforceMessageLimit,
|
|
162
161
|
enforceProcedureLimit: () => enforceProcedureLimit,
|
|
163
162
|
enforceProviderLimit: () => enforceProviderLimit,
|
|
164
|
-
enforceStaffLimit: () => enforceStaffLimit,
|
|
165
163
|
getEffectiveTier: () => getEffectiveTier,
|
|
166
164
|
getFirebaseApp: () => getFirebaseApp,
|
|
167
165
|
getFirebaseAuth: () => getFirebaseAuth,
|
|
@@ -7851,6 +7849,16 @@ var AppointmentService = class extends BaseService {
|
|
|
7851
7849
|
if (!response.ok) {
|
|
7852
7850
|
const errorText = await response.text();
|
|
7853
7851
|
console.error(`[APPOINTMENT_SERVICE] Error response details: ${errorText}`);
|
|
7852
|
+
try {
|
|
7853
|
+
const errorJson = JSON.parse(errorText);
|
|
7854
|
+
if (errorJson.code === "TIER_LIMIT_EXCEEDED") {
|
|
7855
|
+
throw new Error(`TIER_LIMIT_EXCEEDED:${errorJson.message || "You have reached your plan limit. Please upgrade to continue."}`);
|
|
7856
|
+
}
|
|
7857
|
+
} catch (parseError) {
|
|
7858
|
+
if (parseError instanceof Error && parseError.message.startsWith("TIER_LIMIT_EXCEEDED:")) {
|
|
7859
|
+
throw parseError;
|
|
7860
|
+
}
|
|
7861
|
+
}
|
|
7854
7862
|
throw new Error(
|
|
7855
7863
|
`Failed to create appointment: ${response.status} ${response.statusText} - ${errorText}`
|
|
7856
7864
|
);
|
|
@@ -12732,7 +12740,6 @@ var TIER_CONFIG = {
|
|
|
12732
12740
|
maxProcedures: 3,
|
|
12733
12741
|
maxAppointmentsPerMonth: 3,
|
|
12734
12742
|
maxMessagesPerMonth: 10,
|
|
12735
|
-
maxStaff: 1,
|
|
12736
12743
|
maxBranches: 1
|
|
12737
12744
|
}
|
|
12738
12745
|
},
|
|
@@ -12740,11 +12747,10 @@ var TIER_CONFIG = {
|
|
|
12740
12747
|
tier: "connect",
|
|
12741
12748
|
name: "Connect",
|
|
12742
12749
|
limits: {
|
|
12743
|
-
maxProviders:
|
|
12750
|
+
maxProviders: -1,
|
|
12744
12751
|
maxProcedures: 15,
|
|
12745
12752
|
maxAppointmentsPerMonth: 100,
|
|
12746
12753
|
maxMessagesPerMonth: -1,
|
|
12747
|
-
maxStaff: 5,
|
|
12748
12754
|
maxBranches: 1
|
|
12749
12755
|
}
|
|
12750
12756
|
},
|
|
@@ -12756,7 +12762,6 @@ var TIER_CONFIG = {
|
|
|
12756
12762
|
maxProcedures: -1,
|
|
12757
12763
|
maxAppointmentsPerMonth: -1,
|
|
12758
12764
|
maxMessagesPerMonth: -1,
|
|
12759
|
-
maxStaff: -1,
|
|
12760
12765
|
maxBranches: -1
|
|
12761
12766
|
}
|
|
12762
12767
|
}
|
|
@@ -12873,17 +12878,15 @@ var DEFAULT_ROLE_PERMISSIONS = {
|
|
|
12873
12878
|
"billing.manage": false
|
|
12874
12879
|
}
|
|
12875
12880
|
};
|
|
12876
|
-
var
|
|
12877
|
-
|
|
12878
|
-
|
|
12879
|
-
|
|
12881
|
+
var TIER_MAP = {
|
|
12882
|
+
no_subscription: "free",
|
|
12883
|
+
free: "free",
|
|
12884
|
+
connect: "connect",
|
|
12885
|
+
pro: "pro"
|
|
12880
12886
|
};
|
|
12881
12887
|
function resolveEffectiveTier(subscriptionModel) {
|
|
12882
12888
|
const lower = subscriptionModel.toLowerCase();
|
|
12883
|
-
|
|
12884
|
-
return LEGACY_TIER_MAP[lower];
|
|
12885
|
-
}
|
|
12886
|
-
return lower;
|
|
12889
|
+
return TIER_MAP[lower] || "free";
|
|
12887
12890
|
}
|
|
12888
12891
|
|
|
12889
12892
|
// src/services/tier-enforcement.ts
|
|
@@ -12941,7 +12944,7 @@ async function countProceduresInGroup(db, clinicGroupId) {
|
|
|
12941
12944
|
const clinicsSnap = await (0, import_firestore35.getDocs)(clinicsQuery);
|
|
12942
12945
|
const clinicIds = clinicsSnap.docs.map((d) => d.id);
|
|
12943
12946
|
if (clinicIds.length === 0) return 0;
|
|
12944
|
-
|
|
12947
|
+
const uniqueTechnologyIds = /* @__PURE__ */ new Set();
|
|
12945
12948
|
for (let i = 0; i < clinicIds.length; i += 30) {
|
|
12946
12949
|
const batch = clinicIds.slice(i, i + 30);
|
|
12947
12950
|
const proceduresQuery = (0, import_firestore35.query)(
|
|
@@ -12950,9 +12953,14 @@ async function countProceduresInGroup(db, clinicGroupId) {
|
|
|
12950
12953
|
(0, import_firestore35.where)("isActive", "==", true)
|
|
12951
12954
|
);
|
|
12952
12955
|
const proceduresSnap = await (0, import_firestore35.getDocs)(proceduresQuery);
|
|
12953
|
-
|
|
12956
|
+
proceduresSnap.docs.forEach((d) => {
|
|
12957
|
+
const technologyId = d.data().technologyId;
|
|
12958
|
+
if (technologyId) {
|
|
12959
|
+
uniqueTechnologyIds.add(technologyId);
|
|
12960
|
+
}
|
|
12961
|
+
});
|
|
12954
12962
|
}
|
|
12955
|
-
return
|
|
12963
|
+
return uniqueTechnologyIds.size;
|
|
12956
12964
|
}
|
|
12957
12965
|
async function countBranchesInGroup(db, clinicGroupId) {
|
|
12958
12966
|
const clinicsQuery = (0, import_firestore35.query)(
|
|
@@ -12996,23 +13004,6 @@ async function enforceBranchLimit(db, clinicGroupId) {
|
|
|
12996
13004
|
throw new TierLimitError("clinic branches", tier, currentCount, max);
|
|
12997
13005
|
}
|
|
12998
13006
|
}
|
|
12999
|
-
async function enforceStaffLimit(db, clinicGroupId) {
|
|
13000
|
-
const tier = await getEffectiveTier(db, clinicGroupId);
|
|
13001
|
-
const config = TIER_CONFIG[tier];
|
|
13002
|
-
if (!config) return;
|
|
13003
|
-
const max = config.limits.maxStaff;
|
|
13004
|
-
if (max === -1) return;
|
|
13005
|
-
const staffQuery = (0, import_firestore35.query)(
|
|
13006
|
-
(0, import_firestore35.collection)(db, "clinic_staff_members"),
|
|
13007
|
-
(0, import_firestore35.where)("clinicGroupId", "==", clinicGroupId),
|
|
13008
|
-
(0, import_firestore35.where)("isActive", "==", true)
|
|
13009
|
-
);
|
|
13010
|
-
const staffSnap = await (0, import_firestore35.getDocs)(staffQuery);
|
|
13011
|
-
const currentCount = staffSnap.size;
|
|
13012
|
-
if (currentCount + 1 > max) {
|
|
13013
|
-
throw new TierLimitError("staff members", tier, currentCount, max);
|
|
13014
|
-
}
|
|
13015
|
-
}
|
|
13016
13007
|
async function enforceAppointmentLimit(db, clinicGroupId) {
|
|
13017
13008
|
var _a;
|
|
13018
13009
|
const tier = await getEffectiveTier(db, clinicGroupId);
|
|
@@ -27994,7 +27985,6 @@ var RequirementType = /* @__PURE__ */ ((RequirementType2) => {
|
|
|
27994
27985
|
HAIR_SCALP_ASSESSMENT_COLLECTION,
|
|
27995
27986
|
HeadingLevel,
|
|
27996
27987
|
INVITE_TOKENS_COLLECTION,
|
|
27997
|
-
LEGACY_TIER_MAP,
|
|
27998
27988
|
Language,
|
|
27999
27989
|
ListType,
|
|
28000
27990
|
MEDIA_METADATA_COLLECTION,
|
|
@@ -28066,7 +28056,6 @@ var RequirementType = /* @__PURE__ */ ((RequirementType2) => {
|
|
|
28066
28056
|
enforceMessageLimit,
|
|
28067
28057
|
enforceProcedureLimit,
|
|
28068
28058
|
enforceProviderLimit,
|
|
28069
|
-
enforceStaffLimit,
|
|
28070
28059
|
getEffectiveTier,
|
|
28071
28060
|
getFirebaseApp,
|
|
28072
28061
|
getFirebaseAuth,
|
package/dist/index.mjs
CHANGED
|
@@ -7749,6 +7749,16 @@ var AppointmentService = class extends BaseService {
|
|
|
7749
7749
|
if (!response.ok) {
|
|
7750
7750
|
const errorText = await response.text();
|
|
7751
7751
|
console.error(`[APPOINTMENT_SERVICE] Error response details: ${errorText}`);
|
|
7752
|
+
try {
|
|
7753
|
+
const errorJson = JSON.parse(errorText);
|
|
7754
|
+
if (errorJson.code === "TIER_LIMIT_EXCEEDED") {
|
|
7755
|
+
throw new Error(`TIER_LIMIT_EXCEEDED:${errorJson.message || "You have reached your plan limit. Please upgrade to continue."}`);
|
|
7756
|
+
}
|
|
7757
|
+
} catch (parseError) {
|
|
7758
|
+
if (parseError instanceof Error && parseError.message.startsWith("TIER_LIMIT_EXCEEDED:")) {
|
|
7759
|
+
throw parseError;
|
|
7760
|
+
}
|
|
7761
|
+
}
|
|
7752
7762
|
throw new Error(
|
|
7753
7763
|
`Failed to create appointment: ${response.status} ${response.statusText} - ${errorText}`
|
|
7754
7764
|
);
|
|
@@ -12746,7 +12756,6 @@ var TIER_CONFIG = {
|
|
|
12746
12756
|
maxProcedures: 3,
|
|
12747
12757
|
maxAppointmentsPerMonth: 3,
|
|
12748
12758
|
maxMessagesPerMonth: 10,
|
|
12749
|
-
maxStaff: 1,
|
|
12750
12759
|
maxBranches: 1
|
|
12751
12760
|
}
|
|
12752
12761
|
},
|
|
@@ -12754,11 +12763,10 @@ var TIER_CONFIG = {
|
|
|
12754
12763
|
tier: "connect",
|
|
12755
12764
|
name: "Connect",
|
|
12756
12765
|
limits: {
|
|
12757
|
-
maxProviders:
|
|
12766
|
+
maxProviders: -1,
|
|
12758
12767
|
maxProcedures: 15,
|
|
12759
12768
|
maxAppointmentsPerMonth: 100,
|
|
12760
12769
|
maxMessagesPerMonth: -1,
|
|
12761
|
-
maxStaff: 5,
|
|
12762
12770
|
maxBranches: 1
|
|
12763
12771
|
}
|
|
12764
12772
|
},
|
|
@@ -12770,7 +12778,6 @@ var TIER_CONFIG = {
|
|
|
12770
12778
|
maxProcedures: -1,
|
|
12771
12779
|
maxAppointmentsPerMonth: -1,
|
|
12772
12780
|
maxMessagesPerMonth: -1,
|
|
12773
|
-
maxStaff: -1,
|
|
12774
12781
|
maxBranches: -1
|
|
12775
12782
|
}
|
|
12776
12783
|
}
|
|
@@ -12887,17 +12894,15 @@ var DEFAULT_ROLE_PERMISSIONS = {
|
|
|
12887
12894
|
"billing.manage": false
|
|
12888
12895
|
}
|
|
12889
12896
|
};
|
|
12890
|
-
var
|
|
12891
|
-
|
|
12892
|
-
|
|
12893
|
-
|
|
12897
|
+
var TIER_MAP = {
|
|
12898
|
+
no_subscription: "free",
|
|
12899
|
+
free: "free",
|
|
12900
|
+
connect: "connect",
|
|
12901
|
+
pro: "pro"
|
|
12894
12902
|
};
|
|
12895
12903
|
function resolveEffectiveTier(subscriptionModel) {
|
|
12896
12904
|
const lower = subscriptionModel.toLowerCase();
|
|
12897
|
-
|
|
12898
|
-
return LEGACY_TIER_MAP[lower];
|
|
12899
|
-
}
|
|
12900
|
-
return lower;
|
|
12905
|
+
return TIER_MAP[lower] || "free";
|
|
12901
12906
|
}
|
|
12902
12907
|
|
|
12903
12908
|
// src/services/tier-enforcement.ts
|
|
@@ -12955,7 +12960,7 @@ async function countProceduresInGroup(db, clinicGroupId) {
|
|
|
12955
12960
|
const clinicsSnap = await getDocs13(clinicsQuery);
|
|
12956
12961
|
const clinicIds = clinicsSnap.docs.map((d) => d.id);
|
|
12957
12962
|
if (clinicIds.length === 0) return 0;
|
|
12958
|
-
|
|
12963
|
+
const uniqueTechnologyIds = /* @__PURE__ */ new Set();
|
|
12959
12964
|
for (let i = 0; i < clinicIds.length; i += 30) {
|
|
12960
12965
|
const batch = clinicIds.slice(i, i + 30);
|
|
12961
12966
|
const proceduresQuery = query13(
|
|
@@ -12964,9 +12969,14 @@ async function countProceduresInGroup(db, clinicGroupId) {
|
|
|
12964
12969
|
where13("isActive", "==", true)
|
|
12965
12970
|
);
|
|
12966
12971
|
const proceduresSnap = await getDocs13(proceduresQuery);
|
|
12967
|
-
|
|
12972
|
+
proceduresSnap.docs.forEach((d) => {
|
|
12973
|
+
const technologyId = d.data().technologyId;
|
|
12974
|
+
if (technologyId) {
|
|
12975
|
+
uniqueTechnologyIds.add(technologyId);
|
|
12976
|
+
}
|
|
12977
|
+
});
|
|
12968
12978
|
}
|
|
12969
|
-
return
|
|
12979
|
+
return uniqueTechnologyIds.size;
|
|
12970
12980
|
}
|
|
12971
12981
|
async function countBranchesInGroup(db, clinicGroupId) {
|
|
12972
12982
|
const clinicsQuery = query13(
|
|
@@ -13010,23 +13020,6 @@ async function enforceBranchLimit(db, clinicGroupId) {
|
|
|
13010
13020
|
throw new TierLimitError("clinic branches", tier, currentCount, max);
|
|
13011
13021
|
}
|
|
13012
13022
|
}
|
|
13013
|
-
async function enforceStaffLimit(db, clinicGroupId) {
|
|
13014
|
-
const tier = await getEffectiveTier(db, clinicGroupId);
|
|
13015
|
-
const config = TIER_CONFIG[tier];
|
|
13016
|
-
if (!config) return;
|
|
13017
|
-
const max = config.limits.maxStaff;
|
|
13018
|
-
if (max === -1) return;
|
|
13019
|
-
const staffQuery = query13(
|
|
13020
|
-
collection13(db, "clinic_staff_members"),
|
|
13021
|
-
where13("clinicGroupId", "==", clinicGroupId),
|
|
13022
|
-
where13("isActive", "==", true)
|
|
13023
|
-
);
|
|
13024
|
-
const staffSnap = await getDocs13(staffQuery);
|
|
13025
|
-
const currentCount = staffSnap.size;
|
|
13026
|
-
if (currentCount + 1 > max) {
|
|
13027
|
-
throw new TierLimitError("staff members", tier, currentCount, max);
|
|
13028
|
-
}
|
|
13029
|
-
}
|
|
13030
13023
|
async function enforceAppointmentLimit(db, clinicGroupId) {
|
|
13031
13024
|
var _a;
|
|
13032
13025
|
const tier = await getEffectiveTier(db, clinicGroupId);
|
|
@@ -28309,7 +28302,6 @@ export {
|
|
|
28309
28302
|
HAIR_SCALP_ASSESSMENT_COLLECTION,
|
|
28310
28303
|
HeadingLevel,
|
|
28311
28304
|
INVITE_TOKENS_COLLECTION,
|
|
28312
|
-
LEGACY_TIER_MAP,
|
|
28313
28305
|
Language,
|
|
28314
28306
|
ListType,
|
|
28315
28307
|
MEDIA_METADATA_COLLECTION,
|
|
@@ -28381,7 +28373,6 @@ export {
|
|
|
28381
28373
|
enforceMessageLimit,
|
|
28382
28374
|
enforceProcedureLimit,
|
|
28383
28375
|
enforceProviderLimit,
|
|
28384
|
-
enforceStaffLimit,
|
|
28385
28376
|
getEffectiveTier,
|
|
28386
28377
|
getFirebaseApp,
|
|
28387
28378
|
getFirebaseAuth,
|
package/package.json
CHANGED
package/src/config/index.ts
CHANGED
|
@@ -53,10 +53,10 @@ export type PermissionKey = keyof typeof PERMISSION_KEYS;
|
|
|
53
53
|
* All features are available on every tier — tiers differ only in usage caps.
|
|
54
54
|
* -1 means unlimited.
|
|
55
55
|
*
|
|
56
|
-
* Confirmed by client on 2026-03-
|
|
57
|
-
* - Free: 1 provider, 3 procedures, 3 appts/mo, 10 msgs/mo, 1
|
|
58
|
-
* - Connect:
|
|
59
|
-
* - Pro: unlimited everything
|
|
56
|
+
* Confirmed by client on 2026-03-10:
|
|
57
|
+
* - Free: 1 provider, 3 procedures, 3 appts/mo, 10 msgs/mo, 1 location
|
|
58
|
+
* - Connect (CHF 59/mo): unlimited providers, 15 procedures, 100 appts/mo, unlimited msgs, 1 location
|
|
59
|
+
* - Pro (CHF 149/mo): unlimited everything
|
|
60
60
|
*/
|
|
61
61
|
export const TIER_CONFIG: Record<string, TierConfig> = {
|
|
62
62
|
free: {
|
|
@@ -67,7 +67,6 @@ export const TIER_CONFIG: Record<string, TierConfig> = {
|
|
|
67
67
|
maxProcedures: 3,
|
|
68
68
|
maxAppointmentsPerMonth: 3,
|
|
69
69
|
maxMessagesPerMonth: 10,
|
|
70
|
-
maxStaff: 1,
|
|
71
70
|
maxBranches: 1,
|
|
72
71
|
},
|
|
73
72
|
},
|
|
@@ -75,11 +74,10 @@ export const TIER_CONFIG: Record<string, TierConfig> = {
|
|
|
75
74
|
tier: 'connect',
|
|
76
75
|
name: 'Connect',
|
|
77
76
|
limits: {
|
|
78
|
-
maxProviders:
|
|
77
|
+
maxProviders: -1,
|
|
79
78
|
maxProcedures: 15,
|
|
80
79
|
maxAppointmentsPerMonth: 100,
|
|
81
80
|
maxMessagesPerMonth: -1,
|
|
82
|
-
maxStaff: 5,
|
|
83
81
|
maxBranches: 1,
|
|
84
82
|
},
|
|
85
83
|
},
|
|
@@ -91,7 +89,6 @@ export const TIER_CONFIG: Record<string, TierConfig> = {
|
|
|
91
89
|
maxProcedures: -1,
|
|
92
90
|
maxAppointmentsPerMonth: -1,
|
|
93
91
|
maxMessagesPerMonth: -1,
|
|
94
|
-
maxStaff: -1,
|
|
95
92
|
maxBranches: -1,
|
|
96
93
|
},
|
|
97
94
|
},
|
|
@@ -215,23 +212,19 @@ export const DEFAULT_ROLE_PERMISSIONS: Record<ClinicRole, Record<string, boolean
|
|
|
215
212
|
};
|
|
216
213
|
|
|
217
214
|
/**
|
|
218
|
-
* Maps
|
|
219
|
-
* All paid legacy tiers map to PRO.
|
|
215
|
+
* Maps subscription model strings to tier keys.
|
|
220
216
|
*/
|
|
221
|
-
export const
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
217
|
+
export const TIER_MAP: Record<string, string> = {
|
|
218
|
+
no_subscription: 'free',
|
|
219
|
+
free: 'free',
|
|
220
|
+
connect: 'connect',
|
|
221
|
+
pro: 'pro',
|
|
225
222
|
};
|
|
226
223
|
|
|
227
224
|
/**
|
|
228
|
-
* Resolves the effective tier for a subscription model string
|
|
229
|
-
* handling legacy values.
|
|
225
|
+
* Resolves the effective tier for a subscription model string.
|
|
230
226
|
*/
|
|
231
227
|
export function resolveEffectiveTier(subscriptionModel: string): string {
|
|
232
228
|
const lower = subscriptionModel.toLowerCase();
|
|
233
|
-
|
|
234
|
-
return LEGACY_TIER_MAP[lower];
|
|
235
|
-
}
|
|
236
|
-
return lower;
|
|
229
|
+
return TIER_MAP[lower] || 'free';
|
|
237
230
|
}
|
|
@@ -324,6 +324,20 @@ export class AppointmentService extends BaseService {
|
|
|
324
324
|
if (!response.ok) {
|
|
325
325
|
const errorText = await response.text();
|
|
326
326
|
console.error(`[APPOINTMENT_SERVICE] Error response details: ${errorText}`);
|
|
327
|
+
|
|
328
|
+
// Preserve tier limit error code so the frontend can detect it
|
|
329
|
+
try {
|
|
330
|
+
const errorJson = JSON.parse(errorText);
|
|
331
|
+
if (errorJson.code === 'TIER_LIMIT_EXCEEDED') {
|
|
332
|
+
throw new Error(`TIER_LIMIT_EXCEEDED:${errorJson.message || 'You have reached your plan limit. Please upgrade to continue.'}`);
|
|
333
|
+
}
|
|
334
|
+
} catch (parseError) {
|
|
335
|
+
// Not JSON or not a tier error — fall through to generic handling
|
|
336
|
+
if (parseError instanceof Error && parseError.message.startsWith('TIER_LIMIT_EXCEEDED:')) {
|
|
337
|
+
throw parseError;
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
|
|
327
341
|
throw new Error(
|
|
328
342
|
`Failed to create appointment: ${response.status} ${response.statusText} - ${errorText}`,
|
|
329
343
|
);
|
|
@@ -108,7 +108,7 @@ async function countProceduresInGroup(
|
|
|
108
108
|
|
|
109
109
|
if (clinicIds.length === 0) return 0;
|
|
110
110
|
|
|
111
|
-
|
|
111
|
+
const uniqueTechnologyIds = new Set<string>();
|
|
112
112
|
for (let i = 0; i < clinicIds.length; i += 30) {
|
|
113
113
|
const batch = clinicIds.slice(i, i + 30);
|
|
114
114
|
const proceduresQuery = query(
|
|
@@ -117,10 +117,15 @@ async function countProceduresInGroup(
|
|
|
117
117
|
where('isActive', '==', true)
|
|
118
118
|
);
|
|
119
119
|
const proceduresSnap = await getDocs(proceduresQuery);
|
|
120
|
-
|
|
120
|
+
proceduresSnap.docs.forEach(d => {
|
|
121
|
+
const technologyId = d.data().technologyId;
|
|
122
|
+
if (technologyId) {
|
|
123
|
+
uniqueTechnologyIds.add(technologyId);
|
|
124
|
+
}
|
|
125
|
+
});
|
|
121
126
|
}
|
|
122
127
|
|
|
123
|
-
return
|
|
128
|
+
return uniqueTechnologyIds.size;
|
|
124
129
|
}
|
|
125
130
|
|
|
126
131
|
/**
|
|
@@ -202,33 +207,6 @@ export async function enforceBranchLimit(
|
|
|
202
207
|
}
|
|
203
208
|
}
|
|
204
209
|
|
|
205
|
-
/**
|
|
206
|
-
* Enforces tier limit before creating a staff member.
|
|
207
|
-
*/
|
|
208
|
-
export async function enforceStaffLimit(
|
|
209
|
-
db: Firestore,
|
|
210
|
-
clinicGroupId: string
|
|
211
|
-
): Promise<void> {
|
|
212
|
-
const tier = await getEffectiveTier(db, clinicGroupId);
|
|
213
|
-
const config = TIER_CONFIG[tier];
|
|
214
|
-
if (!config) return;
|
|
215
|
-
|
|
216
|
-
const max = config.limits.maxStaff;
|
|
217
|
-
if (max === -1) return;
|
|
218
|
-
|
|
219
|
-
const staffQuery = query(
|
|
220
|
-
collection(db, 'clinic_staff_members'),
|
|
221
|
-
where('clinicGroupId', '==', clinicGroupId),
|
|
222
|
-
where('isActive', '==', true)
|
|
223
|
-
);
|
|
224
|
-
const staffSnap = await getDocs(staffQuery);
|
|
225
|
-
const currentCount = staffSnap.size;
|
|
226
|
-
|
|
227
|
-
if (currentCount + 1 > max) {
|
|
228
|
-
throw new TierLimitError('staff members', tier, currentCount, max);
|
|
229
|
-
}
|
|
230
|
-
}
|
|
231
|
-
|
|
232
210
|
/**
|
|
233
211
|
* Enforces tier limit before creating an appointment.
|
|
234
212
|
* Reads the monthly counter from clinic_groups/{id}/usage_counters/{YYYY-MM}.
|
|
@@ -208,6 +208,8 @@ export interface BillingInfo {
|
|
|
208
208
|
currentPeriodStart: Timestamp | null;
|
|
209
209
|
currentPeriodEnd: Timestamp | null;
|
|
210
210
|
updatedAt: Timestamp;
|
|
211
|
+
seatCount?: number;
|
|
212
|
+
seatPriceId?: string;
|
|
211
213
|
}
|
|
212
214
|
|
|
213
215
|
/**
|
|
@@ -304,6 +306,12 @@ export interface ClinicGroup {
|
|
|
304
306
|
completed?: boolean;
|
|
305
307
|
step?: number;
|
|
306
308
|
};
|
|
309
|
+
featureTrials?: {
|
|
310
|
+
analytics?: {
|
|
311
|
+
startedAt: Timestamp;
|
|
312
|
+
durationDays: number;
|
|
313
|
+
};
|
|
314
|
+
};
|
|
307
315
|
}
|
|
308
316
|
|
|
309
317
|
/**
|
|
@@ -387,6 +395,7 @@ export interface Clinic {
|
|
|
387
395
|
isActive: boolean;
|
|
388
396
|
isVerified: boolean;
|
|
389
397
|
logo?: MediaResource | null;
|
|
398
|
+
acceptingBookings?: boolean;
|
|
390
399
|
}
|
|
391
400
|
|
|
392
401
|
/**
|