@iann29/rastro 0.10.8 → 0.11.0

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 (182) hide show
  1. package/README.md +8 -0
  2. package/agent/integration.md +45 -0
  3. package/agent/manifest.json +4 -4
  4. package/dist/client/federation.d.ts +82 -9
  5. package/dist/client/federation.d.ts.map +1 -1
  6. package/dist/client/federation.js +40 -2
  7. package/dist/client/federation.js.map +1 -1
  8. package/dist/client/index.d.ts +464 -8
  9. package/dist/client/index.d.ts.map +1 -1
  10. package/dist/client/index.js +259 -7
  11. package/dist/client/index.js.map +1 -1
  12. package/dist/component/_generated/api.d.ts +10 -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 +273 -21
  16. package/dist/component/_generated/component.d.ts.map +1 -1
  17. package/dist/component/_generated/server.d.ts +2 -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 +31 -0
  21. package/dist/component/constants.d.ts.map +1 -1
  22. package/dist/component/constants.js +31 -0
  23. package/dist/component/constants.js.map +1 -1
  24. package/dist/component/convex.config.d.ts +2 -0
  25. package/dist/component/convex.config.js +7 -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/http.d.ts.map +1 -1
  31. package/dist/component/http.js +64 -0
  32. package/dist/component/http.js.map +1 -1
  33. package/dist/component/leadAdsValidators.d.ts +1092 -0
  34. package/dist/component/leadAdsValidators.d.ts.map +1 -0
  35. package/dist/component/leadAdsValidators.js +304 -0
  36. package/dist/component/leadAdsValidators.js.map +1 -0
  37. package/dist/component/leadFormRules.d.ts +60 -0
  38. package/dist/component/leadFormRules.d.ts.map +1 -0
  39. package/dist/component/leadFormRules.js +140 -0
  40. package/dist/component/leadFormRules.js.map +1 -0
  41. package/dist/component/leadFormStore.d.ts +16 -0
  42. package/dist/component/leadFormStore.d.ts.map +1 -0
  43. package/dist/component/leadFormStore.js +92 -0
  44. package/dist/component/leadFormStore.js.map +1 -0
  45. package/dist/component/leadgenToken.d.ts +56 -0
  46. package/dist/component/leadgenToken.d.ts.map +1 -0
  47. package/dist/component/leadgenToken.js +262 -0
  48. package/dist/component/leadgenToken.js.map +1 -0
  49. package/dist/component/leads.d.ts +76 -7
  50. package/dist/component/leads.d.ts.map +1 -1
  51. package/dist/component/leads.js +112 -78
  52. package/dist/component/leads.js.map +1 -1
  53. package/dist/component/meta.d.ts.map +1 -1
  54. package/dist/component/meta.js +21 -1
  55. package/dist/component/meta.js.map +1 -1
  56. package/dist/component/metaCapi.d.ts.map +1 -1
  57. package/dist/component/metaCapi.js +10 -0
  58. package/dist/component/metaCapi.js.map +1 -1
  59. package/dist/component/metaFake.d.ts +44 -0
  60. package/dist/component/metaFake.d.ts.map +1 -1
  61. package/dist/component/metaFake.js +400 -1
  62. package/dist/component/metaFake.js.map +1 -1
  63. package/dist/component/metaGraph.d.ts +91 -0
  64. package/dist/component/metaGraph.d.ts.map +1 -1
  65. package/dist/component/metaGraph.js +217 -0
  66. package/dist/component/metaGraph.js.map +1 -1
  67. package/dist/component/metaLeads.d.ts +681 -0
  68. package/dist/component/metaLeads.d.ts.map +1 -0
  69. package/dist/component/metaLeads.js +2634 -0
  70. package/dist/component/metaLeads.js.map +1 -0
  71. package/dist/component/schema.d.ts +414 -5
  72. package/dist/component/schema.d.ts.map +1 -1
  73. package/dist/component/schema.js +169 -1
  74. package/dist/component/schema.js.map +1 -1
  75. package/dist/component/validators.d.ts +235 -11
  76. package/dist/component/validators.d.ts.map +1 -1
  77. package/dist/component/validators.js +14 -1
  78. package/dist/component/validators.js.map +1 -1
  79. package/dist/tracker/generated.d.ts +1 -1
  80. package/dist/tracker/generated.js +1 -1
  81. package/dist/ui/campaigns/CampaignsView.d.ts +5 -1
  82. package/dist/ui/campaigns/CampaignsView.d.ts.map +1 -1
  83. package/dist/ui/campaigns/CampaignsView.js.map +1 -1
  84. package/dist/ui/campaigns/Drawer.d.ts.map +1 -1
  85. package/dist/ui/campaigns/Drawer.js +8 -26
  86. package/dist/ui/campaigns/Drawer.js.map +1 -1
  87. package/dist/ui/campaigns/labels.d.ts +29 -1
  88. package/dist/ui/campaigns/labels.d.ts.map +1 -1
  89. package/dist/ui/campaigns/labels.js +77 -2
  90. package/dist/ui/campaigns/labels.js.map +1 -1
  91. package/dist/ui/campaigns/model.js +2 -2
  92. package/dist/ui/campaigns/model.js.map +1 -1
  93. package/dist/ui/forms/FirstContact.d.ts +19 -0
  94. package/dist/ui/forms/FirstContact.d.ts.map +1 -0
  95. package/dist/ui/forms/FirstContact.js +81 -0
  96. package/dist/ui/forms/FirstContact.js.map +1 -0
  97. package/dist/ui/forms/FormLead.d.ts +28 -0
  98. package/dist/ui/forms/FormLead.d.ts.map +1 -0
  99. package/dist/ui/forms/FormLead.js +199 -0
  100. package/dist/ui/forms/FormLead.js.map +1 -0
  101. package/dist/ui/forms/FormRulesDrawer.d.ts +49 -0
  102. package/dist/ui/forms/FormRulesDrawer.d.ts.map +1 -0
  103. package/dist/ui/forms/FormRulesDrawer.js +149 -0
  104. package/dist/ui/forms/FormRulesDrawer.js.map +1 -0
  105. package/dist/ui/forms/FormsView.d.ts +10 -0
  106. package/dist/ui/forms/FormsView.d.ts.map +1 -0
  107. package/dist/ui/forms/FormsView.js +215 -0
  108. package/dist/ui/forms/FormsView.js.map +1 -0
  109. package/dist/ui/forms/Icons.d.ts +46 -0
  110. package/dist/ui/forms/Icons.d.ts.map +1 -0
  111. package/dist/ui/forms/Icons.js +45 -0
  112. package/dist/ui/forms/Icons.js.map +1 -0
  113. package/dist/ui/forms/RuleRow.d.ts +37 -0
  114. package/dist/ui/forms/RuleRow.d.ts.map +1 -0
  115. package/dist/ui/forms/RuleRow.js +80 -0
  116. package/dist/ui/forms/RuleRow.js.map +1 -0
  117. package/dist/ui/forms/WhatsAppButtonGuide.d.ts +33 -0
  118. package/dist/ui/forms/WhatsAppButtonGuide.d.ts.map +1 -0
  119. package/dist/ui/forms/WhatsAppButtonGuide.js +90 -0
  120. package/dist/ui/forms/WhatsAppButtonGuide.js.map +1 -0
  121. package/dist/ui/forms/index.d.ts +11 -0
  122. package/dist/ui/forms/index.d.ts.map +1 -0
  123. package/dist/ui/forms/index.js +7 -0
  124. package/dist/ui/forms/index.js.map +1 -0
  125. package/dist/ui/forms/journey.d.ts +19 -0
  126. package/dist/ui/forms/journey.d.ts.map +1 -0
  127. package/dist/ui/forms/journey.js +54 -0
  128. package/dist/ui/forms/journey.js.map +1 -0
  129. package/dist/ui/forms/model.d.ts +239 -0
  130. package/dist/ui/forms/model.d.ts.map +1 -0
  131. package/dist/ui/forms/model.js +556 -0
  132. package/dist/ui/forms/model.js.map +1 -0
  133. package/dist/ui/forms/sample.d.ts +36 -0
  134. package/dist/ui/forms/sample.d.ts.map +1 -0
  135. package/dist/ui/forms/sample.js +444 -0
  136. package/dist/ui/forms/sample.js.map +1 -0
  137. package/dist/ui/forms/types.d.ts +454 -0
  138. package/dist/ui/forms/types.d.ts.map +1 -0
  139. package/dist/ui/forms/types.js +2 -0
  140. package/dist/ui/forms/types.js.map +1 -0
  141. package/dist/ui/index.d.ts +2 -0
  142. package/dist/ui/index.d.ts.map +1 -1
  143. package/dist/ui/index.js +4 -0
  144. package/dist/ui/index.js.map +1 -1
  145. package/dist/ui/integrations/Overlay.d.ts +3 -1
  146. package/dist/ui/integrations/Overlay.d.ts.map +1 -1
  147. package/dist/ui/integrations/Overlay.js +2 -2
  148. package/dist/ui/integrations/Overlay.js.map +1 -1
  149. package/dist/ui/portfolio/PortfolioView.d.ts +4 -1
  150. package/dist/ui/portfolio/PortfolioView.d.ts.map +1 -1
  151. package/dist/ui/portfolio/PortfolioView.js.map +1 -1
  152. package/dist/ui/sample.d.ts +3 -1
  153. package/dist/ui/sample.d.ts.map +1 -1
  154. package/dist/ui/sample.js +2 -0
  155. package/dist/ui/sample.js.map +1 -1
  156. package/dist/ui/seed.d.ts +1 -1
  157. package/dist/ui/ui.css +2301 -0
  158. package/docs/federation.md +19 -0
  159. package/docs/meta-ads.md +713 -7
  160. package/docs/upgrading.md +75 -0
  161. package/llms.txt +1 -0
  162. package/package.json +1 -1
  163. package/src/component/_generated/api.ts +10 -0
  164. package/src/component/_generated/component.ts +289 -20
  165. package/src/component/_generated/server.ts +2 -0
  166. package/src/component/constants.ts +33 -0
  167. package/src/component/convex.config.ts +7 -0
  168. package/src/component/errors.ts +3 -1
  169. package/src/component/http.ts +75 -0
  170. package/src/component/leadAdsValidators.ts +365 -0
  171. package/src/component/leadFormRules.ts +202 -0
  172. package/src/component/leadFormStore.ts +129 -0
  173. package/src/component/leadgenToken.ts +348 -0
  174. package/src/component/leads.ts +136 -84
  175. package/src/component/meta.ts +21 -1
  176. package/src/component/metaCapi.ts +13 -1
  177. package/src/component/metaFake.ts +485 -1
  178. package/src/component/metaGraph.ts +327 -0
  179. package/src/component/metaLeads.ts +3101 -0
  180. package/src/component/schema.ts +187 -1
  181. package/src/component/validators.ts +17 -1
  182. package/src/tracker/generated.ts +1 -1
