@happyvertical/smrt-analytics 0.55.7 → 0.55.8

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.
@@ -3,13 +3,13 @@
3
3
  "sensitiveFieldsExcluded": true,
4
4
  "generatedAt": "1970-01-01T00:00:00.000Z",
5
5
  "packageName": "@happyvertical/smrt-analytics",
6
- "packageVersion": "0.55.7",
6
+ "packageVersion": "0.55.8",
7
7
  "sourceManifestPath": "dist/manifest.json",
8
8
  "agentDocPath": "AGENTS.md",
9
9
  "sourceHashes": {
10
- "manifest": "85d63802b4112264669d75aaffff1409812ae1d72f1d4b69c01f624eae056242",
11
- "packageJson": "5aa340d0200b5cf8d023902b98b374ad9c19254779c2538e21c562bded78be57",
12
- "agents": "baaeb44320f95dc5dc86925318e791369681ad80acfbb82a0f667f2aed0e511c"
10
+ "manifest": "13e06c4864f1626ead1e71361caa78ea17d36759f93466401b89777a837f7840",
11
+ "packageJson": "555165f082315ad6ae43e615f456c7b855b2a1faf9d3275c2646926427eef1fd",
12
+ "agents": "52d16fea29774e6ac50038329c1c644f2f25d2b02df4fc75c96effe7ce477713"
13
13
  },
14
14
  "exports": [
15
15
  ".",
@@ -25,6 +25,7 @@
25
25
  "@happyvertical/smrt-tenancy": "workspace:*",
26
26
  "@happyvertical/smrt-types": "workspace:*",
27
27
  "@happyvertical/smrt-ui": "workspace:*",
28
+ "@happyvertical/smrt-scanner": "workspace:*",
28
29
  "@happyvertical/smrt-vitest": "workspace:*",
29
30
  "@happyvertical/sql": "catalog:",
30
31
  "@sveltejs/package": "^2.5.8",
@@ -39,6 +40,7 @@
39
40
  "smrtDependencies": [
40
41
  "@happyvertical/smrt-core",
41
42
  "@happyvertical/smrt-prompts",
43
+ "@happyvertical/smrt-scanner",
42
44
  "@happyvertical/smrt-tenancy",
43
45
  "@happyvertical/smrt-types",
44
46
  "@happyvertical/smrt-ui",
@@ -2295,48 +2297,55 @@
2295
2297
  "type": "text",
2296
2298
  "required": false,
2297
2299
  "columnType": "TEXT",
2298
- "default": ""
2300
+ "default": "",
2301
+ "description": "The name people see for this website or app."
2299
2302
  },
2300
2303
  {
2301
2304
  "name": "provider",
2302
2305
  "type": "text",
2303
2306
  "required": false,
2304
- "columnType": "TEXT"
2307
+ "columnType": "TEXT",
2308
+ "description": "Which analytics service tracks it: Google Analytics 4, Plausible or Matomo."
2305
2309
  },
2306
2310
  {
2307
2311
  "name": "externalId",
2308
2312
  "type": "text",
2309
2313
  "required": false,
2310
2314
  "columnType": "TEXT",
2311
- "default": ""
2315
+ "default": "",
2316
+ "description": "The id the analytics service gives the property, such as properties/123456789 or a Matomo site id."
2312
2317
  },
2313
2318
  {
2314
2319
  "name": "measurementId",
2315
2320
  "type": "text",
2316
2321
  "required": false,
2317
2322
  "columnType": "TEXT",
2318
- "default": ""
2323
+ "default": "",
2324
+ "description": "The tracking id for a web stream, such as G-XXXXXXXXXX."
2319
2325
  },
2320
2326
  {
2321
2327
  "name": "siteDomain",
2322
2328
  "type": "text",
2323
2329
  "required": false,
2324
2330
  "columnType": "TEXT",
2325
- "default": ""
2331
+ "default": "",
2332
+ "description": "The website address, used by Plausible and Matomo."
2326
2333
  },
2327
2334
  {
2328
2335
  "name": "timeZone",
2329
2336
  "type": "text",
2330
2337
  "required": false,
2331
2338
  "columnType": "TEXT",
2332
- "default": "America/Los_Angeles"
2339
+ "default": "America/Los_Angeles",
2340
+ "description": "The time zone the figures are reported in."
2333
2341
  },
2334
2342
  {
2335
2343
  "name": "currencyCode",
2336
2344
  "type": "text",
2337
2345
  "required": false,
2338
2346
  "columnType": "TEXT",
2339
- "default": "USD"
2347
+ "default": "USD",
2348
+ "description": "The currency used for revenue figures, such as USD."
2340
2349
  },
2341
2350
  {
2342
2351
  "name": "industryCategory",
@@ -2356,13 +2365,15 @@
2356
2365
  "name": "status",
2357
2366
  "type": "text",
2358
2367
  "required": false,
2359
- "columnType": "TEXT"
2368
+ "columnType": "TEXT",
2369
+ "description": "Whether tracking is active, inactive or still being set up."
2360
2370
  },
2361
2371
  {
2362
2372
  "name": "lastSyncAt",
2363
2373
  "type": "datetime",
2364
2374
  "required": false,
2365
- "columnType": "TIMESTAMP"
2375
+ "columnType": "TIMESTAMP",
2376
+ "description": "When the property was last synced with the analytics service."
2366
2377
  }
2367
2378
  ],
