@iann29/rastro 0.1.0-alpha.0 → 0.1.0-alpha.2

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 (79) hide show
  1. package/README.md +98 -18
  2. package/dist/component/_generated/api.d.ts +7 -1
  3. package/dist/component/_generated/api.d.ts.map +1 -1
  4. package/dist/component/_generated/api.js.map +1 -1
  5. package/dist/component/constants.d.ts +11 -6
  6. package/dist/component/constants.d.ts.map +1 -1
  7. package/dist/component/constants.js +11 -6
  8. package/dist/component/constants.js.map +1 -1
  9. package/dist/component/convex.config.d.ts +2 -2
  10. package/dist/component/convex.config.d.ts.map +1 -1
  11. package/dist/component/convex.config.js +4 -1
  12. package/dist/component/convex.config.js.map +1 -1
  13. package/dist/component/eventStore.d.ts +102 -0
  14. package/dist/component/eventStore.d.ts.map +1 -0
  15. package/dist/component/eventStore.js +463 -0
  16. package/dist/component/eventStore.js.map +1 -0
  17. package/dist/component/goals.d.ts.map +1 -1
  18. package/dist/component/goals.js +17 -4
  19. package/dist/component/goals.js.map +1 -1
  20. package/dist/component/http.d.ts.map +1 -1
  21. package/dist/component/http.js +39 -7
  22. package/dist/component/http.js.map +1 -1
  23. package/dist/component/ingest.d.ts.map +1 -1
  24. package/dist/component/ingest.js +520 -207
  25. package/dist/component/ingest.js.map +1 -1
  26. package/dist/component/live.d.ts +8 -0
  27. package/dist/component/live.d.ts.map +1 -1
  28. package/dist/component/live.js +72 -8
  29. package/dist/component/live.js.map +1 -1
  30. package/dist/component/migrations.d.ts +17 -0
  31. package/dist/component/migrations.d.ts.map +1 -0
  32. package/dist/component/migrations.js +44 -0
  33. package/dist/component/migrations.js.map +1 -0
  34. package/dist/component/reports.d.ts +16 -16
  35. package/dist/component/reports.d.ts.map +1 -1
  36. package/dist/component/reports.js +228 -65
  37. package/dist/component/reports.js.map +1 -1
  38. package/dist/component/retention.d.ts.map +1 -1
  39. package/dist/component/retention.js +15 -10
  40. package/dist/component/retention.js.map +1 -1
  41. package/dist/component/sanitize.d.ts.map +1 -1
  42. package/dist/component/sanitize.js +11 -3
  43. package/dist/component/sanitize.js.map +1 -1
  44. package/dist/component/schema.d.ts +132 -9
  45. package/dist/component/schema.js +32 -7
  46. package/dist/component/schema.js.map +1 -1
  47. package/dist/component/sites.d.ts.map +1 -1
  48. package/dist/component/sites.js +27 -18
  49. package/dist/component/sites.js.map +1 -1
  50. package/dist/component/validators.d.ts +96 -0
  51. package/dist/component/validators.d.ts.map +1 -1
  52. package/dist/component/validators.js +12 -0
  53. package/dist/component/validators.js.map +1 -1
  54. package/dist/tracker/generated.d.ts +4 -4
  55. package/dist/tracker/generated.d.ts.map +1 -1
  56. package/dist/tracker/generated.js +4 -4
  57. package/dist/tracker/generated.js.map +1 -1
  58. package/dist/tracker/tracker.js +33 -22
  59. package/dist/tracker/tracker.js.map +1 -1
  60. package/dist/tracker.min.js +1 -1
  61. package/docs/benchmarks/2026-08-20-realistic.md +171 -0
  62. package/package.json +15 -5
  63. package/scripts/benchmark-ingest.mjs +499 -0
  64. package/src/component/_generated/api.ts +7 -1
  65. package/src/component/constants.ts +11 -6
  66. package/src/component/convex.config.ts +5 -1
  67. package/src/component/eventStore.ts +684 -0
  68. package/src/component/goals.ts +25 -4
  69. package/src/component/http.ts +49 -6
  70. package/src/component/ingest.ts +671 -215
  71. package/src/component/live.ts +83 -8
  72. package/src/component/migrations.ts +52 -0
  73. package/src/component/reports.ts +295 -86
  74. package/src/component/retention.ts +15 -12
  75. package/src/component/sanitize.ts +10 -3
  76. package/src/component/schema.ts +35 -7
  77. package/src/component/sites.ts +31 -18
  78. package/src/component/validators.ts +16 -0
  79. package/src/test.ts +2 -0
package/README.md CHANGED
@@ -4,7 +4,7 @@
4
4
 
5
5
  Privacy-first, real-time web analytics built as an isolated Convex component.
6
6
 
7
- Amage Rastro combines a 991-byte gzip browser tracker with reactive traffic
7
+ Amage Rastro combines a 1,022-byte gzip browser tracker with reactive traffic
8
8
  metrics, a live visitor atlas, journey timelines, trusted payment attribution,
9
9
  goals, funnels, affiliates, and multi-site reports. Data and functions stay
10
10
  inside your Convex deployment.
@@ -24,7 +24,7 @@ inside your Convex deployment.
24
24
  | Cross-site analytics | Reports over up to ten authorized site IDs with a preloaded pseudonymous visitor ID |
25
25
  | Auto-captured clicks | Anchors, buttons, outbound links, and explicit `data-rastro-event` controls |
26
26
  | Cookieless mode | Session-scoped pseudonymous IDs in `sessionStorage`; no cookies |
27
- | Tiny tracker | 1,890 bytes raw, 991 bytes gzip; the test suite enforces `< 1,024` bytes |
27
+ | Tiny tracker | 1,909 bytes raw, 1,022 bytes gzip; the test suite enforces `< 1,024` bytes |
28
28
 
29
29
  ## Install
30
30
 
@@ -172,6 +172,12 @@ Properties accept bounded string, number, boolean, or null values. Never send
172
172
  emails, names, form values, secrets, or other personal data as analytics
