@updraft-solutions/mcrit-sdk 0.9.0 → 0.11.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (44) hide show
  1. package/README.md +11 -25
  2. package/dist/{chunk-3WKOQDFN.cjs → chunk-RN7XMRGC.cjs} +37 -25
  3. package/dist/{chunk-NYDIYVBI.js → chunk-XEKAC57V.js} +37 -25
  4. package/dist/crew/index.d.cts +1 -1
  5. package/dist/crew/index.d.ts +1 -1
  6. package/dist/index.cjs +5 -3
  7. package/dist/index.d.cts +3 -3
  8. package/dist/index.d.ts +3 -3
  9. package/dist/index.js +8 -6
  10. package/dist/media/index.d.cts +2 -2
  11. package/dist/media/index.d.ts +2 -2
  12. package/dist/money/index.d.cts +5 -5
  13. package/dist/money/index.d.ts +5 -5
  14. package/dist/sanitize/index.cjs +53 -0
  15. package/dist/sanitize/index.d.cts +50 -0
  16. package/dist/sanitize/index.d.ts +50 -0
  17. package/dist/sanitize/index.js +53 -0
  18. package/dist/schemas/index.cjs +4 -2
  19. package/dist/schemas/index.d.cts +16 -17
  20. package/dist/schemas/index.d.ts +16 -17
  21. package/dist/schemas/index.js +7 -5
  22. package/dist/{training-nljZCLW5.d.cts → training-CuiDqGAo.d.cts} +944 -858
  23. package/dist/{training-nljZCLW5.d.ts → training-CuiDqGAo.d.ts} +944 -858
  24. package/dist/types/index.cjs +1 -1
  25. package/dist/types/index.d.cts +153 -2
  26. package/dist/types/index.d.ts +153 -2
  27. package/dist/types/index.js +1 -1
  28. package/package.json +14 -2
  29. package/src/crew/index.ts +1 -1
  30. package/src/index.ts +18 -0
  31. package/src/media/index.ts +2 -2
  32. package/src/money/index.ts +4 -4
  33. package/src/sanitize/index.ts +92 -0
  34. package/src/schemas/common.ts +1 -1
  35. package/src/schemas/equipment.ts +1 -2
  36. package/src/schemas/form-template.ts +1 -1
  37. package/src/schemas/models.ts +46 -30
  38. package/src/schemas/training.ts +2 -2
  39. package/src/types/compliance.ts +1 -1
  40. package/src/types/index.ts +1 -0
  41. package/src/types/models.ts +18 -0
  42. package/src/types/operating-hours.ts +163 -0
  43. /package/dist/{chunk-2WJHTRIE.js → chunk-UV5JLKAL.js} +0 -0
  44. /package/dist/{chunk-DCEOET63.cjs → chunk-YVC6Q3YU.cjs} +0 -0
@@ -1 +1 @@
1
- "use strict";require('../chunk-DCEOET63.cjs');
1
+ "use strict";require('../chunk-YVC6Q3YU.cjs');
@@ -1,5 +1,5 @@
1
1
  import { z } from 'zod';
2
- import { aB as activitySchema, aC as addressSchema, aD as aircraftPositionSchema, aE as aircraftRatingSchema, aJ as airplaneSchema, aI as airplanePermissionSchema, aK as airplaneShareInviteSchema, aL as airportSchema, aM as alertSchema, aN as allowedDocumentTypeSchema, aO as approachTypeSchema, aP as availSchema, aQ as baseMembershipSchema, aS as bookingSchema, aU as commentSchema, aV as companySchema, a$ as courseSchema, aZ as courseEnrollmentSchema, a_ as courseFeeSchema, aG as airplaneIssueSeverityEnum, b5 as documentSchema, b1 as documentComplianceStatus, b2 as documentRequirement, b3 as documentRequirementGroup, b4 as documentRequirementGroupAssignment, b6 as documentShareSchema, b7 as documentType, b9 as eventSchema, bb as expenseSchema, ba as expenseItemSchema, bc as extendedAirplaneSchema, be as feeSchema, bd as feeCategoryOptionsSchema, bf as flightLogSchema, bm as invoiceSchema, bo as landingSchema, bn as landingFeeSchema, bq as maintenanceEventSchema, bp as maintenanceEventEstimationSchema, br as maintenanceStatusSchema, bs as mediaCollection, bu as membershipSchema, bv as membershipSignupSchema, bw as postSchema, by as prePaidPackageSchema, bz as priceSchema, bA as qualificationSchema, bB as recurringFlightSchema, bC as roleSchema, bD as runwaySchema, bE as scheduledFlightSchema, bF as settingSchema, bG as specialFlightSchema, bN as tagSchema, bO as ticketSchema, bY as userSchema, bW as userAircraftRatingSchema, bX as userQualificationSchema, bZ as waypointSchema, aF as airplaneIssueSchema, aH as airplaneIssueStatusEnum, B as BaseModel$1, aX as courseCheckSyllabusSchema, aY as courseEnrollmentMetricsSchema, bt as mediaSchema, l as FormSubmission } from '../training-nljZCLW5.cjs';
2
+ import { aB as activitySchema, aC as addressSchema, aD as aircraftPositionSchema, aE as aircraftRatingSchema, aJ as airplaneSchema, aI as airplanePermissionSchema, aK as airplaneShareInviteSchema, aL as airportSchema, aM as alertSchema, aN as allowedDocumentTypeSchema, aO as approachTypeSchema, aP as availSchema, aQ as baseMembershipSchema, aS as bookingSchema, aU as commentSchema, aV as companySchema, a$ as courseSchema, aZ as courseEnrollmentSchema, a_ as courseFeeSchema, aG as airplaneIssueSeverityEnum, b5 as documentSchema, b1 as documentComplianceStatus, b2 as documentRequirement, b3 as documentRequirementGroup, b4 as documentRequirementGroupAssignment, b6 as documentShareSchema, b7 as documentType, b9 as eventSchema, bb as expenseSchema, ba as expenseItemSchema, bc as extendedAirplaneSchema, be as feeSchema, bd as feeCategoryOptionsSchema, bf as flightLogSchema, bm as invoiceSchema, bo as landingSchema, bn as landingFeeSchema, bq as maintenanceEventSchema, bp as maintenanceEventEstimationSchema, br as maintenanceStatusSchema, bs as mediaCollection, bu as membershipSchema, bv as membershipSignupSchema, bw as postSchema, bx as postSubjectSchema, bz as prePaidPackageSchema, bA as priceSchema, bB as qualificationSchema, bC as recurringFlightSchema, bD as roleSchema, bE as runwaySchema, bF as scheduledFlightSchema, bG as settingSchema, bH as specialFlightSchema, bO as tagSchema, bP as ticketSchema, bZ as userSchema, bX as userAircraftRatingSchema, bY as userQualificationSchema, b_ as waypointSchema, aF as airplaneIssueSchema, aH as airplaneIssueStatusEnum, B as BaseModel$1, aX as courseCheckSyllabusSchema, aY as courseEnrollmentMetricsSchema, bt as mediaSchema, l as FormSubmission } from '../training-CuiDqGAo.cjs';
3
3
 
