@bash-app/bash-common 30.293.0 → 30.297.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 (61) hide show
  1. package/dist/__tests__/bashSectionTitleForBashType.test.js +3 -0
  2. package/dist/__tests__/bashSectionTitleForBashType.test.js.map +1 -1
  3. package/dist/definitions.d.ts +77 -0
  4. package/dist/definitions.d.ts.map +1 -1
  5. package/dist/definitions.js +1 -0
  6. package/dist/definitions.js.map +1 -1
  7. package/dist/extendedSchemas.d.ts +7 -0
  8. package/dist/extendedSchemas.d.ts.map +1 -1
  9. package/dist/extendedSchemas.js.map +1 -1
  10. package/dist/index.d.ts +3 -0
  11. package/dist/index.d.ts.map +1 -1
  12. package/dist/index.js +3 -0
  13. package/dist/index.js.map +1 -1
  14. package/dist/membershipDefinitions.d.ts +9 -0
  15. package/dist/membershipDefinitions.d.ts.map +1 -1
  16. package/dist/membershipDefinitions.js +10 -1
  17. package/dist/membershipDefinitions.js.map +1 -1
  18. package/dist/utils/__tests__/reputationUtils.serviceListing.test.js +18 -0
  19. package/dist/utils/__tests__/reputationUtils.serviceListing.test.js.map +1 -1
  20. package/dist/utils/__tests__/reviewDimensionUtils.test.d.ts +2 -0
  21. package/dist/utils/__tests__/reviewDimensionUtils.test.d.ts.map +1 -0
  22. package/dist/utils/__tests__/reviewDimensionUtils.test.js +48 -0
  23. package/dist/utils/__tests__/reviewDimensionUtils.test.js.map +1 -0
  24. package/dist/utils/__tests__/trustScoreUtils.test.d.ts +2 -0
  25. package/dist/utils/__tests__/trustScoreUtils.test.d.ts.map +1 -0
  26. package/dist/utils/__tests__/trustScoreUtils.test.js +101 -0
  27. package/dist/utils/__tests__/trustScoreUtils.test.js.map +1 -0
  28. package/dist/utils/reputationUtils.d.ts.map +1 -1
  29. package/dist/utils/reputationUtils.js +7 -1
  30. package/dist/utils/reputationUtils.js.map +1 -1
  31. package/dist/utils/reviewDimensionUtils.d.ts +33 -0
  32. package/dist/utils/reviewDimensionUtils.d.ts.map +1 -0
  33. package/dist/utils/reviewDimensionUtils.js +35 -0
  34. package/dist/utils/reviewDimensionUtils.js.map +1 -0
  35. package/dist/utils/service/__tests__/serviceListingMediaUtils.test.d.ts +2 -0
  36. package/dist/utils/service/__tests__/serviceListingMediaUtils.test.d.ts.map +1 -0
  37. package/dist/utils/service/__tests__/serviceListingMediaUtils.test.js +33 -0
  38. package/dist/utils/service/__tests__/serviceListingMediaUtils.test.js.map +1 -0
  39. package/dist/utils/service/serviceListingMediaUtils.d.ts +22 -0
  40. package/dist/utils/service/serviceListingMediaUtils.d.ts.map +1 -0
  41. package/dist/utils/service/serviceListingMediaUtils.js +40 -0
  42. package/dist/utils/service/serviceListingMediaUtils.js.map +1 -0
  43. package/dist/utils/trustScoreUtils.d.ts +25 -0
  44. package/dist/utils/trustScoreUtils.d.ts.map +1 -0
  45. package/dist/utils/trustScoreUtils.js +99 -0
  46. package/dist/utils/trustScoreUtils.js.map +1 -0
  47. package/package.json +1 -1
  48. package/prisma/schema.prisma +133 -15
  49. package/src/__tests__/bashSectionTitleForBashType.test.ts +4 -0
  50. package/src/definitions.ts +85 -1
  51. package/src/extendedSchemas.ts +7 -0
  52. package/src/index.ts +3 -0
  53. package/src/membershipDefinitions.ts +12 -1
  54. package/src/utils/__tests__/reputationUtils.serviceListing.test.ts +24 -0
  55. package/src/utils/__tests__/reviewDimensionUtils.test.ts +65 -0
  56. package/src/utils/__tests__/trustScoreUtils.test.ts +105 -0
  57. package/src/utils/reputationUtils.ts +7 -1
  58. package/src/utils/reviewDimensionUtils.ts +70 -0
  59. package/src/utils/service/__tests__/serviceListingMediaUtils.test.ts +44 -0
  60. package/src/utils/service/serviceListingMediaUtils.ts +62 -0
  61. package/src/utils/trustScoreUtils.ts +136 -0