173
173
  properties.
174
174
 
175
+ Browser telemetry exact retries are idempotent within
176
+ `(siteId, sessionId, event-minute, eventId)`. Reusing an event ID in another
177
+ session or with a timestamp in another minute is allowed. The tracker preserves
178
+ timestamps when retrying. Trusted payment event IDs remain separately
179
+ payload-bound by the site's financial ledger.
180
+
175
181
  ## Attribute trusted payments
176
182
 
177
183
  Browser-created conversion events are untrusted telemetry and never affect
@@ -271,25 +277,99 @@ The `Rastro` class wraps the component boundary for host functions:
271
277
  - Retention: `cleanup`
272
278
 
273
279
  Every public function has argument and return validators. Growing reads are
274
- indexed and bounded. Component pagination uses validated opaque manual cursors
275
- because native `.paginate()` is not supported inside Convex components.
280
+ indexed and bounded. Component pagination uses scope-bound opaque keyset cursors
281
+ because native `.paginate()` is not supported inside Convex components; page
282
+ cost stays constant instead of increasing with an offset.
276
283
 
277
284
  ## Operational limits
278
285
 
279
286
  - HTTP body: 64 KiB
280
- - Events per batch: 20
281
- - Aggregate shards: 16, derived from stable session/visitor identity
282
- - Site ingress budget: eight deterministic per-minute shards with bounded event
283
- and byte caps
284
- - Live session timeout: 60 seconds with one self-rescheduling expiry chain per
285
- session
287
+ - Events per batch: 50
288
+ - Session-minute groups per batch: 4
289
+ - Active goals per exact matcher: 1
290
+ - Primary aggregate shards: 256 hourly and 128 daily, derived from stable
291
+ session identity
292
+ - Funnel and affiliate aggregate shards: 16
293
+ - Site ingress budget: 4,096 deterministic per-minute shards, each capped at
294
+ 300 events and 512 KiB (1,228,800 admitted events/minute at uniform load)
295
+ - Rate-window storage: one reusable row per active session and site shard
296
+ - Live session timeout: 60 seconds with one bounded five-second expiry sweep per
297
+ site; legacy per-session jobs hand off to that sweep during the cutover
286
298
  - Dashboard overview: up to ten sites and bounded report ranges
299
+ - Hourly overview: up to 24 hours; wider ranges use daily buckets
287
300
  - Retention cleanup: bounded batches; schedule host maintenance for the data
288
- classes your policy retains
301
+ classes your policy retains. The `events` cleanup kind covers both legacy
302
+ event rows and new event batches and processes at most 32 heavy batches per
303
+ transaction.
304
+
305
+ Capacity claims use declared workload profiles. Complete release evidence
306
+ reports ten-minute `lean`, `realistic`, `heavy`, and browser `feature` profiles
307
+ separately. The browser `feature` profile exercises configured goals, funnels,
308
+ and affiliate attribution; trusted conversions require a separate server-side
309
+ driver and certification result.
310
+
311
+ The historical development evidence and its certification caveats are recorded
312
+ in [`docs/benchmarks/2026-08-20-realistic.md`](docs/benchmarks/2026-08-20-realistic.md).
313
+
314
+ From a repository checkout, run a duration-based profile against a confirmed
315
+ non-production deployment and a dedicated idle benchmark site:
316
+
317
+ ```bash
318
+ npm run --silent benchmark:ingest -- \
319
+ --url https://example.site/rastro/events \
320
+ --convex-url https://example.convex-backend \
321
+ --site-id your_site_id \
322
+ --origin https://your-allowed-origin.example \
323
+ --profile realistic \
324
+ --duration 600 \
325
+ --concurrency 100 \
326
+ --certify
327
+ ```
328
+
329
+ Profiles are `lean`, `realistic`, `heavy`, and `feature`. The realistic profile
330
+ reuses sessions and sends geographic and user-agent headers so the same load is
331
+ visible in Live Atlas. Only `feature` intentionally matches the demo goal,
332
+ funnel, and affiliate definitions; it does not call the trusted conversion API.
333
+ Use `--dry-run` to inspect generated request size without sending traffic. When
334
+ `--convex-url` is supplied, it must identify the same deployment as `--url` and
335
+ expose this repository's `example:overview` query. The final reconciliation is
336
+ a site-wide before/after delta, so unrelated traffic on that site invalidates
337
+ the result. Reports distinguish accepted ingress, heartbeats, and stored events.
338
+ Shorter completed runs report extrapolated daily estimates only. `--certify`
339
+ requires at least ten minutes and successful reconciliation before emitting
340
+ certified daily capacity fields or exiting successfully as a certification.
341
+
342
+ The ingestion transaction folds metric/dimension deltas, session rate counters,
343
+ site-shard counters, session/live state, visitor attribution, and exact funnel
344
+ progress before writing. Accepted non-heartbeat telemetry from one request is
345
+ grouped into one immutable raw document per session and event-minute, without
346
+ duplicating session geo or user-agent context. A 50-event same-session,
347
+ same-minute baseline stays within 10 document writes. Each touched aggregate
348
+ bucket is written at most once per batch, and dimension overflow folds into an
349
+ explicit `(other)` bucket instead of relabeling old counts.
350
+ Click/outbound/browser-conversion telemetry skips goal and funnel work that
351
+ cannot match those event types.
352
+
353
+ New telemetry is written only to `eventBatches`. Existing `events` rows remain
354
+ readable until an operator runs the resumable migration mounted inside the
355
+ Rastro component:
356
+
357
+ ```bash
358
+ npx convex run --component rastroAnalytics migrations:migrateLegacyEvents \
359
+ '{"dryRun":true,"reset":true}'
360
+ npx convex run --component rastroAnalytics migrations:migrateLegacyEvents '{}'
361
+ npx convex run --component rastroAnalytics migrations:legacyEventsStatus '{}'
362
+ ```
289
363
 