4
4
  type BaseModel = z.infer<typeof BaseModel$1>;
5
5
  type User = z.infer<typeof userSchema>;
@@ -61,17 +61,34 @@ type AirplaneIssueStatus = z.infer<typeof airplaneIssueStatusEnum>;
61
61
  type Event = z.infer<typeof eventSchema>;
62
62
  type Ticket = z.infer<typeof ticketSchema>;
63
63
  type Post = z.infer<typeof postSchema>;
64
+ type PostSubject = z.infer<typeof postSubjectSchema>;
65
+ /**
66
+ * Full-replacement tag sync entry — `id` marks an existing tag (wins over
67
+ * name matching), fresh tags carry only name (+ optional color) and are
68
+ * created server-side on save.
69
+ */
70
+ interface TagSyncEntry {
71
+ id?: number | null;
72
+ name: string;
73
+ color?: string | null;
74
+ }
64
75
  interface CreatePostInput {
65
76
  title?: string | null;
66
77
  content: string;
67
78
  sticky?: boolean;
68
79
  public?: boolean;
80
+ comments_disabled?: boolean;
81
+ tags?: TagSyncEntry[];
82
+ /** Action flag, not persisted: notify company members on publish. */
83
+ notify?: boolean;
69
84
  }
70
85
  interface UpdatePostInput {
71
86
  title?: string | null;
72
87
  content: string;
73
88
  sticky?: boolean;
74
89
  public?: boolean;
90
+ comments_disabled?: boolean;
91
+ tags?: TagSyncEntry[];
75
92
  }