2368
2379
  "relationships": [],
@@ -2651,49 +2662,56 @@
2651
2662
  "type": "foreignKey",
2652
2663
  "required": false,
2653
2664
  "related": "AnalyticsProperty",
2654
- "columnType": "UUID"
2665
+ "columnType": "UUID",
2666
+ "description": "The website or app this report is about."
2655
2667
  },
2656
2668
  {
2657
2669
  "name": "name",
2658
2670
  "type": "text",
2659
2671
  "required": false,
2660
2672
  "columnType": "TEXT",
2661
- "default": ""
2673
+ "default": "",
2674
+ "description": "A short name for the report, such as Weekly traffic."
2662
2675
  },
2663
2676
  {
2664
2677
  "name": "description",
2665
2678
  "type": "text",
2666
2679
  "required": false,
2667
2680
  "columnType": "TEXT",
2668
- "default": ""
2681
+ "default": "",
2682
+ "description": "What the report is for."
2669
2683
  },
2670
2684
  {
2671
2685
  "name": "dimensions",
2672
2686
  "type": "text",
2673
2687
  "required": false,
2674
2688
  "columnType": "TEXT",
2675
- "default": "[]"
2689
+ "default": "[]",
2690
+ "description": "What to break the figures down by, such as country or device, as a list."
2676
2691
  },
2677
2692
  {
2678
2693
  "name": "metrics",
2679
2694
  "type": "text",
2680
2695
  "required": false,
2681
2696
  "columnType": "TEXT",
2682
- "default": "[]"
2697
+ "default": "[]",
2698
+ "description": "What to count, such as active users or sessions, as a list."
2683
2699
  },
2684
2700
  {
2685
2701
  "name": "dateRangeStart",
2686
2702
  "type": "text",
2687
2703
  "required": false,
2688
2704
  "columnType": "TEXT",
2689
- "default": "7daysAgo"
2705
+ "default": "7daysAgo",
2706
+ "description": "Where the period begins: a date, or a relative value such as 7daysAgo."
2690
2707
  },
2691
2708
  {
2692
2709
  "name": "dateRangeEnd",
2693
2710
  "type": "text",
2694
2711
  "required": false,
2695
2712
  "columnType": "TEXT",
2696
- "default": "today"
2713
+ "default": "today",
2714
+ "description": "Where the period ends: a date, or a relative value such as today."
2697
2715
  },
2698
2716
  {
2699
2717
  "name": "dimensionFilter",
@@ -2727,25 +2745,29 @@
2727
2745
  "name": "status",
2728
2746
  "type": "text",
2729
2747
  "required": false,
2730
- "columnType": "TEXT"
2748
+ "columnType": "TEXT",
2749
+ "description": "Where the report stands: draft, scheduled, running, completed or failed."
2731
2750
  },