290
- The ingestion transaction folds metric/dimension deltas and writes each touched
291
- aggregate bucket at most once per batch. Click/outbound/browser-conversion
292
- telemetry skips goal and funnel work that cannot match those event types.
364
+ Replace `rastroAnalytics` if the host mounted the component under another name.
365
+ Proceed only when status returns `complete: true`, which requires both durable
366
+ migration success and an empty legacy source. A source refilled after completion
367
+ requires an explicit `{"reset":true}` rerun. Migrated rows are compacted into
368
+ bounded canonical batches and retain their original per-event browser and geo
369
+ context. Journey `_id` values remain stable strings for both formats during the
370
+ cutover, and session-journey cursors use timestamp, creation time, and ID. The
371
+ compatibility logic remains isolated in `src/component/eventStore.ts` until a
372
+ later release removes the empty legacy table and its read paths.
293
373
 
294
374
  ## Privacy contract
295
375
 
@@ -336,10 +416,10 @@ cd example && npx vite build
336
416
  ```
337
417
 
338
418
  The test suite covers origin enforcement, event/privacy sanitization,
339
- idempotency, session/site rate limits, live expiry scheduling, folded aggregate
340
- writes, goals, funnels, trusted payments, currency safety, affiliate commission,
341
- cross-site journeys, manual pagination, retention, HTTP routes, React
342
- integration, and tracker size/behavior.
419
+ idempotency, reusable session/site rate limits, bounded live expiry chains,
420
+ folded aggregate writes, goals, funnels, trusted payments, currency safety,
421
+ affiliate commission, cross-site journeys, keyset pagination beyond 1,000 rows,
422
+ retention, HTTP routes, React integration, and tracker size/behavior.
343
423
 
344
424
  ## Synapse demo
345
425
 
@@ -9,12 +9,14 @@
9
9
  import type * as affiliates from "../affiliates.js";
10
10
  import type * as constants from "../constants.js";
11
11
  import type * as errors from "../errors.js";
12
+ import type * as eventStore from "../eventStore.js";
12
13
  import type * as funnels from "../funnels.js";
13
14
  import type * as goals from "../goals.js";
14
15
  import type * as guards from "../guards.js";
15
16
  import type * as http from "../http.js";
16
17
  import type * as ingest from "../ingest.js";
17
18
  import type * as live from "../live.js";
19
+ import type * as migrations from "../migrations.js";
18
20
  import type * as reports from "../reports.js";
19
21
  import type * as retention from "../retention.js";
20
22
  import type * as sanitize from "../sanitize.js";
@@ -25,12 +27,14 @@ declare const fullApi: ApiFromModules<{
25
27
  affiliates: typeof affiliates;
26
28
  constants: typeof constants;
27
29
  errors: typeof errors;
30
+ eventStore: typeof eventStore;
28
31
  funnels: typeof funnels;
29
32
  goals: typeof goals;
30
33
  guards: typeof guards;
31
34
  http: typeof http;
32
35
  ingest: typeof ingest;
33
36
  live: typeof live;
37
+ migrations: typeof migrations;
34
38
  reports: typeof reports;
35
39
  retention: typeof retention;
36
40
  sanitize: typeof sanitize;
@@ -55,6 +59,8 @@ export declare const api: FilterApi<typeof fullApi, FunctionReference<any, "publ
55
59
  * ```
56
60
  */
57
61
  export declare const internal: FilterApi<typeof fullApi, FunctionReference<any, "internal">>;
58
- export declare const components: {};
62
+ export declare const components: {
63
+ migrations: import("@convex-dev/migrations/_generated/component.js").ComponentApi<"migrations">;
64
+ };
59
65
  export {};
60
66
  //# sourceMappingURL=api.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"api.d.ts","sourceRoot":"","sources":["../../../src/component/_generated/api.ts"],"names":[],"mappings":"AACA;;;;;;;GAOG;AAEH,OAAO,KAAK,KAAK,UAAU,MAAM,kBAAkB,CAAC;AACpD,OAAO,KAAK,KAAK,SAAS,MAAM,iBAAiB,CAAC;AAClD,OAAO,KAAK,KAAK,MAAM,MAAM,cAAc,CAAC;AAC5C,OAAO,KAAK,KAAK,OAAO,MAAM,eAAe,CAAC;AAC9C,OAAO,KAAK,KAAK,KAAK,MAAM,aAAa,CAAC;AAC1C,OAAO,KAAK,KAAK,MAAM,MAAM,cAAc,CAAC;AAC5C,OAAO,KAAK,KAAK,IAAI,MAAM,YAAY,CAAC;AACxC,OAAO,KAAK,KAAK,MAAM,MAAM,cAAc,CAAC;AAC5C,OAAO,KAAK,KAAK,IAAI,MAAM,YAAY,CAAC;AACxC,OAAO,KAAK,KAAK,OAAO,MAAM,eAAe,CAAC;AAC9C,OAAO,KAAK,KAAK,SAAS,MAAM,iBAAiB,CAAC;AAClD,OAAO,KAAK,KAAK,QAAQ,MAAM,gBAAgB,CAAC;AAChD,OAAO,KAAK,KAAK,KAAK,MAAM,aAAa,CAAC;AAC1C,OAAO,KAAK,KAAK,UAAU,MAAM,kBAAkB,CAAC;AAEpD,OAAO,KAAK,EACV,cAAc,EACd,SAAS,EACT,iBAAiB,EAClB,MAAM,eAAe,CAAC;AAGvB,QAAA,MAAM,OAAO,EAAE,cAAc,CAAC;IAC5B,UAAU,EAAE,OAAO,UAAU,CAAC;IAC9B,SAAS,EAAE,OAAO,SAAS,CAAC;IAC5B,MAAM,EAAE,OAAO,MAAM,CAAC;IACtB,OAAO,EAAE,OAAO,OAAO,CAAC;IACxB,KAAK,EAAE,OAAO,KAAK,CAAC;IACpB,MAAM,EAAE,OAAO,MAAM,CAAC;IACtB,IAAI,EAAE,OAAO,IAAI,CAAC;IAClB,MAAM,EAAE,OAAO,MAAM,CAAC;IACtB,IAAI,EAAE,OAAO,IAAI,CAAC;IAClB,OAAO,EAAE,OAAO,OAAO,CAAC;IACxB,SAAS,EAAE,OAAO,SAAS,CAAC;IAC5B,QAAQ,EAAE,OAAO,QAAQ,CAAC;IAC1B,KAAK,EAAE,OAAO,KAAK,CAAC;IACpB,UAAU,EAAE,OAAO,UAAU,CAAC;CAC/B,CAAiB,CAAC;AAEnB;;;;;;;GAOG;AACH,eAAO,MAAM,GAAG,EAAE,SAAS,CACzB,OAAO,OAAO,EACd,iBAAiB,CAAC,GAAG,EAAE,QAAQ,CAAC,CACjB,CAAC;AAElB;;;;;;;GAOG;AACH,eAAO,MAAM,QAAQ,EAAE,SAAS,CAC9B,OAAO,OAAO,EACd,iBAAiB,CAAC,GAAG,EAAE,UAAU,CAAC,CACnB,CAAC;AAElB,eAAO,MAAM,UAAU,EAAqC,EAAE,CAAC"}
