@bash-app/bash-common 30.329.0 → 30.331.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.
@@ -0,0 +1,95 @@
1
+ /**
2
+ * Event location sharing — consented near-live pins for bash participants
3
+ * (host / organizers / co-hosts, live task assignees, hired providers).
4
+ */
5
+ import { PUBLIC_TEASER_USER_DATA_TO_SELECT } from "./extendedSchemas.js";
6
+ /** Grace after event end before an Active session auto-expires. */
7
+ export const LOCATION_SHARE_GRACE_MS = 4 * 60 * 60 * 1000;
8
+ /** Fallback TTL when the bash has no start/end times. */
9
+ export const LOCATION_SHARE_DEFAULT_TTL_MS = 24 * 60 * 60 * 1000;
10
+ /** Fallback window after start when end is missing. */
11
+ export const LOCATION_SHARE_START_FALLBACK_MS = 12 * 60 * 60 * 1000;
12
+ export const LocationShareStatus = {
13
+ Active: "Active",
14
+ Stopped: "Stopped",
15
+ Expired: "Expired",
16
+ };
17
+ /** EventTask statuses that allow location share (assignee). */
18
+ export const LOCATION_SHARE_TASK_STATUSES = [
19
+ "Accepted",
20
+ "Assigned",
21
+ "InProgress",
22
+ ];
23
+ /** ServiceBooking statuses that allow location share (provider). */
24
+ export const LOCATION_SHARE_BOOKING_STATUSES = [
25
+ "Approved",
26
+ "Confirmed",
27
+ ];
28
+ export function isLocationShareLiveTaskStatus(status) {
29
+ return (status != null &&
30
+ LOCATION_SHARE_TASK_STATUSES.includes(status));
31
+ }
32
+ export function isLocationShareLiveBookingStatus(status) {
33
+ return (status != null &&
34
+ LOCATION_SHARE_BOOKING_STATUSES.includes(status));
35
+ }
36
+ /**
37
+ * True when the user is the event creator or an AssociatedBash organizer/co-host.
38
+ * Super-users are intentionally not included.
39
+ */
40
+ export function isLocationShareCrewMember(userId, bash, association) {
41
+ if (!userId)
42
+ return false;
43
+ if (userId === bash.creatorId)
44
+ return true;
45
+ if (association?.isOrganizer === true || association?.isCoHost === true) {
46
+ return true;
47
+ }
48
+ return false;
49
+ }
50
+ /**
51
+ * Sync eligibility when the caller already knows task/booking flags
52
+ * (e.g. tests or UI that prefetched live assignment). API resolves flags via Prisma.
53
+ */
54
+ export function isLocationShareEventParticipant(userId, bash, options) {
55
+ if (isLocationShareCrewMember(userId, bash, options?.association ?? null)) {
56
+ return true;
57
+ }
58
+ if (!userId)
59
+ return false;
60
+ return Boolean(options?.hasLiveTaskAssignment ||
61
+ options?.hasLiveHiredBooking ||
62
+ options?.hasActivePromoterRole);
63
+ }
64
+ /**
65
+ * Compute session expiry from bash times (end + grace, else start + 12h, else now + 24h).
66
+ */
67
+ export function computeLocationShareExpiresAt(bash, now = new Date()) {
68
+ const end = bash.endDateTime ? new Date(bash.endDateTime) : null;
69
+ if (end && !Number.isNaN(end.getTime())) {
70
+ return new Date(end.getTime() + LOCATION_SHARE_GRACE_MS);
71
+ }
72
+ const start = bash.startDateTime ? new Date(bash.startDateTime) : null;
73
+ if (start && !Number.isNaN(start.getTime())) {
74
+ return new Date(start.getTime() + LOCATION_SHARE_START_FALLBACK_MS);
75
+ }
76
+ return new Date(now.getTime() + LOCATION_SHARE_DEFAULT_TTL_MS);
77
+ }
78
+ export const LOCATION_SHARE_SESSION_USER_SELECT = {
79
+ ...PUBLIC_TEASER_USER_DATA_TO_SELECT,
80
+ };
81
+ export const LOCATION_SHARE_SESSION_LIST_SELECT = {
82
+ id: true,
83
+ bashEventId: true,
84
+ userId: true,
85
+ status: true,
86
+ startedAt: true,
87
+ expiresAt: true,
88
+ stoppedAt: true,
89
+ lastLat: true,
90
+ lastLng: true,
91
+ lastAccuracyM: true,
92
+ lastUpdatedAt: true,
93
+ user: { select: LOCATION_SHARE_SESSION_USER_SELECT },
94
+ };
95
+ //# sourceMappingURL=locationShare.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"locationShare.js","sourceRoot":"","sources":["../src/locationShare.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bash-app/bash-common",
3
- "version": "30.329.0",
3
+ "version": "30.331.0",
4
4
  "description": "Common data and scripts to use on the frontend and backend",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -1028,6 +1028,7 @@ model BashEvent {
1028
1028
  sponsorships SponsoredEvent[]
1029
1029
  tickets Ticket[]
1030
1030
  hostCrmCommunityPromptDismisses HostCrmCommunityPromptDismiss[]
1031
+ hostPromoterPayouts HostPromoterPayout[]
1031
1032
  ticketGiftGrants TicketGiftGrant[]
1032
1033
  ticketTiers TicketTier[]
1033
1034
  tierReleaseReminders TierReleaseReminder[]
@@ -1135,6 +1136,9 @@ model BashEvent {
1135
1136
  promotionBlasts PromotionBlast[]
1136
1137
  orgPromotionalPackages OrgPromotionalPackage[]
1137
1138
 
1139
+ /// Crew location sharing (host + organizers/co-hosts opt-in near-live pins)
1140
+ locationShareSessions LocationShareSession[]
1141
+
1138
1142
  @@index([templateId])
1139
1143
  @@index([parentEventId])
1140
1144
  @@index([organizationId])
@@ -2504,6 +2508,36 @@ model EventNetworkingOptIn {
2504
2508
  @@index([bashEventId])
2505
2509
  }
2506
2510
 
2511
+ /// Consented near-live location share for bash crew (host / organizers / co-hosts).
2512
+ /// One row per (bashEventId, userId); restart reactivates the same row.
2513
+ /// Follow-ons (tasks, door staff, service bookings) can extend audience rules without a second GPS stack.
2514
+ model LocationShareSession {
2515
+ id String @id @default(cuid())
2516
+ bashEventId String
2517
+ userId String
2518
+ status LocationShareStatus @default(Active)
2519
+ startedAt DateTime @default(now())
2520
+ expiresAt DateTime
2521
+ stoppedAt DateTime?
2522
+ lastLat Float?
2523
+ lastLng Float?
2524
+ lastAccuracyM Float?
2525
+ lastUpdatedAt DateTime?
2526
+
2527
+ bashEvent BashEvent @relation(fields: [bashEventId], references: [id], onDelete: Cascade)
2528
+ user User @relation(fields: [userId], references: [id], onDelete: Cascade)
2529
+
2530
+ @@unique([bashEventId, userId])
2531
+ @@index([bashEventId, status, lastUpdatedAt])
2532
+ @@index([userId, status])
2533
+ }
2534
+
2535
+ enum LocationShareStatus {
2536
+ Active
2537
+ Stopped
2538
+ Expired
2539
+ }
2540
+
2507
2541
  /// Host-scoped CRM row for a past guest (VIP tags, notes)
2508
2542
  model HostAttendeeProfile {
2509
2543
  id String @id @default(cuid())
@@ -2568,6 +2602,91 @@ model HostCrmCommunityPromptDismiss {
2568
2602
  @@index([hostUserId])
2569
2603
  }
2570
2604
 
2605
+ /// Host-owned promoter roster (Community Builder → Promoters).
2606
+ /// Distinct from per-bash `Promoter` (promo-code assignment) and hireable Event Promoter bookings.
2607
+ model HostPromoter {
2608
+ id String @id @default(cuid())
2609
+ hostUserId String
2610
+ /// Linked Bash user when known; null for email-only ad-hoc / pending invites.
2611
+ promoterUserId String?
2612
+ /// Normalized lowercase email (required for ad-hoc add and invite).
2613
+ email String
2614
+ displayName String?
2615
+ /// "PromoCode" | "EventPromoter" | "Influencer" | "ContentCreator" | "Model" | "BrandAmbassador"
2616
+ kinds String[] @default([])
2617
+ status HostPromoterStatus @default(Active)
2618
+ notes String? @db.Text
2619
+ defaultBashPointsRewardPerTicket Int?
2620
+ /// Nano / Micro / Macro / Mega when kinds includes Influencer (optional).
2621
+ influencerAudienceTier InfluencerAudienceTier?
2622
+ /// "Manual" | "PastPromoCode" | "PastEventBooking"
2623
+ sources String[] @default([])
2624
+ lastPromotedAt DateTime?
2625
+ createdAt DateTime @default(now())
2626
+ updatedAt DateTime @updatedAt
2627
+
2628
+ host User @relation("HostPromotersOwned", fields: [hostUserId], references: [id], onDelete: Cascade)
2629
+ promoter User? @relation("HostPromotersAsPromoter", fields: [promoterUserId], references: [id], onDelete: SetNull)
2630
+ payouts HostPromoterPayout[]
2631
+
2632
+ @@unique([hostUserId, email])
2633
+ @@index([hostUserId, status])
2634
+ @@index([hostUserId, promoterUserId])
2635
+ }
2636
+
2637
+ enum HostPromoterStatus {
2638
+ Active
2639
+ Archived
2640
+ }
2641
+
2642
+ /// Off-platform cash ledger OR platform Stripe Connect payout for host bookkeeping.
2643
+ /// OffPlatform does not move money. Platform uses Checkout + Connect destination transfer.
2644
+ model HostPromoterPayout {
2645
+ id String @id @default(cuid())
2646
+ hostPromoterId String
2647
+ bashEventId String?
2648
+ serviceBookingId String?
2649
+ amountCents Int
2650
+ currency String @default("usd")
2651
+ status HostPromoterPayoutStatus @default(Unpaid)
2652
+ method HostPromoterPayoutMethod @default(Other)
2653
+ channel HostPromoterPayoutChannel @default(OffPlatform)
2654
+ stripeCheckoutSessionId String?
2655
+ stripePaymentIntentId String?
2656
+ platformFeeCents Int @default(0)
2657
+ paidAt DateTime?
2658
+ note String? @db.Text
2659
+ createdAt DateTime @default(now())
2660
+ updatedAt DateTime @updatedAt
2661
+
2662
+ hostPromoter HostPromoter @relation(fields: [hostPromoterId], references: [id], onDelete: Cascade)
2663
+ bashEvent BashEvent? @relation(fields: [bashEventId], references: [id], onDelete: SetNull)
2664
+ serviceBooking ServiceBooking? @relation(fields: [serviceBookingId], references: [id], onDelete: SetNull)
2665
+
2666
+ @@index([hostPromoterId, status])
2667
+ @@index([bashEventId])
2668
+ @@index([serviceBookingId])
2669
+ }
2670
+
2671
+ enum HostPromoterPayoutStatus {
2672
+ Unpaid
2673
+ Paid
2674
+ Cancelled
2675
+ }
2676
+
2677
+ enum HostPromoterPayoutMethod {
2678
+ Venmo
2679
+ Zelle
2680
+ CashApp
2681
+ Cash
2682
+ Other
2683
+ }
2684
+
2685
+ enum HostPromoterPayoutChannel {
2686
+ OffPlatform
2687
+ Platform
2688
+ }
2689
+
2571
2690
  /// Host-defined reusable CRM audience filters (tag, cadence, lapsed, cohorts).
2572
2691
  model HostCrmSavedSegment {
2573
2692
  id String @id @default(cuid())
@@ -3036,6 +3155,8 @@ model Ticket {
3036
3155
  invitationId String?
3037
3156
  checkoutId String?
3038
3157
  checkedInMethod String? @default("manual")
3158
+ /// Door staff user who confirmed cash collected (door_cash path).
3159
+ cashMarkedById String?
3039
3160
  waitlistPosition Int?
3040
3161
  waitlistJoinedAt DateTime?
3041
3162
  waitlistNotifiedAt DateTime?
@@ -3878,6 +3999,7 @@ model User {
3878
3999
 
3879
4000
  associatedBashes AssociatedBash[]
3880
4001
  associatedServices AssociatedService[]
4002
+ locationShareSessions LocationShareSession[]
3881
4003
  comment BashComment[]
3882
4004
  referredTransactions BashCreditTransaction[] @relation("ReferredUser")
3883
4005
  creditTransactions BashCreditTransaction[]
@@ -4045,6 +4167,8 @@ model User {
4045
4167
  hostAttendeeActivityAsHost HostAttendeeActivity[] @relation("HostAttendeeActivityHost")
4046
4168
  hostAttendeeActivityAsTarget HostAttendeeActivity[] @relation("HostAttendeeActivityAttendee")
4047
4169
  hostCrmCommunityPromptDismisses HostCrmCommunityPromptDismiss[] @relation("HostCrmCommunityPromptDismissHost")
4170
+ hostPromotersOwned HostPromoter[] @relation("HostPromotersOwned")
4171
+ hostPromotersAsPromoter HostPromoter[] @relation("HostPromotersAsPromoter")
4048
4172
  bashListsCreated BashList[]
4049
4173
  userItineraries UserItinerary[]
4050
4174
  aiRecommendationLogs AIRecommendationLog[]
@@ -6468,6 +6592,7 @@ model ServiceBooking {
6468
6592
  sentReminders SentReminder[]
6469
6593
  offers ServiceBookingOffer[]
6470
6594
  promotionBlastEntitlement PromotionBlastEntitlement?
6595
+ hostPromoterPayouts HostPromoterPayout[]
6471
6596
 
6472
6597
  // Agency routing — all nullable; solo bookings unchanged.
6473
6598
  representedByOrganizationId String?
@@ -0,0 +1,122 @@
1
+ import {
2
+ computeLocationShareExpiresAt,
3
+ isLocationShareCrewMember,
4
+ isLocationShareEventParticipant,
5
+ isLocationShareLiveBookingStatus,
6
+ isLocationShareLiveTaskStatus,
7
+ LOCATION_SHARE_BOOKING_STATUSES,
8
+ LOCATION_SHARE_DEFAULT_TTL_MS,
9
+ LOCATION_SHARE_GRACE_MS,
10
+ LOCATION_SHARE_START_FALLBACK_MS,
11
+ LOCATION_SHARE_TASK_STATUSES,
12
+ } from "../locationShare.js";
13
+
14
+ describe("locationShare helpers", () => {
15
+ describe("isLocationShareCrewMember", () => {
16
+ it("allows the creator", () => {
17
+ expect(
18
+ isLocationShareCrewMember("u1", { creatorId: "u1" }, null)
19
+ ).toBe(true);
20
+ });
21
+
22
+ it("allows organizers and co-hosts", () => {
23
+ expect(
24
+ isLocationShareCrewMember("u2", { creatorId: "u1" }, {
25
+ isOrganizer: true,
26
+ })
27
+ ).toBe(true);
28
+ expect(
29
+ isLocationShareCrewMember("u3", { creatorId: "u1" }, {
30
+ isCoHost: true,
31
+ })
32
+ ).toBe(true);
33
+ });
34
+
35
+ it("rejects attendees", () => {
36
+ expect(
37
+ isLocationShareCrewMember("u4", { creatorId: "u1" }, {
38
+ isOrganizer: false,
39
+ isCoHost: false,
40
+ })
41
+ ).toBe(false);
42
+ expect(isLocationShareCrewMember(undefined, { creatorId: "u1" })).toBe(
43
+ false
44
+ );
45
+ });
46
+ });
47
+
48
+ describe("isLocationShareEventParticipant", () => {
49
+ it("allows live task assignees, hired providers, and promoters", () => {
50
+ expect(
51
+ isLocationShareEventParticipant("u2", { creatorId: "u1" }, {
52
+ hasLiveTaskAssignment: true,
53
+ })
54
+ ).toBe(true);
55
+ expect(
56
+ isLocationShareEventParticipant("u3", { creatorId: "u1" }, {
57
+ hasLiveHiredBooking: true,
58
+ })
59
+ ).toBe(true);
60
+ expect(
61
+ isLocationShareEventParticipant("u5", { creatorId: "u1" }, {
62
+ hasActivePromoterRole: true,
63
+ })
64
+ ).toBe(true);
65
+ });
66
+
67
+ it("rejects when no crew and no live role", () => {
68
+ expect(
69
+ isLocationShareEventParticipant("u4", { creatorId: "u1" }, {})
70
+ ).toBe(false);
71
+ });
72
+ });
73
+
74
+ describe("status allow-lists", () => {
75
+ it("includes live task and booking statuses", () => {
76
+ expect(LOCATION_SHARE_TASK_STATUSES).toEqual([
77
+ "Accepted",
78
+ "Assigned",
79
+ "InProgress",
80
+ ]);
81
+ expect(LOCATION_SHARE_BOOKING_STATUSES).toEqual([
82
+ "Approved",
83
+ "Confirmed",
84
+ ]);
85
+ expect(isLocationShareLiveTaskStatus("InProgress")).toBe(true);
86
+ expect(isLocationShareLiveTaskStatus("Completed")).toBe(false);
87
+ expect(isLocationShareLiveBookingStatus("Approved")).toBe(true);
88
+ expect(isLocationShareLiveBookingStatus("Pending")).toBe(false);
89
+ });
90
+ });
91
+
92
+ describe("computeLocationShareExpiresAt", () => {
93
+ const now = new Date("2026-07-23T12:00:00.000Z");
94
+
95
+ it("uses end + grace when end exists", () => {
96
+ const end = new Date("2026-07-23T18:00:00.000Z");
97
+ const expires = computeLocationShareExpiresAt(
98
+ { endDateTime: end, startDateTime: null },
99
+ now
100
+ );
101
+ expect(expires.getTime()).toBe(end.getTime() + LOCATION_SHARE_GRACE_MS);
102
+ });
103
+
104
+ it("falls back to start + 12h", () => {
105
+ const start = new Date("2026-07-23T14:00:00.000Z");
106
+ const expires = computeLocationShareExpiresAt(
107
+ { startDateTime: start, endDateTime: null },
108
+ now
109
+ );
110
+ expect(expires.getTime()).toBe(
111
+ start.getTime() + LOCATION_SHARE_START_FALLBACK_MS
112
+ );
113
+ });
114
+
115
+ it("falls back to now + 24h", () => {
116
+ const expires = computeLocationShareExpiresAt({}, now);
117
+ expect(expires.getTime()).toBe(
118
+ now.getTime() + LOCATION_SHARE_DEFAULT_TTL_MS
119
+ );
120
+ });
121
+ });
122
+ });