2732
2751
  {
2733
2752
  "name": "frequency",
2734
2753
  "type": "text",
2735
2754
  "required": false,
2736
- "columnType": "TEXT"
2755
+ "columnType": "TEXT",
2756
+ "description": "How often the report repeats: once, daily, weekly or monthly."
2737
2757
  },
2738
2758
  {
2739
2759
  "name": "lastRunAt",
2740
2760
  "type": "datetime",
2741
2761
  "required": false,
2742
- "columnType": "TIMESTAMP"
2762
+ "columnType": "TIMESTAMP",
2763
+ "description": "When the report last ran."
2743
2764
  },
2744
2765
  {
2745
2766
  "name": "nextRunAt",
2746
2767
  "type": "datetime",
2747
2768
  "required": false,
2748
- "columnType": "TIMESTAMP"
2769
+ "columnType": "TIMESTAMP",
2770
+ "description": "When the report is next due to run."
2749
2771
  },
2750
2772
  {
2751
2773
  "name": "resultData",
@@ -2759,14 +2781,16 @@
2759
2781
  "type": "integer",
2760
2782
  "required": false,
2761
2783
  "columnType": "INTEGER",
2762
- "default": 0
2784
+ "default": 0,
2785
+ "description": "How many rows the last run returned."
2763
2786
  },
2764
2787
  {
2765
2788
  "name": "lastError",
2766
2789
  "type": "text",
2767
2790
  "required": false,
2768
2791
  "columnType": "TEXT",
2769
- "default": ""
2792
+ "default": "",
2793
+ "description": "Why the last run failed. Empty when it worked."
2770
2794
  }
2771
2795
  ],
2772
2796
  "relationships": [
@@ -4633,5 +4657,145 @@
4633
4657
  "polymorphicAssociations": 0,
4634
4658
  "uuidColumns": 22
4635
4659
  },