@@ -0,0 +1,136 @@
1
+ import { bayesianAverage } from "./reputationUtils.js";
2
+
3
+ export type TrustScoreActorType = "host" | "service";
4
+
5
+ export interface TrustScoreInputs {
6
+ bayesianReviewScore: number | null;
7
+ completedVolume: number;
8
+ cancellationRate: number;
9
+ responseRate: number;
10
+ identityVerified: boolean;
11
+ verifiedAttendanceRate?: number;
12
+ verifiedCompletionRate?: number;
13
+ accountAgeDays: number;
14
+ disputeRate: number;
15
+ repeatCustomerRate: number;
16
+ }
17
+
18
+ export interface TrustScoreBreakdown {
19
+ score: number | null;
20
+ components: Record<string, number>;
21
+ weights: Record<string, number>;
22
+ }
23
+
24
+ const HOST_WEIGHTS: Record<string, number> = {
25
+ reviews: 0.35,
26
+ volume: 0.15,
27
+ cancellation: 0.1,
28
+ response: 0.1,
29
+ identity: 0.1,
30
+ attendance: 0.05,
31
+ accountAge: 0.05,
32
+ disputes: 0.05,
33
+ repeat: 0.05,
34
+ };
35
+
36
+ const SERVICE_WEIGHTS: Record<string, number> = {
37
+ reviews: 0.4,
38
+ volume: 0.15,
39
+ cancellation: 0.1,
40
+ response: 0.1,
41
+ identity: 0.1,
42
+ completion: 0.1,
43
+ accountAge: 0.05,
44
+ disputes: 0.05,
45
+ repeat: 0.05,
46
+ };
47
+
48
+ function clamp01(n: number): number {
49
+ if (n < 0) return 0;
50
+ if (n > 1) return 1;
51
+ return n;
52
+ }
53
+
54
+ function logScaledVolume(count: number, cap = 100): number {
55
+ if (count <= 0) return 0;
56
+ return clamp01(Math.log10(count + 1) / Math.log10(cap + 1));
57
+ }
58
+
59
+ function accountAgeScore(days: number): number {
60
+ return clamp01(Math.log10(Math.max(days, 1) + 1) / Math.log10(365 * 3 + 1));
61
+ }
62
+
63
+ function inverseRate(rate: number): number {
64
+ return clamp01(1 - clamp01(rate));
65
+ }
66
+
67
+ /**
68
+ * Compute a 0–100 trust score from normalized component signals (0–1 each).
69
+ */
70
+ export function computeTrustScoreFromInputs(
71
+ actorType: TrustScoreActorType,
72
+ inputs: TrustScoreInputs
73
+ ): TrustScoreBreakdown {
74
+ const weights = actorType === "host" ? HOST_WEIGHTS : SERVICE_WEIGHTS;
75
+
76
+ const reviewComponent =
77
+ inputs.bayesianReviewScore != null
78
+ ? clamp01(inputs.bayesianReviewScore / 5)
79
+ : 0.5;
80
+
81
+ const components: Record<string, number> = {
82
+ reviews: reviewComponent,
83
+ volume: logScaledVolume(inputs.completedVolume),
84
+ cancellation: inverseRate(inputs.cancellationRate),
85
+ response: clamp01(inputs.responseRate),
86
+ identity: inputs.identityVerified ? 1 : 0,
87
+ accountAge: accountAgeScore(inputs.accountAgeDays),
88
+ disputes: inverseRate(inputs.disputeRate),
89
+ repeat: clamp01(inputs.repeatCustomerRate),
90
+ };
91
+
92
+ if (actorType === "host") {
93
+ components.attendance = clamp01(inputs.verifiedAttendanceRate ?? 0);
94
+ } else {
95
+ components.completion = clamp01(inputs.verifiedCompletionRate ?? 0);
96
+ }
97
+
98
+ let weighted = 0;
99
+ let weightSum = 0;
100
+ for (const [key, weight] of Object.entries(weights)) {
101
+ const val = components[key];
102
+ if (val == null) continue;
103
+ weighted += val * weight;
104
+ weightSum += weight;
105
+ }
106
+
107
+ if (weightSum === 0) {
108
+ return { score: null, components, weights };
109
+ }
110
+
111
+ const normalized = weighted / weightSum;
112
+ const score = Math.round(normalized * 100);
113
+ return { score, components, weights };
114
+ }
115
+
116
+ /** Convenience when only review stats are available (early bootstrap). */
117
+ export function trustScoreFromReviewAverage(
118
+ actorType: TrustScoreActorType,
119
+ averageRating: number | null | undefined,
120
+ totalRatings: number | null | undefined
121
+ ): number | null {
122
+ const bayesian = bayesianAverage(averageRating, totalRatings);
123
+ const result = computeTrustScoreFromInputs(actorType, {
124
+ bayesianReviewScore: bayesian,
125
+ completedVolume: totalRatings ?? 0,
126
+ cancellationRate: 0,
127
+ responseRate: 1,
128
+ identityVerified: false,
129
+ accountAgeDays: 30,
130
+ disputeRate: 0,
131
+ repeatCustomerRate: 0,
132
+ verifiedAttendanceRate: 0,
133
+ verifiedCompletionRate: 0,
134
+ });
135
+ return result.score;
136
+ }