@@ -0,0 +1,92 @@
1
+ import { labelChoices } from "./leadFormRules.js";
2
+ /*
3
+ * Reads and clean-up of a form lead's record (`formLeads`), shared by the
4
+ * lead journey (leads.ts) and the Lead Ads module (metaLeads.ts).
5
+ */
6
+ /** Where a form lead came from, with the names Rastro knows. */
7
+ export async function formLeadOrigin(ctx, row) {
8
+ const link = await ctx.db
9
+ .query("sitePages")
10
+ .withIndex("by_pageId", (range) => range.eq("pageId", row.pageId))
11
+ .first();
12
+ const page = link ??
13
+ (await ctx.db
14
+ .query("metaPages")
15
+ .withIndex("by_pageId", (range) => range.eq("pageId", row.pageId))
16
+ .first());
17
+ const form = await ctx.db
18
+ .query("metaForms")
19
+ .withIndex("by_formId", (range) => range.eq("formId", row.formId))
20
+ .first();
21
+ const catalog = row.adId
22
+ ? await ctx.db
23
+ .query("adCatalog")
24
+ .withIndex("by_siteId_and_adId", (range) => range.eq("siteId", row.siteId).eq("adId", row.adId))
25
+ .unique()
26
+ : null;
27
+ return {
28
+ pageId: row.pageId,
29
+ pageName: page?.name ?? null,
30
+ formId: row.formId,
31
+ formName: form?.name ?? null,
32
+ adId: row.adId ?? null,
33
+ adName: catalog?.adName ?? null,
34
+ adsetId: row.adsetId ?? catalog?.adsetId ?? null,
35
+ adsetName: catalog?.adsetName ?? null,
36
+ campaignId: row.campaignId ?? catalog?.campaignId ?? null,
37
+ campaignName: catalog?.campaignName ?? null,
38
+ platform: row.platform ?? null,
39
+ isOrganic: row.isOrganic,
40
+ };
41
+ }
42
+ /** A form lead's answers, origin and path, for the lead journey. */
43
+ export async function formLeadDetail(ctx, lead) {
44
+ const row = await ctx.db
45
+ .query("formLeads")
46
+ .withIndex("by_leadId", (range) => range.eq("leadId", lead._id))
47
+ .first();
48
+ if (!row)
49
+ return null;
50
+ const form = await ctx.db
51
+ .query("metaForms")
52
+ .withIndex("by_formId", (range) => range.eq("formId", row.formId))
53
+ .first();
54
+ return {
55
+ leadgenId: row.leadgenId,
56
+ receivedAt: row.receivedAt,
57
+ origin: await formLeadOrigin(ctx, row),
58
+ answers: labelChoices(form?.questions ?? [], row.answers),
59
+ decision: row.decision,
60
+ rulePath: row.rulePath,
61
+ ruleIndex: row.ruleIndex ?? null,
62
+ returned: row.returned ?? null,
63
+ };
64
+ }
65
+ /**
66
+ * Deletes a removed lead's ingestion record and leaves its leadgen id behind
67
+ * (nothing else), so the same Meta lead is never ingested again.
68
+ */
69
+ export async function forgetFormLead(ctx, leadId) {
70
+ const rows = await ctx.db
71
+ .query("formLeads")
72
+ .withIndex("by_leadId", (range) => range.eq("leadId", leadId))
73
+ .take(10);
74
+ const now = Date.now();
75
+ for (const row of rows) {
76
+ await ctx.db.delete("formLeads", row._id);
77
+ if (!(await isForgottenFormLead(ctx, row.leadgenId))) {
78
+ await ctx.db.insert("formLeadTombstones", {
79
+ leadgenId: row.leadgenId,
80
+ removedAt: now,
81
+ });
82
+ }
83
+ }
84
+ }
85
+ /** Whether the host removed the lead Meta knows by this leadgen id. */
86
+ export async function isForgottenFormLead(ctx, leadgenId) {
87
+ return ((await ctx.db
88
+ .query("formLeadTombstones")
89
+ .withIndex("by_leadgenId", (range) => range.eq("leadgenId", leadgenId))
90
+ .first()) !== null);
91
+ }
92
+ //# sourceMappingURL=leadFormStore.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"leadFormStore.js","sourceRoot":"","sources":["../../src/component/leadFormStore.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,56 @@
1
+ export declare class LeadgenTokenError extends Error {
2
+ readonly reason: string;
3
+ readonly transient: boolean;
4
+ /**
5
+ * `transient`: the token could not be checked because the issuer's keys
6
+ * could not be read right now (unreachable, 5xx, 429, not JSON). The route
7
+ * answers 503 then, which the control plane retries; any other refusal is a
8
+ * 401, which it does not.
9
+ */
10
+ constructor(reason: string, transient?: boolean);
11
+ }
12
+ type Fetch = typeof fetch;
13
+ /**
14
+ * The production dashboard's federation issuer: what the leadgen route trusts
15
+ * when the host passes no `RASTRO_FEDERATION_ISSUER`, as a host's federation
16
+ * API does. The audience has no default: it is the host's own functions URL.
17
+ */
18
+ export declare const DEFAULT_FEDERATION_ISSUER = "https://site.api.amagerastro.com/federation";
19
+ /**
20
+ * The issuer and audience the leadgen route checks forwards against, from the
21
+ * component's env. `audience` null means the route refuses every forward
22
+ * (`FEDERATION_NOT_CONFIGURED`), so a Page must not be linked or routed here.
23
+ */
24
+ export declare function leadgenTrust(env: {
25
+ RASTRO_FEDERATION_ISSUER?: string;
26
+ RASTRO_FEDERATION_AUDIENCE?: string;
27
+ }): {
28
+ issuer: string;
29
+ audience: string | null;
30
+ };
31
+ /** For tests: forget the cached keys. */
32
+ export declare function clearLeadgenKeyCache(): void;
33
+ export interface LeadgenTokenClaims {
34
+ connectionId: string;
35
+ organizationId: string;
36
+ version: number;
37
+ pageId: string;
38
+ leadgenId: string;
39
+ }
40
+ /**
41
+ * Checks a forwarding token: RS256 under one of the issuer's keys, the
42
+ * issuer and audience the host trusts, alive and short-lived, for the
43
+ * leadgen purpose, and bound to exactly this Page and leadgen id. Throws a
44
+ * `LeadgenTokenError` (no secret in its reason) when anything is off.
45
+ */
46
+ export declare function verifyLeadgenToken(token: string, expected: {
47
+ issuer: string;
48
+ audience: string;
49
+ pageId: string;
50
+ leadgenId: string;
51
+ }, options?: {
52
+ now?: number;
53
+ fetch?: Fetch;
54
+ }): Promise<LeadgenTokenClaims>;
55
+ export {};
56
+ //# sourceMappingURL=leadgenToken.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"leadgenToken.d.ts","sourceRoot":"","sources":["../../src/component/leadgenToken.ts"],"names":[],"mappings":"AAyBA,qBAAa,iBAAkB,SAAQ,KAAK;IAQxC,QAAQ,CAAC,MAAM,EAAE,MAAM;IACvB,QAAQ,CAAC,SAAS;IARpB;;;;;OAKG;IACH,YACW,MAAM,EAAE,MAAM,EACd,SAAS,UAAQ,EAI3B;CACF;AAGD,KAAK,KAAK,GAAG,OAAO,KAAK,CAAC;AAoC1B;;;;GAIG;AACH,eAAO,MAAM,yBAAyB,gDACS,CAAC;AAEhD;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,GAAG,EAAE;IAChC,wBAAwB,CAAC,EAAE,MAAM,CAAC;IAClC,0BAA0B,CAAC,EAAE,MAAM,CAAC;CACrC,GAAG;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE,CAO9C;AAsFD,yCAAyC;AACzC,wBAAgB,oBAAoB,IAAI,IAAI,CAE3C;AAED,MAAM,WAAW,kBAAkB;IACjC,YAAY,EAAE,MAAM,CAAC;IACrB,cAAc,EAAE,MAAM,CAAC;IACvB,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;CACnB;AAED;;;;;GAKG;AACH,wBAAsB,kBAAkB,CACtC,KAAK,EAAE,MAAM,EACb,QAAQ,EAAE;IACR,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;CACnB,EACD,OAAO,GAAE;IAAE,GAAG,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,KAAK,CAAA;CAAO,GAC5C,OAAO,CAAC,kBAAkB,CAAC,CAoI7B"}
@@ -0,0 +1,262 @@
1
+ /*
2
+ * The control plane's word that Meta announced a lead: a short-lived RS256
3
+ * JWT signed with the federation issuer's key (the one the host already
4
+ * trusts for its dashboard connections), audience = the host's federation
5
+ * audience, bound to one Page and one leadgen id. A component has no
6
+ * `ctx.auth`, so the HTTP route checks it here against the issuer's published
7
+ * keys (`<issuer>/.well-known/openid-configuration` → `jwks_uri`). The token
8
+ * only says "go read this lead from Meta": the lead itself is always read
9
+ * from Meta with the Page's own token, so a replay at most repeats an
10
+ * idempotent read.
11
+ */
12
+ import { META_LEADGEN_TOKEN } from "./constants.js";
13
+ // The claim names, purpose, subject and lifetime come from
14
+ // `META_LEADGEN_TOKEN` (constants.ts, contract §12.3): the control plane signs
15
+ // with the same object.
16
+ const CLAIMS = META_LEADGEN_TOKEN.claims;
17
+ const CLOCK_SKEW_SECONDS = 60;
18
+ const JWKS_TTL_MS = 5 * 60_000;
19
+ const JWKS_REFRESH_MIN_MS = 60_000;
20
+ const MAX_TOKEN = 8_192;
21
+ const GRAPH_ID = /^\d{1,32}$/u;
22
+ export class LeadgenTokenError extends Error {
23
+ reason;
24
+ transient;
25
+ /**
26
+ * `transient`: the token could not be checked because the issuer's keys
27
+ * could not be read right now (unreachable, 5xx, 429, not JSON). The route
28
+ * answers 503 then, which the control plane retries; any other refusal is a
29
+ * 401, which it does not.
30
+ */
31
+ constructor(reason, transient = false) {
32
+ super(reason);
33
+ this.reason = reason;
34
+ this.transient = transient;
35
+ this.name = "LeadgenTokenError";
36
+ }
37
+ }
38
+ const jwksCache = new Map();
39
+ function base64UrlBytes(value) {
40
+ if (!/^[A-Za-z0-9_-]*$/u.test(value)) {
41
+ throw new LeadgenTokenError("token is not base64url");
42
+ }
43
+ const padded = value.replace(/-/g, "+").replace(/_/g, "/");
44
+ const binary = atob(padded + "=".repeat((4 - (padded.length % 4)) % 4));
45
+ const bytes = new Uint8Array(binary.length);
46
+ for (let index = 0; index < binary.length; index += 1) {
47
+ bytes[index] = binary.charCodeAt(index);
48
+ }
49
+ return bytes;
50
+ }
51
+ function jsonPart(value) {
52
+ let parsed;
53
+ try {
54
+ parsed = JSON.parse(new TextDecoder().decode(base64UrlBytes(value)));
55
+ }
56
+ catch (error) {
57
+ if (error instanceof LeadgenTokenError)
58
+ throw error;
59
+ throw new LeadgenTokenError("token part is not JSON");
60
+ }
61
+ if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
62
+ throw new LeadgenTokenError("token part is not an object");
63
+ }
64
+ return parsed;
65
+ }
66
+ const trimSlash = (value) => value.replace(/\/+$/u, "");
67
+ /**
68
+ * The production dashboard's federation issuer: what the leadgen route trusts
69
+ * when the host passes no `RASTRO_FEDERATION_ISSUER`, as a host's federation
70
+ * API does. The audience has no default: it is the host's own functions URL.
71
+ */
72
+ export const DEFAULT_FEDERATION_ISSUER = "https://site.api.amagerastro.com/federation";
73
+ /**
74
+ * The issuer and audience the leadgen route checks forwards against, from the
75
+ * component's env. `audience` null means the route refuses every forward
76
+ * (`FEDERATION_NOT_CONFIGURED`), so a Page must not be linked or routed here.
77
+ */
78
+ export function leadgenTrust(env) {
79
+ return {
80
+ issuer: trimSlash(env.RASTRO_FEDERATION_ISSUER?.trim() ?? "") ||
81
+ DEFAULT_FEDERATION_ISSUER,
82
+ audience: trimSlash(env.RASTRO_FEDERATION_AUDIENCE?.trim() ?? "") || null,
83
+ };
84
+ }
85
+ function sameOriginHttps(base, target) {
86
+ try {
87
+ const from = new URL(base);
88
+ const to = new URL(target);
89
+ const local = to.hostname === "localhost" || to.hostname === "127.0.0.1";
90
+ return (from.origin === to.origin &&
91
+ (to.protocol === "https:" || (to.protocol === "http:" && local)));
92
+ }
93
+ catch {
94
+ return false;
95
+ }
96
+ }
97
+ async function fetchJson(fetchImpl, target) {
98
+ let response;
99
+ try {
100
+ response = await fetchImpl(target, {
101
+ headers: { Accept: "application/json" },
102
+ });
103
+ }
104
+ catch {
105
+ throw new LeadgenTokenError("the issuer is unreachable", true);
106
+ }
107
+ if (!response.ok) {
108
+ throw new LeadgenTokenError(`the issuer answered ${response.status}`, response.status >= 500 || response.status === 429);
109
+ }
110
+ try {
111
+ return await response.json();
112
+ }
113
+ catch {
114
+ throw new LeadgenTokenError("the issuer answered something else than JSON", true);
115
+ }
116
+ }
117
+ /**
118
+ * The issuer's signing keys, cached for five minutes; `fetched` says whether
119
+ * they were read from the issuer just now (a forced refresh within a minute
120
+ * of the last read answers from the cache).
121
+ */
122
+ async function issuerKeys(issuer, fetchImpl, now, refresh) {
123
+ const cached = jwksCache.get(issuer);
124
+ if (cached &&
125
+ now - cached.fetchedAt < JWKS_TTL_MS &&
126
+ !(refresh && now - cached.refreshedAt >= JWKS_REFRESH_MIN_MS)) {
127
+ return { keys: cached.keys, fetched: false };
128
+ }
129
+ const discovery = await fetchJson(fetchImpl, `${issuer}/.well-known/openid-configuration`);
130
+ const jwksUri = discovery &&
131
+ typeof discovery === "object" &&
132
+ typeof discovery.jwks_uri === "string"
133
+ ? discovery.jwks_uri
134
+ : `${issuer}/jwks.json`;
135
+ if (!sameOriginHttps(issuer, jwksUri)) {
136
+ throw new LeadgenTokenError("the issuer's jwks_uri is not its own");
137
+ }
138
+ const jwks = await fetchJson(fetchImpl, jwksUri);
139
+ const keys = jwks &&
140
+ typeof jwks === "object" &&
141
+ Array.isArray(jwks.keys)
142
+ ? jwks.keys.filter((key) => key && typeof key === "object")
143
+ : [];
144
+ jwksCache.set(issuer, { keys, fetchedAt: now, refreshedAt: now });
145
+ return { keys, fetched: true };
146
+ }
147
+ /** For tests: forget the cached keys. */
148
+ export function clearLeadgenKeyCache() {
149
+ jwksCache.clear();
150
+ }
151
+ /**
152
+ * Checks a forwarding token: RS256 under one of the issuer's keys, the
153
+ * issuer and audience the host trusts, alive and short-lived, for the
154
+ * leadgen purpose, and bound to exactly this Page and leadgen id. Throws a
155
+ * `LeadgenTokenError` (no secret in its reason) when anything is off.
156
+ */
157
+ export async function verifyLeadgenToken(token, expected, options = {}) {
158
+ const now = options.now ?? Date.now();
159
+ const fetchImpl = options.fetch ?? ((...args) => fetch(...args));
160
+ const issuer = trimSlash(expected.issuer.trim());
161
+ const audience = trimSlash(expected.audience.trim());
162
+ if (!issuer || !audience) {
163
+ throw new LeadgenTokenError("the host has no federation issuer");
164
+ }
165
+ if (token.length > MAX_TOKEN)
166
+ throw new LeadgenTokenError("token too long");
167
+ const parts = token.split(".");
168
+ if (parts.length !== 3)
169
+ throw new LeadgenTokenError("token is not a JWT");
170
+ const [headerPart, payloadPart, signaturePart] = parts;
171
+ const header = jsonPart(headerPart);
172
+ if (header.alg !== "RS256") {
173
+ throw new LeadgenTokenError("token is not RS256");
174
+ }
175
+ const claims = jsonPart(payloadPart);
176
+ // The cheap checks first: a token for something else costs no key fetch.
177
+ const seconds = Math.floor(now / 1000);
178
+ const aud = claims.aud;
179
+ const audiences = (Array.isArray(aud) ? aud : [aud]).map((value) => typeof value === "string" ? trimSlash(value) : "");
180
+ const exp = claims.exp;
181
+ const iat = claims.iat;
182
+ if (typeof claims.iss !== "string" || trimSlash(claims.iss) !== issuer) {
183
+ throw new LeadgenTokenError("token issuer is not trusted");
184
+ }
185
+ if (!audiences.includes(audience)) {
186
+ throw new LeadgenTokenError("token audience is not this host");
187
+ }
188
+ if (typeof exp !== "number" || exp + CLOCK_SKEW_SECONDS < seconds) {
189
+ throw new LeadgenTokenError("token expired");
190
+ }
191
+ if (typeof iat !== "number" ||
192
+ iat - CLOCK_SKEW_SECONDS > seconds ||
193
+ exp - iat > META_LEADGEN_TOKEN.maxLifetimeSeconds) {
194
+ throw new LeadgenTokenError("token lifetime is not a forwarding one");
195
+ }
196
+ if (claims[CLAIMS.purpose] !== META_LEADGEN_TOKEN.purpose ||
197
+ claims.sub !== META_LEADGEN_TOKEN.subject) {
198
+ throw new LeadgenTokenError("token is not for a leadgen");
199
+ }
200
+ const organizationId = claims[CLAIMS.organizationId];
201
+ const version = claims[CLAIMS.version];
202
+ if (typeof organizationId !== "string" ||
203
+ organizationId.length === 0 ||
204
+ organizationId.length > 128 ||
205
+ typeof version !== "number" ||
206
+ !Number.isSafeInteger(version) ||
207
+ version < 0) {
208
+ throw new LeadgenTokenError("token names no organization");
209
+ }
210
+ const connectionId = claims[CLAIMS.connectionId];
211
+ if (typeof connectionId !== "string" ||
212
+ connectionId.length === 0 ||
213
+ connectionId.length > 128) {
214
+ throw new LeadgenTokenError("token names no connection");
215
+ }
216
+ if (claims[CLAIMS.pageId] !== expected.pageId ||
217
+ claims[CLAIMS.leadgenId] !== expected.leadgenId ||
218
+ !GRAPH_ID.test(expected.pageId) ||
219
+ !GRAPH_ID.test(expected.leadgenId)) {
220
+ throw new LeadgenTokenError("token is for another lead");
221
+ }
222
+ const kid = typeof header.kid === "string" ? header.kid : null;
223
+ const pick = (keys) => keys.filter((key) => key.kty === "RSA" &&
224
+ typeof key.n === "string" &&
225
+ typeof key.e === "string" &&
226
+ (kid === null || key.kid === undefined || key.kid === kid));
227
+ let candidates = pick((await issuerKeys(issuer, fetchImpl, now, false)).keys);
228
+ if (candidates.length === 0) {
229
+ // A rotated key: read the issuer again (at most once a minute).
230
+ const again = await issuerKeys(issuer, fetchImpl, now, true);
231
+ candidates = pick(again.keys);
232
+ if (candidates.length === 0) {
233
+ // Keys read a moment ago may predate the rotation: transient (503,
234
+ // retried) until the issuer has been read again.
235
+ throw new LeadgenTokenError(again.fetched
236
+ ? "no issuer key matches the token"
237
+ : "no issuer key matches the token yet", !again.fetched);
238
+ }
239
+ }
240
+ const data = new TextEncoder().encode(`${headerPart}.${payloadPart}`);
241
+ const signature = base64UrlBytes(signaturePart);
242
+ for (const jwk of candidates) {
243
+ let key;
244
+ try {
245
+ key = await crypto.subtle.importKey("jwk", { kty: "RSA", n: jwk.n, e: jwk.e, ext: true }, { name: "RSASSA-PKCS1-v1_5", hash: "SHA-256" }, false, ["verify"]);
246
+ }
247
+ catch {
248
+ continue;
249
+ }
250
+ if (await crypto.subtle.verify("RSASSA-PKCS1-v1_5", key, signature, data)) {
251
+ return {
252
+ connectionId,
253
+ organizationId,
254
+ version,
255
+ pageId: expected.pageId,
256
+ leadgenId: expected.leadgenId,
257
+ };
258
+ }
259
+ }
260
+ throw new LeadgenTokenError("token signature is invalid");
261
+ }
262
+ //# sourceMappingURL=leadgenToken.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"leadgenToken.js","sourceRoot":"","sources":["../../src/component/leadgenToken.ts"],"names":[],"mappings":"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"}
@@ -1,8 +1,19 @@
1
- import type { Id } from "./_generated/dataModel.js";
1
+ import { type Infer } from "convex/values";
2
+ import type { Doc, Id } from "./_generated/dataModel.js";
3
+ import { type MutationCtx } from "./_generated/server.js";
4
+ import { leadAdValidator } from "./validators.js";
2
5
  /** Every lead from any ad falls in this origin bucket, whatever its entry point. */
3
6
  export declare const AD_ORIGIN = "ctwa_ad";
4
7
  /** The bucket for a lead the channel gave no entry point for. */
5
8
  export declare const NO_ORIGIN = "none";
9
+ /**
10
+ * A Meta instant form's leads (since 0.11.0): `lead_form` when an ad brought
11
+ * them, so they count as paid next to `ctwa_ad`; `lead_form_organic` when the
12
+ * form was filled without an ad.
13
+ */
14
+ export declare const LEAD_FORM_ORIGIN = "lead_form";
15
+ export declare const LEAD_FORM_ORGANIC_ORIGIN = "lead_form_organic";
16
+ type LeadAd = Infer<typeof leadAdValidator>;
6
17
  type Counters = {
7
18
  leads: number;
8
19
  qualified: number;
@@ -22,7 +33,7 @@ export declare const record: import("convex/server").RegisteredMutation<"public"
22
33
  sourceUrl?: string | undefined;
23
34
  title?: string | undefined;
24
35
  } | undefined;
25
- channel: "whatsapp";
36
+ channel: "form" | "whatsapp";
26
37
  column?: string | undefined;
27
38
  entryPoint?: string | undefined;
28
39
  label?: string | undefined;
@@ -32,9 +43,32 @@ export declare const record: import("convex/server").RegisteredMutation<"public"
32
43
  siteId: import("convex/values").GenericId<"sites">;
33
44
  visitorId?: string | undefined;
34
45
  }, Promise<{
35
- leadId: import("convex/values").GenericId<"leads">;
46
+ leadId: Id<"leads">;
36
47
  created: boolean;
37
48
  }>>;
49
+ /**
50
+ * `record`'s body, shared with the Lead Ads ingestion (metaLeads.ts), which
51
+ * also files the lead under its instant form (`form`).
52
+ */
53
+ export declare function recordLeadCore(ctx: MutationCtx, args: {
54
+ siteId: Id<"sites">;
55
+ leadKey: string;
56
+ channel: Doc<"leads">["channel"];
57
+ entryPoint?: string | undefined;
58
+ ad?: LeadAd | undefined;
59
+ label?: string | undefined;
60
+ visitorId?: string | undefined;
61
+ column?: string | undefined;
62
+ occurredAt: number;
63
+ meta?: unknown;
64
+ form?: {
65
+ formId: string;
66
+ pageId: string;
67
+ } | undefined;
68
+ }): Promise<{
69
+ leadId: Id<"leads">;
70
+ created: boolean;
71
+ }>;
38
72
  /**
39
73
  * Moves a lead through the host's pipeline, idempotent by `eventId`. A lead the
40
74
  * host never recorded (a conversation older than the integration) is not
@@ -171,8 +205,9 @@ export declare const report: import("convex/server").RegisteredQuery<"public", {
171
205
  /**
172
206
  * The lead funnel per cohort day, for sparklines and the sales × spend chart:
173
207
  * every UTC day in the range, empty days included. With `adId`, only that
174
- * ad's leads; with `origin`, only that origin's (`ctwa_ad` for the leads the
175
- * ads bought). Spend is the day's Meta spend for the same scope, null where
208
+ * ad's leads; with `origin`, only that origin's (`ctwa_ad` for the
209
+ * click-to-WhatsApp ads, `paid` for every lead an ad bought: `ctwa_ad` and
210
+ * `lead_form`). Spend is the day's Meta spend for the same scope, null where
176
211
  * no synced ad account covers it, for an organic origin, or when the sites'
177
212
  * accounts bill in more than one currency.
178
213
  */