4636
- "agentDoc": "# @happyvertical/smrt-analytics\n\nGA4/Plausible/Matomo analytics integration with server-side event tracking and AI-powered reporting.\n\n## Models\n\n- **AnalyticsProperty**: GA4 property, Plausible site, or Matomo site. Provider metadata, status, sync timestamps.\n- **AnalyticsDataStream**: web/iOS/Android data streams. Measurement IDs (G-XXXXXX for GA4, Firebase app ID for mobile).\n- **AnalyticsEvent**: tracked events with params (JSON), retry queue, conversion classification.\n- **AnalyticsReport**: saved report configs with dimensions/metrics (JSON), scheduling (daily/weekly/monthly), result caching.\n\nAll models use STI (`tableStrategy: 'sti'`).\n\nAll four persisted models are `@TenantScoped({ mode: 'optional' })` with a nullable `tenantId` (#1410), matching the framework convention used by sibling domain packages (ads/jobs/commerce). **When a tenant context is active**, the interceptor auto-filters `list`/`get`/raw reads and binds `create`/`save` writes to that tenant, keeping one tenant's properties, data streams, events (end-user PII), and cached report rows from reaching another. Because the mode is `optional`, the interceptor intentionally passes **through unfiltered when no tenant context is established** — so a surface is only safe insofar as it establishes tenant context first. Generated SvelteKit routes do this (#1540); the CLI/MCP code paths do not yet, which is a known framework-level residual (fail-closed tenant context for CLI/MCP) tracked outside this package, not an analytics-specific gap.\n\n## Key Collection Methods\n\n`findByExternalId()`, `findByProvider()`, `findNeedingSync()`, `findGA4Properties()`, `findPlausibleSites()`, `findMatomoSites()`\n\n## AI Operations\n\n`analyzePerformance()`, `analyzeResults()`, `hasPositiveTrends()` route through registered prompts (see Prompt Registry below) so tenant overrides apply via `resolvePrompt()`. `isPerformingWell()` still uses the inline `is()` shortcut.\n\n## Prompt Registry\n\nThree prompts are registered at module-load time via `definePrompt()` from `@happyvertical/smrt-prompts`. Re-exported from the package root for tenant override targeting.\n\n| Key | Method | Variables (PII-conscious) |\n|-----|--------|---------------------------|\n| `smrtAnalytics.property.analyzePerformance` | `AnalyticsProperty.analyzePerformance()` | `period`, `propertyDisplayName`, `propertyProvider` |\n| `smrtAnalytics.report.analyzeResults` | `AnalyticsReport.analyzeResults()` | `reportName`, `reportDimensions`, `reportMetrics`, `dateRangeStart`, `dateRangeEnd`, `rowCount`, `reportData` |\n| `smrtAnalytics.report.hasPositiveTrends` | `AnalyticsReport.hasPositiveTrends()` | `reportMetrics`, `reportData` |\n\n**Excluded from variables (never reach the AI provider):**\n- `id`, `propertyId`, `tenantId`, `externalId` — internal foreign keys / UUIDs that link to identifying records.\n- `apiSecret`, `measurementId`, `siteDomain` — provider credentials and platform-specific identifiers (GA4 API secrets, Matomo `idSite`, custom `G-XXXX` measurement IDs).\n- `providerMetadata` — extensible JSON blob that may contain credentials, account IDs, or other configuration secrets.\n- `lastError`, raw `dimensionFilter` / `metricFilter` JSON — internal error strings (may contain auth tokens) and filter expressions that may reference cookie IDs, user-pseudo-IDs, or IP-derived geos.\n\n**`resultData` is forwarded verbatim.** This package does not — and cannot — strip PII from result rows, because the row schema is determined by the dimensions/metrics the caller asked the analytics provider to return. If the caller persists rows containing a `userPseudoId`, `clientId`, IP-derived geolocation, or any other identifier, those fields WILL reach the AI provider. Callers must:\n\n- exclude PII-bearing dimensions before persisting `resultData` (e.g. don't request `userPseudoId` as a GA4 dimension), or\n- apply a column allowlist at the call site before invoking `analyzeResults()`, or\n- override the prompt template via `PromptOverride` to redact rows.\n\nThe forwarding contract is pinned by a regression test in `src/__tests__/analytics-report-prompt.test.ts`.\n\nSee `src/prompts.ts` for the full rationale block.\n\n## UI Registry\n\nSvelte components live in `src/svelte/` and auto-register with `ModuleUIRegistry` from `@happyvertical/smrt-ui/registry` when `@happyvertical/smrt-analytics/svelte` is imported.\n\nSlot declarations live in `src/ui.ts`, exported via the `./ui` package subpath. The slots are: `analytics-summary`, `events-table`, `property-info`, `property-status-badge`, `stat-card`, `trend-badge` (see `ANALYTICS_UI_SLOTS` for icons / categories / display order).\n\n```typescript\nimport '@happyvertical/smrt-analytics/svelte'; // side-effect: registers slots\nimport { ModuleUIRegistry } from '@happyvertical/smrt-ui/registry';\nconst StatCard = ModuleUIRegistry.get('@happyvertical/smrt-analytics', 'stat-card');\n```\n\n## Gotchas\n\n- **`apiSecret` / `providerMetadata` stripped from API/MCP**: marked `@field({ sensitive: true })` (#1540) so they never appear in generated responses or `where` filters. They are still stored at rest **unencrypted** — envelope encryption via `@happyvertical/smrt-secrets` is a separate, breaking follow-up (tracked, not done here).\n- **Event retry at model level**: no background job integration\n- **JSON fields**: params, dimensions, metrics use string storage with getter/setter helpers\n- **Measurement IDs differ per platform**: G-XXXXXX (GA4 web) vs Firebase app ID (mobile)\n- **`analyzeResults` is now a single AI call**: previously issued a second freeform `do()` to summarize \"top 3 insights\"; folded into the registered template, and `insights` mirrors `analysis` in the response shape.\n"
4660
+ "agentDoc": "# @happyvertical/smrt-analytics\n\nGA4/Plausible/Matomo analytics integration with server-side event tracking and AI-powered reporting.\n\n## Models\n\n- **AnalyticsProperty**: GA4 property, Plausible site, or Matomo site. Provider metadata, status, sync timestamps.\n- **AnalyticsDataStream**: web/iOS/Android data streams. Measurement IDs (G-XXXXXX for GA4, Firebase app ID for mobile).\n- **AnalyticsEvent**: tracked events with params (JSON), retry queue, conversion classification.\n- **AnalyticsReport**: saved report configs with dimensions/metrics (JSON), scheduling (daily/weekly/monthly), result caching.\n\nAll models use STI (`tableStrategy: 'sti'`).\n\nAll four persisted models are `@TenantScoped({ mode: 'optional' })` with a nullable `tenantId` (#1410), matching the framework convention used by sibling domain packages (ads/jobs/commerce). **When a tenant context is active**, the interceptor auto-filters `list`/`get`/raw reads and binds `create`/`save` writes to that tenant, keeping one tenant's properties, data streams, events (end-user PII), and cached report rows from reaching another. Because the mode is `optional`, the interceptor intentionally passes **through unfiltered when no tenant context is established** — so a surface is only safe insofar as it establishes tenant context first. Generated SvelteKit routes do this (#1540); the CLI/MCP code paths do not yet, which is a known framework-level residual (fail-closed tenant context for CLI/MCP) tracked outside this package, not an analytics-specific gap.\n\n## Key Collection Methods\n\n`findByExternalId()`, `findByProvider()`, `findNeedingSync()`, `findGA4Properties()`, `findPlausibleSites()`, `findMatomoSites()`\n\n## AI Operations\n\n`analyzePerformance()`, `analyzeResults()`, `hasPositiveTrends()` route through registered prompts (see Prompt Registry below) so tenant overrides apply via `resolvePrompt()`. `isPerformingWell()` still uses the inline `is()` shortcut.\n\n## Prompt Registry\n\nThree prompts are registered at module-load time via `definePrompt()` from `@happyvertical/smrt-prompts`. Re-exported from the package root for tenant override targeting.\n\n| Key | Method | Variables (PII-conscious) |\n|-----|--------|---------------------------|\n| `smrtAnalytics.property.analyzePerformance` | `AnalyticsProperty.analyzePerformance()` | `period`, `propertyDisplayName`, `propertyProvider` |\n| `smrtAnalytics.report.analyzeResults` | `AnalyticsReport.analyzeResults()` | `reportName`, `reportDimensions`, `reportMetrics`, `dateRangeStart`, `dateRangeEnd`, `rowCount`, `reportData` |\n| `smrtAnalytics.report.hasPositiveTrends` | `AnalyticsReport.hasPositiveTrends()` | `reportMetrics`, `reportData` |\n\n**Excluded from variables (never reach the AI provider):**\n- `id`, `propertyId`, `tenantId`, `externalId` — internal foreign keys / UUIDs that link to identifying records.\n- `apiSecret`, `measurementId`, `siteDomain` — provider credentials and platform-specific identifiers (GA4 API secrets, Matomo `idSite`, custom `G-XXXX` measurement IDs).\n- `providerMetadata` — extensible JSON blob that may contain credentials, account IDs, or other configuration secrets.\n- `lastError`, raw `dimensionFilter` / `metricFilter` JSON — internal error strings (may contain auth tokens) and filter expressions that may reference cookie IDs, user-pseudo-IDs, or IP-derived geos.\n\n**`resultData` is forwarded verbatim.** This package does not — and cannot — strip PII from result rows, because the row schema is determined by the dimensions/metrics the caller asked the analytics provider to return. If the caller persists rows containing a `userPseudoId`, `clientId`, IP-derived geolocation, or any other identifier, those fields WILL reach the AI provider. Callers must:\n\n- exclude PII-bearing dimensions before persisting `resultData` (e.g. don't request `userPseudoId` as a GA4 dimension), or\n- apply a column allowlist at the call site before invoking `analyzeResults()`, or\n- override the prompt template via `PromptOverride` to redact rows.\n\nThe forwarding contract is pinned by a regression test in `src/__tests__/analytics-report-prompt.test.ts`.\n\nSee `src/prompts.ts` for the full rationale block.\n\n## UI Registry\n\nSvelte components live in `src/svelte/` and auto-register with `ModuleUIRegistry` from `@happyvertical/smrt-ui/registry` when `@happyvertical/smrt-analytics/svelte` is imported.\n\nSlot declarations live in `src/ui.ts`, exported via the `./ui` package subpath. The slots are: `analytics-summary`, `events-table`, `property-info`, `property-status-badge`, `stat-card`, `trend-badge` (see `ANALYTICS_UI_SLOTS` for icons / categories / display order).\n\n```typescript\nimport '@happyvertical/smrt-analytics/svelte'; // side-effect: registers slots\nimport { ModuleUIRegistry } from '@happyvertical/smrt-ui/registry';\nconst StatCard = ModuleUIRegistry.get('@happyvertical/smrt-analytics', 'stat-card');\n```\n\n## Recipes (#3719)\n\n`src/recipes.ts` declares `analytics.reports` (`AnalyticsReportsRecipe`:\n`AnalyticsProperty` and `AnalyticsReport`), emitted into the built\n`manifest.json` and `smrt-knowledge.json` `recipes`. `AnalyticsEvent` and\n`AnalyticsDataStream` are left out: event tracking and stream setup are separate\nconcerns. User-facing help is `src/reports.recipe.md` (#3591); keep it and the\n`@field({ description })` text on the two models in plain language, and never\nreference a `sensitive` field (`apiSecret`, `providerMetadata`) in help.\n\n- **Runtime is `server`.** Reports and their rows live in the app database, the\n AI summary needs a server-held key, and provider credentials sit on the\n property row (so no `providers` are declared: there are no env secrets to name).\n- **One route, deliberately.** `/analytics/summary` mounts\n `@happyvertical/smrt-analytics/svelte#AnalyticsSummary`, which renders an empty\n state without data. `PropertyInfo` and `EventsTable` take required row props\n and throw with none, so they are not routes; a host places them in its own\n pages. Add a route only for a component that survives being mounted bare.\n- **No demo seed.** The playground sample data is module-local, not an export.\n- **What the assistant can do.** Generated MCP exposes `list` and `get` on\n `AnalyticsReport` only; `analyzeResults()` is a model method the app calls,\n not a tool. The help says so and points at `reports.query` (declared reports,\n `@happyvertical/smrt-reports`) and `reports.runtime.*` (runtime reports,\n `@happyvertical/smrt-chat`) for aggregates over the app's own data.\n\n`src/__tests__/recipes.test.ts` runs the real scan, manifest and generation\npasses in memory and renders the help. See\n[core recipes](../core/agents/recipes.md).\n\n## Gotchas\n\n- **`apiSecret` / `providerMetadata` stripped from API/MCP**: marked `@field({ sensitive: true })` (#1540) so they never appear in generated responses or `where` filters. They are still stored at rest **unencrypted** — envelope encryption via `@happyvertical/smrt-secrets` is a separate, breaking follow-up (tracked, not done here).\n- **Event retry at model level**: no background job integration\n- **JSON fields**: params, dimensions, metrics use string storage with getter/setter helpers\n- **Measurement IDs differ per platform**: G-XXXXXX (GA4 web) vs Firebase app ID (mobile)\n- **`analyzeResults` is now a single AI call**: previously issued a second freeform `do()` to summarize \"top 3 insights\"; folded into the registered template, and `insights` mirrors `analysis` in the response shape.\n",
4661
+ "recipes": [
4662
+ {
4663
+ "id": "analytics.reports",
4664
+ "className": "AnalyticsReportsRecipe",
4665
+ "label": "Analytics",
4666
+ "summary": "Save traffic reports for your websites and apps and get a plain-language read on the results.",
4667
+ "synonyms": [
4668
+ "analytics",
4669
+ "traffic",
4670
+ "pageviews",
4671
+ "visitors",
4672
+ "web stats",
4673
+ "google analytics",
4674
+ "plausible",
4675
+ "matomo"
4676
+ ],
4677
+ "models": [
4678
+ "@happyvertical/smrt-analytics:AnalyticsProperty",
4679
+ "@happyvertical/smrt-analytics:AnalyticsReport"
4680
+ ],
4681
+ "nav": [
4682
+ {
4683
+ "label": "Analytics properties",
4684
+ "model": "@happyvertical/smrt-analytics:AnalyticsProperty",
4685
+ "icon": "home",
4686
+ "description": "The websites and apps you track, and who tracks them."
4687
+ },
4688
+ {
4689
+ "label": "Analytics reports",
4690
+ "model": "@happyvertical/smrt-analytics:AnalyticsReport",
4691
+ "icon": "fileText",
4692
+ "description": "Saved reports, how often they run and what they found."
4693
+ }
4694
+ ],
4695
+ "requires": [],
4696
+ "section": {
4697
+ "id": "analytics",
4698
+ "label": "Analytics",
4699
+ "icon": "layers",
4700
+ "description": "How your websites and apps are doing."
4701
+ },
4702
+ "options": {
4703
+ "@happyvertical/smrt-analytics:AnalyticsProperty": {
4704
+ "fields": {
4705
+ "name": {
4706
+ "visibility": "hidden"
4707
+ },
4708
+ "industryCategory": {
4709
+ "visibility": "advanced"
4710
+ },
4711
+ "serviceLevel": {
4712
+ "visibility": "advanced"
4713
+ },
4714
+ "lastSyncAt": {
4715
+ "locked": true
4716
+ }
4717
+ }
4718
+ },
4719
+ "@happyvertical/smrt-analytics:AnalyticsReport": {
4720
+ "fields": {
4721
+ "dimensionFilter": {
4722
+ "visibility": "advanced"
4723
+ },
4724
+ "metricFilter": {
4725
+ "visibility": "advanced"
4726
+ },
4727
+ "orderBy": {
4728
+ "visibility": "advanced"
4729
+ },
4730
+ "maxResults": {
4731
+ "visibility": "advanced"
4732
+ },
4733
+ "resultData": {
4734
+ "visibility": "hidden",
4735
+ "locked": true
4736
+ },
4737
+ "rowCount": {
4738
+ "locked": true
4739
+ },
4740
+ "lastRunAt": {
4741
+ "locked": true
4742
+ },
4743
+ "nextRunAt": {
4744
+ "locked": true
4745
+ },
4746
+ "lastError": {
4747
+ "locked": true
4748
+ }
4749
+ }
4750
+ }
4751
+ },
4752
+ "help": {
4753
+ "markdown": "## Overview\n\nAnalytics keeps the traffic reports you care about for your websites and apps.\nAdd a property for each site or app you track in Google Analytics 4, Plausible\nor Matomo. Save a report on it that says what to count, what to break the\nfigures down by, and over which dates. The rows each run returns are stored\nwith the report, and the assistant can read them back to you in plain words.\n\nProperties and reports are kept on your server. Provider secrets are stored on\nthe property and never sent to the assistant or returned in responses, but they\nare not encrypted in the database.\n\n## Tasks\n\n### Add a property\n\n1. Create a new property.\n2. Enter the **{field:AnalyticsProperty.displayName}** and pick the\n **{field:AnalyticsProperty.provider}**.\n3. Enter the **{field:AnalyticsProperty.externalId}** the analytics service\n gives it.\n4. For Google Analytics, enter the **{field:AnalyticsProperty.measurementId}**.\n For Plausible or Matomo, enter the **{field:AnalyticsProperty.siteDomain}**.\n5. Keep **{field:AnalyticsProperty.status}** on active while you want it\n tracked.\n\n### Save a report\n\n1. Create a new report and choose the property in\n **{field:AnalyticsReport.propertyId}**.\n2. Give it a **{field:AnalyticsReport.name}**.\n3. List what to break the figures down by in\n **{field:AnalyticsReport.dimensions}** and what to count in\n **{field:AnalyticsReport.metrics}**.\n4. Set the period with **{field:AnalyticsReport.dateRangeStart}** and\n **{field:AnalyticsReport.dateRangeEnd}**.\n5. Pick **{field:AnalyticsReport.frequency}** to repeat it daily, weekly or\n monthly.\n\n### Check what a report found\n\n1. **{field:AnalyticsReport.status}** says where the report stands, and\n **{field:AnalyticsReport.lastRunAt}** when it last ran.\n2. **{field:AnalyticsReport.rowCount}** shows how many rows came back.\n3. If a run failed, **{field:AnalyticsReport.lastError}** says why.\n\n### Ask the assistant\n\n1. Ask about a saved report by name, for example \"how did last week's traffic\n report look?\". When your app has the analytics tools switched on, the\n assistant can list your saved reports and open one to read its figures.\n2. A written summary of a report comes from your app, which sends the stored\n rows to the AI provider as they are. Leave out dimensions that identify a\n person.\n3. For totals your own app calculates, such as orders or signups, ask for a\n refreshed report. The assistant reads those with `reports.query`; see\n Reports.\n4. For a one-off question those reports do not answer, the assistant can\n propose a report with `reports.runtime.define`. Nothing is saved until you\n confirm it.\n",
4754
+ "fieldRefs": [
4755
+ "AnalyticsProperty.displayName",
4756
+ "AnalyticsProperty.externalId",
4757
+ "AnalyticsProperty.measurementId",
4758
+ "AnalyticsProperty.provider",
4759
+ "AnalyticsProperty.siteDomain",
4760
+ "AnalyticsProperty.status",
4761
+ "AnalyticsReport.dateRangeEnd",
4762
+ "AnalyticsReport.dateRangeStart",
4763
+ "AnalyticsReport.dimensions",
4764
+ "AnalyticsReport.frequency",
4765
+ "AnalyticsReport.lastError",
4766
+ "AnalyticsReport.lastRunAt",
4767
+ "AnalyticsReport.metrics",
4768
+ "AnalyticsReport.name",
4769
+ "AnalyticsReport.propertyId",
4770
+ "AnalyticsReport.rowCount",
4771
+ "AnalyticsReport.status"
4772
+ ]
4773
+ },
4774
+ "surfaces": [
4775
+ {
4776
+ "kind": "route",
4777
+ "path": "/analytics/summary",
4778
+ "export": "@happyvertical/smrt-analytics/svelte#AnalyticsSummary",
4779
+ "label": "Traffic summary"
4780
+ }
4781
+ ],
4782
+ "runtime": "server",
4783
+ "demo": {
4784
+ "mode": "server",
4785
+ "reasons": [
4786
+ "The recipe declares runtime \"server\".",
4787
+ "Needs a server because its package depends on @happyvertical/smrt-tenancy, which do not build for a browser (#3624)."
4788
+ ]
4789
+ }
4790
+ }
4791
+ ],
4792
+ "browser": {
4793
+ "status": "server-only",
4794
+ "issues": [
4795
+ "#3624"
4796
+ ],
4797
+ "via": [
4798
+ "@happyvertical/smrt-tenancy"
4799
+ ]
4800
+ }
4637
4801
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@happyvertical/smrt-analytics",
3
- "version": "0.55.7",
3
+ "version": "0.55.8",
4
4
  "smrtJsdoc": "strict",