76
93
  interface CreateAirplaneIssueInput {
77
94
  title?: string | null;
@@ -420,4 +437,138 @@ interface LandingFeeInvoiceApplyResult {
420
437
  issues: string[];
421
438
  }
422
439
 
423
- export type { Activity, Address, AiSuggestedMilestone, AiSuggestion, AiSuggestionStatus, AircraftBlock, AircraftBlockReason, AircraftPosition, AircraftRating, Airplane, AirplaneIssue, AirplaneIssueSeverity, AirplaneIssueStatus, AirplanePermission, AirplaneShareInvite, Airport, Alert, AllowedDocumentType, ApiResponse, ApproachType, Avail, BackgroundTask, BackgroundTaskStatus, BaseMembership, BaseModel, Booking, Comment, Company, ComplianceData, ComplianceGroup, ComplianceGroupSource, ComplianceRequirement, ComplianceRequirementGroup, ComplianceResponse, ComplianceSummary, Course, CourseCheckSyllabus, CourseDescriptionSuggestionPayload, CourseEnrollment, CourseEnrollmentMetrics, CourseFee, CreateAirplaneIssueInput, CreateCommentInput, CreatePostInput, DataWrappedResponse, DeferAirplaneIssueInput, DiscardedRow, Document, DocumentComplianceStatus, DocumentRequirement, DocumentRequirementGroup, DocumentRequirementGroupAssignment, DocumentShare, DocumentType, Event, Expense, ExpenseItem, ExtendedAirplane, Fee, FeeCategoryOptions, FlightLog, GroupedPermissions, Invoice, Landing, LandingFee, LandingFeeImportResult, LandingFeeInvoiceApplyPayload, LandingFeeInvoiceApplyResult, LandingFeeInvoicePreview, LandingFeeInvoicePreviewRow, LandingFeeTemplateParams, LogbookFlightLogPayload, LogbookStageResult, LogbookSuggestion, LogbookSuggestionMeta, MaintenanceEvent, MaintenanceEventEstimation, MaintenanceStatus, Media, MediaCollection, Membership, MembershipSignup, PaginatedResponse, PermissionItem, Post, PrePaidPackage, Price, Qualification, RecurringFlight, ResolveAirplaneIssueInput, Resource, Role, RoleDetail, RoleListItem, Runway, ScheduledFlight, Setting, SpecialFlight, Tag, Ticket, ToggleFavoriteResponse, UpdateAirplaneIssueInput, UpdateCommentInput, UpdatePostInput, User, UserAircraftRating, UserQualification, Waypoint };
440
+ /**
441
+ * Operating hours — an organization defines several independent groups (its
442
+ * own office hours, a military field it flies from, the tower, an FBO). Each
443
+ * group is self-contained (own IANA timezone + optional airport) and is
444
+ * materialised server-side into merged, half-open UTC windows; status is
445
+ * answered per group as open / partial / closed / unknown.
446
+ */
447
+ type OperatingHourKind = "company" | "airport" | "atc" | "fbo" | "military" | "fuel" | "customs" | "handling" | "maintenance" | "other";
448
+ type TimeAnchor = "fixed" | "sunrise" | "sunset";
449
+ type OperatingStatusValue = "open" | "partial" | "closed" | "unknown";
450
+ /**
451
+ * One open block. Each bound is a fixed local time, or sunrise/sunset with a
452
+ * signed offset and an optional cap ("SR-30 aber nicht vor 07:00"). An end at
453
+ * or before its start crosses midnight.
454
+ */
455
+ type OperatingHourInterval = {
456
+ id?: number;
457
+ sort: number;
458
+ start_kind: TimeAnchor;
459
+ start_time: string | null;
460
+ start_offset_minutes: number | null;
461
+ start_not_before: string | null;
462
+ end_kind: TimeAnchor;
463
+ end_time: string | null;
464
+ end_offset_minutes: number | null;
465
+ end_not_after: string | null;
466
+ };
467
+ /** One weekday. ISO: 1 = Monday .. 7 = Sunday. */
468
+ type OperatingHourDay = {
469
+ id?: number;
470
+ schedule_id?: number;
471
+ day_of_week: number;
472
+ is_closed: boolean;
473
+ is_24_hours: boolean;
474
+ notes: string | null;
475
+ intervals: OperatingHourInterval[];
476
+ };
477
+ /** A hand-entered override for a date range. No recurrence, by design. */
478
+ type OperatingHourException = {
479
+ id: number;
480
+ schedule_id: number;
481
+ starts_on: string;
482
+ ends_on: string;
483
+ is_closed: boolean;
484
+ is_24_hours: boolean;
485
+ reason: string;
486
+ intervals: OperatingHourInterval[];
487
+ };
488
+ /**
489
+ * What the client composes before an exception exists — no id, no owner yet.
490
+ * The read type above is what comes back; keeping the two apart lets the
491
+ * dialog's `createItem` seed a blank without lying about an id.
492
+ */
493
+ type OperatingHourExceptionInput = Omit<OperatingHourException, "id" | "schedule_id">;
494
+ /** A concrete, merged, half-open UTC window. Derived — read-only. */
495
+ type OperatingHourWindow = {
496
+ starts_at: string;
497
+ ends_at: string;
498
+ };
499
+ /**
500
+ * A group. Self-contained: carries its own timezone and airport, resolved
501
+ * from nowhere else. `materialized_from`/`materialized_through` bound the
502
+ * range in which "no window" genuinely means closed rather than unknown.
503
+ */
504
+ type OperatingHourSchedule = {
505
+ id: number;
506
+ company_id: number;
507
+ airport_id: number | null;
508
+ airport?: {
509
+ id: number;
510
+ ident: string;
511
+ name: string;
512
+ } | null;
513
+ kind: OperatingHourKind;
514
+ name: string;
515
+ description: string | null;
516
+ timezone: string;
517
+ valid_from: string;
518
+ valid_until: string | null;
519
+ is_active: boolean;
520
+ sort_order: number;
521
+ source: string | null;
522
+ verified_at: string | null;
523
+ materialized_from: string | null;
524
+ materialized_through: string | null;
525
+ days: OperatingHourDay[];
526
+ exceptions: OperatingHourException[];
527
+ created_at?: string;
528
+ updated_at?: string;
529
+ };
530
+ /** The fields a client may send when creating a group. */
531
+ type OperatingHourScheduleInput = Partial<Omit<OperatingHourSchedule, "id" | "company_id" | "airport" | "materialized_from" | "materialized_through" | "days" | "exceptions" | "created_at" | "updated_at">>;
532
+ /**
533
+ * What the saved rules resolve to on ONE named calendar date — used for the
534
+ * solstice hints. Carries its own date and status precisely so the extremes
535
+ * can never be merged into a weekday bucket alongside the current week, and
536
+ * so an `unknown` date is reported as unknown rather than as closed.
537
+ */
538
+ type OperatingHourResolvedDate = {
539
+ /** `Y-m-d` in the group's timezone. */
540
+ date: string;
541
+ status: OperatingStatusValue;
542
+ windows: OperatingHourWindow[];
543
+ };
544
+ type OperatingHourStatusEntry = {
545
+ schedule_id: number;
546
+ kind: OperatingHourKind;
547
+ name: string;
548
+ timezone: string;
549
+ status: OperatingStatusValue;
550
+ windows: OperatingHourWindow[];
551
+ };
552
+ type OperatingHoursStatusResponse = {
553
+ from: string;
554
+ to: string;
555
+ data: OperatingHourStatusEntry[];
556
+ };
557
+ type OperatingHoursNextOpenEntry = {
558
+ schedule_id: number;
559
+ kind: OperatingHourKind;
560
+ name: string;
561
+ next_opening: string | null;
562
+ };
563
+ type OperatingHoursNextOpenResponse = {
564
+ after: string;
565
+ data: OperatingHoursNextOpenEntry[];
566
+ };
567
+ type OperatingHoursMeta = {
568
+ kinds: OperatingHourKind[];
569
+ anchors: TimeAnchor[];
570
+ statuses: OperatingStatusValue[];
571
+ max_status_range_days: number;
572
+ };
573
+
574
+ export type { Activity, Address, AiSuggestedMilestone, AiSuggestion, AiSuggestionStatus, AircraftBlock, AircraftBlockReason, AircraftPosition, AircraftRating, Airplane, AirplaneIssue, AirplaneIssueSeverity, AirplaneIssueStatus, AirplanePermission, AirplaneShareInvite, Airport, Alert, AllowedDocumentType, ApiResponse, ApproachType, Avail, BackgroundTask, BackgroundTaskStatus, BaseMembership, BaseModel, Booking, Comment, Company, ComplianceData, ComplianceGroup, ComplianceGroupSource, ComplianceRequirement, ComplianceRequirementGroup, ComplianceResponse, ComplianceSummary, Course, CourseCheckSyllabus, CourseDescriptionSuggestionPayload, CourseEnrollment, CourseEnrollmentMetrics, CourseFee, CreateAirplaneIssueInput, CreateCommentInput, CreatePostInput, DataWrappedResponse, DeferAirplaneIssueInput, DiscardedRow, Document, DocumentComplianceStatus, DocumentRequirement, DocumentRequirementGroup, DocumentRequirementGroupAssignment, DocumentShare, DocumentType, Event, Expense, ExpenseItem, ExtendedAirplane, Fee, FeeCategoryOptions, FlightLog, GroupedPermissions, Invoice, Landing, LandingFee, LandingFeeImportResult, LandingFeeInvoiceApplyPayload, LandingFeeInvoiceApplyResult, LandingFeeInvoicePreview, LandingFeeInvoicePreviewRow, LandingFeeTemplateParams, LogbookFlightLogPayload, LogbookStageResult, LogbookSuggestion, LogbookSuggestionMeta, MaintenanceEvent, MaintenanceEventEstimation, MaintenanceStatus, Media, MediaCollection, Membership, MembershipSignup, OperatingHourDay, OperatingHourException, OperatingHourExceptionInput, OperatingHourInterval, OperatingHourKind, OperatingHourResolvedDate, OperatingHourSchedule, OperatingHourScheduleInput, OperatingHourStatusEntry, OperatingHourWindow, OperatingHoursMeta, OperatingHoursNextOpenEntry, OperatingHoursNextOpenResponse, OperatingHoursStatusResponse, OperatingStatusValue, PaginatedResponse, PermissionItem, Post, PostSubject, PrePaidPackage, Price, Qualification, RecurringFlight, ResolveAirplaneIssueInput, Resource, Role, RoleDetail, RoleListItem, Runway, ScheduledFlight, Setting, SpecialFlight, Tag, TagSyncEntry, Ticket, TimeAnchor, ToggleFavoriteResponse, UpdateAirplaneIssueInput, UpdateCommentInput, UpdatePostInput, User, UserAircraftRating, UserQualification, Waypoint };
@@ -1,5 +1,5 @@
1
1
  import { z } from 'zod';
2
- import { aB as activitySchema, aC as addressSchema, aD as aircraftPositionSchema, aE as aircraftRatingSchema, aJ as airplaneSchema, aI as airplanePermissionSchema, aK as airplaneShareInviteSchema, aL as airportSchema, aM as alertSchema, aN as allowedDocumentTypeSchema, aO as approachTypeSchema, aP as availSchema, aQ as baseMembershipSchema, aS as bookingSchema, aU as commentSchema, aV as companySchema, a$ as courseSchema, aZ as courseEnrollmentSchema, a_ as courseFeeSchema, aG as airplaneIssueSeverityEnum, b5 as documentSchema, b1 as documentComplianceStatus, b2 as documentRequirement, b3 as documentRequirementGroup, b4 as documentRequirementGroupAssignment, b6 as documentShareSchema, b7 as documentType, b9 as eventSchema, bb as expenseSchema, ba as expenseItemSchema, bc as extendedAirplaneSchema, be as feeSchema, bd as feeCategoryOptionsSchema, bf as flightLogSchema, bm as invoiceSchema, bo as landingSchema, bn as landingFeeSchema, bq as maintenanceEventSchema, bp as maintenanceEventEstimationSchema, br as maintenanceStatusSchema, bs as mediaCollection, bu as membershipSchema, bv as membershipSignupSchema, bw as postSchema, by as prePaidPackageSchema, bz as priceSchema, bA as qualificationSchema, bB as recurringFlightSchema, bC as roleSchema, bD as runwaySchema, bE as scheduledFlightSchema, bF as settingSchema, bG as specialFlightSchema, bN as tagSchema, bO as ticketSchema, bY as userSchema, bW as userAircraftRatingSchema, bX as userQualificationSchema, bZ as waypointSchema, aF as airplaneIssueSchema, aH as airplaneIssueStatusEnum, B as BaseModel$1, aX as courseCheckSyllabusSchema, aY as courseEnrollmentMetricsSchema, bt as mediaSchema, l as FormSubmission } from '../training-nljZCLW5.js';
2
+ import { aB as activitySchema, aC as addressSchema, aD as aircraftPositionSchema, aE as aircraftRatingSchema, aJ as airplaneSchema, aI as airplanePermissionSchema, aK as airplaneShareInviteSchema, aL as airportSchema, aM as alertSchema, aN as allowedDocumentTypeSchema, aO as approachTypeSchema, aP as availSchema, aQ as baseMembershipSchema, aS as bookingSchema, aU as commentSchema, aV as companySchema, a$ as courseSchema, aZ as courseEnrollmentSchema, a_ as courseFeeSchema, aG as airplaneIssueSeverityEnum, b5 as documentSchema, b1 as documentComplianceStatus, b2 as documentRequirement, b3 as documentRequirementGroup, b4 as documentRequirementGroupAssignment, b6 as documentShareSchema, b7 as documentType, b9 as eventSchema, bb as expenseSchema, ba as expenseItemSchema, bc as extendedAirplaneSchema, be as feeSchema, bd as feeCategoryOptionsSchema, bf as flightLogSchema, bm as invoiceSchema, bo as landingSchema, bn as landingFeeSchema, bq as maintenanceEventSchema, bp as maintenanceEventEstimationSchema, br as maintenanceStatusSchema, bs as mediaCollection, bu as membershipSchema, bv as membershipSignupSchema, bw as postSchema, bx as postSubjectSchema, bz as prePaidPackageSchema, bA as priceSchema, bB as qualificationSchema, bC as recurringFlightSchema, bD as roleSchema, bE as runwaySchema, bF as scheduledFlightSchema, bG as settingSchema, bH as specialFlightSchema, bO as tagSchema, bP as ticketSchema, bZ as userSchema, bX as userAircraftRatingSchema, bY as userQualificationSchema, b_ as waypointSchema, aF as airplaneIssueSchema, aH as airplaneIssueStatusEnum, B as BaseModel$1, aX as courseCheckSyllabusSchema, aY as courseEnrollmentMetricsSchema, bt as mediaSchema, l as FormSubmission } from '../training-CuiDqGAo.js';
3
3
 
4
4
  type BaseModel = z.infer<typeof BaseModel$1>;
5
5
  type User = z.infer<typeof userSchema>;
@@ -61,17 +61,34 @@ type AirplaneIssueStatus = z.infer<typeof airplaneIssueStatusEnum>;
61
61
  type Event = z.infer<typeof eventSchema>;
62
62
  type Ticket = z.infer<typeof ticketSchema>;
63
63
  type Post = z.infer<typeof postSchema>;
64
+ type PostSubject = z.infer<typeof postSubjectSchema>;
65
+ /**
66
+ * Full-replacement tag sync entry — `id` marks an existing tag (wins over
67
+ * name matching), fresh tags carry only name (+ optional color) and are
68
+ * created server-side on save.
69
+ */
70
+ interface TagSyncEntry {
71
+ id?: number | null;
72
+ name: string;
73
+ color?: string | null;
74
+ }
64
75
  interface CreatePostInput {
65
76
  title?: string | null;
66
77
  content: string;
67
78
  sticky?: boolean;
68
79
  public?: boolean;
80
+ comments_disabled?: boolean;
81
+ tags?: TagSyncEntry[];
82
+ /** Action flag, not persisted: notify company members on publish. */
83
+ notify?: boolean;
69
84
  }
70
85
  interface UpdatePostInput {
71
86
  title?: string | null;
72
87
  content: string;
73
88
  sticky?: boolean;
74
89
  public?: boolean;
90
+ comments_disabled?: boolean;
91
+ tags?: TagSyncEntry[];
75
92
  }
76
93
  interface CreateAirplaneIssueInput {
77
94
  title?: string | null;
@@ -420,4 +437,138 @@ interface LandingFeeInvoiceApplyResult {
420
437
  issues: string[];
421
438
  }
422
439
 
423
- export type { Activity, Address, AiSuggestedMilestone, AiSuggestion, AiSuggestionStatus, AircraftBlock, AircraftBlockReason, AircraftPosition, AircraftRating, Airplane, AirplaneIssue, AirplaneIssueSeverity, AirplaneIssueStatus, AirplanePermission, AirplaneShareInvite, Airport, Alert, AllowedDocumentType, ApiResponse, ApproachType, Avail, BackgroundTask, BackgroundTaskStatus, BaseMembership, BaseModel, Booking, Comment, Company, ComplianceData, ComplianceGroup, ComplianceGroupSource, ComplianceRequirement, ComplianceRequirementGroup, ComplianceResponse, ComplianceSummary, Course, CourseCheckSyllabus, CourseDescriptionSuggestionPayload, CourseEnrollment, CourseEnrollmentMetrics, CourseFee, CreateAirplaneIssueInput, CreateCommentInput, CreatePostInput, DataWrappedResponse, DeferAirplaneIssueInput, DiscardedRow, Document, DocumentComplianceStatus, DocumentRequirement, DocumentRequirementGroup, DocumentRequirementGroupAssignment, DocumentShare, DocumentType, Event, Expense, ExpenseItem, ExtendedAirplane, Fee, FeeCategoryOptions, FlightLog, GroupedPermissions, Invoice, Landing, LandingFee, LandingFeeImportResult, LandingFeeInvoiceApplyPayload, LandingFeeInvoiceApplyResult, LandingFeeInvoicePreview, LandingFeeInvoicePreviewRow, LandingFeeTemplateParams, LogbookFlightLogPayload, LogbookStageResult, LogbookSuggestion, LogbookSuggestionMeta, MaintenanceEvent, MaintenanceEventEstimation, MaintenanceStatus, Media, MediaCollection, Membership, MembershipSignup, PaginatedResponse, PermissionItem, Post, PrePaidPackage, Price, Qualification, RecurringFlight, ResolveAirplaneIssueInput, Resource, Role, RoleDetail, RoleListItem, Runway, ScheduledFlight, Setting, SpecialFlight, Tag, Ticket, ToggleFavoriteResponse, UpdateAirplaneIssueInput, UpdateCommentInput, UpdatePostInput, User, UserAircraftRating, UserQualification, Waypoint };
440
+ /**
441
+ * Operating hours — an organization defines several independent groups (its
442
+ * own office hours, a military field it flies from, the tower, an FBO). Each
443
+ * group is self-contained (own IANA timezone + optional airport) and is
444
+ * materialised server-side into merged, half-open UTC windows; status is
445
+ * answered per group as open / partial / closed / unknown.
446
+ */
447
+ type OperatingHourKind = "company" | "airport" | "atc" | "fbo" | "military" | "fuel" | "customs" | "handling" | "maintenance" | "other";
448
+ type TimeAnchor = "fixed" | "sunrise" | "sunset";
449
+ type OperatingStatusValue = "open" | "partial" | "closed" | "unknown";
450
+ /**
451
+ * One open block. Each bound is a fixed local time, or sunrise/sunset with a
452
+ * signed offset and an optional cap ("SR-30 aber nicht vor 07:00"). An end at
453
+ * or before its start crosses midnight.
454
+ */
455
+ type OperatingHourInterval = {
456
+ id?: number;
457
+ sort: number;
458
+ start_kind: TimeAnchor;
459
+ start_time: string | null;
460
+ start_offset_minutes: number | null;
461
+ start_not_before: string | null;
462
+ end_kind: TimeAnchor;
463
+ end_time: string | null;
464
+ end_offset_minutes: number | null;
465
+ end_not_after: string | null;
466
+ };
467
+ /** One weekday. ISO: 1 = Monday .. 7 = Sunday. */
468
+ type OperatingHourDay = {
469
+ id?: number;
470
+ schedule_id?: number;
471
+ day_of_week: number;
472
+ is_closed: boolean;
473
+ is_24_hours: boolean;
474
+ notes: string | null;
475
+ intervals: OperatingHourInterval[];
476
+ };
477
+ /** A hand-entered override for a date range. No recurrence, by design. */
478
+ type OperatingHourException = {
479
+ id: number;
480
+ schedule_id: number;
481
+ starts_on: string;
482
+ ends_on: string;
483
+ is_closed: boolean;
484
+ is_24_hours: boolean;
485
+ reason: string;
486
+ intervals: OperatingHourInterval[];
487
+ };
488
+ /**
489
+ * What the client composes before an exception exists — no id, no owner yet.
490
+ * The read type above is what comes back; keeping the two apart lets the
491
+ * dialog's `createItem` seed a blank without lying about an id.
492
+ */
493
+ type OperatingHourExceptionInput = Omit<OperatingHourException, "id" | "schedule_id">;
494
+ /** A concrete, merged, half-open UTC window. Derived — read-only. */
495
+ type OperatingHourWindow = {
496
+ starts_at: string;
497
+ ends_at: string;
498
+ };
499
+ /**
500
+ * A group. Self-contained: carries its own timezone and airport, resolved
501
+ * from nowhere else. `materialized_from`/`materialized_through` bound the
502
+ * range in which "no window" genuinely means closed rather than unknown.
503
+ */
504
+ type OperatingHourSchedule = {
505
+ id: number;
506
+ company_id: number;
507
+ airport_id: number | null;
508
+ airport?: {
509
+ id: number;
510
+ ident: string;
511
+ name: string;
512
+ } | null;
513
+ kind: OperatingHourKind;
514
+ name: string;
515
+ description: string | null;
516
+ timezone: string;
517
+ valid_from: string;
518
+ valid_until: string | null;
519
+ is_active: boolean;
520
+ sort_order: number;
521
+ source: string | null;
522
+ verified_at: string | null;
523
+ materialized_from: string | null;
524
+ materialized_through: string | null;
525
+ days: OperatingHourDay[];
526
+ exceptions: OperatingHourException[];
527
+ created_at?: string;
528
+ updated_at?: string;
529
+ };
530
+ /** The fields a client may send when creating a group. */
531
+ type OperatingHourScheduleInput = Partial<Omit<OperatingHourSchedule, "id" | "company_id" | "airport" | "materialized_from" | "materialized_through" | "days" | "exceptions" | "created_at" | "updated_at">>;
532
+ /**
533
+ * What the saved rules resolve to on ONE named calendar date — used for the
534
+ * solstice hints. Carries its own date and status precisely so the extremes
535
+ * can never be merged into a weekday bucket alongside the current week, and
536
+ * so an `unknown` date is reported as unknown rather than as closed.
537
+ */
538
+ type OperatingHourResolvedDate = {
539
+ /** `Y-m-d` in the group's timezone. */
540
+ date: string;
541
+ status: OperatingStatusValue;
542
+ windows: OperatingHourWindow[];
543
+ };
544
+ type OperatingHourStatusEntry = {
545
+ schedule_id: number;
546
+ kind: OperatingHourKind;
547
+ name: string;
548
+ timezone: string;
549
+ status: OperatingStatusValue;
550
+ windows: OperatingHourWindow[];
551
+ };
552
+ type OperatingHoursStatusResponse = {
553
+ from: string;
554
+ to: string;
555
+ data: OperatingHourStatusEntry[];
556
+ };
557
+ type OperatingHoursNextOpenEntry = {
558
+ schedule_id: number;
559
+ kind: OperatingHourKind;
560
+ name: string;
561
+ next_opening: string | null;
562
+ };
563
+ type OperatingHoursNextOpenResponse = {
564
+ after: string;
565
+ data: OperatingHoursNextOpenEntry[];
566
+ };
567
+ type OperatingHoursMeta = {
568
+ kinds: OperatingHourKind[];
569
+ anchors: TimeAnchor[];
570
+ statuses: OperatingStatusValue[];
571
+ max_status_range_days: number;
572
+ };
573
+
574
+ export type { Activity, Address, AiSuggestedMilestone, AiSuggestion, AiSuggestionStatus, AircraftBlock, AircraftBlockReason, AircraftPosition, AircraftRating, Airplane, AirplaneIssue, AirplaneIssueSeverity, AirplaneIssueStatus, AirplanePermission, AirplaneShareInvite, Airport, Alert, AllowedDocumentType, ApiResponse, ApproachType, Avail, BackgroundTask, BackgroundTaskStatus, BaseMembership, BaseModel, Booking, Comment, Company, ComplianceData, ComplianceGroup, ComplianceGroupSource, ComplianceRequirement, ComplianceRequirementGroup, ComplianceResponse, ComplianceSummary, Course, CourseCheckSyllabus, CourseDescriptionSuggestionPayload, CourseEnrollment, CourseEnrollmentMetrics, CourseFee, CreateAirplaneIssueInput, CreateCommentInput, CreatePostInput, DataWrappedResponse, DeferAirplaneIssueInput, DiscardedRow, Document, DocumentComplianceStatus, DocumentRequirement, DocumentRequirementGroup, DocumentRequirementGroupAssignment, DocumentShare, DocumentType, Event, Expense, ExpenseItem, ExtendedAirplane, Fee, FeeCategoryOptions, FlightLog, GroupedPermissions, Invoice, Landing, LandingFee, LandingFeeImportResult, LandingFeeInvoiceApplyPayload, LandingFeeInvoiceApplyResult, LandingFeeInvoicePreview, LandingFeeInvoicePreviewRow, LandingFeeTemplateParams, LogbookFlightLogPayload, LogbookStageResult, LogbookSuggestion, LogbookSuggestionMeta, MaintenanceEvent, MaintenanceEventEstimation, MaintenanceStatus, Media, MediaCollection, Membership, MembershipSignup, OperatingHourDay, OperatingHourException, OperatingHourExceptionInput, OperatingHourInterval, OperatingHourKind, OperatingHourResolvedDate, OperatingHourSchedule, OperatingHourScheduleInput, OperatingHourStatusEntry, OperatingHourWindow, OperatingHoursMeta, OperatingHoursNextOpenEntry, OperatingHoursNextOpenResponse, OperatingHoursStatusResponse, OperatingStatusValue, PaginatedResponse, PermissionItem, Post, PostSubject, PrePaidPackage, Price, Qualification, RecurringFlight, ResolveAirplaneIssueInput, Resource, Role, RoleDetail, RoleListItem, Runway, ScheduledFlight, Setting, SpecialFlight, Tag, TagSyncEntry, Ticket, TimeAnchor, ToggleFavoriteResponse, UpdateAirplaneIssueInput, UpdateCommentInput, UpdatePostInput, User, UserAircraftRating, UserQualification, Waypoint };
@@ -1 +1 @@
1
- import "../chunk-2WJHTRIE.js";
1
+ import "../chunk-UV5JLKAL.js";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@updraft-solutions/mcrit-sdk",
3
- "version": "0.9.0",
3
+ "version": "0.11.0",
4
4
  "description": "Shared TypeScript types, Zod schemas, and pure helpers for the MCRIT aviation fleet management platform",
5
5
  "homepage": "https://github.com/updraft-solutions/mcrit-sdk#readme",
6
6
  "bugs": {
@@ -126,6 +126,17 @@
126
126
  "types": "./dist/pagination/index.d.cts",
127
127
  "default": "./dist/pagination/index.cjs"
128
128
  }
129
+ },
130
+ "./sanitize": {
131
+ "source": "./src/sanitize/index.ts",
132
+ "import": {
133
+ "types": "./dist/sanitize/index.d.ts",
134
+ "default": "./dist/sanitize/index.js"
135
+ },
136
+ "require": {
137
+ "types": "./dist/sanitize/index.d.cts",
138
+ "default": "./dist/sanitize/index.cjs"
139
+ }
129
140
  }
130
141
  },
