@iann29/rastro 0.9.0 → 0.10.1

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 (265) hide show
  1. package/README.md +9 -1
  2. package/agent/integration.md +23 -1
  3. package/agent/manifest.json +4 -4
  4. package/dist/client/federation.d.ts +114 -9
  5. package/dist/client/federation.d.ts.map +1 -1
  6. package/dist/client/federation.js +54 -2
  7. package/dist/client/federation.js.map +1 -1
  8. package/dist/client/index.d.ts +642 -8
  9. package/dist/client/index.d.ts.map +1 -1
  10. package/dist/client/index.js +391 -9
  11. package/dist/client/index.js.map +1 -1
  12. package/dist/component/_generated/api.d.ts +14 -0
  13. package/dist/component/_generated/api.d.ts.map +1 -1
  14. package/dist/component/_generated/api.js.map +1 -1
  15. package/dist/component/_generated/component.d.ts +278 -1
  16. package/dist/component/_generated/component.d.ts.map +1 -1
  17. package/dist/component/_generated/server.d.ts +4 -0
  18. package/dist/component/_generated/server.d.ts.map +1 -1
  19. package/dist/component/_generated/server.js.map +1 -1
  20. package/dist/component/constants.d.ts +5 -0
  21. package/dist/component/constants.d.ts.map +1 -1
  22. package/dist/component/constants.js +10 -0
  23. package/dist/component/constants.js.map +1 -1
  24. package/dist/component/convex.config.d.ts +4 -0
  25. package/dist/component/convex.config.js +9 -0
  26. package/dist/component/convex.config.js.map +1 -1
  27. package/dist/component/errors.d.ts +1 -1
  28. package/dist/component/errors.d.ts.map +1 -1
  29. package/dist/component/errors.js.map +1 -1
  30. package/dist/component/leads.d.ts +69 -3
  31. package/dist/component/leads.d.ts.map +1 -1
  32. package/dist/component/leads.js +419 -16
  33. package/dist/component/leads.js.map +1 -1
  34. package/dist/component/meta.d.ts +358 -0
  35. package/dist/component/meta.d.ts.map +1 -0
  36. package/dist/component/meta.js +1295 -0
  37. package/dist/component/meta.js.map +1 -0
  38. package/dist/component/metaCapi.d.ts +162 -0
  39. package/dist/component/metaCapi.d.ts.map +1 -0
  40. package/dist/component/metaCapi.js +754 -0
  41. package/dist/component/metaCapi.js.map +1 -0
  42. package/dist/component/metaFake.d.ts +5 -0
  43. package/dist/component/metaFake.d.ts.map +1 -0
  44. package/dist/component/metaFake.js +225 -0
  45. package/dist/component/metaFake.js.map +1 -0
  46. package/dist/component/metaGraph.d.ts +165 -0
  47. package/dist/component/metaGraph.d.ts.map +1 -0
  48. package/dist/component/metaGraph.js +507 -0
  49. package/dist/component/metaGraph.js.map +1 -0
  50. package/dist/component/metaSync.d.ts +186 -0
  51. package/dist/component/metaSync.d.ts.map +1 -0
  52. package/dist/component/metaSync.js +961 -0
  53. package/dist/component/metaSync.js.map +1 -0
  54. package/dist/component/pipeline.d.ts +99 -0
  55. package/dist/component/pipeline.d.ts.map +1 -0
  56. package/dist/component/pipeline.js +337 -0
  57. package/dist/component/pipeline.js.map +1 -0
  58. package/dist/component/schema.d.ts +404 -2
  59. package/dist/component/schema.d.ts.map +1 -1
  60. package/dist/component/schema.js +168 -2
  61. package/dist/component/schema.js.map +1 -1
  62. package/dist/component/secrets.d.ts +15 -0
  63. package/dist/component/secrets.d.ts.map +1 -0
  64. package/dist/component/secrets.js +67 -0
  65. package/dist/component/secrets.js.map +1 -0
  66. package/dist/component/validators.d.ts +1052 -15
  67. package/dist/component/validators.d.ts.map +1 -1
  68. package/dist/component/validators.js +307 -3
  69. package/dist/component/validators.js.map +1 -1
  70. package/dist/tracker/generated.d.ts +1 -1
  71. package/dist/tracker/generated.d.ts.map +1 -1
  72. package/dist/tracker/generated.js +1 -1
  73. package/dist/tracker/generated.js.map +1 -1
  74. package/dist/ui/campaigns/CampaignsView.d.ts +48 -0
  75. package/dist/ui/campaigns/CampaignsView.d.ts.map +1 -0
  76. package/dist/ui/campaigns/CampaignsView.js +47 -0
  77. package/dist/ui/campaigns/CampaignsView.js.map +1 -0
  78. package/dist/ui/campaigns/Conversions.d.ts +16 -0
  79. package/dist/ui/campaigns/Conversions.d.ts.map +1 -0
  80. package/dist/ui/campaigns/Conversions.js +40 -0
  81. package/dist/ui/campaigns/Conversions.js.map +1 -0
  82. package/dist/ui/campaigns/Drawer.d.ts +24 -0
  83. package/dist/ui/campaigns/Drawer.d.ts.map +1 -0
  84. package/dist/ui/campaigns/Drawer.js +120 -0
  85. package/dist/ui/campaigns/Drawer.js.map +1 -0
  86. package/dist/ui/campaigns/Icons.d.ts +35 -0
  87. package/dist/ui/campaigns/Icons.d.ts.map +1 -0
  88. package/dist/ui/campaigns/Icons.js +41 -0
  89. package/dist/ui/campaigns/Icons.js.map +1 -0
  90. package/dist/ui/campaigns/Summary.d.ts +21 -0
  91. package/dist/ui/campaigns/Summary.d.ts.map +1 -0
  92. package/dist/ui/campaigns/Summary.js +56 -0
  93. package/dist/ui/campaigns/Summary.js.map +1 -0
  94. package/dist/ui/campaigns/Thumbnail.d.ts +11 -0
  95. package/dist/ui/campaigns/Thumbnail.d.ts.map +1 -0
  96. package/dist/ui/campaigns/Thumbnail.js +23 -0
  97. package/dist/ui/campaigns/Thumbnail.js.map +1 -0
  98. package/dist/ui/campaigns/Tree.d.ts +12 -0
  99. package/dist/ui/campaigns/Tree.d.ts.map +1 -0
  100. package/dist/ui/campaigns/Tree.js +105 -0
  101. package/dist/ui/campaigns/Tree.js.map +1 -0
  102. package/dist/ui/campaigns/glyphs.d.ts +20 -0
  103. package/dist/ui/campaigns/glyphs.d.ts.map +1 -0
  104. package/dist/ui/campaigns/glyphs.js +19 -0
  105. package/dist/ui/campaigns/glyphs.js.map +1 -0
  106. package/dist/ui/campaigns/index.d.ts +4 -0
  107. package/dist/ui/campaigns/index.d.ts.map +1 -0
  108. package/dist/ui/campaigns/index.js +3 -0
  109. package/dist/ui/campaigns/index.js.map +1 -0
  110. package/dist/ui/campaigns/labels.d.ts +53 -0
  111. package/dist/ui/campaigns/labels.d.ts.map +1 -0
  112. package/dist/ui/campaigns/labels.js +169 -0
  113. package/dist/ui/campaigns/labels.js.map +1 -0
  114. package/dist/ui/campaigns/model.d.ts +99 -0
  115. package/dist/ui/campaigns/model.d.ts.map +1 -0
  116. package/dist/ui/campaigns/model.js +230 -0
  117. package/dist/ui/campaigns/model.js.map +1 -0
  118. package/dist/ui/campaigns/modes.d.ts +18 -0
  119. package/dist/ui/campaigns/modes.d.ts.map +1 -0
  120. package/dist/ui/campaigns/modes.js +7 -0
  121. package/dist/ui/campaigns/modes.js.map +1 -0
  122. package/dist/ui/index.d.ts +21 -0
  123. package/dist/ui/index.d.ts.map +1 -0
  124. package/dist/ui/index.js +20 -0
  125. package/dist/ui/index.js.map +1 -0
  126. package/dist/ui/integrations/AccountPicker.d.ts +26 -0
  127. package/dist/ui/integrations/AccountPicker.d.ts.map +1 -0
  128. package/dist/ui/integrations/AccountPicker.js +101 -0
  129. package/dist/ui/integrations/AccountPicker.js.map +1 -0
  130. package/dist/ui/integrations/ClientCards.d.ts +17 -0
  131. package/dist/ui/integrations/ClientCards.d.ts.map +1 -0
  132. package/dist/ui/integrations/ClientCards.js +42 -0
  133. package/dist/ui/integrations/ClientCards.js.map +1 -0
  134. package/dist/ui/integrations/ClientsTable.d.ts +36 -0
  135. package/dist/ui/integrations/ClientsTable.d.ts.map +1 -0
  136. package/dist/ui/integrations/ClientsTable.js +143 -0
  137. package/dist/ui/integrations/ClientsTable.js.map +1 -0
  138. package/dist/ui/integrations/Connect.d.ts +35 -0
  139. package/dist/ui/integrations/Connect.d.ts.map +1 -0
  140. package/dist/ui/integrations/Connect.js +62 -0
  141. package/dist/ui/integrations/Connect.js.map +1 -0
  142. package/dist/ui/integrations/Connection.d.ts +37 -0
  143. package/dist/ui/integrations/Connection.d.ts.map +1 -0
  144. package/dist/ui/integrations/Connection.js +108 -0
  145. package/dist/ui/integrations/Connection.js.map +1 -0
  146. package/dist/ui/integrations/Dialogs.d.ts +21 -0
  147. package/dist/ui/integrations/Dialogs.d.ts.map +1 -0
  148. package/dist/ui/integrations/Dialogs.js +34 -0
  149. package/dist/ui/integrations/Dialogs.js.map +1 -0
  150. package/dist/ui/integrations/EventsFeed.d.ts +15 -0
  151. package/dist/ui/integrations/EventsFeed.d.ts.map +1 -0
  152. package/dist/ui/integrations/EventsFeed.js +61 -0
  153. package/dist/ui/integrations/EventsFeed.js.map +1 -0
  154. package/dist/ui/integrations/EventsSheet.d.ts +34 -0
  155. package/dist/ui/integrations/EventsSheet.d.ts.map +1 -0
  156. package/dist/ui/integrations/EventsSheet.js +136 -0
  157. package/dist/ui/integrations/EventsSheet.js.map +1 -0
  158. package/dist/ui/integrations/Icons.d.ts +38 -0
  159. package/dist/ui/integrations/Icons.d.ts.map +1 -0
  160. package/dist/ui/integrations/Icons.js +40 -0
  161. package/dist/ui/integrations/Icons.js.map +1 -0
  162. package/dist/ui/integrations/IntegrationsView.d.ts +15 -0
  163. package/dist/ui/integrations/IntegrationsView.d.ts.map +1 -0
  164. package/dist/ui/integrations/IntegrationsView.js +141 -0
  165. package/dist/ui/integrations/IntegrationsView.js.map +1 -0
  166. package/dist/ui/integrations/Overlay.d.ts +18 -0
  167. package/dist/ui/integrations/Overlay.d.ts.map +1 -0
  168. package/dist/ui/integrations/Overlay.js +36 -0
  169. package/dist/ui/integrations/Overlay.js.map +1 -0
  170. package/dist/ui/integrations/Partner.d.ts +14 -0
  171. package/dist/ui/integrations/Partner.d.ts.map +1 -0
  172. package/dist/ui/integrations/Partner.js +38 -0
  173. package/dist/ui/integrations/Partner.js.map +1 -0
  174. package/dist/ui/integrations/RowMenu.d.ts +15 -0
  175. package/dist/ui/integrations/RowMenu.d.ts.map +1 -0
  176. package/dist/ui/integrations/RowMenu.js +47 -0
  177. package/dist/ui/integrations/RowMenu.js.map +1 -0
  178. package/dist/ui/integrations/UnlinkDialog.d.ts +18 -0
  179. package/dist/ui/integrations/UnlinkDialog.d.ts.map +1 -0
  180. package/dist/ui/integrations/UnlinkDialog.js +29 -0
  181. package/dist/ui/integrations/UnlinkDialog.js.map +1 -0
  182. package/dist/ui/integrations/audience.d.ts +12 -0
  183. package/dist/ui/integrations/audience.d.ts.map +1 -0
  184. package/dist/ui/integrations/audience.js +12 -0
  185. package/dist/ui/integrations/audience.js.map +1 -0
  186. package/dist/ui/integrations/format.d.ts +28 -0
  187. package/dist/ui/integrations/format.d.ts.map +1 -0
  188. package/dist/ui/integrations/format.js +101 -0
  189. package/dist/ui/integrations/format.js.map +1 -0
  190. package/dist/ui/integrations/index.d.ts +5 -0
  191. package/dist/ui/integrations/index.d.ts.map +1 -0
  192. package/dist/ui/integrations/index.js +3 -0
  193. package/dist/ui/integrations/index.js.map +1 -0
  194. package/dist/ui/integrations/modal.d.ts +10 -0
  195. package/dist/ui/integrations/modal.d.ts.map +1 -0
  196. package/dist/ui/integrations/modal.js +77 -0
  197. package/dist/ui/integrations/modal.js.map +1 -0
  198. package/dist/ui/integrations/model.d.ts +99 -0
  199. package/dist/ui/integrations/model.d.ts.map +1 -0
  200. package/dist/ui/integrations/model.js +164 -0
  201. package/dist/ui/integrations/model.js.map +1 -0
  202. package/dist/ui/integrations/parts.d.ts +36 -0
  203. package/dist/ui/integrations/parts.d.ts.map +1 -0
  204. package/dist/ui/integrations/parts.js +85 -0
  205. package/dist/ui/integrations/parts.js.map +1 -0
  206. package/dist/ui/integrations/types.d.ts +146 -0
  207. package/dist/ui/integrations/types.d.ts.map +1 -0
  208. package/dist/ui/integrations/types.js +2 -0
  209. package/dist/ui/integrations/types.js.map +1 -0
  210. package/dist/ui/metrics.d.ts +106 -0
  211. package/dist/ui/metrics.d.ts.map +1 -0
  212. package/dist/ui/metrics.js +166 -0
  213. package/dist/ui/metrics.js.map +1 -0
  214. package/dist/ui/portfolio/PortfolioView.d.ts +26 -0
  215. package/dist/ui/portfolio/PortfolioView.d.ts.map +1 -0
  216. package/dist/ui/portfolio/PortfolioView.js +216 -0
  217. package/dist/ui/portfolio/PortfolioView.js.map +1 -0
  218. package/dist/ui/portfolio/SpendChart.d.ts +10 -0
  219. package/dist/ui/portfolio/SpendChart.d.ts.map +1 -0
  220. package/dist/ui/portfolio/SpendChart.js +196 -0
  221. package/dist/ui/portfolio/SpendChart.js.map +1 -0
  222. package/dist/ui/portfolio/alerts.d.ts +74 -0
  223. package/dist/ui/portfolio/alerts.d.ts.map +1 -0
  224. package/dist/ui/portfolio/alerts.js +291 -0
  225. package/dist/ui/portfolio/alerts.js.map +1 -0
  226. package/dist/ui/portfolio/figures.d.ts +79 -0
  227. package/dist/ui/portfolio/figures.d.ts.map +1 -0
  228. package/dist/ui/portfolio/figures.js +103 -0
  229. package/dist/ui/portfolio/figures.js.map +1 -0
  230. package/dist/ui/portfolio/format.d.ts +8 -0
  231. package/dist/ui/portfolio/format.d.ts.map +1 -0
  232. package/dist/ui/portfolio/format.js +28 -0
  233. package/dist/ui/portfolio/format.js.map +1 -0
  234. package/dist/ui/sample.d.ts +536 -0
  235. package/dist/ui/sample.d.ts.map +1 -0
  236. package/dist/ui/sample.js +574 -0
  237. package/dist/ui/sample.js.map +1 -0
  238. package/dist/ui/seed.d.ts +188 -0
  239. package/dist/ui/seed.d.ts.map +1 -0
  240. package/dist/ui/seed.js +563 -0
  241. package/dist/ui/seed.js.map +1 -0
  242. package/dist/ui/ui.css +3424 -0
  243. package/docs/federation.md +46 -1
  244. package/docs/meta-ads.md +795 -0
  245. package/docs/upgrading.md +116 -0
  246. package/llms.txt +3 -0
  247. package/package.json +15 -3
  248. package/src/component/_generated/api.ts +14 -0
  249. package/src/component/_generated/component.ts +324 -1
  250. package/src/component/_generated/server.ts +4 -0
  251. package/src/component/constants.ts +10 -0
  252. package/src/component/convex.config.ts +9 -0
  253. package/src/component/errors.ts +5 -1
  254. package/src/component/leads.ts +517 -17
  255. package/src/component/meta.ts +1525 -0
  256. package/src/component/metaCapi.ts +921 -0
  257. package/src/component/metaFake.ts +277 -0
  258. package/src/component/metaGraph.ts +722 -0
  259. package/src/component/metaSync.ts +1164 -0
  260. package/src/component/pipeline.ts +410 -0
  261. package/src/component/schema.ts +197 -1
  262. package/src/component/secrets.ts +98 -0
  263. package/src/component/validators.ts +376 -3
  264. package/src/tracker/generated.ts +1 -1
  265. package/src/ui/seed.ts +755 -0
package/docs/upgrading.md CHANGED
@@ -1,5 +1,121 @@
1
1
  # Upgrading Amage Rastro
2
2
 
3
+ ## The business screen and the owner checks (0.10.1)
4
+
5
+ No schema change, env var or re-export. Install `@iann29/rastro@0.10.1` and
6
+ deploy the host. Two behaviors change on purpose:
7
+
8
+ - `setMetaEventMap` (federated) refuses with `CONFLICT` on a site whose pixel
9
+ another owner set: the dashboard no longer rewrites the map of a pixel the
10
+ host's own owner linked. The host's `setEventMap` is unchanged unless it
11
+ passes the new optional `ownerKey`.
12
+ - `removeMetaConnection` (and `removeFederatedMetaConnection`, so revoking a
13
+ dashboard connection) now also removes the pixels the owner set with their own
14
+ token (plan B), not only those of its connection. A host that sets plan B
15
+ pixels for an owner should pass that owner as `setBy` in `setSitePixel`, so
16
+ removing the owner reaches them.
17
+
18
+ Hosts embedding `IntegrationsView` can render it for one company with
19
+ `audience="business"` (and `partner`, `productName`), and offer "Usar o mesmo
20
+ mapa nos outros clientes" with `onCopyEventMap`; see
21
+ [the Integrações screen](meta-ads.md#the-integrações-screen-integrationsview).
22
+ Nothing changes for a host that passes neither.
23
+
24
+ ## Meta ads, conversions and the Integrações screen (0.10.0)
25
+
26
+ Install `@iann29/rastro@0.10.0` and deploy the consuming host. The release is
27
+ additive: every schema change is a new table (the Meta connections, linked ad
28
+ accounts, spend, pixels, board columns and the conversion queue), the new
29
+ `leadsReport` fields are optional, and nothing is removed or rewritten. A host
30
+ that skips Meta changes nothing: it needs no new env var, re-export or grant,
31
+ `leadsReport` answers spend as `null`, and its manifest advertises nothing new.
32
+
33
+ A host on `leads: true` gains `leadsDaily` by re-exporting it from
34
+ `convex/rastroFederation.ts`; no flag is needed.
35
+
36
+ A host that connects Meta ads opts in, all in one deploy:
37
+
38
+ 1. Declare the four optional env bindings in `convex/convex.config.ts` and pass
39
+ them to the component, the same way as GeoIP:
40
+
41
+ ```ts
42
+ const app = defineApp({
43
+ env: {
44
+ // ...the bindings the host already declares
45
+ RASTRO_SECRETS_KEY: v.optional(v.string()),
46
+ RASTRO_META_FAKE: v.optional(v.literal("true")),
47
+ RASTRO_META_APP_ID: v.optional(v.string()),
48
+ RASTRO_META_APP_SECRET: v.optional(v.string()),
49
+ },
50
+ });
51
+ app.use(rastro, {
52
+ env: {
53
+ // ...
54
+ RASTRO_SECRETS_KEY: app.env.RASTRO_SECRETS_KEY,
55
+ RASTRO_META_FAKE: app.env.RASTRO_META_FAKE,
56
+ RASTRO_META_APP_ID: app.env.RASTRO_META_APP_ID,
57
+ RASTRO_META_APP_SECRET: app.env.RASTRO_META_APP_SECRET,
58
+ },
59
+ });
60
+ ```
61
+
62
+ 2. Set the env vars as deployment secrets, never in code:
63
+ - `RASTRO_SECRETS_KEY`, required to connect Meta or a pixel: 32 random bytes,
64
+ base64 (`openssl rand -base64 32`), a new one per deployment. Without it
65
+ those calls fail with `SECRETS_KEY_MISSING` and everything else works.
66
+ - `RASTRO_META_APP_ID` and `RASTRO_META_APP_SECRET`, for Facebook Login for
67
+ Business: the "Amage Rastro" app. Without both, the login fails with
68
+ `META_LOGIN_UNAVAILABLE` and a pasted system user token still connects.
69
+ - `RASTRO_META_FAKE=true` only on the example host, demos and tests; never on
70
+ a customer deployment.
71
+ 3. Pass `metaAds: true` beside `leads: true` to `exposeFederatedAnalyticsApi`
72
+ and add the Meta functions to the module's exports, including the internal
73
+ `authorizeMetaAction` the three federated actions authorize through:
74
+
75
+ ```ts
76
+ const federated = exposeFederatedAnalyticsApi(components.rastroAnalytics, {
77
+ issuer: federationIssuer,
78
+ resolveConnection,
79
+ leads: true,
80
+ metaAds: true,
81
+ });
82
+
83
+ export const {
84
+ // ...the functions the module already exports
85
+ leadsDaily,
86
+ metaStatus,
87
+ metaConversions,
88
+ metaConnection,
89
+ metaEventMap,
90
+ metaUnlinkPreview,
91
+ connectMeta,
92
+ disconnectMeta,
93
+ refreshMetaAccounts,
94
+ linkMetaAdAccount,
95
+ unlinkMetaAdAccount,
96
+ setMetaPixel,
97
+ removeMetaPixel,
98
+ setMetaEventMap,
99
+ syncMetaNow,
100
+ authorizeMetaAction,
101
+ } = federated;
102
+ ```
103
+
104
+ 4. Where the host revokes or deletes a dashboard connection's grant, call
105
+ `rastro.removeFederatedMetaConnection(ctx, { connectionId })` in the same
106
+ mutation, so the Meta owner that connection acted as goes with it.
107
+ 5. Deploy and use **Verificar novamente** in the dashboard's Conexões. The
108
+ connection records `metaAds`, and the dashboard's **Integrações** screen
109
+ reads and changes that host's Meta setup. Its writes need
110
+ `analytics:configure` on both the token and the local grant.
111
+
112
+ To send conversions, pass the optional `meta` hashes to `recordLead` and
113
+ `setLeadStage`, and declare the board columns with `setPipeline` and their
114
+ events with `setEventMap` (or let the dashboard map them). A host that embeds
115
+ the screens itself imports them from `@iann29/rastro/ui` with
116
+ `@iann29/rastro/ui.css`, and then needs React. Shapes, limits and the security
117
+ invariants are in [Meta ads](meta-ads.md).
118
+
3
119
  ## Tracked paths (0.9.0)
4
120
 
5
121
  Install `@iann29/rastro@0.9.0` and deploy the consuming host. The site's
package/llms.txt CHANGED
@@ -19,6 +19,7 @@ Do not infer federation availability from this website, a dist-tag, or a source
19
19
  - The tracker is 2,999 bytes raw and 1,565 gzip. It sends the click-ID key **names** of the landing URL in `clid` (`gclid`, `fbclid`, `ttclid`…), at most eight, never a value, and the referrer as scheme and host, so an `android-app://<package>` referrer keeps its package.
20
20
  - Tracked links (0.5.0+): browser -> customer HTTP-actions URL `/rastro/l/<slug>` -> `302` (`Cache-Control: no-store`) to a destination on one of the site's domains, with `utm_source` (platform), `utm_medium` (channel), `utm_campaign` (campaign, or the slug) and `utm_content` (slug) appended; the destination's own query and `utm_*` keys stay. Unknown or disabled slug: `404`. Clicks count in four-shard daily counters; self-declared bots are redirected and counted apart.
21
21
  - Leads (0.8.0+): the host's server -> `recordLead` / `setLeadStage` on its own Rastro component, for conversations with no web session (a WhatsApp lead from a Click-to-WhatsApp ad). Keyed by the host's opaque id, never a phone number; cohort counts by origin and by campaign -> ad set -> ad; the ad click id never leaves the host.
22
+ - Meta ads (0.10.0+): the host's Rastro component -> Meta Marketing API for each linked ad account's daily spend and ad names, and -> the site's Meta pixel for qualified leads and sales. Tokens are encrypted at rest with the host's `RASTRO_SECRETS_KEY` and no read returns them; phone numbers arrive only as SHA-256 hashes and are erased after delivery. See the [Meta ads guide](https://www.amagerastro.com/docs/reference/meta-ads.md).
22
23
  - Optional field Web Vitals (alpha.6+): a second browser module at `/rastro/vitals.js` reports LCP, CLS, INP, FCP, and TTFB to the same events endpoint, into bounded daily histograms; it needs the base tracker on the page.
23
24
  - Reactive dashboard reads: amagerastro.com browser -> customer functions URL -> `rastroFederation:*`.
24
25
  - Control plane: account, organization, connection metadata, short-lived token issuance, and revocation.
@@ -35,6 +36,7 @@ Do not infer federation availability from this website, a dist-tag, or a source
35
36
  - Use the canonical module name `convex/rastroFederation.ts`.
36
37
  - A host on 0.5.0 re-exports `listTrackedLinks`, `createTrackedLink`, `updateTrackedLink` and `deleteTrackedLink` from that module and reverifies, which advertises the optional `trackedLinks` capability; listing needs a reader, the other three need `analytics:configure`. A host that skips it keeps working without the capability.
37
38
  - A host on 0.8.0 that records leads from its server re-exports `leadsReport`, `listLeads` and `leadJourney` and passes `leads: true` to `exposeFederatedAnalyticsApi`, which advertises the opt-in `leads` capability for any reader; without the option the three refuse and nothing is advertised.
39
+ - A host on 0.10.0 also re-exports `leadsDaily` under `leads`. One that links Meta ad accounts or a pixel passes `metaAds: true` and re-exports `metaStatus` and `metaConversions`, which advertises the opt-in `metaAds` capability for any reader; without the option those two refuse with `FEDERATION_INVALID_SCOPE`. With `metaAds: true` the host also exports the dashboard's own Meta setup (`metaConnection`, `metaEventMap`, `metaUnlinkPreview`, and the `analytics:configure` writes `connectMeta`, `refreshMetaAccounts`, `setMetaPixel`, `disconnectMeta`, `linkMetaAdAccount`, `unlinkMetaAdAccount`, `removeMetaPixel`, `setMetaEventMap`, `syncMetaNow`) plus the internal `authorizeMetaAction`; see docs/upgrading.md for the 0.10.0 steps.
38
40
  - Expose only the manifest, connection status, site summaries, reports, journeys, conversions, affiliates, funnels, goals, web vitals, coverage, tracked links, and the configure functions listed in the manifest; the configure functions run only when the token and the local grant both carry `analytics:configure`. A public link's token carries `analytics:public` alone and reaches only the manifest, connection status, site summaries, a redacted overview, redacted live visitors, and coverage, and only when the local grant lists `analytics:public`.
39
41
  - Use the functions URL as JWT audience and the HTTP-actions URL for tracker ingestion.
40
42
  - Rehearse on an explicit development target. Production changes require fresh operator consent.
@@ -72,6 +74,7 @@ Do not infer federation availability from this website, a dist-tag, or a source
72
74
  - Goal, funnel, and affiliate reports include read-only definitions plus aggregates. Configuration writes (goals, funnels, affiliates, a site's name/domains/timezone, retention) exist only in the configure scope and fail with `FEDERATION_CONFIGURE_FORBIDDEN` for a read-only token or grant; `listSites` never returns domains, only `siteSettings` does, to a connection allowed to change them.
73
75
  - A public token (`analytics:public`) gets `overview` with zero `conversions` and `revenueCents` and empty `topCampaigns`, `topMediums`, `topEvents`, and `topGoals`, `liveVisitors` with `visitorId` equal to `sessionId` and without `entryPath`, `returning`, `utmCampaign`, `affiliateSlug`, `conversionCount`, or `funnel`, and `FEDERATION_PUBLIC_FORBIDDEN` for sessions, journeys, conversions, goals, funnels, affiliates, vitals, the site map, and the configure scope.
74
76
  - Session and visitor journeys include bounded custom properties. Hosts must never place personal data or secrets in event properties.
77
+ - Spend (0.10.0+): `leadsReport` rows, `bySite`, and `leadsDaily` days carry `spendCents` in integer cents; `null` means no linked ad account covers the row, never zero. Cost per lead and return are never stored: compute them with the `@iann29/rastro/ui` helpers from counters the spend bought (ad, ad set, campaign, the `ctwa_ad` origin, a site's `paid`), and not at all when `currencyMismatch` is true.
75
78
  - Audit retained routes, identity strategy, sessions, live location, campaigns, affiliates, conversions, custom properties, retention, and intended organization membership before granting federation; stop if their sensitivity or audience cannot be established.
76
79
  - Overview ranges require complete UTC hours, complete UTC days, or (hosts from `alpha.11`, optional capability `localDays`) complete calendar days in the timezone every requested site shares; `metadata.range.timezone` names the zone the answer follows. Manual pagination honors `numItems` and `cursor` only.
77
80
  - Right after an accepted request, `liveVisitors` and `sessionJourney` reflect it; `listSessions` and the bucketed reports can trail it by seconds, so an empty result from those is not proof of failed ingestion.
package/package.json CHANGED
@@ -6,7 +6,7 @@
6
6
  "bugs": {
7
7
  "url": "https://github.com/amageweb/amage-rastro/issues"
8
8
  },
9
- "version": "0.9.0",
9
+ "version": "0.10.1",
10
10
  "license": "Apache-2.0",
11
11
  "publishConfig": {
12
12
  "access": "public"
@@ -28,12 +28,13 @@
28
28
  "scripts": {
29
29
  "dev": "synapse dev --start 'npm run dev:build'",
30
30
  "dev:frontend": "cd control-plane && vite",
31
- "dev:build": "chokidar 'tsconfig*.json' 'src/**/*.{ts,js}' 'scripts/build-tracker.mjs' -i '**/*.test.ts' -c 'npm run build:codegen' --initial",
31
+ "dev:build": "chokidar 'tsconfig*.json' 'src/**/*.{ts,tsx,js,css}' 'scripts/build-tracker.mjs' 'scripts/build-ui-css.mjs' -i '**/*.test.ts' -i '**/*.test.tsx' -c 'npm run build:codegen' --initial",
32
32
  "deploy:dashboard": "static-hosting upload --build --dist control-plane/dist --build-command \"npm exec vite -- build control-plane\"",
33
33
  "predev": "npm run build:codegen",
34
34
  "prebuild": "rm -rf dist *.tsbuildinfo",
35
- "build": "npm run build:tracker && tsc --project ./tsconfig.build.json",
35
+ "build": "npm run build:tracker && tsc --project ./tsconfig.build.json && npm run build:ui-css",
36
36
  "build:tracker": "node ./scripts/build-tracker.mjs",
37
+ "build:ui-css": "node ./scripts/build-ui-css.mjs",
37
38
  "federation:keys": "node ./scripts/generate-federation-keys.mjs",
38
39
  "benchmark:ingest": "node ./scripts/benchmark-ingest.mjs",
39
40
  "benchmark:local": "vitest run src/component/benchmark.test.ts",
@@ -59,6 +60,7 @@
59
60
  "src/test.ts",
60
61
  "src/component/**/*.ts",
61
62
  "!src/component/**/*.test.ts",
63
+ "src/ui/seed.ts",
62
64
  "src/tracker/generated.ts",
63
65
  "scripts/benchmark-ingest.mjs",
64
66
  "scripts/generate-federation-keys.mjs",
@@ -70,6 +72,7 @@
70
72
  "docs/federation-setup.md",
71
73
  "docs/upgrading.md",
72
74
  "docs/identity.md",
75
+ "docs/meta-ads.md",
73
76
  "docs/benchmarks/*.md",
74
77
  "assets/rastro-live-atlas.png"
75
78
  ],
@@ -83,6 +86,15 @@
83
86
  "types": "./dist/react/index.d.ts",
84
87
  "default": "./dist/react/index.js"
85
88
  },
89
+ "./ui": {
90
+ "types": "./dist/ui/index.d.ts",
91
+ "default": "./dist/ui/index.js"
92
+ },
93
+ "./ui/sample": {
94
+ "types": "./dist/ui/sample.d.ts",
95
+ "default": "./dist/ui/sample.js"
96
+ },
97
+ "./ui.css": "./dist/ui/ui.css",
86
98
  "./tracker.js": "./dist/tracker.min.js",
87
99
  "./vitals.js": "./dist/vitals.min.js",
88
100
  "./test": "./src/test.ts",
@@ -25,14 +25,21 @@ import type * as ingest from "../ingest.js";
25
25
  import type * as leads from "../leads.js";
26
26
  import type * as live from "../live.js";
27
27
  import type * as localTime from "../localTime.js";
28
+ import type * as meta from "../meta.js";
29
+ import type * as metaCapi from "../metaCapi.js";
30
+ import type * as metaFake from "../metaFake.js";
31
+ import type * as metaGraph from "../metaGraph.js";
32
+ import type * as metaSync from "../metaSync.js";
28
33
  import type * as origin from "../origin.js";
29
34
  import type * as people from "../people.js";
35
+ import type * as pipeline from "../pipeline.js";
30
36
  import type * as platforms from "../platforms.js";
31
37
  import type * as reports from "../reports.js";
32
38
  import type * as retention from "../retention.js";
33
39
  import type * as rollupStore from "../rollupStore.js";
34
40
  import type * as rollups from "../rollups.js";
35
41
  import type * as sanitize from "../sanitize.js";
42
+ import type * as secrets from "../secrets.js";
36
43
  import type * as sites from "../sites.js";
37
44
  import type * as trackedLinks from "../trackedLinks.js";
38
45
  import type * as useragent from "../useragent.js";
@@ -65,14 +72,21 @@ const fullApi: ApiFromModules<{
65
72
  leads: typeof leads;
66
73
  live: typeof live;
67
74
  localTime: typeof localTime;
75
+ meta: typeof meta;
76
+ metaCapi: typeof metaCapi;
77
+ metaFake: typeof metaFake;
78
+ metaGraph: typeof metaGraph;
79
+ metaSync: typeof metaSync;
68
80
  origin: typeof origin;
69
81
  people: typeof people;
82
+ pipeline: typeof pipeline;
70
83
  platforms: typeof platforms;
71
84
  reports: typeof reports;
72
85
  retention: typeof retention;
73
86
  rollupStore: typeof rollupStore;
74
87
  rollups: typeof rollups;
75
88
  sanitize: typeof sanitize;
89
+ secrets: typeof secrets;
76
90
  sites: typeof sites;
77
91
  trackedLinks: typeof trackedLinks;
78
92
  useragent: typeof useragent;
@@ -242,6 +242,26 @@ export type ComponentApi<Name extends string | undefined = string | undefined> =
242
242
  >;
243
243
  };
244
244
  leads: {
245
+ daily: FunctionReference<
246
+ "query",
247
+ "internal",
248
+ {
249
+ adId?: string;
250
+ from: number;
251
+ origin?: string;
252
+ siteIds: Array<string>;
253
+ to: number;
254
+ },
255
+ Array<{
256
+ dayStart: number;
257
+ leads: number;
258
+ qualified: number;
259
+ revenueCents: number;
260
+ spendCents: number | null;
261
+ won: number;
262
+ }>,
263
+ Name
264
+ >;
245
265
  journey: FunctionReference<
246
266
  "query",
247
267
  "internal",
@@ -320,9 +340,11 @@ export type ComponentApi<Name extends string | undefined = string | undefined> =
320
340
  title?: string;
321
341
  };
322
342
  channel: "whatsapp";
343
+ column?: string;
323
344
  entryPoint?: string;
324
345
  label?: string;
325
346
  leadKey: string;
347
+ meta?: any;
326
348
  occurredAt: number;
327
349
  siteId: string;
328
350
  visitorId?: string;
@@ -342,48 +364,85 @@ export type ComponentApi<Name extends string | undefined = string | undefined> =
342
364
  "internal",
343
365
  { from: number; siteIds: Array<string>; to: number },
344
366
  {
367
+ bySite?: Array<{
368
+ currencyMismatch?: boolean;
369
+ leads: number;
370
+ paid: {
371
+ leads: number;
372
+ qualified: number;
373
+ revenueCents: number;
374
+ won: number;
375
+ };
376
+ qualified: number;
377
+ revenueCents: number;
378
+ siteId: string;
379
+ spendCents?: number | null;
380
+ spendCurrency?: string | null;
381
+ won: number;
382
+ }>;
345
383
  campaigns: Array<{
346
384
  adsets: Array<{
347
385
  ads: Array<{
348
386
  adId: string;
349
387
  adName: string | null;
388
+ adStatus?: string | null;
389
+ clicks?: number | null;
390
+ creativeType?: string | null;
391
+ impressions?: number | null;
350
392
  leads: number;
351
393
  qualified: number;
352
394
  revenueCents: number;
395
+ siteId?: string;
353
396
  sourceApp: string | null;
354
397
  sourceUrl: string | null;
398
+ spendCents?: number | null;
355
399
  thumbnailUrl: string | null;
356
400
  title: string | null;
357
401
  won: number;
358
402
  }>;
359
403
  adsetId: string | null;
360
404
  adsetName: string | null;
405
+ clicks?: number | null;
406
+ impressions?: number | null;
361
407
  leads: number;
362
408
  qualified: number;
363
409
  revenueCents: number;
410
+ spendCents?: number | null;
364
411
  won: number;
365
412
  }>;
366
413
  campaignId: string | null;
367
414
  campaignName: string | null;
415
+ clicks?: number | null;
416
+ impressions?: number | null;
368
417
  leads: number;
369
418
  qualified: number;
370
419
  revenueCents: number;
420
+ spendCents?: number | null;
371
421
  won: number;
372
422
  }>;
373
423
  currency: string | null;
424
+ currencyMismatch?: boolean;
374
425
  from: number;
375
426
  origins: Array<{
427
+ clicks?: number | null;
428
+ impressions?: number | null;
376
429
  key: string;
377
430
  leads: number;
378
431
  qualified: number;
379
432
  revenueCents: number;
433
+ spendCents?: number | null;
380
434
  won: number;
381
435
  }>;
436
+ spendCurrency?: string | null;
437
+ spendIncomplete?: boolean;
382
438
  to: number;
383
439
  totals: {
440
+ clicks?: number | null;
441
+ impressions?: number | null;
384
442
  leads: number;
385
443
  qualified: number;
386
444
  revenueCents: number;
445
+ spendCents?: number | null;
387
446
  won: number;
388
447
  };
389
448
  },
@@ -393,12 +452,14 @@ export type ComponentApi<Name extends string | undefined = string | undefined> =
393
452
  "mutation",
394
453
  "internal",
395
454
  {
455
+ column?: string;
396
456
  eventId: string;
397
457
  leadKey: string;
458
+ meta?: any;
398
459
  occurredAt: number;
399
460
  revenueCents?: number;
400
461
  siteId: string;
401
- stage: "qualified" | "won" | "lost" | "open";
462
+ stage?: "qualified" | "won" | "lost" | "open";
402
463
  },
403
464
  { applied: boolean },
404
465
  Name
@@ -422,6 +483,221 @@ export type ComponentApi<Name extends string | undefined = string | undefined> =
422
483
  Name
423
484
  >;
424
485
  };
486
+ meta: {
487
+ connect: FunctionReference<
488
+ "action",
489
+ "internal",
490
+ { accessToken: string; ownerKey: string },
491
+ {
492
+ adAccounts: Array<{
493
+ adAccountId: string;
494
+ currency: string;
495
+ name: string;
496
+ timezone: string;
497
+ }>;
498
+ businessName: string | null;
499
+ connectionId: string;
500
+ pixels: Array<{ name: string; pixelId: string }>;
501
+ },
502
+ Name
503
+ >;
504
+ connectWithCode: FunctionReference<
505
+ "action",
506
+ "internal",
507
+ { code: string; ownerKey: string; redirectUri: string },
508
+ {
509
+ adAccounts: Array<{
510
+ adAccountId: string;
511
+ currency: string;
512
+ name: string;
513
+ timezone: string;
514
+ }>;
515
+ businessName: string | null;
516
+ connectionId: string;
517
+ pixels: Array<{ name: string; pixelId: string }>;
518
+ },
519
+ Name
520
+ >;
521
+ connection: FunctionReference<
522
+ "query",
523
+ "internal",
524
+ { ownerKey: string },
525
+ null | {
526
+ adAccounts: Array<{
527
+ adAccountId: string;
528
+ currency: string;
529
+ linkedOutsideScope?: boolean;
530
+ linkedSiteId: string | null;
531
+ name: string;
532
+ timezone: string;
533
+ }>;
534
+ authorizedAt: number | null;
535
+ authorizedBy: { name: string | null } | null;
536
+ businessName: string | null;
537
+ expiresAt: number | null;
538
+ expiringSoon: boolean;
539
+ invalidSince: number | null;
540
+ lastError: string | null;
541
+ pixels: Array<{ name: string; pixelId: string }>;
542
+ status: "active" | "invalid";
543
+ },
544
+ Name
545
+ >;
546
+ connectionSites: FunctionReference<
547
+ "query",
548
+ "internal",
549
+ { ownerKey: string },
550
+ Array<string>,
551
+ Name
552
+ >;
553
+ conversions: FunctionReference<
554
+ "query",
555
+ "internal",
556
+ {
557
+ before?: number;
558
+ beforeEventId?: string;
559
+ limit?: number;
560
+ siteId: string;
561
+ },
562
+ Array<{
563
+ adId: string | null;
564
+ adName: string | null;
565
+ createdAt: number;
566
+ eventId: string;
567
+ eventName: "Lead" | "QualifiedLead" | "Schedule" | "Purchase";
568
+ leadId: string | null;
569
+ leadLabel: string | null;
570
+ sentAt: number | null;
571
+ status: "pending" | "sent" | "failed";
572
+ valueCents: number | null;
573
+ }>,
574
+ Name
575
+ >;
576
+ linkAdAccount: FunctionReference<
577
+ "mutation",
578
+ "internal",
579
+ {
580
+ adAccountId: string;
581
+ onlyOwn?: boolean;
582
+ ownerKey: string;
583
+ siteId: string;
584
+ },
585
+ { linked: boolean },
586
+ Name
587
+ >;
588
+ listAdAccounts: FunctionReference<
589
+ "action",
590
+ "internal",
591
+ { ownerKey: string },
592
+ Array<{
593
+ adAccountId: string;
594
+ currency: string;
595
+ name: string;
596
+ timezone: string;
597
+ }>,
598
+ Name
599
+ >;
600
+ removeConnection: FunctionReference<
601
+ "mutation",
602
+ "internal",
603
+ { ownerKey: string },
604
+ { removed: boolean },
605
+ Name
606
+ >;
607
+ removePixel: FunctionReference<
608
+ "mutation",
609
+ "internal",
610
+ { ownerKey?: string; siteId: string },
611
+ { removed: boolean },
612
+ Name
613
+ >;
614
+ setPixel: FunctionReference<
615
+ "action",
616
+ "internal",
617
+ {
618
+ accessToken?: string;
619
+ enabled: boolean;
620
+ onlyOwn?: boolean;
621
+ ownerKey?: string;
622
+ pixelId: string;
623
+ sendLeadEvent?: boolean;
624
+ setBy?: string;
625
+ siteId: string;
626
+ testEventCode?: string;
627
+ },
628
+ { ok: true },
629
+ Name
630
+ >;
631
+ status: FunctionReference<
632
+ "query",
633
+ "internal",
634
+ { now?: number; ownerKey?: string; siteIds: Array<string> },
635
+ Array<{
636
+ adAccounts: Array<{
637
+ adAccountId: string;
638
+ backfill?: { done: number; total: number } | null;
639
+ currency: string;
640
+ lastError: string | null;
641
+ lastSyncAt: number | null;
642
+ name: string;
643
+ own?: boolean;
644
+ syncState: "backfill" | "live" | "error";
645
+ timezone: string;
646
+ }>;
647
+ conversions: {
648
+ failed: number;
649
+ last30d?: {
650
+ Lead: number;
651
+ Purchase: number;
652
+ QualifiedLead: number;
653
+ Schedule: number;
654
+ } | null;
655
+ pending: number;
656
+ sent: number;
657
+ sentToday?: number | null;
658
+ };
659
+ linked: boolean;
660
+ pixel: {
661
+ enabled: boolean;
662
+ lastError?: string | null;
663
+ name?: string | null;
664
+ own?: boolean;
665
+ pixelId: string | null;
666
+ source?: "connection" | "token" | null;
667
+ testMode?: boolean;
668
+ };
669
+ siteId: string;
670
+ }>,
671
+ Name
672
+ >;
673
+ syncNow: FunctionReference<
674
+ "mutation",
675
+ "internal",
676
+ { siteId: string },
677
+ { scheduled: boolean },
678
+ Name
679
+ >;
680
+ unlinkAdAccount: FunctionReference<
681
+ "mutation",
682
+ "internal",
683
+ { adAccountId: string; ownerKey?: string; siteId: string },
684
+ { unlinked: boolean },
685
+ Name
686
+ >;
687
+ unlinkPreview: FunctionReference<
688
+ "query",
689
+ "internal",
690
+ { adAccountId: string; siteId: string },
691
+ {
692
+ campaigns: number;
693
+ currency: string;
694
+ days: number;
695
+ partial: boolean;
696
+ spendCents: number;
697
+ },
698
+ Name
699
+ >;
700
+ };
425
701
  people: {
426
702
  backfillSearch: FunctionReference<
427
703
  "mutation",
@@ -462,6 +738,53 @@ export type ComponentApi<Name extends string | undefined = string | undefined> =
462
738
  Name
463
739
  >;
464
740
  };
741
+ pipeline: {
742
+ eventMap: FunctionReference<
743
+ "query",
744
+ "internal",
745
+ { now?: number; siteId: string },
746
+ {
747
+ columns: Array<{
748
+ color: string | null;
749
+ event: "Lead" | "QualifiedLead" | "Schedule" | null;
750
+ group: string | null;
751
+ key: string;
752
+ monthCount: number | null;
753
+ name: string;
754
+ }>;
755
+ purchase: { enabled: boolean };
756
+ sendLeadEvent: boolean;
757
+ },
758
+ Name
759
+ >;
760
+ setEventMap: FunctionReference<
761
+ "mutation",
762
+ "internal",
763
+ {
764
+ columns: Record<string, "Lead" | "QualifiedLead" | "Schedule" | null>;
765
+ ownerKey?: string;
766
+ sendLeadEvent: boolean;
767
+ siteId: string;
768
+ },
769
+ null,
770
+ Name
771
+ >;
772
+ setPipeline: FunctionReference<
773
+ "mutation",
774
+ "internal",
775
+ {
776
+ columns: Array<{
777
+ color?: string;
778
+ group?: string;
779
+ key: string;
780
+ name: string;
781
+ }>;
782
+ siteId: string;
783
+ },
784
+ null,
785
+ Name
786
+ >;
787
+ };
465
788
  reports: {
466
789
  affiliatesReport: FunctionReference<
467
790
  "query",
@@ -43,6 +43,10 @@ type Env = {
43
43
  readonly RASTRO_GEOIP_DAILY_LIMIT: string | undefined;
44
44
  readonly RASTRO_GEOIP_PROVIDER: "ipinfo" | "ipwhois" | undefined;
45
45
  readonly RASTRO_GEOIP_TOKEN: string | undefined;
46
+ readonly RASTRO_META_APP_ID: string | undefined;
47
+ readonly RASTRO_META_APP_SECRET: string | undefined;
48
+ readonly RASTRO_META_FAKE: "true" | undefined;
49
+ readonly RASTRO_SECRETS_KEY: string | undefined;
46
50
  readonly RASTRO_TRUST_PROXY: "true" | undefined;
47
51
  };
48
52