5
5
  "description": "Analytics integration models for SMRT framework",
6
6
  "type": "module",
@@ -33,11 +33,11 @@
33
33
  }
34
34
  },
35
35
  "dependencies": {
36
- "@happyvertical/smrt-core": "0.55.7",
37
- "@happyvertical/smrt-prompts": "0.55.7",
38
- "@happyvertical/smrt-tenancy": "0.55.7",
39
- "@happyvertical/smrt-types": "0.55.7",
40
- "@happyvertical/smrt-ui": "0.55.7"
36
+ "@happyvertical/smrt-core": "0.55.8",
37
+ "@happyvertical/smrt-prompts": "0.55.8",
38
+ "@happyvertical/smrt-tenancy": "0.55.8",
39
+ "@happyvertical/smrt-types": "0.55.8",
40
+ "@happyvertical/smrt-ui": "0.55.8"
41
41
  },
42
42
  "peerDependencies": {
43
43
  "svelte": "^5.57.0"
@@ -48,8 +48,9 @@
48
48
  }
49
49
  },
50
50
  "devDependencies": {
51
- "@happyvertical/smrt-vitest": "0.55.7",
52
- "@happyvertical/sql": "^0.102.5",
51
+ "@happyvertical/smrt-scanner": "0.55.8",
52
+ "@happyvertical/smrt-vitest": "0.55.8",
53
+ "@happyvertical/sql": "^0.103.1",
53
54
  "@sveltejs/package": "^2.5.8",
54
55
  "@types/node": "24.13.6",
55
56
  "fast-glob": "3.3.3",