131
142
  "files": [
@@ -139,7 +150,8 @@
139
150
  "dev": "tsup --watch",
140
151
  "typecheck": "tsc --noEmit",
141
152
  "test": "vitest run",
142
- "prepublishOnly": "pnpm build"
153
+ "prepublishOnly": "pnpm check:leaks && pnpm build && pnpm check:leaks",
154
+ "check:leaks": "node scripts/check-public-surface.js"
143
155
  },
144
156
  "publishConfig": {
145
157
  "access": "public"
package/src/crew/index.ts CHANGED
@@ -2,7 +2,7 @@
2
2
  * Crew configuration consumer for the MCRIT SDK.
3
3
  *
4
4
  * No crew-role data lives in this module — the canonical source is the
5
- * backend `App\Crew\CrewConfiguration`, served via `GET /meta/crew`.
5
+ * server crew configuration, served via `GET /meta/crew`.
6
6
  * Apps fetch the config once at boot, hand it to `createCrewValidator`,
7
7
  * and use the returned validator to drive UI feedback on a live crew
8
8
  * list.
package/src/index.ts CHANGED
@@ -54,6 +54,7 @@ export {
54
54
  type Event,
55
55
  type Ticket,
56
56
  type Post,
57
+ type PostSubject,
57
58
  type CreatePostInput,
58
59
  type UpdatePostInput,
59
60
  type CreateAirplaneIssueInput,
@@ -109,6 +110,23 @@ export {
109
110
  type LandingFeeInvoicePreview,
110
111
  type LandingFeeInvoiceApplyPayload,
111
112
  type LandingFeeInvoiceApplyResult,
113
+ // types/operating-hours.ts
114
+ type OperatingHourKind,
115
+ type TimeAnchor,
116
+ type OperatingStatusValue,
117
+ type OperatingHourInterval,
118
+ type OperatingHourDay,
119
+ type OperatingHourException,
120
+ type OperatingHourExceptionInput,
121
+ type OperatingHourWindow,
122
+ type OperatingHourSchedule,
123
+ type OperatingHourScheduleInput,
124
+ type OperatingHourResolvedDate,
125
+ type OperatingHourStatusEntry,
126
+ type OperatingHoursStatusResponse,
127
+ type OperatingHoursNextOpenEntry,
128
+ type OperatingHoursNextOpenResponse,
129
+ type OperatingHoursMeta,
112
130
  } from "./types/index.js";
113
131
 
114
132
  export * from "./money/index.js";
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Media conversion + classification helpers for spatie/laravel-medialibrary
2
+ * Media conversion + classification helpers for API media
3
3
  * payloads. All functions are pure and locale-agnostic.
4
4
  */
5
5
 
@@ -155,7 +155,7 @@ export function getMediaDisplayName(
155
155
  return labels[t] ?? defaults[t];
156
156
  }
157
157
 
158
- /** Permissive Media shape — accepts spatie/laravel-medialibrary payloads. */
158
+ /** Permissive Media shape — accepts API media payloads. */
159
159
  export interface MediaLike {
160
160
  url?: string;
161
161
  mime_type?: string;
@@ -6,7 +6,7 @@ Dinero.globalLocale = "de-DE";
6
6
 
7
7
  export type NetGross = "net" | "gross";
8
8
 
9
- export interface PhpMoneyObject {
9
+ export interface MoneyObject {
10
10
  amount?: number;
11
11
  currency?: string;
12
12
  formatted?: string;
@@ -19,8 +19,8 @@ export interface PhpMoneyObject {
19
19
  */
20
20
  export interface PriceLike {
21
21
  id?: number;
22
- net_total?: PhpMoneyObject;
23
- gross_total?: PhpMoneyObject;
22
+ net_total?: MoneyObject;
23
+ gross_total?: MoneyObject;
24
24
  tax_percentage?: number;
25
25
  valid_from?: string;
26
26
  input_value?: number;
@@ -55,7 +55,7 @@ interface MoneyShape {
55
55
  value?: { amount?: number };
56
56
  }
57
57
 
58
- type MoneyInput = number | string | MoneyShape | PhpMoneyObject | null | undefined;
58
+ type MoneyInput = number | string | MoneyShape | MoneyObject | null | undefined;
59
59
 
60
60
  export function money(amount: MoneyInput): DineroType {
61
61
  try {
@@ -0,0 +1,92 @@
1
+ /**
2
+ * Shared HTML-sanitizing policy for TipTap rich text (posts, knowledge
3
+ * articles, …). The allow-lists live HERE so the app that writes content
4
+ * and the surfaces that render it (homepage, future clients)
5
+ * can never drift apart — a drift would mean content is sanitized
6
+ * differently where it's written versus where it's publicly shown.
7
+ *
8
+ * The SDK deliberately has no DOMPurify dependency: consumers pass their
9
+ * own instance to {@link createHtmlSanitizers} (browser DOMPurify,
10
+ * isomorphic-dompurify on SSR, …).
11
+ */
12
+
13
+ /** Structural subset of DOMPurify we rely on — keeps it a peer concern. */
14
+ export interface HtmlPurifier {
15
+ sanitize(html: string, config?: Record<string, unknown>): string;
16
+ }
17
+
18
+ /**
19
+ * Rich text from the TipTap post editor: common formatting, headings,
20
+ * links, lists, quotes and code.
21
+ */
22
+ export const richTextSanitizeConfig = {
23
+ ALLOWED_TAGS: [
24
+ "p",
25
+ "br",
26
+ "strong",
27
+ "em",
28
+ "u",
29
+ "s",
30
+ "a",
31
+ "h1",
32
+ "h2",
33
+ "h3",
34
+ "h4",
35
+ "h5",
36
+ "h6",
37
+ "ul",
38
+ "ol",
39
+ "li",
40
+ "blockquote",
41
+ "code",
42
+ "pre",
43
+ ],
44
+ ALLOWED_ATTR: ["href", "target", "rel", "class", "style"],
45
+ ALLOW_DATA_ATTR: false,
46
+ } as const;
47
+
48
+ /** Minimal inline formatting — simple comments and basic text fields. */
49
+ export const basicTextSanitizeConfig = {
50
+ ALLOWED_TAGS: ["br", "a", "strong", "em", "code", "p"],
51
+ ALLOWED_ATTR: ["href", "target", "rel", "class"],
52
+ ALLOW_DATA_ATTR: false,
53
+ } as const;
54
+
55
+ /** Everything stripped — plain-text snippets and previews. */
56
+ export const stripSanitizeConfig = {
57
+ ALLOWED_TAGS: [],
58
+ ALLOWED_ATTR: [],
59
+ } as const;
60
+
61
+ /**
62
+ * Bind the shared policies to a DOMPurify(-compatible) instance.
63
+ *
64
+ * @example
65
+ * import DOMPurify from "dompurify";
66
+ * const { sanitizeRichText, stripHtml } = createHtmlSanitizers(DOMPurify);
67
+ */
68
+ export function createHtmlSanitizers(purifier: HtmlPurifier) {
69
+ const sanitize = (
70
+ html: string | null | undefined,
71
+ config?: Record<string, unknown>,
72
+ ): string => {
73
+ if (!html) {
74
+ return "";
75
+ }
76
+ return purifier.sanitize(html, config);
77
+ };
78
+
79
+ const sanitizeRichText = (html: string | null | undefined): string =>
80
+ sanitize(html, richTextSanitizeConfig as unknown as Record<string, unknown>);
81
+
82
+ const sanitizeBasicText = (html: string | null | undefined): string =>
83
+ sanitize(html, basicTextSanitizeConfig as unknown as Record<string, unknown>);
84
+
85
+ /** Strip all HTML to whitespace-normalized plain text. */
86
+ const stripHtml = (html: string | null | undefined): string =>
87
+ sanitize(html, stripSanitizeConfig as unknown as Record<string, unknown>)
88
+ .replace(/\s+/g, " ")
89
+ .trim();
90
+
91
+ return { sanitize, sanitizeRichText, sanitizeBasicText, stripHtml };
92
+ }
@@ -11,7 +11,7 @@ export const zContactDTO = z.object({
11
11
  company: z.string().nullable().optional(),
12
12
  fax: z.string().nullable().optional(),
13
13
  });
14
- export const zPhpMoneyObject = z.object({
14
+ export const zMoneyObject = z.object({
15
15
  amount: z.number(),
16
16
  currency: z.string(),
17
17
  formatted: z.string(),
@@ -1,8 +1,7 @@
1
1
  import { z } from "zod";
2
2
 
3
3
  /**
4
- * Company-scoped equipment catalog entry (m-crit-api
5
- * docs/features/airplane-equipment.md). Assigned to airplanes via the
4
+ * Company-scoped equipment catalog entry, assigned to airplanes via the
6
5
  * airplane PATCH `equipment` array.
7
6
  */
8
7
  export const equipmentSchema = z.object({
@@ -202,7 +202,7 @@ export const SignatureSchema = z.object({
202
202
  updated_at: z.string().optional(),
203
203
  });
204
204
 
205
- // Spatie MediaResource subset used by file_upload fields.
205
+ // MediaResource subset used by file_upload fields.
206
206
  export const SubmissionFileSchema = z.object({
207
207
  id: z.number(),
208
208
  file_name: z.string(),