@bash-app/bash-common 30.367.0 → 30.370.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.
@@ -10,20 +10,29 @@ export declare const ACTIVE_ORG_SUBSCRIPTION_STATUSES: readonly ["Active", "Tria
10
10
  export interface OrganizationEntitlementInput {
11
11
  subscriptionTier?: string | null;
12
12
  subscriptionStatus?: string | null;
13
+ /**
14
+ * True only when ops provisioned Enterprise via a signed deal (admin
15
+ * enterprise-provisioning endpoint). Self-serve Stripe checkout can also set
16
+ * subscriptionTier="Enterprise" but never sets this. Optional/undefined is
17
+ * treated as false so legacy call sites that don't select this field fail
18
+ * closed on the sales-gated surface rather than open.
19
+ */
20
+ enterpriseSalesProvisioned?: boolean | null;
13
21
  }
14
22
  /**
15
- * Vanity subdomains ({slug}.bash.community) are an Enterprise-only perk. All other
16
- * orgs use the canonical path URL (bash.community/org/{slug}). Requires an active
17
- * (or trialing) subscription so a lapsed Enterprise org falls back to the path.
23
+ * Vanity subdomains ({slug}.bash.community) and custom domains (white-label)
24
+ * are self-serve-eligible Enterprise perks available whether Enterprise was
25
+ * bought via self-serve Stripe checkout or a sales-negotiated deal.
18
26
  */
19
27
  export declare function organizationHasVanitySubdomain(org: OrganizationEntitlementInput | null | undefined): boolean;
20
28
  /**
21
29
  * Shared gate for the enterprise platform surface: org-scoped audit logs,
22
30
  * SSO/identity setup, procurement approval policy, API keys, webhooks, and
23
- * third-party integrations (Mailchimp/Salesforce). All are Enterprise-tier
24
- * perks today same predicate as {@link organizationHasVanitySubdomain}, kept
25
- * as a distinct name so the two can diverge later (e.g. Growth gets audit
26
- * logs before SSO) without touching every call site.
31
+ * third-party integrations (Mailchimp/Salesforce). Unlike the white-label
32
+ * perks above, this surface requires a sales-negotiated deal
33
+ * (`enterpriseSalesProvisioned`) self-serve $495/mo checkout alone does not
34
+ * unlock SSO, compliance, procurement, or API access, since those typically
35
+ * involve a security review or contract terms sales owns.
27
36
  */
28
37
  export declare function organizationHasEnterprisePlatformAccess(org: OrganizationEntitlementInput | null | undefined): boolean;
29
38
  /** Org-admin audit log viewer + CSV export. */
@@ -36,4 +45,15 @@ export declare function organizationHasProcurementAccess(org: OrganizationEntitl
36
45
  export declare function organizationHasApiAccess(org: OrganizationEntitlementInput | null | undefined): boolean;
37
46
  /** Compliance docs (W-9 tax collection, certificate-of-insurance tracking). */
38
47
  export declare function organizationHasComplianceAccess(org: OrganizationEntitlementInput | null | undefined): boolean;
48
+ /**
49
+ * Custom domains (white-label tier): real DNS (e.g. members.acme.com) provisioned
50
+ * via AWS CloudFront SaaS Manager Distribution Tenants, plus the "Powered by Bash"
51
+ * removal toggle. Same Enterprise + active/trialing gate as
52
+ * {@link organizationHasVanitySubdomain} for MVP — reuse the existing tier rather
53
+ * than invent a new pricing tier now. A dedicated "White-label" tier is a
54
+ * fast-follow if sales needs separate pricing. Self-serve-eligible: does NOT
55
+ * require {@link organizationHasEnterprisePlatformAccess}'s
56
+ * `enterpriseSalesProvisioned` flag.
57
+ */
58
+ export declare function organizationHasCustomDomainAccess(org: OrganizationEntitlementInput | null | undefined): boolean;
39
59
  //# sourceMappingURL=organizationEntitlements.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"organizationEntitlements.d.ts","sourceRoot":"","sources":["../../src/utils/organizationEntitlements.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,2EAA2E;AAC3E,eAAO,MAAM,gCAAgC,iCAGnC,CAAC;AAEX,MAAM,WAAW,4BAA4B;IAC3C,gBAAgB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACjC,kBAAkB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CACpC;AAED;;;;GAIG;AACH,wBAAgB,8BAA8B,CAC5C,GAAG,EAAE,4BAA4B,GAAG,IAAI,GAAG,SAAS,GACnD,OAAO,CAUT;AAED;;;;;;;GAOG;AACH,wBAAgB,uCAAuC,CACrD,GAAG,EAAE,4BAA4B,GAAG,IAAI,GAAG,SAAS,GACnD,OAAO,CAET;AAED,+CAA+C;AAC/C,wBAAgB,6BAA6B,CAC3C,GAAG,EAAE,4BAA4B,GAAG,IAAI,GAAG,SAAS,GACnD,OAAO,CAET;AAED,0BAA0B;AAC1B,wBAAgB,wBAAwB,CACtC,GAAG,EAAE,4BAA4B,GAAG,IAAI,GAAG,SAAS,GACnD,OAAO,CAET;AAED,+DAA+D;AAC/D,wBAAgB,gCAAgC,CAC9C,GAAG,EAAE,4BAA4B,GAAG,IAAI,GAAG,SAAS,GACnD,OAAO,CAET;AAED,iEAAiE;AACjE,wBAAgB,wBAAwB,CACtC,GAAG,EAAE,4BAA4B,GAAG,IAAI,GAAG,SAAS,GACnD,OAAO,CAET;AAED,+EAA+E;AAC/E,wBAAgB,+BAA+B,CAC7C,GAAG,EAAE,4BAA4B,GAAG,IAAI,GAAG,SAAS,GACnD,OAAO,CAET"}
1
+ {"version":3,"file":"organizationEntitlements.d.ts","sourceRoot":"","sources":["../../src/utils/organizationEntitlements.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,2EAA2E;AAC3E,eAAO,MAAM,gCAAgC,iCAGnC,CAAC;AAEX,MAAM,WAAW,4BAA4B;IAC3C,gBAAgB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACjC,kBAAkB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACnC;;;;;;OAMG;IACH,0BAA0B,CAAC,EAAE,OAAO,GAAG,IAAI,CAAC;CAC7C;AAgBD;;;;GAIG;AACH,wBAAgB,8BAA8B,CAC5C,GAAG,EAAE,4BAA4B,GAAG,IAAI,GAAG,SAAS,GACnD,OAAO,CAET;AAED;;;;;;;;GAQG;AACH,wBAAgB,uCAAuC,CACrD,GAAG,EAAE,4BAA4B,GAAG,IAAI,GAAG,SAAS,GACnD,OAAO,CAET;AAED,+CAA+C;AAC/C,wBAAgB,6BAA6B,CAC3C,GAAG,EAAE,4BAA4B,GAAG,IAAI,GAAG,SAAS,GACnD,OAAO,CAET;AAED,0BAA0B;AAC1B,wBAAgB,wBAAwB,CACtC,GAAG,EAAE,4BAA4B,GAAG,IAAI,GAAG,SAAS,GACnD,OAAO,CAET;AAED,+DAA+D;AAC/D,wBAAgB,gCAAgC,CAC9C,GAAG,EAAE,4BAA4B,GAAG,IAAI,GAAG,SAAS,GACnD,OAAO,CAET;AAED,iEAAiE;AACjE,wBAAgB,wBAAwB,CACtC,GAAG,EAAE,4BAA4B,GAAG,IAAI,GAAG,SAAS,GACnD,OAAO,CAET;AAED,+EAA+E;AAC/E,wBAAgB,+BAA+B,CAC7C,GAAG,EAAE,4BAA4B,GAAG,IAAI,GAAG,SAAS,GACnD,OAAO,CAET;AAED;;;;;;;;;GASG;AACH,wBAAgB,iCAAiC,CAC/C,GAAG,EAAE,4BAA4B,GAAG,IAAI,GAAG,SAAS,GACnD,OAAO,CAET"}
@@ -10,12 +10,7 @@ export const ACTIVE_ORG_SUBSCRIPTION_STATUSES = [
10
10
  "Active",
11
11
  "Trialing",
12
12
  ];
13
- /**
14
- * Vanity subdomains ({slug}.bash.community) are an Enterprise-only perk. All other
15
- * orgs use the canonical path URL (bash.community/org/{slug}). Requires an active
16
- * (or trialing) subscription so a lapsed Enterprise org falls back to the path.
17
- */
18
- export function organizationHasVanitySubdomain(org) {
13
+ function hasActiveEnterpriseTier(org) {
19
14
  if (!org)
20
15
  return false;
21
16
  if (org.subscriptionTier !== "Enterprise")
@@ -27,16 +22,25 @@ export function organizationHasVanitySubdomain(org) {
27
22
  return true;
28
23
  return ACTIVE_ORG_SUBSCRIPTION_STATUSES.includes(org.subscriptionStatus);
29
24
  }
25
+ /**
26
+ * Vanity subdomains ({slug}.bash.community) and custom domains (white-label)
27
+ * are self-serve-eligible Enterprise perks — available whether Enterprise was
28
+ * bought via self-serve Stripe checkout or a sales-negotiated deal.
29
+ */
30
+ export function organizationHasVanitySubdomain(org) {
31
+ return hasActiveEnterpriseTier(org);
32
+ }
30
33
  /**
31
34
  * Shared gate for the enterprise platform surface: org-scoped audit logs,
32
35
  * SSO/identity setup, procurement approval policy, API keys, webhooks, and
33
- * third-party integrations (Mailchimp/Salesforce). All are Enterprise-tier
34
- * perks today same predicate as {@link organizationHasVanitySubdomain}, kept
35
- * as a distinct name so the two can diverge later (e.g. Growth gets audit
36
- * logs before SSO) without touching every call site.
36
+ * third-party integrations (Mailchimp/Salesforce). Unlike the white-label
37
+ * perks above, this surface requires a sales-negotiated deal
38
+ * (`enterpriseSalesProvisioned`) self-serve $495/mo checkout alone does not
39
+ * unlock SSO, compliance, procurement, or API access, since those typically
40
+ * involve a security review or contract terms sales owns.
37
41
  */
38
42
  export function organizationHasEnterprisePlatformAccess(org) {
39
- return organizationHasVanitySubdomain(org);
43
+ return hasActiveEnterpriseTier(org) && org?.enterpriseSalesProvisioned === true;
40
44
  }
41
45
  /** Org-admin audit log viewer + CSV export. */
42
46
  export function organizationHasAuditLogAccess(org) {
@@ -58,4 +62,17 @@ export function organizationHasApiAccess(org) {
58
62
  export function organizationHasComplianceAccess(org) {
59
63
  return organizationHasEnterprisePlatformAccess(org);
60
64
  }
65
+ /**
66
+ * Custom domains (white-label tier): real DNS (e.g. members.acme.com) provisioned
67
+ * via AWS CloudFront SaaS Manager Distribution Tenants, plus the "Powered by Bash"
68
+ * removal toggle. Same Enterprise + active/trialing gate as
69
+ * {@link organizationHasVanitySubdomain} for MVP — reuse the existing tier rather
70
+ * than invent a new pricing tier now. A dedicated "White-label" tier is a
71
+ * fast-follow if sales needs separate pricing. Self-serve-eligible: does NOT
72
+ * require {@link organizationHasEnterprisePlatformAccess}'s
73
+ * `enterpriseSalesProvisioned` flag.
74
+ */
75
+ export function organizationHasCustomDomainAccess(org) {
76
+ return organizationHasVanitySubdomain(org);
77
+ }
61
78
  //# sourceMappingURL=organizationEntitlements.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"organizationEntitlements.js","sourceRoot":"","sources":["../../src/utils/organizationEntitlements.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,2EAA2E;AAC3E,MAAM,CAAC,MAAM,gCAAgC,GAAG;IAC9C,QAAQ;IACR,UAAU;CACF,CAAC;AAOX;;;;GAIG;AACH,MAAM,UAAU,8BAA8B,CAC5C,GAAoD;IAEpD,IAAI,CAAC,GAAG;QAAE,OAAO,KAAK,CAAC;IACvB,IAAI,GAAG,CAAC,gBAAgB,KAAK,YAAY;QAAE,OAAO,KAAK,CAAC;IACxD,+EAA+E;IAC/E,4EAA4E;IAC5E,4BAA4B;IAC5B,IAAI,GAAG,CAAC,kBAAkB,IAAI,IAAI;QAAE,OAAO,IAAI,CAAC;IAChD,OAAQ,gCAAsD,CAAC,QAAQ,CACrE,GAAG,CAAC,kBAAkB,CACvB,CAAC;AACJ,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,uCAAuC,CACrD,GAAoD;IAEpD,OAAO,8BAA8B,CAAC,GAAG,CAAC,CAAC;AAC7C,CAAC;AAED,+CAA+C;AAC/C,MAAM,UAAU,6BAA6B,CAC3C,GAAoD;IAEpD,OAAO,uCAAuC,CAAC,GAAG,CAAC,CAAC;AACtD,CAAC;AAED,0BAA0B;AAC1B,MAAM,UAAU,wBAAwB,CACtC,GAAoD;IAEpD,OAAO,uCAAuC,CAAC,GAAG,CAAC,CAAC;AACtD,CAAC;AAED,+DAA+D;AAC/D,MAAM,UAAU,gCAAgC,CAC9C,GAAoD;IAEpD,OAAO,uCAAuC,CAAC,GAAG,CAAC,CAAC;AACtD,CAAC;AAED,iEAAiE;AACjE,MAAM,UAAU,wBAAwB,CACtC,GAAoD;IAEpD,OAAO,uCAAuC,CAAC,GAAG,CAAC,CAAC;AACtD,CAAC;AAED,+EAA+E;AAC/E,MAAM,UAAU,+BAA+B,CAC7C,GAAoD;IAEpD,OAAO,uCAAuC,CAAC,GAAG,CAAC,CAAC;AACtD,CAAC"}
1
+ {"version":3,"file":"organizationEntitlements.js","sourceRoot":"","sources":["../../src/utils/organizationEntitlements.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,2EAA2E;AAC3E,MAAM,CAAC,MAAM,gCAAgC,GAAG;IAC9C,QAAQ;IACR,UAAU;CACF,CAAC;AAeX,SAAS,uBAAuB,CAC9B,GAAoD;IAEpD,IAAI,CAAC,GAAG;QAAE,OAAO,KAAK,CAAC;IACvB,IAAI,GAAG,CAAC,gBAAgB,KAAK,YAAY;QAAE,OAAO,KAAK,CAAC;IACxD,+EAA+E;IAC/E,4EAA4E;IAC5E,4BAA4B;IAC5B,IAAI,GAAG,CAAC,kBAAkB,IAAI,IAAI;QAAE,OAAO,IAAI,CAAC;IAChD,OAAQ,gCAAsD,CAAC,QAAQ,CACrE,GAAG,CAAC,kBAAkB,CACvB,CAAC;AACJ,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,8BAA8B,CAC5C,GAAoD;IAEpD,OAAO,uBAAuB,CAAC,GAAG,CAAC,CAAC;AACtC,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,UAAU,uCAAuC,CACrD,GAAoD;IAEpD,OAAO,uBAAuB,CAAC,GAAG,CAAC,IAAI,GAAG,EAAE,0BAA0B,KAAK,IAAI,CAAC;AAClF,CAAC;AAED,+CAA+C;AAC/C,MAAM,UAAU,6BAA6B,CAC3C,GAAoD;IAEpD,OAAO,uCAAuC,CAAC,GAAG,CAAC,CAAC;AACtD,CAAC;AAED,0BAA0B;AAC1B,MAAM,UAAU,wBAAwB,CACtC,GAAoD;IAEpD,OAAO,uCAAuC,CAAC,GAAG,CAAC,CAAC;AACtD,CAAC;AAED,+DAA+D;AAC/D,MAAM,UAAU,gCAAgC,CAC9C,GAAoD;IAEpD,OAAO,uCAAuC,CAAC,GAAG,CAAC,CAAC;AACtD,CAAC;AAED,iEAAiE;AACjE,MAAM,UAAU,wBAAwB,CACtC,GAAoD;IAEpD,OAAO,uCAAuC,CAAC,GAAG,CAAC,CAAC;AACtD,CAAC;AAED,+EAA+E;AAC/E,MAAM,UAAU,+BAA+B,CAC7C,GAAoD;IAEpD,OAAO,uCAAuC,CAAC,GAAG,CAAC,CAAC;AACtD,CAAC;AAED;;;;;;;;;GASG;AACH,MAAM,UAAU,iCAAiC,CAC/C,GAAoD;IAEpD,OAAO,8BAA8B,CAAC,GAAG,CAAC,CAAC;AAC7C,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bash-app/bash-common",
3
- "version": "30.367.0",
3
+ "version": "30.370.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",
@@ -929,6 +929,9 @@ model BashEvent {
929
929
  attendeeListPublic Boolean @default(false)
930
930
  /// Preview = count + curated faces; Public = full list for everyone; TicketHolders = full list for ticket buyers only.
931
931
  attendeeListAccess String @default("Preview")
932
+ /// When true, only accounts with a published service profile (Vendor/Venue/Entertainment/Exhibitor/Sponsor/Event
933
+ /// Service) can view budget lines revealed via `Budget.showOnBashDetailPage`. Default off = anyone can click to view.
934
+ budgetRestrictedToServiceProviders Boolean @default(false)
932
935
  /// When true on Rsvp-mode events, affirmative RSVPs land in a host approval queue first.
933
936
  rsvpRequiresApproval Boolean @default(false)
934
937
  /// Hide when guests RSVP'd on host-facing attendee views.
@@ -1036,6 +1039,12 @@ model BashEvent {
1036
1039
  allowMemberGuests Boolean @default(false) // Members can bring +1s
1037
1040
  maxGuestsPerMember Int? // Guest limit per member (null = unlimited)
1038
1041
  restrictToOrgDepartments String[] @default([]) // Empty = all departments can see/join
1042
+ /// Discovery opt-out for portal-created events. DB default `true` preserves current
1043
+ /// behavior for every existing/consumer-created event. The Organization Workspace's
1044
+ /// event wizard sets this to `false` at creation (app-level default, not this DB
1045
+ /// default) so private-portal events don't leak into public Bash discovery unless
1046
+ /// the host flips "Publish to Bash" on. See publicDiscoveryPredicate.ts.
1047
+ publishToBashDiscovery Boolean @default(true)
1039
1048
 
1040
1049
  /// When true, new event expenses default to Pending until host/org approves (see Expense.status).
1041
1050
  requireExpenseApproval Boolean @default(false)
@@ -3377,6 +3386,14 @@ model Ticket {
3377
3386
  lastReminded24hAt DateTime?
3378
3387
  lastReminded1weekAt DateTime?
3379
3388
  lastReminded3hAt DateTime?
3389
+ /// Per-activity ActivityKit update/end push token, reported by the client once its
3390
+ /// Live Activity actually starts (distinct from the user-level push-to-start token
3391
+ /// in LiveActivityPushToken, which can only start new activities, not update/end them).
3392
+ liveActivityPushToken String?
3393
+ /// Set once the liveActivityLifecycle cron has sent the start push for this ticket; avoids duplicate sends.
3394
+ liveActivityStartPushedAt DateTime?
3395
+ /// Set once the liveActivityLifecycle cron has sent the end push for this ticket; avoids duplicate sends.
3396
+ liveActivityEndPushedAt DateTime?
3380
3397
  refundRequestedAt DateTime? // Set when RefundPending; cleared once refund processes
3381
3398
  /// Set when the guest keeps or declines after a postponement; cleared on each new Postpone.
3382
3399
  postponeRespondedAt DateTime?
@@ -3761,6 +3778,8 @@ model Media {
3761
3778
  sponsoredEventsReferencingMe SponsoredEvent[] @relation("MediaToSponsoredEvent")
3762
3779
  organizationsNonprofitDeterminationDoc Organization[] @relation("OrganizationNonprofitDeterminationDoc")
3763
3780
  memoryCaptures BashMemoryCapture[]
3781
+ courseLessonsReferencingMe CourseLesson[]
3782
+ organizationResourcesReferencingMe OrganizationResource[]
3764
3783
  }
3765
3784
 
3766
3785
  model Prize {
@@ -4385,6 +4404,7 @@ model User {
4385
4404
  feedbackTeamApplications FeedbackTeamApplication[]
4386
4405
  newsletterSubscriptions NewsletterSubscriber[]
4387
4406
  pushNotificationTokens PushNotificationToken[]
4407
+ liveActivityPushTokens LiveActivityPushToken[]
4388
4408
  redeemedVouchers Voucher[]
4389
4409
  bashEventPromoCodesIUsed BashEventPromoCode[] @relation("BashEventPromoCodeToUser")
4390
4410
  ticketTiersWaitListsIveJoined TicketTier[] @relation("TicketTierToUser")
@@ -4484,6 +4504,16 @@ model User {
4484
4504
  organizationEmailSubscriptions OrganizationSubscriber[]
4485
4505
  eventSeriesCreated EventSeries[] @relation("EventSeriesCreator")
4486
4506
 
4507
+ /// Organization Workspace: courses, quizzes/certificates, and community.
4508
+ coursesInstructed Course[] @relation("CourseInstructor")
4509
+ courseEnrollments CourseEnrollment[]
4510
+ courseQuizAttempts CourseQuizAttempt[]
4511
+ courseCertificates CourseCertificate[]
4512
+ communityPostsAuthored OrganizationCommunityPost[] @relation("OrganizationCommunityPostAuthor")
4513
+ communityCommentsAuthored OrganizationCommunityComment[] @relation("OrganizationCommunityCommentAuthor")
4514
+ communityPostLikes OrganizationCommunityPostLike[]
4515
+ communityPostReports OrganizationCommunityPostReport[]
4516
+
4487
4517
  // Service Includes & Add-On Requests
4488
4518
  suggestedIncludes ServiceInclude[] @relation("SuggestedIncludes")
4489
4519
  includeVotes ServiceIncludeVote[]
@@ -5572,6 +5602,14 @@ model Exhibitor {
5572
5602
  paymentTerms String? // Payment terms and conditions
5573
5603
  setupRequirements String? // Setup and breakdown requirements
5574
5604
 
5605
+ /// Phase 1 host bid/RFP matching opt-in — shared shape with VendorPreferences and Sponsor
5606
+ /// (see docs/product/VENDOR_HIRE_BID_SIGNUP_SPEC.md).
5607
+ openToHostBids Boolean @default(false)
5608
+ bidCategories String[] @default([])
5609
+ bidMinLeadDays Int?
5610
+ /// small | medium | large — typical event size the exhibitor is comfortable with.
5611
+ bidProjectSize String?
5612
+
5575
5613
  crowdSize AmountOfGuests? @relation(fields: [crowdSizeId], references: [id], onDelete: Cascade)
5576
5614
  serviceRange ServiceRange? @relation(fields: [serviceRangeId], references: [id])
5577
5615
  service Service?
@@ -5600,6 +5638,14 @@ model Sponsor {
5600
5638
  contractTerms String? // Contract terms and conditions
5601
5639
  paymentTerms String? // Payment terms and requirements
5602
5640
 
5641
+ /// Phase 1 host bid/RFP matching opt-in — shared shape with VendorPreferences and Exhibitor
5642
+ /// (see docs/product/VENDOR_HIRE_BID_SIGNUP_SPEC.md).
5643
+ openToHostBids Boolean @default(false)
5644
+ bidCategories String[] @default([])
5645
+ bidMinLeadDays Int?
5646
+ /// small | medium | large — typical event size the sponsor is comfortable with.
5647
+ bidProjectSize String?
5648
+
5603
5649
  service Service?
5604
5650
  crowdSize AmountOfGuests? @relation(fields: [crowdSizeId], references: [id])
5605
5651
  serviceRange ServiceRange? @relation(fields: [serviceRangeId], references: [id])
@@ -5874,6 +5920,31 @@ model Organization {
5874
5920
  stripeConnectedAccountId String? // Org-level Stripe account for wallet display
5875
5921
  accentColor String? // Hex color for org page branding (e.g. "#6366f1")
5876
5922
  inheritBrandingFromParent Boolean @default(true)
5923
+
5924
+ /// White-label branding + Organization Workspace modules. All additive with safe
5925
+ /// defaults — existing orgs are unaffected until a module is explicitly enabled.
5926
+ faviconUrl String?
5927
+ secondaryBrandColor String?
5928
+ fontPreset String? @default("default")
5929
+ coursesEnabled Boolean @default(false)
5930
+ communityEnabled Boolean @default(false)
5931
+ resourcesEnabled Boolean @default(false)
5932
+ removeBashBranding Boolean @default(false)
5933
+ /// Marks the single first-party "Bash Academy" org that hosts Bash's own courses/
5934
+ /// certificates (e.g. the event-planning certification program). Drives a
5935
+ /// "Certified by Bash" trust badge; no other special-casing anywhere else in the stack.
5936
+ isBashOfficial Boolean @default(false)
5937
+
5938
+ /// Custom domain (white-label tier), provisioned via AWS CloudFront SaaS Manager
5939
+ /// Distribution Tenants + CloudFront-managed ACM certs. See organizationDomainApi.ts.
5940
+ customDomain String? @unique
5941
+ customDomainStatus CustomDomainStatus @default(Unverified)
5942
+ customDomainCname String?
5943
+ cloudfrontTenantId String?
5944
+ cloudfrontTenantArn String?
5945
+ customDomainVerifiedAt DateTime?
5946
+ customDomainLastCheckedAt DateTime?
5947
+
5877
5948
  latitude Float?
5878
5949
  longitude Float?
5879
5950
  createdAt DateTime @default(now())
@@ -5895,6 +5966,11 @@ model Organization {
5895
5966
  awayTeamGames Game[] @relation("AwayTeamGames")
5896
5967
  products OrgProduct[]
5897
5968
 
5969
+ /// Organization Workspace modules (additive, gated by the *Enabled flags above).
5970
+ courses Course[]
5971
+ communityPosts OrganizationCommunityPost[]
5972
+ resources OrganizationResource[]
5973
+
5898
5974
  /// Verified-nonprofit fields. Verification is a Bash-side admin action driven by
5899
5975
  /// the host's uploaded determination letter (nonprofitDeterminationDocId). These
5900
5976
  /// are the ONLY signals fee-math is allowed to read — `BashEvent.nonProfit` is
@@ -5949,6 +6025,15 @@ model Organization {
5949
6025
  accountManager User? @relation("OrganizationAccountManager", fields: [accountManagerUserId], references: [id], onDelete: SetNull)
5950
6026
  /// "Standard" | "Priority" | "Dedicated" — drives named-AM banner + support routing copy.
5951
6027
  supportTier String @default("Standard")
6028
+ /// True only when ops set subscriptionTier="Enterprise" via the admin
6029
+ /// enterprise-provisioning endpoint (a signed deal). Self-serve Stripe checkout
6030
+ /// (organizationSubscriptionUtils.ts) can also set subscriptionTier="Enterprise"
6031
+ /// but never sets this flag. organizationHasEnterprisePlatformAccess() and the
6032
+ /// SSO/audit-log/procurement/compliance/API entitlements below require this flag
6033
+ /// in addition to the Enterprise tier — self-serve Enterprise unlocks white-label
6034
+ /// (organizationHasCustomDomainAccess/organizationHasVanitySubdomain do NOT
6035
+ /// require this flag) but not the sales-negotiated platform surface.
6036
+ enterpriseSalesProvisioned Boolean @default(false)
5952
6037
 
5953
6038
  /// SSO / identity (Organization Enterprise only). `ssoEnforced` blocks password
5954
6039
  /// login for members whose email matches `ssoDomain` once `ssoConnection.status`
@@ -5989,6 +6074,301 @@ model Organization {
5989
6074
  @@index([accountManagerUserId])
5990
6075
  }
5991
6076
 
6077
+ /// Custom-domain provisioning status (white-label tier). See Organization.customDomain*
6078
+ /// fields and organizationDomainApi.ts (AWS CloudFront SaaS Manager Distribution Tenants).
6079
+ enum CustomDomainStatus {
6080
+ Unverified
6081
+ PendingValidation
6082
+ Active
6083
+ Failed
6084
+ }
6085
+
6086
+ // ─── Organization Workspace: Courses, Quizzes & Certificates ─────────────────────
6087
+ // Generic, org-scoped course platform any Organization can enable via
6088
+ // `Organization.coursesEnabled`. Bash's own event-planning certification program
6089
+ // is not special-cased here — it is authored on a first-party "Bash Academy"
6090
+ // Organization (`Organization.isBashOfficial`) through this exact same model.
6091
+
6092
+ enum CourseVisibility {
6093
+ Public
6094
+ MembersOnly
6095
+ PremiumOnly
6096
+ Paid
6097
+ }
6098
+
6099
+ enum CourseStatus {
6100
+ Draft
6101
+ Published
6102
+ Archived
6103
+ }
6104
+
6105
+ model Course {
6106
+ id String @id @default(cuid())
6107
+ organizationId String
6108
+ title String
6109
+ slug String
6110
+ description String? @db.Text
6111
+ coverImage String?
6112
+ instructorUserId String
6113
+ visibility CourseVisibility @default(MembersOnly)
6114
+ priceCents Int?
6115
+ status CourseStatus @default(Draft)
6116
+ /// Requires a published CourseQuiz with >=1 question before this can be turned on.
6117
+ certificateEnabled Boolean @default(false)
6118
+ createdAt DateTime @default(now())
6119
+ updatedAt DateTime @updatedAt
6120
+
6121
+ organization Organization @relation(fields: [organizationId], references: [id], onDelete: Cascade)
6122
+ instructor User @relation("CourseInstructor", fields: [instructorUserId], references: [id], onDelete: Restrict)
6123
+ modules CourseModule[]
6124
+ lessons CourseLesson[]
6125
+ enrollments CourseEnrollment[]
6126
+ quiz CourseQuiz?
6127
+ certificates CourseCertificate[]
6128
+
6129
+ @@unique([organizationId, slug])
6130
+ @@index([organizationId])
6131
+ @@index([instructorUserId])
6132
+ }
6133
+
6134
+ model CourseModule {
6135
+ id String @id @default(cuid())
6136
+ courseId String
6137
+ title String
6138
+ sortOrder Int @default(0)
6139
+
6140
+ course Course @relation(fields: [courseId], references: [id], onDelete: Cascade)
6141
+ lessons CourseLesson[]
6142
+
6143
+ @@index([courseId])
6144
+ }
6145
+
6146
+ enum CourseLessonContentType {
6147
+ Video
6148
+ Text
6149
+ Embed
6150
+ File
6151
+ }
6152
+
6153
+ model CourseLesson {
6154
+ id String @id @default(cuid())
6155
+ courseId String
6156
+ moduleId String?
6157
+ title String
6158
+ contentType CourseLessonContentType @default(Text)
6159
+ videoUrl String?
6160
+ richTextContent String? @db.Text
6161
+ mediaId String?
6162
+ sortOrder Int @default(0)
6163
+ /// Viewable without enrolling — course "trailer" lesson(s).
6164
+ isPreviewable Boolean @default(false)
6165
+
6166
+ course Course @relation(fields: [courseId], references: [id], onDelete: Cascade)
6167
+ module CourseModule? @relation(fields: [moduleId], references: [id], onDelete: SetNull)
6168
+ media Media? @relation(fields: [mediaId], references: [id], onDelete: SetNull)
6169
+ progressEntries CourseLessonProgress[]
6170
+
6171
+ @@index([courseId])
6172
+ @@index([moduleId])
6173
+ }
6174
+
6175
+ enum CourseEnrollmentSource {
6176
+ Membership
6177
+ Purchase
6178
+ Manual
6179
+ }
6180
+
6181
+ model CourseEnrollment {
6182
+ id String @id @default(cuid())
6183
+ courseId String
6184
+ userId String
6185
+ source CourseEnrollmentSource @default(Membership)
6186
+ stripePaymentIntentId String?
6187
+ enrolledAt DateTime @default(now())
6188
+
6189
+ course Course @relation(fields: [courseId], references: [id], onDelete: Cascade)
6190
+ user User @relation(fields: [userId], references: [id], onDelete: Cascade)
6191
+ lessonProgress CourseLessonProgress[]
6192
+ quizAttempts CourseQuizAttempt[]
6193
+ certificate CourseCertificate?
6194
+
6195
+ @@unique([courseId, userId])
6196
+ @@index([courseId])
6197
+ @@index([userId])
6198
+ }
6199
+
6200
+ model CourseLessonProgress {
6201
+ id String @id @default(cuid())
6202
+ enrollmentId String
6203
+ lessonId String
6204
+ completedAt DateTime?
6205
+
6206
+ enrollment CourseEnrollment @relation(fields: [enrollmentId], references: [id], onDelete: Cascade)
6207
+ lesson CourseLesson @relation(fields: [lessonId], references: [id], onDelete: Cascade)
6208
+
6209
+ @@unique([enrollmentId, lessonId])
6210
+ @@index([lessonId])
6211
+ }
6212
+
6213
+ /// One final quiz gates the certificate (MVP). Per-module quizzes are a natural
6214
+ /// fast-follow with the same shape.
6215
+ model CourseQuiz {
6216
+ id String @id @default(cuid())
6217
+ courseId String @unique
6218
+ passThresholdPercent Int @default(80)
6219
+
6220
+ course Course @relation(fields: [courseId], references: [id], onDelete: Cascade)
6221
+ questions CourseQuizQuestion[]
6222
+ attempts CourseQuizAttempt[]
6223
+ }
6224
+
6225
+ model CourseQuizQuestion {
6226
+ id String @id @default(cuid())
6227
+ quizId String
6228
+ prompt String @db.Text
6229
+ /// [{ id: string, text: string }, ...]
6230
+ choices Json
6231
+ correctChoiceId String
6232
+ sortOrder Int @default(0)
6233
+
6234
+ quiz CourseQuiz @relation(fields: [quizId], references: [id], onDelete: Cascade)
6235
+
6236
+ @@index([quizId])
6237
+ }
6238
+
6239
+ model CourseQuizAttempt {
6240
+ id String @id @default(cuid())
6241
+ quizId String
6242
+ enrollmentId String
6243
+ userId String
6244
+ scorePercent Int
6245
+ passed Boolean
6246
+ /// [{ questionId: string, choiceId: string }, ...]
6247
+ answers Json
6248
+ attemptedAt DateTime @default(now())
6249
+
6250
+ quiz CourseQuiz @relation(fields: [quizId], references: [id], onDelete: Cascade)
6251
+ enrollment CourseEnrollment @relation(fields: [enrollmentId], references: [id], onDelete: Cascade)
6252
+ user User @relation(fields: [userId], references: [id], onDelete: Cascade)
6253
+
6254
+ @@index([quizId])
6255
+ @@index([enrollmentId])
6256
+ }
6257
+
6258
+ /// Auto-issued (server-side, never client-trusted) the moment a CourseQuizAttempt
6259
+ /// for the user's enrollment passes AND all non-preview lessons are complete.
6260
+ /// `certificateNumber` — never the DB id — is the public verification token used by
6261
+ /// GET /courses/certificates/verify/:certificateNumber.
6262
+ model CourseCertificate {
6263
+ id String @id @default(cuid())
6264
+ courseId String
6265
+ enrollmentId String @unique
6266
+ userId String
6267
+ certificateNumber String @unique @default(cuid())
6268
+ quizAttemptId String?
6269
+ issuedAt DateTime @default(now())
6270
+ revokedAt DateTime?
6271
+
6272
+ course Course @relation(fields: [courseId], references: [id], onDelete: Cascade)
6273
+ enrollment CourseEnrollment @relation(fields: [enrollmentId], references: [id], onDelete: Cascade)
6274
+ user User @relation(fields: [userId], references: [id], onDelete: Cascade)
6275
+
6276
+ @@unique([courseId, userId])
6277
+ @@index([certificateNumber])
6278
+ @@index([userId])
6279
+ }
6280
+
6281
+ // ─── Organization Workspace: Resources ────────────────────────────────────────────
6282
+
6283
+ enum ResourceVisibility {
6284
+ Public
6285
+ MembersOnly
6286
+ }
6287
+
6288
+ model OrganizationResource {
6289
+ id String @id @default(cuid())
6290
+ organizationId String
6291
+ title String
6292
+ description String? @db.Text
6293
+ url String?
6294
+ mediaId String?
6295
+ category String?
6296
+ visibility ResourceVisibility @default(MembersOnly)
6297
+ sortOrder Int @default(0)
6298
+ createdAt DateTime @default(now())
6299
+
6300
+ organization Organization @relation(fields: [organizationId], references: [id], onDelete: Cascade)
6301
+ media Media? @relation(fields: [mediaId], references: [id], onDelete: SetNull)
6302
+
6303
+ @@index([organizationId])
6304
+ }
6305
+
6306
+ // ─── Organization Workspace: Community ────────────────────────────────────────────
6307
+ // Mirrors the EventDiscussionComment shape, scoped to an Organization instead of a
6308
+ // single BashEvent. Gated by `Organization.communityEnabled` + active membership or
6309
+ // `Organization.visibility === "Public"`.
6310
+
6311
+ model OrganizationCommunityPost {
6312
+ id String @id @default(cuid())
6313
+ organizationId String
6314
+ authorUserId String
6315
+ content String @db.Text
6316
+ pinnedAt DateTime?
6317
+ createdAt DateTime @default(now())
6318
+ updatedAt DateTime @updatedAt
6319
+
6320
+ organization Organization @relation(fields: [organizationId], references: [id], onDelete: Cascade)
6321
+ author User @relation("OrganizationCommunityPostAuthor", fields: [authorUserId], references: [id], onDelete: Cascade)
6322
+ comments OrganizationCommunityComment[]
6323
+ likes OrganizationCommunityPostLike[]
6324
+ reports OrganizationCommunityPostReport[]
6325
+
6326
+ @@index([organizationId])
6327
+ @@index([authorUserId])
6328
+ }
6329
+
6330
+ model OrganizationCommunityComment {
6331
+ id String @id @default(cuid())
6332
+ postId String
6333
+ authorUserId String
6334
+ content String @db.Text
6335
+ createdAt DateTime @default(now())
6336
+
6337
+ post OrganizationCommunityPost @relation(fields: [postId], references: [id], onDelete: Cascade)
6338
+ author User @relation("OrganizationCommunityCommentAuthor", fields: [authorUserId], references: [id], onDelete: Cascade)
6339
+
6340
+ @@index([postId])
6341
+ }
6342
+
6343
+ model OrganizationCommunityPostLike {
6344
+ id String @id @default(cuid())
6345
+ postId String
6346
+ userId String
6347
+
6348
+ post OrganizationCommunityPost @relation(fields: [postId], references: [id], onDelete: Cascade)
6349
+ user User @relation(fields: [userId], references: [id], onDelete: Cascade)
6350
+
6351
+ @@unique([postId, userId])
6352
+ @@index([postId])
6353
+ }
6354
+
6355
+ /// Moderation report on a top-level community post (mirrors EventDiscussionCommentReport).
6356
+ /// Scoped to posts, not comments, for MVP — the atomic unit worth a host's review.
6357
+ model OrganizationCommunityPostReport {
6358
+ id String @id @default(cuid())
6359
+ postId String
6360
+ userId String
6361
+ reason BashFeedReportReason
6362
+ description String? @db.Text
6363
+ createdAt DateTime @default(now())
6364
+
6365
+ post OrganizationCommunityPost @relation(fields: [postId], references: [id], onDelete: Cascade)
6366
+ user User @relation(fields: [userId], references: [id], onDelete: Cascade)
6367
+
6368
+ @@unique([postId, userId])
6369
+ @@index([postId])
6370
+ }
6371
+
5992
6372
  /// Email-first followers of a public organizer (org landing). Authenticated users who
5993
6373
  /// Follow also get a row here when we know their email. Distinct from org membership.
5994
6374
  model OrganizationSubscriber {
@@ -6510,6 +6890,8 @@ model Budget {
6510
6890
  totalBudgetCents Int? // Alias for backward compatibility
6511
6891
  spentCents Int @default(0)
6512
6892
  remainingCents Int? // Can be computed: totalAllocatedCents - spentCents
6893
+ /// Host opt-in: reveal this line's category + amount to providers on the public bash detail page.
6894
+ showOnBashDetailPage Boolean @default(false)
6513
6895
 
6514
6896
  // Categorization
6515
6897
  category String? // "Marketing", "Catering", "Venue", "Annual", "Activities"
@@ -7557,6 +7939,22 @@ model PushNotificationToken {
7557
7939
  @@map("push_notification_tokens")
7558
7940
  }
7559
7941
 
7942
+ // iOS ActivityKit "push-to-start" token — distinct from PushNotificationToken (FCM).
7943
+ // One per device; used to auto-start a Live Activity for an upcoming bash via raw APNs.
7944
+ // Android has no equivalent: it reuses the existing FCM token in PushNotificationToken.
7945
+ model LiveActivityPushToken {
7946
+ id String @id @default(cuid())
7947
+ userId String
7948
+ token String @unique
7949
+ platform String @default("ios")
7950
+ isActive Boolean @default(true)
7951
+ createdAt DateTime @default(now())
7952
+ updatedAt DateTime @updatedAt
7953
+ user User @relation(fields: [userId], references: [id], onDelete: Cascade)
7954
+
7955
+ @@unique([userId, platform])
7956
+ }
7957
+
7560
7958
  model AmbashadorApplication {
7561
7959
  id String @id @default(cuid())
7562
7960
  userId String?
@@ -544,6 +544,8 @@ type BashEventExtBase = Override<
544
544
  datePollPublicSummary?: IdeaDatePollPublicSummary;
545
545
  /** GET /event/:id — tickets sold (non-cancelled), for social proof */
546
546
  goingCount?: number;
547
+ /** GET /event/:id — true when at least one Budget line has `showOnBashDetailPage` set. Drives the "View budget" reveal on the public bash page; never carries dollar amounts. */
548
+ hasVisibleBudget?: boolean;
547
549
  /** GET /event/:id when status=Idea — total IdeaInterest rows */
548
550
  ideaInterestCount?: number;
549
551
  /** Feed/card alias for idea interest (some list payloads use this name). */
package/src/index.ts CHANGED
@@ -49,6 +49,7 @@ export * from "./utils/featuredDiscoveryGeo.js";
49
49
  export * from "./utils/organizationEntitlements.js";
50
50
  export * from "./serviceTypeLabels.js";
51
51
  export * from "./targetAudienceLabels.js";
52
+ export * from "./liveActivity/liveActivityTypes.js";
52
53
 
53
54
  // Re-export ALL Prisma enums as values (usable as runtime constants, e.g. ServiceTypes.Entertainment)
54
55
  // Excludes enums already re-exported by definitions.ts, mirroredPrismaEnums.ts, and membershipDefinitions.ts: