@evinvest/kitstart 0.17.0 → 0.18.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 (87) hide show
  1. package/README.md +147 -10
  2. package/dist/core/accept.d.ts +14 -0
  3. package/dist/core/accept.js +21 -3
  4. package/dist/core/analytics.d.ts +11 -2
  5. package/dist/core/analytics.js +22 -0
  6. package/dist/core/channels.d.ts +12 -4
  7. package/dist/core/channels.js +11 -1
  8. package/dist/core/lead-capture-text.d.ts +6 -2
  9. package/dist/core/lead.d.ts +33 -10
  10. package/dist/core/lead.js +21 -8
  11. package/dist/core/messenger-message.d.ts +31 -0
  12. package/dist/core/messenger-message.js +33 -0
  13. package/dist/core/messenger-text.d.ts +104 -0
  14. package/dist/core/messenger-text.js +150 -0
  15. package/dist/core/messenger.d.ts +92 -0
  16. package/dist/core/messenger.js +55 -0
  17. package/dist/core/place/index.d.ts +1 -1
  18. package/dist/core/place/live.d.ts +5 -1
  19. package/dist/core/place/live.js +22 -1
  20. package/dist/core/place/types.d.ts +17 -1
  21. package/dist/core/site.d.ts +8 -1
  22. package/dist/core/site.js +22 -1
  23. package/dist/index.d.ts +8 -5
  24. package/dist/index.js +7 -4
  25. package/dist/next/quote-route.js +4 -7
  26. package/dist/react/AnalyticsBoundary.js +3 -3
  27. package/dist/react/LeadCapture.d.ts +24 -1
  28. package/dist/react/LeadCapture.js +96 -11
  29. package/dist/react/LeadCaptureChannels.d.ts +7 -2
  30. package/dist/react/LeadCaptureChannels.js +2 -2
  31. package/dist/react/LeadCaptureEstimate.d.ts +6 -0
  32. package/dist/react/LeadCaptureFields.d.ts +17 -0
  33. package/dist/react/LeadCaptureFields.js +42 -33
  34. package/dist/react/LeadCaptureMessenger.d.ts +41 -0
  35. package/dist/react/LeadCaptureMessenger.js +133 -0
  36. package/dist/react/LeadCapturePrice.d.ts +9 -3
  37. package/dist/react/LeadCapturePrice.js +24 -4
  38. package/dist/react/LeadCaptureSubmit.d.ts +3 -0
  39. package/dist/react/LeadCaptureSubmit.js +2 -2
  40. package/dist/react/LeadCaptureTiles.js +9 -4
  41. package/dist/react/analytics-context.d.ts +9 -3
  42. package/dist/react/analytics-context.js +7 -3
  43. package/dist/react/index.d.ts +1 -0
  44. package/dist/react/messenger/action.d.ts +144 -0
  45. package/dist/react/messenger/action.js +301 -0
  46. package/dist/react/messenger/chip.d.ts +8 -0
  47. package/dist/react/messenger/chip.js +22 -0
  48. package/dist/react/messenger/fallback.d.ts +8 -0
  49. package/dist/react/messenger/fallback.js +11 -0
  50. package/dist/react/messenger/saga.d.ts +10 -0
  51. package/dist/react/messenger/saga.js +33 -0
  52. package/dist/react/messenger/segment.d.ts +8 -0
  53. package/dist/react/messenger/segment.js +15 -0
  54. package/dist/react/messenger/select.d.ts +10 -0
  55. package/dist/react/messenger/select.js +26 -0
  56. package/dist/react/messenger/sheet.d.ts +10 -0
  57. package/dist/react/messenger/sheet.js +57 -0
  58. package/dist/react/messenger/split.d.ts +9 -0
  59. package/dist/react/messenger/split.js +17 -0
  60. package/dist/react/messenger/swap.d.ts +10 -0
  61. package/dist/react/messenger/swap.js +18 -0
  62. package/dist/react/messenger/thanks.d.ts +10 -0
  63. package/dist/react/messenger/thanks.js +18 -0
  64. package/dist/react/messenger/tiles.d.ts +8 -0
  65. package/dist/react/messenger/tiles.js +20 -0
  66. package/dist/react/messenger/types.d.ts +98 -0
  67. package/dist/react/messenger/types.js +1 -0
  68. package/dist/react/messenger/urgency.d.ts +10 -0
  69. package/dist/react/messenger/urgency.js +29 -0
  70. package/dist/react/use-lead-error.d.ts +3 -3
  71. package/dist/react/use-lead-events.d.ts +21 -1
  72. package/dist/react/use-lead-events.js +9 -3
  73. package/dist/react/use-lead-submit.d.ts +20 -6
  74. package/dist/react/use-lead-submit.js +23 -1
  75. package/dist/server/index.d.ts +1 -1
  76. package/dist/server/lead-store-sqlite.js +11 -5
  77. package/dist/server/lead-webhook.d.ts +30 -5
  78. package/dist/server/lead-webhook.js +13 -7
  79. package/dist/server/notify.js +11 -5
  80. package/dist/testing/index.d.ts +1 -1
  81. package/dist/testing/index.js +1 -1
  82. package/dist/testing/landing-contract.js +6 -1
  83. package/dist/testing/lead-rules.d.ts +8 -0
  84. package/dist/testing/lead-rules.js +30 -1
  85. package/package.json +5 -2
  86. package/template/flake.nix +1 -1
  87. package/template/package.json +2 -2
@@ -2,7 +2,7 @@ import { describe, expect, it } from "vitest";
2
2
  import { isPublished, publicationGaps } from "../core/place/publication.js";
3
3
  import { createRouting, NON_PAGE_ROUTES, pointSuffixes, THANKS } from "../core/routing.js";
4
4
  import { openLaunchBlockers } from "../core/site.js";
5
- import { leadRuleDisagreements } from "./lead-rules.js";
5
+ import { leadRuleDisagreements, messengerRuleDisagreements } from "./lead-rules.js";
6
6
  import { servedPaths } from "./served-files.js";
7
7
  const SOURCE_LINE = /@source\s+["'][^"']*node_modules\/@evinvest\/kitstart\/dist["']/;
8
8
  const MATCHER = "/((?!_next/).*)";
@@ -48,6 +48,11 @@ export function describeLandingContract(site, options = {}) {
48
48
  it("refuses exactly the phone numbers the form blocks", () => {
49
49
  expect(leadRuleDisagreements(site.lead)).toEqual([]);
50
50
  });
51
+ // A messenger lead is posted as the visitor leaves for the chat: the
52
+ // message carries the rest, and a refusal would be shown to no one.
53
+ it("takes a messenger lead without a postcode or a phone", () => {
54
+ expect(messengerRuleDisagreements(site.lead)).toEqual([]);
55
+ });
51
56
  it("publishes nothing without a domain", () => {
52
57
  if (site.brand.domain !== null)
53
58
  return;
@@ -16,3 +16,11 @@ export declare const PHONE_MATRIX: readonly {
16
16
  * a postcode — so only the phone is judged. Empty is agreement.
17
17
  */
18
18
  export declare function leadRuleDisagreements(schema: LeadSchema<string>): string[];
19
+ /**
20
+ * Where a brand's form rule refuses a messenger lead it must take: one with
21
+ * the subject chosen and nothing else — no postcode, no phone — since the
22
+ * chat carries the rest and is how the business answers. And where it takes
23
+ * a typed number the form would block: a phone given to a messenger lead is
24
+ * still one the operator may call. Empty is agreement.
25
+ */
26
+ export declare function messengerRuleDisagreements(schema: LeadSchema<string>): string[];
@@ -1,4 +1,4 @@
1
- import { readCandidate, validateCandidate } from "../core/lead.js";
1
+ import { CHANNEL_FIELD, readCandidate, validateCandidate } from "../core/lead.js";
2
2
  import { phoneProblem } from "../core/phone.js";
3
3
  /**
4
4
  * Numbers people type, and whether each is a way to reach them — the
@@ -62,3 +62,32 @@ export function leadRuleDisagreements(schema) {
62
62
  }
63
63
  return out;
64
64
  }
65
+ /**
66
+ * Where a brand's form rule refuses a messenger lead it must take: one with
67
+ * the subject chosen and nothing else — no postcode, no phone — since the
68
+ * chat carries the rest and is how the business answers. And where it takes
69
+ * a typed number the form would block: a phone given to a messenger lead is
70
+ * still one the operator may call. Empty is agreement.
71
+ */
72
+ export function messengerRuleDisagreements(schema) {
73
+ const out = [];
74
+ for (const channel of ["whatsapp", "telegram"]) {
75
+ const bare = new FormData();
76
+ bare.set(schema.wire.subject, schema.subjects[0] ?? "");
77
+ bare.set(CHANNEL_FIELD, channel);
78
+ const refused = validateCandidate(schema, readCandidate(schema, bare, null));
79
+ if (refused)
80
+ out.push(`${channel}: a lead with no postcode and no phone is refused at ${refused.field} (${refused.why})`);
81
+ for (const { mobile } of PHONE_MATRIX) {
82
+ const form = new FormData();
83
+ form.set(schema.wire.subject, schema.subjects[0] ?? "");
84
+ form.set(CHANNEL_FIELD, channel);
85
+ form.set(schema.wire.mobile, mobile);
86
+ const blocked = phoneProblem(mobile) !== null;
87
+ const refused = validateCandidate(schema, readCandidate(schema, form, null)) !== null;
88
+ if (blocked !== refused)
89
+ out.push(`${channel} ${mobile}: the form ${blocked ? "blocks" : "takes"} it, the server ${refused ? "refuses" : "takes"} it`);
90
+ }
91
+ }
92
+ return out;
93
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@evinvest/kitstart",
3
- "version": "0.17.0",
3
+ "version": "0.18.0",
4
4
  "description": "Landing-site machinery for local-service brands: a site composition root, the Place/Presence/ServiceArea model with a publication gate, host/locale routing, schema.org and SEO builders, the lead funnel with its antispam, and analytics events. Pure core at '.', more subpaths per runtime.",
5
5
  "license": "BlueOak-1.0.0",
6
6
  "publishConfig": {
@@ -126,5 +126,8 @@
126
126
  "template/proxy.ts",
127
127
  "template/app/[locale]/[location]/layout.tsx",
128
128
  "dist/cli/kitstart-size.js"
129
- ]
129
+ ],
130
+ "dependencies": {
131
+ "qrcode-generator": "^2.0.4"
132
+ }
130
133
  }
@@ -3,7 +3,7 @@
3
3
  v_flakes.url = "github:valeratrades/v_flakes?ref=v1.6";
4
4
  # The lib flake at the tag of the @evinvest/kitstart version in
5
5
  # package-lock.json — mkLanding refuses a mismatch.
6
- ev.url = "github:EV-invest/lib?ref=@evinvest/kitstart-v0.17.0";
6
+ ev.url = "github:EV-invest/lib?ref=@evinvest/kitstart-v0.18.0";
7
7
  ev.inputs.v_flakes.follows = "v_flakes";
8
8
  };
9
9
 
@@ -20,9 +20,9 @@
20
20
  "dependencies": {
21
21
  "@evinvest/analytics": "^0.4.0",
22
22
  "@evinvest/i18n": "^0.9.0",
23
- "@evinvest/kitstart": "^0.17.0",
23
+ "@evinvest/kitstart": "^0.18.0",
24
24
  "@evinvest/marketing": "^0.3.0",
25
- "@evinvest/uikit": "^0.26.0",
25
+ "@evinvest/uikit": "^0.27.0",
26
26
  "next": "16.3.6",
27
27
  "react": "19.3.0",
28
28
  "react-dom": "19.3.0",