@@ -203,7 +238,7 @@ export declare const list: import("convex/server").RegisteredQuery<"public", {
203
238
  to: number;
204
239
  }, Promise<{
205
240
  adId: string | null;
206
- channel: "whatsapp";
241
+ channel: "form" | "whatsapp";
207
242
  entryPoint: string | null;
208
243
  firstAt: number;
209
244
  hasVisitor: boolean;
@@ -223,7 +258,7 @@ export declare const journey: import("convex/server").RegisteredQuery<"public",
223
258
  }, Promise<{
224
259
  lead: {
225
260
  adId: string | null;
226
- channel: "whatsapp";
261
+ channel: "form" | "whatsapp";
227
262
  entryPoint: string | null;
228
263
  firstAt: number;
229
264
  hasVisitor: boolean;
@@ -246,6 +281,40 @@ export declare const journey: import("convex/server").RegisteredQuery<"public",
246
281
  title: string | null;
247
282
  } | null;
248
283
  visitorId: string | null;
284
+ form?: {
285
+ answers: {
286
+ label: string;
287
+ questionKey: string;
288
+ values: string[];
289
+ }[];
290
+ decision: {
291
+ column: string | null;
292
+ } | {
293
+ discard: string;
294
+ };
295
+ leadgenId: string;
296
+ origin: {
297
+ adId: string | null;
298
+ adName: string | null;
299
+ adsetId: string | null;
300
+ adsetName: string | null;
301
+ campaignId: string | null;
302
+ campaignName: string | null;
303
+ formId: string;
304
+ formName: string | null;
305
+ isOrganic: boolean;
306
+ pageId: string;
307
+ pageName: string | null;
308
+ platform: string | null;
309
+ };
310
+ receivedAt: number;
311
+ returned: {
312
+ at: number;
313
+ reason: string;
314
+ } | null;
315
+ ruleIndex: number | null;
316
+ rulePath: number[];
317
+ } | null | undefined;
249
318
  events: {
250
319
  type: "created" | "lost" | "open" | "qualified" | "won";
251
320
  at: number;
@@ -1 +1 @@
1
- {"version":3,"file":"leads.d.ts","sourceRoot":"","sources":["../../src/component/leads.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAO,EAAE,EAAE,MAAM,2BAA2B,CAAC;AAoEzD,oFAAoF;AACpF,eAAO,MAAM,SAAS,YAAY,CAAC;AACnC,iEAAiE;AACjE,eAAO,MAAM,SAAS,SAAS,CAAC;AAGhC,KAAK,QAAQ,GAAG;IACd,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;IAClB,GAAG,EAAE,MAAM,CAAC;IACZ,YAAY,EAAE,MAAM,CAAC;CACtB,CAAC;AAoIF;;;;GAIG;AACH,eAAO,MAAM,MAAM;;;;;;;;;;;;;;;;;;;;GAoGjB,CAAC;AAEH;;;;;;GAMG;AACH,eAAO,MAAM,QAAQ;;;;;;;;;;;GAuInB,CAAC;AAEH;;;GAGG;AACH,eAAO,MAAM,MAAM;;;;;GA0BjB,CAAC;AAEH;;;GAGG;AACH,eAAO,MAAM,eAAe;;;;;;;;;;;;;GAgE1B,CAAC;AAgNH;;;GAGG;AACH,eAAO,MAAM,MAAM;;;;;;;;;eA3rBV,MAAM;mBACF,MAAM;aACZ,MAAM;sBACG,MAAM;;;;;;eAHb,MAAM;mBACF,MAAM;aACZ,MAAM;sBACG,MAAM;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;eAHb,MAAM;mBACF,MAAM;aACZ,MAAM;sBACG,MAAM;;;;;;;;;;GAs+BpB,CAAC;AAEH;;;;;;;GAOG;AACH,eAAO,MAAM,KAAK;;;;;;;WAn/BT,MAAM;eACF,MAAM;SACZ,MAAM;kBACG,MAAM;;;KA+lCpB,CAAC;AAsBH;;;GAGG;AACH,eAAO,MAAM,IAAI;;;;;;;;;;;;;;;;;;;;;KAsDf,CAAC;AAEH,+CAA+C;AAC/C,eAAO,MAAM,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;UAyClB,CAAC"}
1
+ {"version":3,"file":"leads.d.ts","sourceRoot":"","sources":["../../src/component/leads.ts"],"names":[],"mappings":"AAAA,OAAO,EAAK,KAAK,KAAK,EAAE,MAAM,eAAe,CAAC;AAC9C,OAAO,KAAK,EAAE,GAAG,EAAE,EAAE,EAAE,MAAM,2BAA2B,CAAC;AACzD,OAAO,EAGL,KAAK,WAAW,EAEjB,MAAM,wBAAwB,CAAC;AA8BhC,OAAO,EAEL,eAAe,EAShB,MAAM,iBAAiB,CAAC;AAuBzB,oFAAoF;AACpF,eAAO,MAAM,SAAS,YAAY,CAAC;AACnC,iEAAiE;AACjE,eAAO,MAAM,SAAS,SAAS,CAAC;AAChC;;;;GAIG;AACH,eAAO,MAAM,gBAAgB,cAAc,CAAC;AAC5C,eAAO,MAAM,wBAAwB,sBAAsB,CAAC;AAS5D,KAAK,MAAM,GAAG,KAAK,CAAC,OAAO,eAAe,CAAC,CAAC;AAC5C,KAAK,QAAQ,GAAG;IACd,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;IAClB,GAAG,EAAE,MAAM,CAAC;IACZ,YAAY,EAAE,MAAM,CAAC;CACtB,CAAC;AAwIF;;;;GAIG;AACH,eAAO,MAAM,MAAM;;;;;;;;;;;;;;;;;;YA2CE,EAAE,CAAC,OAAO,CAAC;aAAW,OAAO;GArBhD,CAAC;AAEH;;;GAGG;AACH,wBAAsB,cAAc,CAClC,GAAG,EAAE,WAAW,EAChB,IAAI,EAAE;IACJ,MAAM,EAAE,EAAE,CAAC,OAAO,CAAC,CAAC;IACpB,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,GAAG,CAAC,OAAO,CAAC,CAAC,SAAS,CAAC,CAAC;IACjC,UAAU,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAChC,EAAE,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACxB,KAAK,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC3B,SAAS,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC/B,MAAM,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC5B,UAAU,EAAE,MAAM,CAAC;IACnB,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,IAAI,CAAC,EAAE;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,GAAG,SAAS,CAAC;CACvD,GACA,OAAO,CAAC;IAAE,MAAM,EAAE,EAAE,CAAC,OAAO,CAAC,CAAC;IAAC,OAAO,EAAE,OAAO,CAAA;CAAE,CAAC,CA+EpD;AAED;;;;;;GAMG;AACH,eAAO,MAAM,QAAQ;;;;;;;;;;;GAuInB,CAAC;AAEH;;;GAGG;AACH,eAAO,MAAM,MAAM;;;;;GA2BjB,CAAC;AAEH;;;GAGG;AACH,eAAO,MAAM,eAAe;;;;;;;;;;;;;GAgE1B,CAAC;AAgNH;;;GAGG;AACH,eAAO,MAAM,MAAM;;;;;;;;;eAttBV,MAAM;mBACF,MAAM;aACZ,MAAM;sBACG,MAAM;;;;;;eAHb,MAAM;mBACF,MAAM;aACZ,MAAM;sBACG,MAAM;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;eAHb,MAAM;mBACF,MAAM;aACZ,MAAM;sBACG,MAAM;;;;;;;;;;GAigCpB,CAAC;AAEH;;;;;;;;GAQG;AACH,eAAO,MAAM,KAAK;;;;;;;WA/gCT,MAAM;eACF,MAAM;SACZ,MAAM;kBACG,MAAM;;;KAioCpB,CAAC;AAsBH;;;GAGG;AACH,eAAO,MAAM,IAAI;;;;;;;;;;;;;;;;;;;;;KAsDf,CAAC;AAEH,+CAA+C;AAC/C,eAAO,MAAM,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;UA2ClB,CAAC"}