1
+ {"version":3,"file":"api.d.ts","sourceRoot":"","sources":["../../../src/component/_generated/api.ts"],"names":[],"mappings":"AACA;;;;;;;GAOG;AAEH,OAAO,KAAK,KAAK,UAAU,MAAM,kBAAkB,CAAC;AACpD,OAAO,KAAK,KAAK,SAAS,MAAM,iBAAiB,CAAC;AAClD,OAAO,KAAK,KAAK,MAAM,MAAM,cAAc,CAAC;AAC5C,OAAO,KAAK,KAAK,UAAU,MAAM,kBAAkB,CAAC;AACpD,OAAO,KAAK,KAAK,OAAO,MAAM,eAAe,CAAC;AAC9C,OAAO,KAAK,KAAK,KAAK,MAAM,aAAa,CAAC;AAC1C,OAAO,KAAK,KAAK,MAAM,MAAM,cAAc,CAAC;AAC5C,OAAO,KAAK,KAAK,IAAI,MAAM,YAAY,CAAC;AACxC,OAAO,KAAK,KAAK,MAAM,MAAM,cAAc,CAAC;AAC5C,OAAO,KAAK,KAAK,IAAI,MAAM,YAAY,CAAC;AACxC,OAAO,KAAK,KAAK,UAAU,MAAM,kBAAkB,CAAC;AACpD,OAAO,KAAK,KAAK,OAAO,MAAM,eAAe,CAAC;AAC9C,OAAO,KAAK,KAAK,SAAS,MAAM,iBAAiB,CAAC;AAClD,OAAO,KAAK,KAAK,QAAQ,MAAM,gBAAgB,CAAC;AAChD,OAAO,KAAK,KAAK,KAAK,MAAM,aAAa,CAAC;AAC1C,OAAO,KAAK,KAAK,UAAU,MAAM,kBAAkB,CAAC;AAEpD,OAAO,KAAK,EACV,cAAc,EACd,SAAS,EACT,iBAAiB,EAClB,MAAM,eAAe,CAAC;AAGvB,QAAA,MAAM,OAAO,EAAE,cAAc,CAAC;IAC5B,UAAU,EAAE,OAAO,UAAU,CAAC;IAC9B,SAAS,EAAE,OAAO,SAAS,CAAC;IAC5B,MAAM,EAAE,OAAO,MAAM,CAAC;IACtB,UAAU,EAAE,OAAO,UAAU,CAAC;IAC9B,OAAO,EAAE,OAAO,OAAO,CAAC;IACxB,KAAK,EAAE,OAAO,KAAK,CAAC;IACpB,MAAM,EAAE,OAAO,MAAM,CAAC;IACtB,IAAI,EAAE,OAAO,IAAI,CAAC;IAClB,MAAM,EAAE,OAAO,MAAM,CAAC;IACtB,IAAI,EAAE,OAAO,IAAI,CAAC;IAClB,UAAU,EAAE,OAAO,UAAU,CAAC;IAC9B,OAAO,EAAE,OAAO,OAAO,CAAC;IACxB,SAAS,EAAE,OAAO,SAAS,CAAC;IAC5B,QAAQ,EAAE,OAAO,QAAQ,CAAC;IAC1B,KAAK,EAAE,OAAO,KAAK,CAAC;IACpB,UAAU,EAAE,OAAO,UAAU,CAAC;CAC/B,CAAiB,CAAC;AAEnB;;;;;;;GAOG;AACH,eAAO,MAAM,GAAG,EAAE,SAAS,CACzB,OAAO,OAAO,EACd,iBAAiB,CAAC,GAAG,EAAE,QAAQ,CAAC,CACjB,CAAC;AAElB;;;;;;;GAOG;AACH,eAAO,MAAM,QAAQ,EAAE,SAAS,CAC9B,OAAO,OAAO,EACd,iBAAiB,CAAC,GAAG,EAAE,UAAU,CAAC,CACnB,CAAC;AAElB,eAAO,MAAM,UAAU,EAAqC;IAC1D,UAAU,EAAE,OAAO,gDAAgD,EAAE,YAAY,CAAC,YAAY,CAAC,CAAC;CACjG,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"api.js","sourceRoot":"","sources":["../../../src/component/_generated/api.ts"],"names":[],"mappings":"AAAA,oBAAoB;AACpB;;;;;;;GAOG;AAsBH,OAAO,EAAE,MAAM,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;AAE1D,MAAM,OAAO,GAeR,MAAa,CAAC;AAEnB;;;;;;;GAOG;AACH,MAAM,CAAC,MAAM,GAAG,GAGZ,MAAa,CAAC;AAElB;;;;;;;GAOG;AACH,MAAM,CAAC,MAAM,QAAQ,GAGjB,MAAa,CAAC;AAElB,MAAM,CAAC,MAAM,UAAU,GAAG,iBAAiB,EAAmB,CAAC"}
1
+ {"version":3,"file":"api.js","sourceRoot":"","sources":["../../../src/component/_generated/api.ts"],"names":[],"mappings":"AAAA,oBAAoB;AACpB;;;;;;;GAOG;AAwBH,OAAO,EAAE,MAAM,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;AAE1D,MAAM,OAAO,GAiBR,MAAa,CAAC;AAEnB;;;;;;;GAOG;AACH,MAAM,CAAC,MAAM,GAAG,GAGZ,MAAa,CAAC;AAElB;;;;;;;GAOG;AACH,MAAM,CAAC,MAAM,QAAQ,GAGjB,MAAa,CAAC;AAElB,MAAM,CAAC,MAAM,UAAU,GAAG,iBAAiB,EAE1C,CAAC"}
@@ -1,13 +1,17 @@
1
- export declare const MAX_BATCH_EVENTS = 20;
1
+ export declare const MAX_BATCH_EVENTS = 50;
2
+ export declare const MAX_BATCH_EVENT_GROUPS = 4;
2
3
  export declare const MAX_BATCH_BYTES: number;
3
4
  export declare const MAX_EVENTS_PER_SESSION_WINDOW = 120;
4
5
  export declare const RATE_LIMIT_WINDOW_MS = 60000;
5
6
  export declare const MAX_BYTES_PER_SESSION_WINDOW: number;
6
- export declare const SITE_INGEST_SHARDS = 8;
7
- export declare const MAX_SITE_EVENTS_PER_SHARD_WINDOW = 120;
7
+ export declare const SITE_INGEST_SHARDS = 4096;
8
+ export declare const MAX_SITE_EVENTS_PER_SHARD_WINDOW = 300;
8
9
  export declare const MAX_SITE_BYTES_PER_SHARD_WINDOW: number;
9
10
  export declare const LIVE_SESSION_TTL_MS = 60000;
10
- export declare const AGGREGATE_SHARDS = 16;
11
+ export declare const LIVE_SWEEP_INTERVAL_MS = 5000;
12
+ export declare const AGGREGATE_SHARDS = 128;
13
+ export declare const HOURLY_AGGREGATE_SHARDS = 256;
14
+ export declare const SECONDARY_AGGREGATE_SHARDS = 16;
11
15
  export declare const DIMENSION_SLOTS = 16;
12
16
  export declare const MAX_SITE_DOMAINS = 32;
13
17
  export declare const MAX_SITES_PER_OWNER = 100;
@@ -20,9 +24,10 @@ export declare const MAX_REPORT_SITES = 10;
20
24
  export declare const MAX_REPORT_RANGE_DAYS = 366;
21
25
  export declare const MAX_LIVE_VISITORS = 500;
22
26
  export declare const MAX_JOURNEY_EVENTS = 500;
27
+ export declare const JOURNEY_READ_BYTE_RESERVE: number;
28
+ export declare const JOURNEY_READ_DOCUMENT_RESERVE = 1000;
23
29
  export declare const MAX_RETENTION_BATCH = 500;
24
- export declare const MAX_OVERVIEW_AGGREGATE_ROWS = 12000;
30
+ export declare const MAX_OVERVIEW_AGGREGATE_ROWS = 13000;
25
31
  export declare const DAY_MS = 86400000;
26
32
  export declare const HOUR_MS = 3600000;
27
- export declare const MAX_MANUAL_PAGINATION_OFFSET = 1000;
28
33
  //# sourceMappingURL=constants.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../../src/component/constants.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,gBAAgB,KAAK,CAAC;AACnC,eAAO,MAAM,eAAe,QAAY,CAAC;AACzC,eAAO,MAAM,6BAA6B,MAAM,CAAC;AACjD,eAAO,MAAM,oBAAoB,QAAS,CAAC;AAC3C,eAAO,MAAM,4BAA4B,QAAa,CAAC;AACvD,eAAO,MAAM,kBAAkB,IAAI,CAAC;AACpC,eAAO,MAAM,gCAAgC,MAAM,CAAC;AACpD,eAAO,MAAM,+BAA+B,QAAa,CAAC;AAC1D,eAAO,MAAM,mBAAmB,QAAS,CAAC;AAC1C,eAAO,MAAM,gBAAgB,KAAK,CAAC;AACnC,eAAO,MAAM,eAAe,KAAK,CAAC;AAClC,eAAO,MAAM,gBAAgB,KAAK,CAAC;AACnC,eAAO,MAAM,mBAAmB,MAAM,CAAC;AACvC,eAAO,MAAM,kBAAkB,KAAK,CAAC;AACrC,eAAO,MAAM,oBAAoB,KAAK,CAAC;AACvC,eAAO,MAAM,uBAAuB,MAAM,CAAC;AAC3C,eAAO,MAAM,gBAAgB,KAAK,CAAC;AACnC,eAAO,MAAM,cAAc,KAAK,CAAC;AACjC,eAAO,MAAM,gBAAgB,KAAK,CAAC;AACnC,eAAO,MAAM,qBAAqB,MAAM,CAAC;AACzC,eAAO,MAAM,iBAAiB,MAAM,CAAC;AACrC,eAAO,MAAM,kBAAkB,MAAM,CAAC;AACtC,eAAO,MAAM,mBAAmB,MAAM,CAAC;AACvC,eAAO,MAAM,2BAA2B,QAAS,CAAC;AAElD,eAAO,MAAM,MAAM,WAAa,CAAC;AACjC,eAAO,MAAM,OAAO,UAAY,CAAC;AACjC,eAAO,MAAM,4BAA4B,OAAQ,CAAC"}
1
+ {"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../../src/component/constants.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,gBAAgB,KAAK,CAAC;AACnC,eAAO,MAAM,sBAAsB,IAAI,CAAC;AACxC,eAAO,MAAM,eAAe,QAAY,CAAC;AACzC,eAAO,MAAM,6BAA6B,MAAM,CAAC;AACjD,eAAO,MAAM,oBAAoB,QAAS,CAAC;AAC3C,eAAO,MAAM,4BAA4B,QAAa,CAAC;AACvD,eAAO,MAAM,kBAAkB,OAAQ,CAAC;AACxC,eAAO,MAAM,gCAAgC,MAAM,CAAC;AACpD,eAAO,MAAM,+BAA+B,QAAa,CAAC;AAC1D,eAAO,MAAM,mBAAmB,QAAS,CAAC;AAC1C,eAAO,MAAM,sBAAsB,OAAQ,CAAC;AAC5C,eAAO,MAAM,gBAAgB,MAAM,CAAC;AACpC,eAAO,MAAM,uBAAuB,MAAM,CAAC;AAC3C,eAAO,MAAM,0BAA0B,KAAK,CAAC;AAC7C,eAAO,MAAM,eAAe,KAAK,CAAC;AAClC,eAAO,MAAM,gBAAgB,KAAK,CAAC;AACnC,eAAO,MAAM,mBAAmB,MAAM,CAAC;AACvC,eAAO,MAAM,kBAAkB,KAAK,CAAC;AACrC,eAAO,MAAM,oBAAoB,KAAK,CAAC;AACvC,eAAO,MAAM,uBAAuB,MAAM,CAAC;AAC3C,eAAO,MAAM,gBAAgB,KAAK,CAAC;AACnC,eAAO,MAAM,cAAc,KAAK,CAAC;AACjC,eAAO,MAAM,gBAAgB,KAAK,CAAC;AACnC,eAAO,MAAM,qBAAqB,MAAM,CAAC;AACzC,eAAO,MAAM,iBAAiB,MAAM,CAAC;AACrC,eAAO,MAAM,kBAAkB,MAAM,CAAC;AACtC,eAAO,MAAM,yBAAyB,QAAkB,CAAC;AACzD,eAAO,MAAM,6BAA6B,OAAQ,CAAC;AACnD,eAAO,MAAM,mBAAmB,MAAM,CAAC;AACvC,eAAO,MAAM,2BAA2B,QAAS,CAAC;AAElD,eAAO,MAAM,MAAM,WAAa,CAAC;AACjC,eAAO,MAAM,OAAO,UAAY,CAAC"}
@@ -1,13 +1,17 @@
1
- export const MAX_BATCH_EVENTS = 20;
1
+ export const MAX_BATCH_EVENTS = 50;
2
+ export const MAX_BATCH_EVENT_GROUPS = 4;
2
3
  export const MAX_BATCH_BYTES = 64 * 1024;
3
4
  export const MAX_EVENTS_PER_SESSION_WINDOW = 120;
4
5
  export const RATE_LIMIT_WINDOW_MS = 60_000;
5
6
  export const MAX_BYTES_PER_SESSION_WINDOW = 256 * 1024;
6
- export const SITE_INGEST_SHARDS = 8;
7
- export const MAX_SITE_EVENTS_PER_SHARD_WINDOW = 120;
7
+ export const SITE_INGEST_SHARDS = 4_096;
8
+ export const MAX_SITE_EVENTS_PER_SHARD_WINDOW = 300;
8
9
  export const MAX_SITE_BYTES_PER_SHARD_WINDOW = 512 * 1024;
9
10
  export const LIVE_SESSION_TTL_MS = 60_000;
10
- export const AGGREGATE_SHARDS = 16;
11
+ export const LIVE_SWEEP_INTERVAL_MS = 5_000;
12
+ export const AGGREGATE_SHARDS = 128;
13
+ export const HOURLY_AGGREGATE_SHARDS = 256;
14
+ export const SECONDARY_AGGREGATE_SHARDS = 16;
11
15
  export const DIMENSION_SLOTS = 16;
12
16
  export const MAX_SITE_DOMAINS = 32;
13
17
  export const MAX_SITES_PER_OWNER = 100;
@@ -20,9 +24,10 @@ export const MAX_REPORT_SITES = 10;
20
24
  export const MAX_REPORT_RANGE_DAYS = 366;
21
25
  export const MAX_LIVE_VISITORS = 500;
22
26
  export const MAX_JOURNEY_EVENTS = 500;
27
+ export const JOURNEY_READ_BYTE_RESERVE = 4 * 1024 * 1024;
28
+ export const JOURNEY_READ_DOCUMENT_RESERVE = 1_000;
23
29
  export const MAX_RETENTION_BATCH = 500;
24
- export const MAX_OVERVIEW_AGGREGATE_ROWS = 12_000;
30
+ export const MAX_OVERVIEW_AGGREGATE_ROWS = 13_000;
25
31
  export const DAY_MS = 86_400_000;
26
32
  export const HOUR_MS = 3_600_000;
27
- export const MAX_MANUAL_PAGINATION_OFFSET = 1_000;
28
33
  //# sourceMappingURL=constants.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"constants.js","sourceRoot":"","sources":["../../src/component/constants.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,gBAAgB,GAAG,EAAE,CAAC;AACnC,MAAM,CAAC,MAAM,eAAe,GAAG,EAAE,GAAG,IAAI,CAAC;AACzC,MAAM,CAAC,MAAM,6BAA6B,GAAG,GAAG,CAAC;AACjD,MAAM,CAAC,MAAM,oBAAoB,GAAG,MAAM,CAAC;AAC3C,MAAM,CAAC,MAAM,4BAA4B,GAAG,GAAG,GAAG,IAAI,CAAC;AACvD,MAAM,CAAC,MAAM,kBAAkB,GAAG,CAAC,CAAC;AACpC,MAAM,CAAC,MAAM,gCAAgC,GAAG,GAAG,CAAC;AACpD,MAAM,CAAC,MAAM,+BAA+B,GAAG,GAAG,GAAG,IAAI,CAAC;AAC1D,MAAM,CAAC,MAAM,mBAAmB,GAAG,MAAM,CAAC;AAC1C,MAAM,CAAC,MAAM,gBAAgB,GAAG,EAAE,CAAC;AACnC,MAAM,CAAC,MAAM,eAAe,GAAG,EAAE,CAAC;AAClC,MAAM,CAAC,MAAM,gBAAgB,GAAG,EAAE,CAAC;AACnC,MAAM,CAAC,MAAM,mBAAmB,GAAG,GAAG,CAAC;AACvC,MAAM,CAAC,MAAM,kBAAkB,GAAG,EAAE,CAAC;AACrC,MAAM,CAAC,MAAM,oBAAoB,GAAG,EAAE,CAAC;AACvC,MAAM,CAAC,MAAM,uBAAuB,GAAG,GAAG,CAAC;AAC3C,MAAM,CAAC,MAAM,gBAAgB,GAAG,EAAE,CAAC;AACnC,MAAM,CAAC,MAAM,cAAc,GAAG,EAAE,CAAC;AACjC,MAAM,CAAC,MAAM,gBAAgB,GAAG,EAAE,CAAC;AACnC,MAAM,CAAC,MAAM,qBAAqB,GAAG,GAAG,CAAC;AACzC,MAAM,CAAC,MAAM,iBAAiB,GAAG,GAAG,CAAC;AACrC,MAAM,CAAC,MAAM,kBAAkB,GAAG,GAAG,CAAC;AACtC,MAAM,CAAC,MAAM,mBAAmB,GAAG,GAAG,CAAC;AACvC,MAAM,CAAC,MAAM,2BAA2B,GAAG,MAAM,CAAC;AAElD,MAAM,CAAC,MAAM,MAAM,GAAG,UAAU,CAAC;AACjC,MAAM,CAAC,MAAM,OAAO,GAAG,SAAS,CAAC;AACjC,MAAM,CAAC,MAAM,4BAA4B,GAAG,KAAK,CAAC"}
1
+ {"version":3,"file":"constants.js","sourceRoot":"","sources":["../../src/component/constants.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,gBAAgB,GAAG,EAAE,CAAC;AACnC,MAAM,CAAC,MAAM,sBAAsB,GAAG,CAAC,CAAC;AACxC,MAAM,CAAC,MAAM,eAAe,GAAG,EAAE,GAAG,IAAI,CAAC;AACzC,MAAM,CAAC,MAAM,6BAA6B,GAAG,GAAG,CAAC;AACjD,MAAM,CAAC,MAAM,oBAAoB,GAAG,MAAM,CAAC;AAC3C,MAAM,CAAC,MAAM,4BAA4B,GAAG,GAAG,GAAG,IAAI,CAAC;AACvD,MAAM,CAAC,MAAM,kBAAkB,GAAG,KAAK,CAAC;AACxC,MAAM,CAAC,MAAM,gCAAgC,GAAG,GAAG,CAAC;AACpD,MAAM,CAAC,MAAM,+BAA+B,GAAG,GAAG,GAAG,IAAI,CAAC;AAC1D,MAAM,CAAC,MAAM,mBAAmB,GAAG,MAAM,CAAC;AAC1C,MAAM,CAAC,MAAM,sBAAsB,GAAG,KAAK,CAAC;AAC5C,MAAM,CAAC,MAAM,gBAAgB,GAAG,GAAG,CAAC;AACpC,MAAM,CAAC,MAAM,uBAAuB,GAAG,GAAG,CAAC;AAC3C,MAAM,CAAC,MAAM,0BAA0B,GAAG,EAAE,CAAC;AAC7C,MAAM,CAAC,MAAM,eAAe,GAAG,EAAE,CAAC;AAClC,MAAM,CAAC,MAAM,gBAAgB,GAAG,EAAE,CAAC;AACnC,MAAM,CAAC,MAAM,mBAAmB,GAAG,GAAG,CAAC;AACvC,MAAM,CAAC,MAAM,kBAAkB,GAAG,EAAE,CAAC;AACrC,MAAM,CAAC,MAAM,oBAAoB,GAAG,EAAE,CAAC;AACvC,MAAM,CAAC,MAAM,uBAAuB,GAAG,GAAG,CAAC;AAC3C,MAAM,CAAC,MAAM,gBAAgB,GAAG,EAAE,CAAC;AACnC,MAAM,CAAC,MAAM,cAAc,GAAG,EAAE,CAAC;AACjC,MAAM,CAAC,MAAM,gBAAgB,GAAG,EAAE,CAAC;AACnC,MAAM,CAAC,MAAM,qBAAqB,GAAG,GAAG,CAAC;AACzC,MAAM,CAAC,MAAM,iBAAiB,GAAG,GAAG,CAAC;AACrC,MAAM,CAAC,MAAM,kBAAkB,GAAG,GAAG,CAAC;AACtC,MAAM,CAAC,MAAM,yBAAyB,GAAG,CAAC,GAAG,IAAI,GAAG,IAAI,CAAC;AACzD,MAAM,CAAC,MAAM,6BAA6B,GAAG,KAAK,CAAC;AACnD,MAAM,CAAC,MAAM,mBAAmB,GAAG,GAAG,CAAC;AACvC,MAAM,CAAC,MAAM,2BAA2B,GAAG,MAAM,CAAC;AAElD,MAAM,CAAC,MAAM,MAAM,GAAG,UAAU,CAAC;AACjC,MAAM,CAAC,MAAM,OAAO,GAAG,SAAS,CAAC"}
@@ -1,3 +1,3 @@
1
- declare const _default: import("convex/server").ComponentDefinition<any, {}>;
2
- export default _default;
1
+ declare const component: import("convex/server").ComponentDefinition<any, {}>;
2
+ export default component;
3
3
  //# sourceMappingURL=convex.config.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"convex.config.d.ts","sourceRoot":"","sources":["../../src/component/convex.config.ts"],"names":[],"mappings":""}
1
+ {"version":3,"file":"convex.config.d.ts","sourceRoot":"","sources":["../../src/component/convex.config.ts"],"names":[],"mappings":"AAGA,QAAA,MAAM,SAAS,sDAAqC,CAAC;eAGtC,SAAS"}
@@ -1,3 +1,6 @@
1
+ import migrations from "@convex-dev/migrations/convex.config.js";
1
2
  import { defineComponent } from "convex/server";
2
- export default defineComponent("rastroAnalytics");
3
+ const component = defineComponent("rastroAnalytics");
4
+ component.use(migrations);
5
+ export default component;
3
6
  //# sourceMappingURL=convex.config.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"convex.config.js","sourceRoot":"","sources":["../../src/component/convex.config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAEhD,eAAe,eAAe,CAAC,iBAAiB,CAAC,CAAC"}
1
+ {"version":3,"file":"convex.config.js","sourceRoot":"","sources":["../../src/component/convex.config.ts"],"names":[],"mappings":"AAAA,OAAO,UAAU,MAAM,yCAAyC,CAAC;AACjE,OAAO,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAEhD,MAAM,SAAS,GAAG,eAAe,CAAC,iBAAiB,CAAC,CAAC;AACrD,SAAS,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC;AAE1B,eAAe,SAAS,CAAC"}
@@ -0,0 +1,102 @@
1
+ import type { Doc, Id } from "./_generated/dataModel.js";
2
+ import type { MutationCtx, QueryCtx } from "./_generated/server.js";
3
+ import type { TrackerEvent } from "./validators.js";
4
+ export type TelemetryMatch = {
5
+ sessionId: string;
6
+ visitorId: string;
7
+ country?: string;
8
+ city?: string;
9
+ latitude?: number;
10
+ longitude?: number;
11
+ browser?: string;
12
+ os?: string;
13
+ device?: string;
14
+ };
15
+ type BufferedEventBatch = {
16
+ siteId: Id<"sites">;
17
+ sessionId: string;
18
+ visitorId: string;
19
+ bucketStart: number;
20
+ events: TrackerEvent[];
21
+ };
22
+ export type EventBatchBuffer = Map<string, BufferedEventBatch>;
23
+ export type JourneyCursor = {
24
+ timestamp: number;
25
+ creationTime: number;
26
+ id: string;
27
+ };
28
+ export type RawJourneyEvent = Omit<Doc<"events">, "_id"> & {
29
+ _id: string;
30
+ };
31
+ export declare function eventBucketStart(timestamp: number): number;
32
+ export declare function eventBatchKey(sessionId: string, bucketStart: number): string;
33
+ export declare function inspectTelemetryMinute(ctx: MutationCtx, input: {
34
+ siteId: Id<"sites">;
35
+ sessionId: string;
36
+ bucketStart: number;
37
+ candidateEventIds: Set<string>;
38
+ }): Promise<{
39
+ eventIds: Set<string>;
40
+ persistedCount: number;
41
+ }>;
42
+ export declare function findTelemetry(ctx: MutationCtx, siteId: Id<"sites">, event: TrackerEvent): Promise<{
43
+ match: TelemetryMatch | null;
44
+ saturated: boolean;
45
+ }>;
46
+ export declare function bufferEventBatch(siteId: Id<"sites">, event: TrackerEvent, buffer: EventBatchBuffer): void;
47
+ export declare function insertEventBatch(ctx: MutationCtx, siteId: Id<"sites">, event: TrackerEvent): Promise<void>;
48
+ export declare function flushEventBatches(ctx: MutationCtx, buffer: EventBatchBuffer): Promise<void>;
49
+ export declare function migrateLegacyEventToBatch(ctx: MutationCtx, event: Doc<"events">): Promise<void>;
50
+ export declare function loadSessionJourneyEvents(ctx: QueryCtx, input: {
51
+ siteId: Id<"sites">;
52
+ sessionId: string;
53
+ from: number;
54
+ to: number;
55
+ cursor: JourneyCursor | null;
56
+ resultLimit: number;
57
+ }): Promise<RawJourneyEvent[]>;
58
+ export declare function loadVisitorJourneyEvents(ctx: QueryCtx, input: {
59
+ siteId: Id<"sites">;
60
+ visitorId: string;
61
+ from: number;
62
+ to: number;
63
+ resultLimit: number;
64
+ }): Promise<RawJourneyEvent[]>;
65
+ export declare function compareJourneyEvents(left: Pick<RawJourneyEvent, "timestamp" | "_creationTime" | "_id">, right: Pick<RawJourneyEvent, "timestamp" | "_creationTime" | "_id">): number;
66
+ export declare function hydrateEventContexts(ctx: QueryCtx, rows: RawJourneyEvent[]): Promise<{
67
+ _creationTime: number;
68
+ _id: string;
69
+ country?: string | undefined;
70
+ city?: string | undefined;
71
+ latitude?: number | undefined;
72
+ longitude?: number | undefined;
73
+ browser: string;
74
+ os: string;
75
+ device: string;
76
+ affiliateSlug?: string | undefined;
77
+ currency?: string | undefined;
78
+ eventId: string;
79
+ href?: string | undefined;
80
+ name?: string | undefined;
81
+ path: string;
82
+ properties?: Record<string, string | number | boolean | null> | undefined;
83
+ referrer?: string | undefined;
84
+ revenueCents?: number | undefined;
85
+ sequence: number;
86
+ sessionId: string;
87
+ siteId: import("convex/values").GenericId<"sites">;
88
+ target?: string | undefined;
89
+ timestamp: number;
90
+ type: "click" | "conversion" | "custom" | "heartbeat" | "outbound" | "pageview";
91
+ visitorId: string;
92
+ }[]>;
93
+ export declare function deleteTelemetryBefore(ctx: MutationCtx, input: {
94
+ siteId: Id<"sites">;
95
+ before: number;
96
+ batchSize: number;
97
+ }): Promise<{
98
+ deleted: number;
99
+ hasMore: boolean;
100
+ }>;
101
+ export {};
102
+ //# sourceMappingURL=eventStore.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"eventStore.d.ts","sourceRoot":"","sources":["../../src/component/eventStore.ts"],"names":[],"mappings":"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"}