@coursebuilder/analytics 1.1.0 → 1.1.2-canary.0.0c9beb2ae

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.
@@ -117,6 +117,7 @@ export interface SurveyAnalyticsProvider {
117
117
  getSurveyResponses: (
118
118
  range?: AnalyticsRange,
119
119
  limit?: number,
120
+ offset?: number,
120
121
  ) => Promise<
121
122
  Array<{
122
123
  responseId: string
@@ -458,10 +459,11 @@ export function createSurveyProvider(
458
459
  async function getSurveyResponses(
459
460
  range: AnalyticsRange = '30d',
460
461
  limit = 100,
462
+ offset = 0,
461
463
  ) {
462
464
  const canonicalRows = await fetchCanonicalRows(range)
463
465
 
464
- return canonicalRows.slice(0, limit).map((row) => ({
466
+ return canonicalRows.slice(offset, offset + limit).map((row) => ({
465
467
  responseId: row.responseId,
466
468
  surveyId: row.surveyId,
467
469
  surveyTitle: row.surveyTitle ?? '',
package/src/types.ts CHANGED
@@ -9,6 +9,7 @@ export type Minutes = Brand<number, 'Minutes'>
9
9
  export type Seconds = Brand<number, 'Seconds'>
10
10
 
11
11
  export type AnalyticsRange = '24h' | '7d' | '30d' | '90d' | 'all'
12
+ export type TrafficAnalyticsRange = AnalyticsRange | '180d'
12
13
 
13
14
  export interface RevenueSummary {
14
15
  totalRevenue: USD
@@ -45,6 +46,8 @@ export interface RecentPurchase {
45
46
  couponId: string | null
46
47
  userName: string | null
47
48
  userEmail: string | null
49
+ isTeam?: boolean
50
+ seats?: number | null
48
51
  }
49
52
 
50
53
  export interface AttributionCount {
@@ -57,11 +60,20 @@ export interface ShortlinkPerformance {
57
60
  slug: string
58
61
  url: string
59
62
  clicks: Count
63
+ signups?: Count
64
+ purchases?: Count
60
65
  }
61
66
 
67
+ export type CommerceRecordKind =
68
+ | 'paid_conversion'
69
+ | 'access_grant'
70
+ | 'synthetic'
71
+ | 'unknown'
72
+
62
73
  export interface RevenueBySource {
63
- source: string
64
- medium: string
74
+ kind?: CommerceRecordKind
75
+ source: string | null
76
+ medium: string | null
65
77
  campaign: string | null
66
78
  revenue: USD
67
79
  count: Count
@@ -81,12 +93,85 @@ export interface ContentCorrelation {
81
93
  purchaserCount: Count
82
94
  }
83
95
 
96
+ export interface CommerceLaneSummary {
97
+ commerceRecords: Count
98
+ paidPurchases: Count
99
+ paidRevenue: USD
100
+ accessGrants: Count
101
+ accessGrantRevenue: USD
102
+ freeUpgrades: Count
103
+ syntheticPurchases: Count
104
+ byAccessGrantReason: Record<string, Count>
105
+ }
106
+
107
+ export interface AttributionSignalSummary {
108
+ shortlink: Count
109
+ utm: Count
110
+ paidClickId: Count
111
+ gaClientId: Count
112
+ selfReportedSource: Count
113
+ recoveredFromShortlinkAttributionTable?: Count
114
+ internalFreeUpgrade: Count
115
+ }
116
+
117
+ export type AttributionQualityLaneName =
118
+ | 'strong'
119
+ | 'medium'
120
+ | 'weak'
121
+ | 'unknown'
122
+
123
+ export interface AttributionQualityLane {
124
+ lane: AttributionQualityLaneName
125
+ purchases: Count
126
+ revenue: USD
127
+ revenuePercent: Percentage
128
+ notes: string[]
129
+ }
130
+
131
+ export interface AttributionQualitySummary {
132
+ strong: AttributionQualityLane
133
+ medium: AttributionQualityLane
134
+ weak: AttributionQualityLane
135
+ unknown: AttributionQualityLane
136
+ }
137
+
84
138
  export interface AttributionCoverage {
85
139
  totalRevenue: USD
86
140
  attributedRevenue: USD
87
141
  unattributedRevenue: USD
88
142
  attributionRate: Percentage
89
143
  totalPurchases: Count
144
+ paidPurchases?: Count
145
+ purchaseFieldAttributedPurchases?: Count
146
+ purchaseFieldAttributedRevenue?: USD
147
+ recoveredFromShortlinkAttributionTablePurchases?: Count
148
+ recoveredFromShortlinkAttributionTableRevenue?: USD
149
+ commerceRecords?: Count
150
+ accessGrants?: Count
151
+ freeUpgrades?: Count
152
+ syntheticPurchases?: Count
153
+ commerce?: CommerceLaneSummary
154
+ signals?: AttributionSignalSummary
155
+ quality?: AttributionQualitySummary
156
+ }
157
+
158
+ export interface TrafficBreakdownRow {
159
+ sessions: Count
160
+ users: Count
161
+ sessionPercent: Percentage
162
+ trafficSessionPercent: Percentage
163
+ }
164
+
165
+ export interface DeviceCategoryBreakdown extends TrafficBreakdownRow {
166
+ deviceCategory: string
167
+ }
168
+
169
+ export interface OperatingSystemBreakdown extends TrafficBreakdownRow {
170
+ operatingSystem: string
171
+ }
172
+
173
+ export interface ScreenResolutionBreakdown extends TrafficBreakdownRow {
174
+ screenResolution: string
90
175
  }
91
176
 
92
177
  export interface TrafficOverview {
@@ -96,6 +181,9 @@ export interface TrafficOverview {
96
181
  pageviews: Count
97
182
  avgSessionDuration: Seconds
98
183
  bounceRate: Percentage
184
+ deviceCategories?: DeviceCategoryBreakdown[]
185
+ operatingSystems?: OperatingSystemBreakdown[]
186
+ screenResolutions?: ScreenResolutionBreakdown[]
99
187
  }
100
188
 
101
189
  export interface TrafficDaily {
@@ -279,6 +367,119 @@ export interface SurveyRevenueCorrelation {
279
367
  byQuestion: SurveyConversionByQuestion[]
280
368
  }
281
369
 
370
+ /** One survey answer bucket correlated to paid product revenue. */
371
+ export interface ProductSurveyRevenueAnswer {
372
+ surveyId: string
373
+ surveyTitle: string | null
374
+ surveySlug: string | null
375
+ questionId: string
376
+ question: string | null
377
+ answer: string
378
+ responses: Count
379
+ uniqueRespondents: Count
380
+ paidPurchasers: Count
381
+ paidRevenue: USD
382
+ conversionRate: Percentage
383
+ }
384
+
385
+ /** Product-filtered survey revenue report with aggregate counts and answer buckets. */
386
+ export interface ProductSurveyRevenueCorrelation {
387
+ productId: string | null
388
+ surveyId: string | null
389
+ surveySlug: string | null
390
+ totalResponses: Count
391
+ uniqueRespondents: Count
392
+ respondentsWithUserId: Count
393
+ paidPurchasers: Count
394
+ paidRevenue: USD
395
+ byAnswer: ProductSurveyRevenueAnswer[]
396
+ }
397
+
398
+ /** Single-purchase attribution receipt used by operator audits and checkout debugging. */
399
+ export interface CheckoutAttributionReceipt {
400
+ purchase: {
401
+ id: string
402
+ createdAt: Date | string | null
403
+ productId: string | null
404
+ productName: string | null
405
+ totalAmount: USD
406
+ status: string | null
407
+ country: string | null
408
+ } | null
409
+ checks: {
410
+ purchaseFound: boolean
411
+ attributionSnapshot: boolean
412
+ utm: boolean
413
+ actualUtm: boolean
414
+ clickId: boolean
415
+ synthetic: boolean
416
+ shortlink: boolean
417
+ selfReportedSource: boolean
418
+ gaClientId: boolean
419
+ }
420
+ attribution: Record<string, unknown> | null
421
+ legacy: Record<string, unknown>
422
+ fieldKeys: string[]
423
+ }
424
+
425
+ /** Checkout survey answer bucket for otherwise dark purchase recovery analysis. */
426
+ export interface CheckoutSurveyFallbackAnswer {
427
+ answer: string
428
+ confidence: 'exact_purchase_link' | 'user_linked'
429
+ purchases: Count
430
+ revenue: USD
431
+ }
432
+
433
+ /** Report-only fallback from checkout survey responses to dark purchase revenue. */
434
+ export interface CheckoutSurveyFallbackReport {
435
+ label: 'recovered_from_checkout_survey_response'
436
+ productId: string | null
437
+ totalDarkPurchases: Count
438
+ totalDarkRevenue: USD
439
+ exactPurchaseLinkedPurchases: Count
440
+ exactPurchaseLinkedRevenue: USD
441
+ userLinkedPurchases: Count
442
+ userLinkedRevenue: USD
443
+ byAnswer: CheckoutSurveyFallbackAnswer[]
444
+ notes: string[]
445
+ }
446
+
447
+ export interface ValuePathAnswerBucket {
448
+ key: string
449
+ step: string
450
+ optionValue: string
451
+ count: Count
452
+ }
453
+
454
+ export interface ValuePathStepBucket {
455
+ step: string
456
+ count: Count
457
+ }
458
+
459
+ export interface ValuePathTerminalBucket {
460
+ emailResourceId: string
461
+ count: Count
462
+ }
463
+
464
+ export interface ValuePathSummary {
465
+ contacts: Count
466
+ events: Count
467
+ intents: Count
468
+ completedIntents: Count
469
+ pendingIntents: Count
470
+ blockedIntents: Count
471
+ answerEvents: Count
472
+ dripEvents: Count
473
+ enteredEvents: Count
474
+ participantsWithAnswerClicks: Count
475
+ participantsWithNoAnswerClicks: Count
476
+ terminalParticipants: Count
477
+ answerOptions: ValuePathAnswerBucket[]
478
+ answerSteps: ValuePathStepBucket[]
479
+ terminalSteps: ValuePathTerminalBucket[]
480
+ notes: string[]
481
+ }
482
+
282
483
  export interface SurfaceMap {
283
484
  summary: RevenueSummary
284
485
  'revenue/daily': RevenueDaily[]
@@ -291,6 +492,7 @@ export interface SurfaceMap {
291
492
  'attribution/funnel': ConversionFunnel
292
493
  'attribution/content': ContentCorrelation[]
293
494
  'attribution/coverage': AttributionCoverage
495
+ 'attribution/commerce-lanes': CommerceLaneSummary
294
496
  traffic: TrafficOverview
295
497
  'traffic/daily': TrafficDaily[]
296
498
  'traffic/pages': TopPage[]
@@ -307,7 +509,12 @@ export interface SurfaceMap {
307
509
  'surveys/questions': SurveyQuestionBreakdown[]
308
510
  'surveys/responses': SurveyResponseRow[]
309
511
  'correlation/survey-revenue': SurveyRevenueCorrelation
512
+ 'correlation/survey-revenue/product': ProductSurveyRevenueCorrelation
310
513
  'attribution/email-campaigns': EmailRevenueOverview
514
+ 'attribution/email-campaigns/strict': EmailRevenueOverview
515
+ 'attribution/checkout-receipt': CheckoutAttributionReceipt
516
+ 'attribution/checkout-survey-fallback': CheckoutSurveyFallbackReport
517
+ 'value-paths/summary': ValuePathSummary
311
518
  }
312
519
 
313
520
  export type SurfaceName = keyof SurfaceMap
@@ -315,6 +522,12 @@ export type SurfaceName = keyof SurfaceMap
315
522
  export interface QueryOptions {
316
523
  range?: AnalyticsRange
317
524
  limit?: number
525
+ offset?: number
526
+ productId?: string
527
+ purchaseId?: string
528
+ surveyId?: string
529
+ surveySlug?: string
530
+ questionId?: string
318
531
  }
319
532
 
320
533
  export type QueryResult<S extends SurfaceName> =