@stacksjs/ts-analytics 0.1.6
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.
- package/CHANGELOG.md +68 -0
- package/LICENSE.md +21 -0
- package/README.md +361 -0
- package/bin/cli.ts +169 -0
- package/dist/Analytics.d.ts +558 -0
- package/dist/api.d.ts +109 -0
- package/dist/batching.d.ts +93 -0
- package/dist/chunk-2mx7fq49.js +4 -0
- package/dist/chunk-3z29508k.js +204 -0
- package/dist/chunk-deephkz6.js +56 -0
- package/dist/chunk-j261vgyp.js +305 -0
- package/dist/chunk-xga17tz7.js +207 -0
- package/dist/config.d.ts +132 -0
- package/dist/dashboard/components/index.d.ts +80 -0
- package/dist/dashboard/composables/useAnalytics.d.ts +99 -0
- package/dist/dashboard/index.d.ts +110 -0
- package/dist/dashboard/types/index.d.ts +144 -0
- package/dist/dashboard/utils/index.d.ts +81 -0
- package/dist/dynamodb.d.ts +86 -0
- package/dist/funnels.d.ts +104 -0
- package/dist/geolocation.d.ts +96 -0
- package/dist/index.d.ts +371 -0
- package/dist/index.js +10211 -0
- package/dist/infrastructure/cdk.d.ts +60 -0
- package/dist/infrastructure/cloudformation.d.ts +44 -0
- package/dist/infrastructure/index.d.ts +45 -0
- package/dist/infrastructure/setup.d.ts +133 -0
- package/dist/integrations/cloudflare.d.ts +76 -0
- package/dist/integrations/hono.d.ts +60 -0
- package/dist/integrations/index.d.ts +24 -0
- package/dist/integrations/nuxt.d.ts +7 -0
- package/dist/integrations/nuxt.js +42 -0
- package/dist/integrations/runtime/use-ts-analytics.d.ts +18 -0
- package/dist/integrations/runtime/use-ts-analytics.js +17 -0
- package/dist/integrations/stx.d.ts +88 -0
- package/dist/integrations/stx.js +18 -0
- package/dist/lib/crypto-random.d.ts +4 -0
- package/dist/lib/salt.d.ts +16 -0
- package/dist/local.d.ts +56 -0
- package/dist/model-connector.d.ts +145 -0
- package/dist/models/AggregatedStats.d.ts +9 -0
- package/dist/models/CampaignStats.d.ts +9 -0
- package/dist/models/Conversion.d.ts +11 -0
- package/dist/models/CustomEvent.d.ts +11 -0
- package/dist/models/DeviceStats.d.ts +9 -0
- package/dist/models/EventStats.d.ts +9 -0
- package/dist/models/GeoStats.d.ts +9 -0
- package/dist/models/Goal.d.ts +9 -0
- package/dist/models/GoalStats.d.ts +9 -0
- package/dist/models/PageStats.d.ts +11 -0
- package/dist/models/PageView.d.ts +13 -0
- package/dist/models/RealtimeStats.d.ts +9 -0
- package/dist/models/ReferrerStats.d.ts +9 -0
- package/dist/models/Session.d.ts +11 -0
- package/dist/models/Site.d.ts +11 -0
- package/dist/models/index.d.ts +28 -0
- package/dist/models/types.d.ts +60 -0
- package/dist/sqs-buffering.d.ts +243 -0
- package/dist/stacks-integration.d.ts +159 -0
- package/dist/tracking-script.d.ts +71 -0
- package/dist/tracking.d.ts +17 -0
- package/dist/tracking.js +26 -0
- package/dist/types.d.ts +595 -0
- package/dist/utils/geolocation.d.ts +111 -0
- package/dist/utils/user-agent.d.ts +17 -0
- package/dist/version.d.ts +7 -0
- package/package.json +119 -0
- package/src/Analytics.ts +3349 -0
- package/src/api.ts +1286 -0
- package/src/assets/crosswind.css +2220 -0
- package/src/batching.ts +452 -0
- package/src/components/dashboard/index.ts +18 -0
- package/src/config.ts +456 -0
- package/src/dashboard/Dashboard.stx +1517 -0
- package/src/dashboard/components/AlertCard.stx +177 -0
- package/src/dashboard/components/AnalyticsDashboard.stx +354 -0
- package/src/dashboard/components/AnimatedNumber.stx +86 -0
- package/src/dashboard/components/BarChart.stx +220 -0
- package/src/dashboard/components/BrowserBreakdown.stx +98 -0
- package/src/dashboard/components/BrowsersTable.stx +125 -0
- package/src/dashboard/components/CampaignBreakdown.stx +163 -0
- package/src/dashboard/components/CampaignTable.stx +238 -0
- package/src/dashboard/components/CountryList.stx +101 -0
- package/src/dashboard/components/DataTable.stx +226 -0
- package/src/dashboard/components/DateRangePicker.stx +77 -0
- package/src/dashboard/components/DeviceBreakdown.stx +94 -0
- package/src/dashboard/components/DevicesTable.stx +163 -0
- package/src/dashboard/components/DonutChart.stories.ts +55 -0
- package/src/dashboard/components/DonutChart.stx +157 -0
- package/src/dashboard/components/EmptyState.stx +90 -0
- package/src/dashboard/components/EngagementMetrics.stx +183 -0
- package/src/dashboard/components/EventsSection.stx +192 -0
- package/src/dashboard/components/FilterBar.stx +104 -0
- package/src/dashboard/components/FullAnalyticsDashboard.stx +455 -0
- package/src/dashboard/components/FunnelChart.stx +142 -0
- package/src/dashboard/components/GeoTable.stx +337 -0
- package/src/dashboard/components/GoalsPanel.stx +109 -0
- package/src/dashboard/components/Header.stx +39 -0
- package/src/dashboard/components/HeatmapChart.stx +140 -0
- package/src/dashboard/components/LiveActivityFeed.stx +172 -0
- package/src/dashboard/components/MetricComparison.stx +106 -0
- package/src/dashboard/components/MiniStats.stx +96 -0
- package/src/dashboard/components/OSBreakdown.stx +124 -0
- package/src/dashboard/components/PageDetailCard.stx +102 -0
- package/src/dashboard/components/PagesTable.stx +127 -0
- package/src/dashboard/components/ProgressRing.stx +89 -0
- package/src/dashboard/components/RealtimeCounter.stories.ts +45 -0
- package/src/dashboard/components/RealtimeCounter.stx +46 -0
- package/src/dashboard/components/ReferrersTable.stx +180 -0
- package/src/dashboard/components/SparklineChart.stx +160 -0
- package/src/dashboard/components/StatCard.stories.ts +58 -0
- package/src/dashboard/components/StatCard.stx +90 -0
- package/src/dashboard/components/SummaryStats.stx +81 -0
- package/src/dashboard/components/TabNav.stx +66 -0
- package/src/dashboard/components/ThemeSwitcher.stx +124 -0
- package/src/dashboard/components/TimeSeriesChart.stx +106 -0
- package/src/dashboard/components/TopList.stories.ts +58 -0
- package/src/dashboard/components/TopList.stx +74 -0
- package/src/dashboard/components/TrendIndicator.stx +84 -0
- package/src/dashboard/components/heatmap/ClickHeatmap.stx +264 -0
- package/src/dashboard/components/heatmap/ElementClickList.stx +125 -0
- package/src/dashboard/components/heatmap/HeatmapControls.stx +125 -0
- package/src/dashboard/components/heatmap/HeatmapLegend.stx +69 -0
- package/src/dashboard/components/heatmap/PageHeatmap.stx +264 -0
- package/src/dashboard/components/heatmap/ScrollHeatmap.stx +127 -0
- package/src/dashboard/components/heatmap/index.ts +12 -0
- package/src/dashboard/components/index.ts +86 -0
- package/src/dashboard/composables/useAnalytics.ts +465 -0
- package/src/dashboard/demo/DemoApp.stx +370 -0
- package/src/dashboard/demo/index.ts +8 -0
- package/src/dashboard/demo/mockData.ts +234 -0
- package/src/dashboard/index.ts +117 -0
- package/src/dashboard/stx-shim.d.ts +4 -0
- package/src/dashboard/types/index.ts +203 -0
- package/src/dashboard/utils/index.ts +426 -0
- package/src/dynamodb.ts +344 -0
- package/src/funnels.ts +534 -0
- package/src/geolocation.ts +515 -0
- package/src/handlers/alerts.ts +328 -0
- package/src/handlers/annotations.ts +128 -0
- package/src/handlers/api-keys.ts +240 -0
- package/src/handlers/auth.ts +1020 -0
- package/src/handlers/authz.ts +137 -0
- package/src/handlers/collect.ts +724 -0
- package/src/handlers/data.ts +625 -0
- package/src/handlers/experiments.ts +138 -0
- package/src/handlers/funnels.ts +216 -0
- package/src/handlers/goals.ts +218 -0
- package/src/handlers/heatmaps.ts +272 -0
- package/src/handlers/index.ts +56 -0
- package/src/handlers/lib/read-cache.ts +63 -0
- package/src/handlers/misc.ts +486 -0
- package/src/handlers/oauth.ts +233 -0
- package/src/handlers/performance.ts +388 -0
- package/src/handlers/sessions.ts +413 -0
- package/src/handlers/sharing.ts +198 -0
- package/src/handlers/stats.ts +1368 -0
- package/src/handlers/team.ts +161 -0
- package/src/handlers/uptime.ts +283 -0
- package/src/handlers/views.ts +390 -0
- package/src/handlers/webhooks.ts +226 -0
- package/src/heatmap/index.ts +32 -0
- package/src/heatmap/tracking-script.ts +452 -0
- package/src/heatmap/types.ts +79 -0
- package/src/index.ts +387 -0
- package/src/infrastructure/cdk.ts +496 -0
- package/src/infrastructure/cloudformation.ts +595 -0
- package/src/infrastructure/index.ts +48 -0
- package/src/infrastructure/setup.ts +611 -0
- package/src/integrations/cloudflare.ts +732 -0
- package/src/integrations/hono.ts +589 -0
- package/src/integrations/index.ts +27 -0
- package/src/integrations/nuxt.ts +78 -0
- package/src/integrations/runtime/use-ts-analytics.ts +32 -0
- package/src/integrations/stx.ts +138 -0
- package/src/jobs/index.ts +127 -0
- package/src/lib/crypto-random.ts +41 -0
- package/src/lib/ddb-errors.ts +20 -0
- package/src/lib/dynamodb.ts +216 -0
- package/src/lib/email.ts +38 -0
- package/src/lib/ga-import.ts +471 -0
- package/src/lib/ga4-api.ts +244 -0
- package/src/lib/goals.ts +205 -0
- package/src/lib/index.ts +6 -0
- package/src/lib/ingest-counters.ts +123 -0
- package/src/lib/log.ts +36 -0
- package/src/lib/membership.ts +98 -0
- package/src/lib/plans.ts +90 -0
- package/src/lib/quota.ts +46 -0
- package/src/lib/rate-limit.ts +27 -0
- package/src/lib/rollups.ts +472 -0
- package/src/lib/salt.ts +97 -0
- package/src/lib/scheduler.ts +97 -0
- package/src/lib/significance.ts +66 -0
- package/src/lib/site-retention.ts +56 -0
- package/src/local.ts +360 -0
- package/src/model-connector.ts +616 -0
- package/src/models/AggregatedStats.ts +162 -0
- package/src/models/CampaignStats.ts +141 -0
- package/src/models/Conversion.ts +135 -0
- package/src/models/CustomEvent.ts +123 -0
- package/src/models/DeviceStats.ts +105 -0
- package/src/models/EventStats.ts +108 -0
- package/src/models/GeoStats.ts +112 -0
- package/src/models/Goal.ts +105 -0
- package/src/models/GoalStats.ts +106 -0
- package/src/models/PageStats.ts +152 -0
- package/src/models/PageView.ts +277 -0
- package/src/models/RealtimeStats.ts +96 -0
- package/src/models/ReferrerStats.ts +115 -0
- package/src/models/Session.ts +235 -0
- package/src/models/Site.ts +115 -0
- package/src/models/index.ts +50 -0
- package/src/models/orm/index.ts +2043 -0
- package/src/models/types.ts +71 -0
- package/src/router.ts +521 -0
- package/src/sqs-buffering.ts +806 -0
- package/src/stacks-integration.ts +527 -0
- package/src/tracking-script.ts +944 -0
- package/src/tracking.ts +27 -0
- package/src/types/analytics.ts +219 -0
- package/src/types/api.ts +75 -0
- package/src/types/bun-router.d.ts +15 -0
- package/src/types/dashboard.ts +62 -0
- package/src/types/index.ts +66 -0
- package/src/types/stx.d.ts +27 -0
- package/src/types/window.d.ts +101 -0
- package/src/types.ts +911 -0
- package/src/utils/cache.ts +148 -0
- package/src/utils/date.ts +118 -0
- package/src/utils/filters.ts +71 -0
- package/src/utils/geolocation.ts +323 -0
- package/src/utils/index.ts +9 -0
- package/src/utils/response.ts +180 -0
- package/src/utils/timezone-country.ts +242 -0
- package/src/utils/user-agent.ts +110 -0
- package/src/version.ts +7 -0
package/src/config.ts
ADDED
|
@@ -0,0 +1,456 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Analytics Configuration
|
|
3
|
+
*
|
|
4
|
+
* Configuration for the analytics system using DynamoDB single-table design.
|
|
5
|
+
* Integrates with dynamodb-tooling for table management.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import type {
|
|
9
|
+
AnalyticsTableConfig,
|
|
10
|
+
BillingMode,
|
|
11
|
+
GSIDefinition,
|
|
12
|
+
SingleTableDesignConfig,
|
|
13
|
+
} from './types'
|
|
14
|
+
|
|
15
|
+
// ============================================================================
|
|
16
|
+
// Default Configuration
|
|
17
|
+
// ============================================================================
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Default single-table design configuration
|
|
21
|
+
*/
|
|
22
|
+
export const defaultSingleTableConfig: SingleTableDesignConfig = {
|
|
23
|
+
enabled: true,
|
|
24
|
+
partitionKeyName: 'pk',
|
|
25
|
+
sortKeyName: 'sk',
|
|
26
|
+
gsi1pkName: 'gsi1pk',
|
|
27
|
+
gsi1skName: 'gsi1sk',
|
|
28
|
+
gsi2pkName: 'gsi2pk',
|
|
29
|
+
gsi2skName: 'gsi2sk',
|
|
30
|
+
entityTypeAttribute: '_et',
|
|
31
|
+
pkPrefix: '{ENTITY}#',
|
|
32
|
+
skPrefix: '{ENTITY}#',
|
|
33
|
+
gsiCount: 2,
|
|
34
|
+
keyDelimiter: '#',
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Default GSI definitions for analytics
|
|
39
|
+
*/
|
|
40
|
+
export const defaultGSIs: GSIDefinition[] = [
|
|
41
|
+
{
|
|
42
|
+
name: 'gsi1',
|
|
43
|
+
partitionKey: 'gsi1pk',
|
|
44
|
+
sortKey: 'gsi1sk',
|
|
45
|
+
projection: { type: 'ALL' },
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
name: 'gsi2',
|
|
49
|
+
partitionKey: 'gsi2pk',
|
|
50
|
+
sortKey: 'gsi2sk',
|
|
51
|
+
projection: { type: 'ALL' },
|
|
52
|
+
},
|
|
53
|
+
]
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Default analytics table configuration
|
|
57
|
+
*/
|
|
58
|
+
export const defaultAnalyticsConfig: AnalyticsTableConfig = {
|
|
59
|
+
tableName: 'AnalyticsTable',
|
|
60
|
+
billingMode: 'PAY_PER_REQUEST',
|
|
61
|
+
singleTable: defaultSingleTableConfig,
|
|
62
|
+
globalSecondaryIndexes: defaultGSIs,
|
|
63
|
+
localSecondaryIndexes: [],
|
|
64
|
+
ttlAttributeName: 'ttl',
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// ============================================================================
|
|
68
|
+
// Configuration Types
|
|
69
|
+
// ============================================================================
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Analytics configuration options
|
|
73
|
+
*/
|
|
74
|
+
export interface AnalyticsConfig {
|
|
75
|
+
/** DynamoDB table configuration */
|
|
76
|
+
table: AnalyticsTableConfig
|
|
77
|
+
|
|
78
|
+
/** AWS region */
|
|
79
|
+
region: string
|
|
80
|
+
|
|
81
|
+
/** Custom endpoint (for local development) */
|
|
82
|
+
endpoint?: string
|
|
83
|
+
|
|
84
|
+
/** Data retention settings */
|
|
85
|
+
retention: {
|
|
86
|
+
/** Raw event TTL in seconds (default: 30 days) */
|
|
87
|
+
rawEventTtl: number
|
|
88
|
+
/** Hourly aggregate TTL in seconds (default: 90 days) */
|
|
89
|
+
hourlyAggregateTtl: number
|
|
90
|
+
/** Daily aggregate TTL in seconds (default: 2 years) */
|
|
91
|
+
dailyAggregateTtl: number
|
|
92
|
+
/** Monthly aggregates kept forever by default */
|
|
93
|
+
monthlyAggregateTtl?: number
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/** Privacy settings */
|
|
97
|
+
privacy: {
|
|
98
|
+
/** Hash visitor IDs for privacy */
|
|
99
|
+
hashVisitorIds: boolean
|
|
100
|
+
/** Collect geolocation data */
|
|
101
|
+
collectGeolocation: boolean
|
|
102
|
+
/** Honor Do Not Track header */
|
|
103
|
+
honorDnt: boolean
|
|
104
|
+
/** IP anonymization level: 'none' | 'partial' | 'full' */
|
|
105
|
+
ipAnonymization: 'none' | 'partial' | 'full'
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/** Tracking settings */
|
|
109
|
+
tracking: {
|
|
110
|
+
/** Track referrers */
|
|
111
|
+
trackReferrers: boolean
|
|
112
|
+
/** Track UTM parameters */
|
|
113
|
+
trackUtmParams: boolean
|
|
114
|
+
/** Track device type */
|
|
115
|
+
trackDeviceType: boolean
|
|
116
|
+
/** Track hash changes as page views */
|
|
117
|
+
trackHashChanges: boolean
|
|
118
|
+
/** Track outbound link clicks */
|
|
119
|
+
trackOutboundLinks: boolean
|
|
120
|
+
/** IPs whose events are dropped at ingest (exact match). */
|
|
121
|
+
excludedIps?: string[]
|
|
122
|
+
/** Path patterns (regex) whose events are dropped at ingest. */
|
|
123
|
+
excludedPaths?: string[]
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
/** API settings */
|
|
127
|
+
api: {
|
|
128
|
+
/** Base path for API routes */
|
|
129
|
+
basePath: string
|
|
130
|
+
/** CORS allowed origins */
|
|
131
|
+
corsOrigins: string[]
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
/** Aggregation settings */
|
|
135
|
+
aggregation: {
|
|
136
|
+
/** Batch size for processing events */
|
|
137
|
+
batchSize: number
|
|
138
|
+
/** Enable hourly aggregation */
|
|
139
|
+
hourlyEnabled: boolean
|
|
140
|
+
/** Enable daily aggregation */
|
|
141
|
+
dailyEnabled: boolean
|
|
142
|
+
/** Enable monthly aggregation */
|
|
143
|
+
monthlyEnabled: boolean
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
/**
|
|
147
|
+
* Scale settings for high-throughput scenarios
|
|
148
|
+
* Based on learnings from Fathom Analytics' DynamoDB experience
|
|
149
|
+
*/
|
|
150
|
+
scale: {
|
|
151
|
+
/**
|
|
152
|
+
* Enable SQS-based write buffering
|
|
153
|
+
* Routes /collect writes through SQS for better handling of traffic spikes
|
|
154
|
+
*/
|
|
155
|
+
sqsBuffering: {
|
|
156
|
+
enabled: boolean
|
|
157
|
+
/** SQS Queue URL */
|
|
158
|
+
queueUrl?: string
|
|
159
|
+
/** Dead letter queue URL for failed messages */
|
|
160
|
+
deadLetterQueueUrl?: string
|
|
161
|
+
/** Max retries before sending to DLQ */
|
|
162
|
+
maxRetries: number
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
/**
|
|
166
|
+
* DAX (DynamoDB Accelerator) caching for reads
|
|
167
|
+
* Dramatically reduces read latency and cost for hot data
|
|
168
|
+
*/
|
|
169
|
+
daxCaching: {
|
|
170
|
+
enabled: boolean
|
|
171
|
+
/** DAX cluster endpoint */
|
|
172
|
+
endpoint?: string
|
|
173
|
+
/** TTL for cached items in seconds */
|
|
174
|
+
ttlSeconds: number
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
/**
|
|
178
|
+
* Partition sharding for high-volume sites
|
|
179
|
+
* Distributes writes across multiple partitions to avoid throttling
|
|
180
|
+
*/
|
|
181
|
+
partitionSharding: {
|
|
182
|
+
enabled: boolean
|
|
183
|
+
/** Number of shards per site (default: 10) */
|
|
184
|
+
shardCount: number
|
|
185
|
+
/** Sites that require sharding (empty = all sites) */
|
|
186
|
+
enabledSiteIds: string[]
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
/**
|
|
190
|
+
* Write coalescing to reduce duplicate writes
|
|
191
|
+
* Combines multiple updates to same key within a time window
|
|
192
|
+
*/
|
|
193
|
+
writeCoalescing: {
|
|
194
|
+
enabled: boolean
|
|
195
|
+
/** Window in milliseconds to coalesce writes */
|
|
196
|
+
windowMs: number
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
/**
|
|
200
|
+
* Batch write settings
|
|
201
|
+
*/
|
|
202
|
+
batchWrites: {
|
|
203
|
+
enabled: boolean
|
|
204
|
+
/** Max items per batch (DynamoDB limit: 25) */
|
|
205
|
+
maxBatchSize: number
|
|
206
|
+
/** Flush interval in milliseconds */
|
|
207
|
+
flushIntervalMs: number
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
/**
|
|
213
|
+
* Partial configuration for user overrides
|
|
214
|
+
*/
|
|
215
|
+
export type UserAnalyticsConfig = {
|
|
216
|
+
[K in keyof AnalyticsConfig]?: K extends 'table'
|
|
217
|
+
? Partial<AnalyticsTableConfig>
|
|
218
|
+
: K extends 'retention' | 'privacy' | 'tracking' | 'api' | 'aggregation'
|
|
219
|
+
? Partial<AnalyticsConfig[K]>
|
|
220
|
+
: K extends 'scale'
|
|
221
|
+
? {
|
|
222
|
+
sqsBuffering?: Partial<AnalyticsConfig['scale']['sqsBuffering']>
|
|
223
|
+
daxCaching?: Partial<AnalyticsConfig['scale']['daxCaching']>
|
|
224
|
+
partitionSharding?: Partial<AnalyticsConfig['scale']['partitionSharding']>
|
|
225
|
+
writeCoalescing?: Partial<AnalyticsConfig['scale']['writeCoalescing']>
|
|
226
|
+
batchWrites?: Partial<AnalyticsConfig['scale']['batchWrites']>
|
|
227
|
+
}
|
|
228
|
+
: AnalyticsConfig[K]
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
// ============================================================================
|
|
232
|
+
// Default Values
|
|
233
|
+
// ============================================================================
|
|
234
|
+
|
|
235
|
+
const ONE_DAY = 24 * 60 * 60
|
|
236
|
+
const THIRTY_DAYS = 30 * ONE_DAY
|
|
237
|
+
const NINETY_DAYS = 90 * ONE_DAY
|
|
238
|
+
const TWO_YEARS = 2 * 365 * ONE_DAY
|
|
239
|
+
|
|
240
|
+
/**
|
|
241
|
+
* Complete default configuration
|
|
242
|
+
*/
|
|
243
|
+
export const defaultConfig: AnalyticsConfig = {
|
|
244
|
+
table: defaultAnalyticsConfig,
|
|
245
|
+
region: 'us-east-1',
|
|
246
|
+
endpoint: undefined,
|
|
247
|
+
|
|
248
|
+
retention: {
|
|
249
|
+
rawEventTtl: THIRTY_DAYS,
|
|
250
|
+
hourlyAggregateTtl: NINETY_DAYS,
|
|
251
|
+
dailyAggregateTtl: TWO_YEARS,
|
|
252
|
+
monthlyAggregateTtl: undefined, // Keep forever
|
|
253
|
+
},
|
|
254
|
+
|
|
255
|
+
privacy: {
|
|
256
|
+
hashVisitorIds: true,
|
|
257
|
+
collectGeolocation: false,
|
|
258
|
+
honorDnt: true,
|
|
259
|
+
ipAnonymization: 'partial',
|
|
260
|
+
},
|
|
261
|
+
|
|
262
|
+
tracking: {
|
|
263
|
+
trackReferrers: true,
|
|
264
|
+
trackUtmParams: true,
|
|
265
|
+
trackDeviceType: true,
|
|
266
|
+
trackHashChanges: false,
|
|
267
|
+
trackOutboundLinks: true,
|
|
268
|
+
excludedIps: [],
|
|
269
|
+
excludedPaths: [],
|
|
270
|
+
},
|
|
271
|
+
|
|
272
|
+
api: {
|
|
273
|
+
basePath: '/api/analytics',
|
|
274
|
+
corsOrigins: ['*'],
|
|
275
|
+
},
|
|
276
|
+
|
|
277
|
+
aggregation: {
|
|
278
|
+
batchSize: 100,
|
|
279
|
+
hourlyEnabled: true,
|
|
280
|
+
dailyEnabled: true,
|
|
281
|
+
monthlyEnabled: true,
|
|
282
|
+
},
|
|
283
|
+
|
|
284
|
+
// Scale settings - disabled by default for simplicity
|
|
285
|
+
// Enable these for high-traffic sites (>10k req/sec)
|
|
286
|
+
scale: {
|
|
287
|
+
sqsBuffering: {
|
|
288
|
+
enabled: false,
|
|
289
|
+
queueUrl: undefined,
|
|
290
|
+
deadLetterQueueUrl: undefined,
|
|
291
|
+
maxRetries: 3,
|
|
292
|
+
},
|
|
293
|
+
daxCaching: {
|
|
294
|
+
enabled: false,
|
|
295
|
+
endpoint: undefined,
|
|
296
|
+
ttlSeconds: 300, // 5 minutes default cache
|
|
297
|
+
},
|
|
298
|
+
partitionSharding: {
|
|
299
|
+
enabled: false,
|
|
300
|
+
shardCount: 10,
|
|
301
|
+
enabledSiteIds: [], // Empty = disabled
|
|
302
|
+
},
|
|
303
|
+
writeCoalescing: {
|
|
304
|
+
enabled: true, // Enabled by default - reduces redundant writes
|
|
305
|
+
windowMs: 100,
|
|
306
|
+
},
|
|
307
|
+
batchWrites: {
|
|
308
|
+
enabled: true, // Enabled by default - more efficient
|
|
309
|
+
maxBatchSize: 25, // DynamoDB limit
|
|
310
|
+
flushIntervalMs: 1000,
|
|
311
|
+
},
|
|
312
|
+
},
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
// ============================================================================
|
|
316
|
+
// Configuration Functions
|
|
317
|
+
// ============================================================================
|
|
318
|
+
|
|
319
|
+
/**
|
|
320
|
+
* Merge user config with defaults
|
|
321
|
+
*/
|
|
322
|
+
export function defineConfig(userConfig: UserAnalyticsConfig = {}): AnalyticsConfig {
|
|
323
|
+
return {
|
|
324
|
+
table: {
|
|
325
|
+
...defaultConfig.table,
|
|
326
|
+
...userConfig.table,
|
|
327
|
+
singleTable: {
|
|
328
|
+
...defaultConfig.table.singleTable,
|
|
329
|
+
...userConfig.table?.singleTable,
|
|
330
|
+
},
|
|
331
|
+
globalSecondaryIndexes: userConfig.table?.globalSecondaryIndexes ?? defaultConfig.table.globalSecondaryIndexes,
|
|
332
|
+
localSecondaryIndexes: userConfig.table?.localSecondaryIndexes ?? defaultConfig.table.localSecondaryIndexes,
|
|
333
|
+
},
|
|
334
|
+
region: userConfig.region ?? defaultConfig.region,
|
|
335
|
+
endpoint: userConfig.endpoint ?? defaultConfig.endpoint,
|
|
336
|
+
retention: {
|
|
337
|
+
...defaultConfig.retention,
|
|
338
|
+
...userConfig.retention,
|
|
339
|
+
},
|
|
340
|
+
privacy: {
|
|
341
|
+
...defaultConfig.privacy,
|
|
342
|
+
...userConfig.privacy,
|
|
343
|
+
},
|
|
344
|
+
tracking: {
|
|
345
|
+
...defaultConfig.tracking,
|
|
346
|
+
...userConfig.tracking,
|
|
347
|
+
},
|
|
348
|
+
api: {
|
|
349
|
+
...defaultConfig.api,
|
|
350
|
+
...userConfig.api,
|
|
351
|
+
},
|
|
352
|
+
aggregation: {
|
|
353
|
+
...defaultConfig.aggregation,
|
|
354
|
+
...userConfig.aggregation,
|
|
355
|
+
},
|
|
356
|
+
scale: {
|
|
357
|
+
sqsBuffering: {
|
|
358
|
+
...defaultConfig.scale.sqsBuffering,
|
|
359
|
+
...userConfig.scale?.sqsBuffering,
|
|
360
|
+
},
|
|
361
|
+
daxCaching: {
|
|
362
|
+
...defaultConfig.scale.daxCaching,
|
|
363
|
+
...userConfig.scale?.daxCaching,
|
|
364
|
+
},
|
|
365
|
+
partitionSharding: {
|
|
366
|
+
...defaultConfig.scale.partitionSharding,
|
|
367
|
+
...userConfig.scale?.partitionSharding,
|
|
368
|
+
},
|
|
369
|
+
writeCoalescing: {
|
|
370
|
+
...defaultConfig.scale.writeCoalescing,
|
|
371
|
+
...userConfig.scale?.writeCoalescing,
|
|
372
|
+
},
|
|
373
|
+
batchWrites: {
|
|
374
|
+
...defaultConfig.scale.batchWrites,
|
|
375
|
+
...userConfig.scale?.batchWrites,
|
|
376
|
+
},
|
|
377
|
+
},
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
/**
|
|
382
|
+
* Create table configuration from analytics config
|
|
383
|
+
*/
|
|
384
|
+
export function getTableConfig(config: AnalyticsConfig): {
|
|
385
|
+
tableName: string
|
|
386
|
+
billingMode: BillingMode
|
|
387
|
+
partitionKey: string
|
|
388
|
+
sortKey: string
|
|
389
|
+
gsis: GSIDefinition[]
|
|
390
|
+
ttlAttribute?: string
|
|
391
|
+
} {
|
|
392
|
+
return {
|
|
393
|
+
tableName: config.table.tableName,
|
|
394
|
+
billingMode: config.table.billingMode,
|
|
395
|
+
partitionKey: config.table.singleTable.partitionKeyName,
|
|
396
|
+
sortKey: config.table.singleTable.sortKeyName,
|
|
397
|
+
gsis: config.table.globalSecondaryIndexes,
|
|
398
|
+
ttlAttribute: config.table.ttlAttributeName,
|
|
399
|
+
}
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
/**
|
|
403
|
+
* Get TTL value for a given entity type
|
|
404
|
+
*/
|
|
405
|
+
export function getTtlForEntity(
|
|
406
|
+
config: AnalyticsConfig,
|
|
407
|
+
entityType: 'raw' | 'hourly' | 'daily' | 'monthly',
|
|
408
|
+
): number | undefined {
|
|
409
|
+
const now = Math.floor(Date.now() / 1000)
|
|
410
|
+
|
|
411
|
+
switch (entityType) {
|
|
412
|
+
case 'raw':
|
|
413
|
+
return now + config.retention.rawEventTtl
|
|
414
|
+
case 'hourly':
|
|
415
|
+
return now + config.retention.hourlyAggregateTtl
|
|
416
|
+
case 'daily':
|
|
417
|
+
return now + config.retention.dailyAggregateTtl
|
|
418
|
+
case 'monthly':
|
|
419
|
+
return config.retention.monthlyAggregateTtl
|
|
420
|
+
? now + config.retention.monthlyAggregateTtl
|
|
421
|
+
: undefined
|
|
422
|
+
default:
|
|
423
|
+
return undefined
|
|
424
|
+
}
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
// ============================================================================
|
|
428
|
+
// Config Singleton
|
|
429
|
+
// ============================================================================
|
|
430
|
+
|
|
431
|
+
let _config: AnalyticsConfig | null = null
|
|
432
|
+
|
|
433
|
+
/**
|
|
434
|
+
* Set global analytics configuration
|
|
435
|
+
*/
|
|
436
|
+
export function setConfig(config: UserAnalyticsConfig): AnalyticsConfig {
|
|
437
|
+
_config = defineConfig(config)
|
|
438
|
+
return _config
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
/**
|
|
442
|
+
* Get current analytics configuration
|
|
443
|
+
*/
|
|
444
|
+
export function getConfig(): AnalyticsConfig {
|
|
445
|
+
if (!_config) {
|
|
446
|
+
_config = defaultConfig
|
|
447
|
+
}
|
|
448
|
+
return _config
|
|
449
|
+
}
|
|
450
|
+
|
|
451
|
+
/**
|
|
452
|
+
* Reset configuration to defaults
|
|
453
|
+
*/
|
|
454
|
+
export function resetConfig(): void {
|
|
455
|
+
_config = null
|
|
456
|
+
}
|