keystone-design-bootstrap 1.0.87 → 1.0.88

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 (51) hide show
  1. package/dist/design_system/sections/index.d.ts +1 -2
  2. package/dist/index.d.ts +24 -5
  3. package/dist/lib/server-api.d.ts +1 -2
  4. package/dist/lib/server-api.js +1 -1
  5. package/dist/lib/server-api.js.map +1 -1
  6. package/dist/package-DeHKpQp7.d.ts +121 -0
  7. package/dist/types/index.d.ts +68 -6
  8. package/package.json +28 -28
  9. package/src/design_system/portal/PortalPage.tsx +2 -3
  10. package/src/lib/server-api.ts +1 -2
  11. package/dist/company-information-C1pP-SvU.d.ts +0 -50
  12. package/dist/config-C_XBZixg.d.ts +0 -21
  13. package/dist/consumer-BWjQawiO.d.ts +0 -48
  14. package/dist/design_system/portal/index.d.ts +0 -52
  15. package/dist/design_system/portal/index.js +0 -3113
  16. package/dist/design_system/portal/index.js.map +0 -1
  17. package/dist/lib/consumer-session.d.ts +0 -16
  18. package/dist/lib/consumer-session.js +0 -85
  19. package/dist/lib/consumer-session.js.map +0 -1
  20. package/dist/lib/cta-urls.d.ts +0 -34
  21. package/dist/lib/cta-urls.js +0 -33
  22. package/dist/lib/cta-urls.js.map +0 -1
  23. package/dist/next/contexts/form-definitions.d.ts +0 -17
  24. package/dist/next/contexts/form-definitions.js +0 -21
  25. package/dist/next/contexts/form-definitions.js.map +0 -1
  26. package/dist/next/gallery/design-gallery.d.ts +0 -103
  27. package/dist/next/gallery/design-gallery.js +0 -19301
  28. package/dist/next/gallery/design-gallery.js.map +0 -1
  29. package/dist/next/layouts/root-layout.d.ts +0 -55
  30. package/dist/next/layouts/root-layout.js +0 -19713
  31. package/dist/next/layouts/root-layout.js.map +0 -1
  32. package/dist/next/legal/privacy-policy.d.ts +0 -7
  33. package/dist/next/legal/privacy-policy.js +0 -18949
  34. package/dist/next/legal/privacy-policy.js.map +0 -1
  35. package/dist/next/legal/terms-of-service.d.ts +0 -7
  36. package/dist/next/legal/terms-of-service.js +0 -18949
  37. package/dist/next/legal/terms-of-service.js.map +0 -1
  38. package/dist/next/providers/ssr-provider.d.ts +0 -12
  39. package/dist/next/providers/ssr-provider.js +0 -12
  40. package/dist/next/providers/ssr-provider.js.map +0 -1
  41. package/dist/next/routes/chat.d.ts +0 -26
  42. package/dist/next/routes/chat.js +0 -160
  43. package/dist/next/routes/chat.js.map +0 -1
  44. package/dist/next/routes/consumer-auth.d.ts +0 -33
  45. package/dist/next/routes/consumer-auth.js +0 -254
  46. package/dist/next/routes/consumer-auth.js.map +0 -1
  47. package/dist/next/routes/form.d.ts +0 -37
  48. package/dist/next/routes/form.js +0 -97
  49. package/dist/next/routes/form.js.map +0 -1
  50. package/dist/package-IU_GpDA0.d.ts +0 -74
  51. package/src/types/rails-actioncable.d.ts +0 -16
@@ -1,12 +0,0 @@
1
- import React__default from 'react';
2
-
3
- /**
4
- * React Aria relies on an SSR id provider for deterministic ids between
5
- * server-rendered HTML and client hydration. Without this, you can get
6
- * hydration mismatch warnings for `id`/`htmlFor` attributes.
7
- */
8
- declare function KeystoneSSRProvider(props: {
9
- children: React__default.ReactNode;
10
- }): React__default.JSX.Element;
11
-
12
- export { KeystoneSSRProvider };
@@ -1,12 +0,0 @@
1
- "use client";
2
-
3
- // src/next/providers/ssr-provider.tsx
4
- import React from "react";
5
- import { SSRProvider } from "react-aria";
6
- function KeystoneSSRProvider(props) {
7
- return /* @__PURE__ */ React.createElement(SSRProvider, null, props.children);
8
- }
9
- export {
10
- KeystoneSSRProvider
11
- };
12
- //# sourceMappingURL=ssr-provider.js.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../../../src/next/providers/ssr-provider.tsx"],"sourcesContent":["'use client';\n\nimport React from 'react';\nimport { SSRProvider } from 'react-aria';\n\n/**\n * React Aria relies on an SSR id provider for deterministic ids between\n * server-rendered HTML and client hydration. Without this, you can get\n * hydration mismatch warnings for `id`/`htmlFor` attributes.\n */\nexport function KeystoneSSRProvider(props: { children: React.ReactNode }) {\n return <SSRProvider>{props.children}</SSRProvider>;\n}\n\n"],"mappings":";;;AAEA,OAAO,WAAW;AAClB,SAAS,mBAAmB;AAOrB,SAAS,oBAAoB,OAAsC;AACxE,SAAO,oCAAC,mBAAa,MAAM,QAAS;AACtC;","names":[]}
@@ -1,26 +0,0 @@
1
- /**
2
- * Chat API proxy route handlers for Next.js App Router.
3
- *
4
- * Usage in a site/template:
5
- * // app/api/chat/route.ts
6
- * export { GET, POST } from 'keystone-design-bootstrap/next/routes/chat';
7
- *
8
- * Supports both anonymous (session-based) and authenticated (contact-driven) flows.
9
- * Both flows hit the same backend endpoint (`/public/messages`); the discriminator
10
- * is whether `identifier` (session string) or `contact_id` (integer) is supplied.
11
- *
12
- * Env (server-side only):
13
- * - API_URL (default: http://localhost:3000/api/v1)
14
- * - API_KEY
15
- */
16
- type JsonResponder = (body: unknown, init?: ResponseInit) => Response;
17
- declare function createChatRouteHandlers(deps?: {
18
- NextResponse?: {
19
- json: JsonResponder;
20
- };
21
- }): {
22
- POST: (request: Request) => Promise<Response>;
23
- GET: (request: Request) => Promise<Response>;
24
- };
25
-
26
- export { createChatRouteHandlers };
@@ -1,160 +0,0 @@
1
- var __defProp = Object.defineProperty;
2
- var __defProps = Object.defineProperties;
3
- var __getOwnPropDescs = Object.getOwnPropertyDescriptors;
4
- var __getOwnPropSymbols = Object.getOwnPropertySymbols;
5
- var __hasOwnProp = Object.prototype.hasOwnProperty;
6
- var __propIsEnum = Object.prototype.propertyIsEnumerable;
7
- var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
8
- var __spreadValues = (a, b) => {
9
- for (var prop in b || (b = {}))
10
- if (__hasOwnProp.call(b, prop))
11
- __defNormalProp(a, prop, b[prop]);
12
- if (__getOwnPropSymbols)
13
- for (var prop of __getOwnPropSymbols(b)) {
14
- if (__propIsEnum.call(b, prop))
15
- __defNormalProp(a, prop, b[prop]);
16
- }
17
- return a;
18
- };
19
- var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
20
-
21
- // src/next/routes/proxy-headers.ts
22
- function clientContextHeaders(request) {
23
- var _a, _b;
24
- const ip = request.headers.get("x-real-ip") || ((_b = (_a = request.headers.get("x-forwarded-for")) == null ? void 0 : _a.split(",")[0]) == null ? void 0 : _b.trim());
25
- const ua = request.headers.get("user-agent");
26
- const cookieHeader = request.headers.get("cookie") || "";
27
- const cookies = Object.fromEntries(
28
- cookieHeader.split(";").map((c) => {
29
- const [k, ...v] = c.trim().split("=");
30
- return [k, v.join("=")];
31
- })
32
- );
33
- const fbp = cookies["_fbp"];
34
- const fbc = cookies["_fbc"];
35
- const headers = {};
36
- if (ip) headers["X-Real-Client-IP"] = ip;
37
- if (ua) headers["X-Real-Client-UA"] = ua;
38
- if (fbp) headers["X-Meta-FBP"] = fbp;
39
- if (fbc) headers["X-Meta-FBC"] = fbc;
40
- return headers;
41
- }
42
-
43
- // src/next/routes/chat.ts
44
- var API_URL = process.env.API_URL || "http://localhost:3000/api/v1";
45
- var API_KEY = process.env.API_KEY || "";
46
- var CONSUMER_TOKEN_COOKIE = "ks_consumer_token";
47
- function cookieValue(cookieHeader, key) {
48
- var _a;
49
- if (!cookieHeader) return null;
50
- const token = (_a = cookieHeader.split(";").map((part) => part.trim()).find((part) => part.startsWith(`${key}=`))) == null ? void 0 : _a.split("=").slice(1).join("=");
51
- return token ? decodeURIComponent(token) : null;
52
- }
53
- function createChatRouteHandlers(deps) {
54
- var _a, _b;
55
- const json = (_b = (_a = deps == null ? void 0 : deps.NextResponse) == null ? void 0 : _a.json) != null ? _b : ((body, init) => Response.json(body, init));
56
- return {
57
- // POST /api/chat — send a message (session-based or contact-driven)
58
- POST: async (request) => {
59
- try {
60
- const body = await request.json();
61
- const { identifier, contact_id, body: messageBody, display_name, page_url } = body;
62
- if (!messageBody) {
63
- return json({ success: false, error: "Message body is required." }, { status: 400 });
64
- }
65
- if (!identifier && !contact_id) {
66
- return json(
67
- { success: false, error: "identifier or contact_id is required." },
68
- { status: 400 }
69
- );
70
- }
71
- const response = await fetch(`${API_URL}/public/messages`, {
72
- method: "POST",
73
- headers: __spreadValues({
74
- "Content-Type": "application/json",
75
- "X-API-Key": API_KEY
76
- }, clientContextHeaders(request)),
77
- body: JSON.stringify({ identifier, contact_id, body: messageBody, display_name, page_url })
78
- });
79
- const data = await response.json();
80
- if (!response.ok) {
81
- return json(
82
- { success: false, error: data.error || "Failed to send message. Please try again." },
83
- { status: response.status }
84
- );
85
- }
86
- const responseData = data.data || {};
87
- const cableUrl = API_URL.replace(/\/api\/v1\/?$/, "").replace(/^http/, "ws") + "/cable";
88
- return json({ success: true, data: __spreadProps(__spreadValues({}, responseData), { cable_url: cableUrl }) });
89
- } catch (error) {
90
- console.error("Chat message error:", error);
91
- return json({ success: false, error: "Network error. Please try again later." }, { status: 500 });
92
- }
93
- },
94
- // GET /api/chat?identifier=... or ?contact_id=... — load message history
95
- GET: async (request) => {
96
- try {
97
- const { searchParams } = new URL(request.url);
98
- const action = searchParams.get("action");
99
- const identifier = searchParams.get("identifier");
100
- const contactId = searchParams.get("contact_id");
101
- if (action === "realtime_token") {
102
- if (!identifier && !contactId) {
103
- return json({ success: false, error: "identifier or contact_id is required for realtime token." }, { status: 400 });
104
- }
105
- const response2 = contactId ? await (async () => {
106
- const consumerToken = cookieValue(request.headers.get("cookie"), CONSUMER_TOKEN_COOKIE);
107
- if (!consumerToken) {
108
- return new Response(JSON.stringify({ error: "Unauthorized" }), {
109
- status: 401,
110
- headers: { "Content-Type": "application/json" }
111
- });
112
- }
113
- return fetch(
114
- `${API_URL}/consumer/me/contacts/${encodeURIComponent(contactId)}/realtime_token`,
115
- {
116
- headers: __spreadValues({
117
- Authorization: `Bearer ${consumerToken}`
118
- }, API_KEY ? { "X-API-Key": API_KEY } : {})
119
- }
120
- );
121
- })() : await fetch(
122
- `${API_URL}/public/messages/realtime_token?identifier=${encodeURIComponent(identifier)}`,
123
- { headers: { "X-API-Key": API_KEY } }
124
- );
125
- const data2 = await response2.json();
126
- if (!response2.ok) {
127
- return json(
128
- { success: false, error: data2.error || "Failed to create realtime token." },
129
- { status: response2.status }
130
- );
131
- }
132
- const cableUrl = API_URL.replace(/\/api\/v1\/?$/, "").replace(/^http/, "ws") + "/cable";
133
- return json({ success: true, data: __spreadProps(__spreadValues({}, data2.data || {}), { cable_url: cableUrl }) });
134
- }
135
- if (!identifier && !contactId) {
136
- return json({ success: false, error: "identifier or contact_id is required." }, { status: 400 });
137
- }
138
- const query = contactId ? `contact_id=${encodeURIComponent(contactId)}` : `identifier=${encodeURIComponent(identifier)}`;
139
- const response = await fetch(`${API_URL}/public/messages?${query}`, {
140
- headers: { "X-API-Key": API_KEY }
141
- });
142
- const data = await response.json();
143
- if (!response.ok) {
144
- return json(
145
- { success: false, error: data.error || "Failed to load messages." },
146
- { status: response.status }
147
- );
148
- }
149
- return json({ success: true, data: data.data || [] });
150
- } catch (error) {
151
- console.error("Chat history error:", error);
152
- return json({ success: false, error: "Network error. Please try again later." }, { status: 500 });
153
- }
154
- }
155
- };
156
- }
157
- export {
158
- createChatRouteHandlers
159
- };
160
- //# sourceMappingURL=chat.js.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../../../src/next/routes/proxy-headers.ts","../../../src/next/routes/chat.ts"],"sourcesContent":["/**\n * Extracts the real client IP, user-agent, and Meta browser cookies (_fbp / _fbc)\n * from an incoming Next.js route request and returns them as headers to forward\n * to the upstream Rails API.\n *\n * Cloudflare and other load-balancers set x-real-ip (or x-forwarded-for) on\n * inbound requests before they reach the Next.js function. Without this, the\n * Rails API sees the Next.js server IP instead of the real browser IP, which\n * produces inaccurate server-side CAPI signals.\n *\n * _fbp (Meta Browser ID) and _fbc (Meta Click ID) are first-party cookies set by\n * the Meta Pixel. Forwarding them allows the API to store them on the Contact\n * record so they can be included in all subsequent CAPI events — even those fired\n * from background jobs that have no live HTTP request.\n *\n * Convention:\n * X-Real-Client-IP — real browser IP\n * X-Real-Client-UA — real browser user-agent\n * X-Meta-FBP — value of the _fbp cookie\n * X-Meta-FBC — value of the _fbc cookie (or built from fbclid param)\n */\nexport function clientContextHeaders(request: Request): Record<string, string> {\n const ip =\n request.headers.get('x-real-ip') ||\n request.headers.get('x-forwarded-for')?.split(',')[0]?.trim();\n const ua = request.headers.get('user-agent');\n\n const cookieHeader = request.headers.get('cookie') || '';\n const cookies = Object.fromEntries(\n cookieHeader.split(';').map((c) => {\n const [k, ...v] = c.trim().split('=');\n return [k, v.join('=')];\n })\n );\n const fbp = cookies['_fbp'];\n const fbc = cookies['_fbc'];\n\n const headers: Record<string, string> = {};\n if (ip) headers['X-Real-Client-IP'] = ip;\n if (ua) headers['X-Real-Client-UA'] = ua;\n if (fbp) headers['X-Meta-FBP'] = fbp;\n if (fbc) headers['X-Meta-FBC'] = fbc;\n return headers;\n}\n","/**\n * Chat API proxy route handlers for Next.js App Router.\n *\n * Usage in a site/template:\n * // app/api/chat/route.ts\n * export { GET, POST } from 'keystone-design-bootstrap/next/routes/chat';\n *\n * Supports both anonymous (session-based) and authenticated (contact-driven) flows.\n * Both flows hit the same backend endpoint (`/public/messages`); the discriminator\n * is whether `identifier` (session string) or `contact_id` (integer) is supplied.\n *\n * Env (server-side only):\n * - API_URL (default: http://localhost:3000/api/v1)\n * - API_KEY\n */\n\n// IMPORTANT:\n// Do NOT import NextRequest/NextResponse here.\n// When `keystone-design-bootstrap` is used as a local file dependency, it may have its own\n// `next` installation under its own `node_modules`, which causes type identity conflicts\n// for route handlers. Instead, export a factory so the consuming app can pass in its\n// own `NextResponse` (from its own `next/server`) while we keep the core logic shared.\n\nimport { clientContextHeaders } from './proxy-headers';\n\nconst API_URL = process.env.API_URL || 'http://localhost:3000/api/v1';\nconst API_KEY = process.env.API_KEY || '';\nconst CONSUMER_TOKEN_COOKIE = 'ks_consumer_token';\n\ntype JsonResponder = (body: unknown, init?: ResponseInit) => Response;\n\nfunction cookieValue(cookieHeader: string | null, key: string): string | null {\n if (!cookieHeader) return null;\n const token = cookieHeader\n .split(';')\n .map((part) => part.trim())\n .find((part) => part.startsWith(`${key}=`))\n ?.split('=')\n .slice(1)\n .join('=');\n return token ? decodeURIComponent(token) : null;\n}\n\nexport function createChatRouteHandlers(deps?: { NextResponse?: { json: JsonResponder } }) {\n const json: JsonResponder = deps?.NextResponse?.json ?? ((body, init) => Response.json(body, init));\n\n return {\n // POST /api/chat — send a message (session-based or contact-driven)\n POST: async (request: Request): Promise<Response> => {\n try {\n const body = await request.json();\n const { identifier, contact_id, body: messageBody, display_name, page_url } = body;\n\n if (!messageBody) {\n return json({ success: false, error: 'Message body is required.' }, { status: 400 });\n }\n if (!identifier && !contact_id) {\n return json(\n { success: false, error: 'identifier or contact_id is required.' },\n { status: 400 }\n );\n }\n\n const response = await fetch(`${API_URL}/public/messages`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'X-API-Key': API_KEY,\n ...clientContextHeaders(request),\n },\n body: JSON.stringify({ identifier, contact_id, body: messageBody, display_name, page_url }),\n });\n\n const data = await response.json();\n if (!response.ok) {\n return json(\n { success: false, error: data.error || 'Failed to send message. Please try again.' },\n { status: response.status }\n );\n }\n const responseData = data.data || {};\n const cableUrl = API_URL.replace(/\\/api\\/v1\\/?$/, '').replace(/^http/, 'ws') + '/cable';\n return json({ success: true, data: { ...responseData, cable_url: cableUrl } });\n } catch (error) {\n console.error('Chat message error:', error);\n return json({ success: false, error: 'Network error. Please try again later.' }, { status: 500 });\n }\n },\n\n // GET /api/chat?identifier=... or ?contact_id=... — load message history\n GET: async (request: Request): Promise<Response> => {\n try {\n const { searchParams } = new URL(request.url);\n const action = searchParams.get('action');\n const identifier = searchParams.get('identifier');\n const contactId = searchParams.get('contact_id');\n\n if (action === 'realtime_token') {\n if (!identifier && !contactId) {\n return json({ success: false, error: 'identifier or contact_id is required for realtime token.' }, { status: 400 });\n }\n\n const response = contactId\n ? await (async () => {\n const consumerToken = cookieValue(request.headers.get('cookie'), CONSUMER_TOKEN_COOKIE);\n if (!consumerToken) {\n return new Response(JSON.stringify({ error: 'Unauthorized' }), {\n status: 401,\n headers: { 'Content-Type': 'application/json' },\n });\n }\n return fetch(\n `${API_URL}/consumer/me/contacts/${encodeURIComponent(contactId)}/realtime_token`,\n {\n headers: {\n Authorization: `Bearer ${consumerToken}`,\n ...(API_KEY ? { 'X-API-Key': API_KEY } : {}),\n },\n }\n );\n })()\n : await fetch(\n `${API_URL}/public/messages/realtime_token?identifier=${encodeURIComponent(identifier!)}`,\n { headers: { 'X-API-Key': API_KEY } }\n );\n const data = await response.json();\n if (!response.ok) {\n return json(\n { success: false, error: data.error || 'Failed to create realtime token.' },\n { status: response.status }\n );\n }\n\n const cableUrl = API_URL.replace(/\\/api\\/v1\\/?$/, '').replace(/^http/, 'ws') + '/cable';\n return json({ success: true, data: { ...(data.data || {}), cable_url: cableUrl } });\n }\n\n if (!identifier && !contactId) {\n return json({ success: false, error: 'identifier or contact_id is required.' }, { status: 400 });\n }\n\n const query = contactId\n ? `contact_id=${encodeURIComponent(contactId)}`\n : `identifier=${encodeURIComponent(identifier!)}`;\n\n const response = await fetch(`${API_URL}/public/messages?${query}`, {\n headers: { 'X-API-Key': API_KEY },\n });\n\n const data = await response.json();\n if (!response.ok) {\n return json(\n { success: false, error: data.error || 'Failed to load messages.' },\n { status: response.status }\n );\n }\n return json({ success: true, data: data.data || [] });\n } catch (error) {\n console.error('Chat history error:', error);\n return json({ success: false, error: 'Network error. Please try again later.' }, { status: 500 });\n }\n },\n };\n}\n"],"mappings":"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","names":["response","data"]}
@@ -1,33 +0,0 @@
1
- /**
2
- * Consumer auth API route handlers for Next.js App Router.
3
- *
4
- * Usage in a customer site:
5
- * // app/api/consumer/[action]/route.ts
6
- * import { NextResponse } from 'next/server';
7
- * import { createConsumerAuthHandlers } from 'keystone-design-bootstrap/next/routes/consumer-auth';
8
- * export const { POST } = createConsumerAuthHandlers({ NextResponse });
9
- *
10
- * Handles: initiate, login, signup, send_code, verify_code, passwordless_auth, logout
11
- *
12
- * Env (server-side only):
13
- * - API_URL (default: http://localhost:3000/api/v1)
14
- * - API_KEY
15
- */
16
- type NextResponseLike = {
17
- json: (body: unknown, init?: ResponseInit) => any;
18
- };
19
- /**
20
- * Creates a single POST handler that routes to the correct auth action based on
21
- * the dynamic `[action]` path segment.
22
- */
23
- declare function createConsumerAuthHandlers({ NextResponse }: {
24
- NextResponse: NextResponseLike;
25
- }): {
26
- POST: (request: Request, context: {
27
- params: Promise<{
28
- action: string;
29
- }>;
30
- }) => Promise<Response>;
31
- };
32
-
33
- export { createConsumerAuthHandlers };
@@ -1,254 +0,0 @@
1
- var __defProp = Object.defineProperty;
2
- var __getOwnPropSymbols = Object.getOwnPropertySymbols;
3
- var __hasOwnProp = Object.prototype.hasOwnProperty;
4
- var __propIsEnum = Object.prototype.propertyIsEnumerable;
5
- var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
6
- var __spreadValues = (a, b) => {
7
- for (var prop in b || (b = {}))
8
- if (__hasOwnProp.call(b, prop))
9
- __defNormalProp(a, prop, b[prop]);
10
- if (__getOwnPropSymbols)
11
- for (var prop of __getOwnPropSymbols(b)) {
12
- if (__propIsEnum.call(b, prop))
13
- __defNormalProp(a, prop, b[prop]);
14
- }
15
- return a;
16
- };
17
-
18
- // src/lib/consumer-session.ts
19
- var CONSUMER_TOKEN_COOKIE = "ks_consumer_token";
20
-
21
- // src/next/routes/proxy-headers.ts
22
- function clientContextHeaders(request) {
23
- var _a, _b;
24
- const ip = request.headers.get("x-real-ip") || ((_b = (_a = request.headers.get("x-forwarded-for")) == null ? void 0 : _a.split(",")[0]) == null ? void 0 : _b.trim());
25
- const ua = request.headers.get("user-agent");
26
- const cookieHeader = request.headers.get("cookie") || "";
27
- const cookies = Object.fromEntries(
28
- cookieHeader.split(";").map((c) => {
29
- const [k, ...v] = c.trim().split("=");
30
- return [k, v.join("=")];
31
- })
32
- );
33
- const fbp = cookies["_fbp"];
34
- const fbc = cookies["_fbc"];
35
- const headers = {};
36
- if (ip) headers["X-Real-Client-IP"] = ip;
37
- if (ua) headers["X-Real-Client-UA"] = ua;
38
- if (fbp) headers["X-Meta-FBP"] = fbp;
39
- if (fbc) headers["X-Meta-FBC"] = fbc;
40
- return headers;
41
- }
42
-
43
- // src/next/routes/consumer-auth.ts
44
- var COOKIE_MAX_AGE = 60 * 60 * 24 * 30;
45
- function getApiUrl() {
46
- return process.env.API_URL || "http://localhost:3000/api/v1";
47
- }
48
- function getApiKey() {
49
- return process.env.API_KEY || "";
50
- }
51
- function apiHeaders(request) {
52
- const key = getApiKey();
53
- return __spreadValues(__spreadValues({
54
- "Content-Type": "application/json"
55
- }, key ? { "X-API-Key": key } : {}), request ? clientContextHeaders(request) : {});
56
- }
57
- async function handleInitiate(request, NR) {
58
- var _a;
59
- const body = await request.json().catch(() => ({}));
60
- const { email, phone } = body;
61
- if (!email && !phone) {
62
- return NR.json({ exists: null });
63
- }
64
- try {
65
- const res = await fetch(`${getApiUrl()}/consumer/auth/initiate`, {
66
- method: "POST",
67
- headers: apiHeaders(request),
68
- body: JSON.stringify({ email: email || void 0, phone: phone || void 0 })
69
- });
70
- if (res.status === 404) return NR.json({ exists: false });
71
- if (!res.ok) return NR.json({ exists: null });
72
- const json = await res.json().catch(() => ({}));
73
- const data = json.data;
74
- return NR.json({
75
- exists: true,
76
- firstName: (_a = data == null ? void 0 : data.first_name) != null ? _a : void 0,
77
- hasPassword: (data == null ? void 0 : data.has_password) != null ? Boolean(data.has_password) : true
78
- });
79
- } catch (e) {
80
- return NR.json({ exists: null });
81
- }
82
- }
83
- async function handleLogin(request, NR) {
84
- var _a;
85
- const body = await request.json().catch(() => ({}));
86
- const { email, phone, password } = body;
87
- if (!email && !phone) return NR.json({ error: "Email or phone is required." }, { status: 422 });
88
- if (!password) return NR.json({ error: "Password is required." }, { status: 422 });
89
- const res = await fetch(`${getApiUrl()}/consumer/auth/login`, {
90
- method: "POST",
91
- headers: apiHeaders(request),
92
- body: JSON.stringify({ email: email || void 0, phone: phone || void 0, password })
93
- });
94
- const json = await res.json().catch(() => ({}));
95
- if (!res.ok) {
96
- return NR.json(
97
- { error: json.error || "Login failed. Please try again.", code: json.code },
98
- { status: res.status }
99
- );
100
- }
101
- const token = (_a = json.data) == null ? void 0 : _a.token;
102
- if (!token) return NR.json({ error: "No token received." }, { status: 500 });
103
- const response = NR.json({});
104
- response.cookies.set(CONSUMER_TOKEN_COOKIE, token, {
105
- httpOnly: true,
106
- secure: process.env.NODE_ENV === "production",
107
- sameSite: "lax",
108
- path: "/",
109
- maxAge: COOKIE_MAX_AGE
110
- });
111
- return response;
112
- }
113
- async function handleSignup(request, NR) {
114
- var _a, _b, _c;
115
- const body = await request.json().catch(() => ({}));
116
- const { email, phone, password, password_confirmation, first_name, last_name } = body;
117
- if (!email && !phone) return NR.json({ error: "Email or phone is required." }, { status: 422 });
118
- const res = await fetch(`${getApiUrl()}/consumer/auth/signup`, {
119
- method: "POST",
120
- headers: apiHeaders(request),
121
- body: JSON.stringify({
122
- email: email || void 0,
123
- phone: phone || void 0,
124
- password,
125
- password_confirmation,
126
- first_name: first_name || void 0,
127
- last_name: last_name || void 0
128
- })
129
- });
130
- const json = await res.json().catch(() => ({}));
131
- if (!res.ok) {
132
- return NR.json({ error: json.error || "Signup failed. Please try again." }, { status: res.status });
133
- }
134
- const token = (_a = json.data) == null ? void 0 : _a.token;
135
- if (!token) return NR.json({ error: "No token received." }, { status: 500 });
136
- const response = NR.json({ claimed: (_c = (_b = json.data) == null ? void 0 : _b.claimed) != null ? _c : false });
137
- response.cookies.set(CONSUMER_TOKEN_COOKIE, token, {
138
- httpOnly: true,
139
- secure: process.env.NODE_ENV === "production",
140
- sameSite: "lax",
141
- path: "/",
142
- maxAge: COOKIE_MAX_AGE
143
- });
144
- return response;
145
- }
146
- async function handleSendCode(request, NR) {
147
- var _a, _b;
148
- const body = await request.json().catch(() => ({}));
149
- const { phone } = body;
150
- if (!phone) return NR.json({ error: "Phone is required." }, { status: 422 });
151
- const res = await fetch(`${getApiUrl()}/consumer/auth/send_code`, {
152
- method: "POST",
153
- headers: apiHeaders(request),
154
- body: JSON.stringify({ phone })
155
- });
156
- const json = await res.json().catch(() => ({}));
157
- if (!res.ok) {
158
- return NR.json(
159
- {
160
- error: json.error || "Failed to send verification code. Please try again.",
161
- code: json.code,
162
- retry_in_seconds: json.retry_in_seconds
163
- },
164
- { status: res.status }
165
- );
166
- }
167
- return NR.json({
168
- resend_available_at: (_b = (_a = json.data) == null ? void 0 : _a.resend_available_at) != null ? _b : null
169
- });
170
- }
171
- async function handleVerifyCode(request, NR) {
172
- var _a, _b, _c, _d, _e, _f, _g;
173
- const body = await request.json().catch(() => ({}));
174
- const { phone, code } = body;
175
- if (!phone || !code) return NR.json({ error: "Phone and code are required." }, { status: 422 });
176
- const res = await fetch(`${getApiUrl()}/consumer/auth/verify_code`, {
177
- method: "POST",
178
- headers: apiHeaders(request),
179
- body: JSON.stringify({ phone, code })
180
- });
181
- const json = await res.json().catch(() => ({}));
182
- if (!res.ok) {
183
- return NR.json(
184
- { error: json.error || "Verification failed. Please try again.", code: json.code },
185
- { status: res.status }
186
- );
187
- }
188
- return NR.json({
189
- verification_token: (_a = json.data) == null ? void 0 : _a.verification_token,
190
- first_name: (_c = (_b = json.data) == null ? void 0 : _b.first_name) != null ? _c : "",
191
- last_name: (_e = (_d = json.data) == null ? void 0 : _d.last_name) != null ? _e : "",
192
- email: (_g = (_f = json.data) == null ? void 0 : _f.email) != null ? _g : ""
193
- });
194
- }
195
- async function handlePasswordlessAuth(request, NR) {
196
- var _a;
197
- const body = await request.json().catch(() => ({}));
198
- const { phone, verification_token, first_name, last_name, email } = body;
199
- if (!phone) return NR.json({ error: "Phone is required." }, { status: 422 });
200
- if (!verification_token) return NR.json({ error: "Verification token is required." }, { status: 422 });
201
- if (!first_name || !last_name || !email) {
202
- return NR.json({ error: "First name, last name, and email are required." }, { status: 422 });
203
- }
204
- const res = await fetch(`${getApiUrl()}/consumer/auth/passwordless_auth`, {
205
- method: "POST",
206
- headers: apiHeaders(request),
207
- body: JSON.stringify({
208
- phone,
209
- verification_token,
210
- first_name,
211
- last_name,
212
- email
213
- })
214
- });
215
- const json = await res.json().catch(() => ({}));
216
- if (!res.ok) {
217
- return NR.json({ error: json.error || "Authentication failed. Please try again." }, { status: res.status });
218
- }
219
- const token = (_a = json.data) == null ? void 0 : _a.token;
220
- if (!token) return NR.json({ error: "No token received." }, { status: 500 });
221
- const response = NR.json({});
222
- response.cookies.set(CONSUMER_TOKEN_COOKIE, token, {
223
- httpOnly: true,
224
- secure: process.env.NODE_ENV === "production",
225
- sameSite: "lax",
226
- path: "/",
227
- maxAge: COOKIE_MAX_AGE
228
- });
229
- return response;
230
- }
231
- async function handleLogout(_request, NR) {
232
- const response = NR.json({ success: true });
233
- response.cookies.delete(CONSUMER_TOKEN_COOKIE);
234
- return response;
235
- }
236
- function createConsumerAuthHandlers({ NextResponse }) {
237
- return {
238
- POST: async (request, context) => {
239
- const { action } = await context.params;
240
- if (action === "initiate") return handleInitiate(request, NextResponse);
241
- if (action === "login") return handleLogin(request, NextResponse);
242
- if (action === "signup") return handleSignup(request, NextResponse);
243
- if (action === "send_code") return handleSendCode(request, NextResponse);
244
- if (action === "verify_code") return handleVerifyCode(request, NextResponse);
245
- if (action === "passwordless_auth") return handlePasswordlessAuth(request, NextResponse);
246
- if (action === "logout") return handleLogout(request, NextResponse);
247
- return NextResponse.json({ error: "Not found" }, { status: 404 });
248
- }
249
- };
250
- }
251
- export {
252
- createConsumerAuthHandlers
253
- };
254
- //# sourceMappingURL=consumer-auth.js.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../../../src/lib/consumer-session.ts","../../../src/next/routes/proxy-headers.ts","../../../src/next/routes/consumer-auth.ts"],"sourcesContent":["/**\n * Server-side consumer session helpers.\n * Runs on the server only — accepts the JWT token read from cookies by the page component.\n */\n\nexport const CONSUMER_TOKEN_COOKIE = 'ks_consumer_token';\n\nimport type { Consumer, ConversationSummary, Message, ContactSummary } from '../types/api/consumer';\nexport type { Consumer, ConversationSummary, Message, ContactSummary };\n\nfunction getApiUrl(): string {\n return process.env.API_URL || 'http://localhost:3000/api/v1';\n}\n\nasync function consumerFetch<T>(path: string, token: string): Promise<T | null> {\n try {\n const res = await fetch(`${getApiUrl()}${path}`, {\n headers: {\n 'Content-Type': 'application/json',\n Authorization: `Bearer ${token}`,\n },\n cache: 'no-store',\n });\n if (!res.ok) return null;\n const json = await res.json();\n return (json.data ?? json) as T;\n } catch {\n return null;\n }\n}\n\nexport async function fetchConsumerMe(token: string): Promise<Consumer | null> {\n return consumerFetch<Consumer>('/consumer/me', token);\n}\n\nexport async function fetchConsumerConversations(token: string): Promise<ConversationSummary[]> {\n const apiKey = process.env.API_KEY;\n const headers: Record<string, string> = {\n 'Content-Type': 'application/json',\n Authorization: `Bearer ${token}`,\n ...(apiKey ? { 'X-API-Key': apiKey } : {}),\n };\n try {\n const res = await fetch(`${getApiUrl()}/consumer/me/conversations`, { headers, cache: 'no-store' });\n if (!res.ok) return [];\n const json = await res.json();\n return (json.data ?? []) as ConversationSummary[];\n } catch {\n return [];\n }\n}\n\nexport async function fetchConsumerMessages(\n token: string,\n contactId: number\n): Promise<{ messages: Message[]; contact: ContactSummary | null }> {\n try {\n const res = await fetch(\n `${getApiUrl()}/consumer/me/contacts/${contactId}/messages?per_page=100`,\n {\n headers: { Authorization: `Bearer ${token}` },\n cache: 'no-store',\n }\n );\n if (!res.ok) return { messages: [], contact: null };\n const json = await res.json();\n return {\n messages: (json.data ?? []) as Message[],\n contact: (json.contact ?? null) as ContactSummary | null,\n };\n } catch {\n return { messages: [], contact: null };\n }\n}\n","/**\n * Extracts the real client IP, user-agent, and Meta browser cookies (_fbp / _fbc)\n * from an incoming Next.js route request and returns them as headers to forward\n * to the upstream Rails API.\n *\n * Cloudflare and other load-balancers set x-real-ip (or x-forwarded-for) on\n * inbound requests before they reach the Next.js function. Without this, the\n * Rails API sees the Next.js server IP instead of the real browser IP, which\n * produces inaccurate server-side CAPI signals.\n *\n * _fbp (Meta Browser ID) and _fbc (Meta Click ID) are first-party cookies set by\n * the Meta Pixel. Forwarding them allows the API to store them on the Contact\n * record so they can be included in all subsequent CAPI events — even those fired\n * from background jobs that have no live HTTP request.\n *\n * Convention:\n * X-Real-Client-IP — real browser IP\n * X-Real-Client-UA — real browser user-agent\n * X-Meta-FBP — value of the _fbp cookie\n * X-Meta-FBC — value of the _fbc cookie (or built from fbclid param)\n */\nexport function clientContextHeaders(request: Request): Record<string, string> {\n const ip =\n request.headers.get('x-real-ip') ||\n request.headers.get('x-forwarded-for')?.split(',')[0]?.trim();\n const ua = request.headers.get('user-agent');\n\n const cookieHeader = request.headers.get('cookie') || '';\n const cookies = Object.fromEntries(\n cookieHeader.split(';').map((c) => {\n const [k, ...v] = c.trim().split('=');\n return [k, v.join('=')];\n })\n );\n const fbp = cookies['_fbp'];\n const fbc = cookies['_fbc'];\n\n const headers: Record<string, string> = {};\n if (ip) headers['X-Real-Client-IP'] = ip;\n if (ua) headers['X-Real-Client-UA'] = ua;\n if (fbp) headers['X-Meta-FBP'] = fbp;\n if (fbc) headers['X-Meta-FBC'] = fbc;\n return headers;\n}\n","/**\n * Consumer auth API route handlers for Next.js App Router.\n *\n * Usage in a customer site:\n * // app/api/consumer/[action]/route.ts\n * import { NextResponse } from 'next/server';\n * import { createConsumerAuthHandlers } from 'keystone-design-bootstrap/next/routes/consumer-auth';\n * export const { POST } = createConsumerAuthHandlers({ NextResponse });\n *\n * Handles: initiate, login, signup, send_code, verify_code, passwordless_auth, logout\n *\n * Env (server-side only):\n * - API_URL (default: http://localhost:3000/api/v1)\n * - API_KEY\n */\n\nimport { CONSUMER_TOKEN_COOKIE } from '../../lib/consumer-session';\nimport { clientContextHeaders } from './proxy-headers';\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\ntype NextResponseLike = { json: (body: unknown, init?: ResponseInit) => any };\n\nconst COOKIE_MAX_AGE = 60 * 60 * 24 * 30; // 30 days\n\nfunction getApiUrl(): string {\n return process.env.API_URL || 'http://localhost:3000/api/v1';\n}\n\nfunction getApiKey(): string {\n return process.env.API_KEY || '';\n}\n\nfunction apiHeaders(request?: Request): Record<string, string> {\n const key = getApiKey();\n return {\n 'Content-Type': 'application/json',\n ...(key ? { 'X-API-Key': key } : {}),\n ...(request ? clientContextHeaders(request) : {}),\n };\n}\n\n// POST /api/consumer/initiate\n// Looks up an existing user by email or phone, creating a Contact if needed.\n// Returns { exists, firstName, hasPassword }.\nasync function handleInitiate(request: Request, NR: NextResponseLike): Promise<Response> {\n const body = await request.json().catch(() => ({})) as Record<string, unknown>;\n const { email, phone } = body;\n\n if (!email && !phone) {\n return NR.json({ exists: null });\n }\n\n try {\n const res = await fetch(`${getApiUrl()}/consumer/auth/initiate`, {\n method: 'POST',\n headers: apiHeaders(request),\n body: JSON.stringify({ email: email || undefined, phone: phone || undefined }),\n });\n\n if (res.status === 404) return NR.json({ exists: false });\n if (!res.ok) return NR.json({ exists: null });\n\n const json = await res.json().catch(() => ({}));\n const data = json.data as Record<string, unknown> | undefined;\n return NR.json({\n exists: true,\n firstName: data?.first_name ?? undefined,\n hasPassword: data?.has_password != null ? Boolean(data.has_password) : true,\n });\n } catch {\n return NR.json({ exists: null });\n }\n}\n\n// POST /api/consumer/login\n// Authenticates an existing user. Sets HttpOnly JWT cookie on success.\n// Returns {} on success or { error, code } on failure.\nasync function handleLogin(request: Request, NR: NextResponseLike): Promise<Response> {\n const body = await request.json().catch(() => ({})) as Record<string, string>;\n const { email, phone, password } = body;\n\n if (!email && !phone) return NR.json({ error: 'Email or phone is required.' }, { status: 422 });\n if (!password) return NR.json({ error: 'Password is required.' }, { status: 422 });\n\n const res = await fetch(`${getApiUrl()}/consumer/auth/login`, {\n method: 'POST',\n headers: apiHeaders(request),\n body: JSON.stringify({ email: email || undefined, phone: phone || undefined, password }),\n });\n\n const json = await res.json().catch(() => ({}));\n if (!res.ok) {\n return NR.json(\n { error: json.error || 'Login failed. Please try again.', code: json.code },\n { status: res.status }\n );\n }\n\n const token = json.data?.token;\n if (!token) return NR.json({ error: 'No token received.' }, { status: 500 });\n\n const response = NR.json({});\n response.cookies.set(CONSUMER_TOKEN_COOKIE, token, {\n httpOnly: true,\n secure: process.env.NODE_ENV === 'production',\n sameSite: 'lax',\n path: '/',\n maxAge: COOKIE_MAX_AGE,\n });\n return response;\n}\n\n// POST /api/consumer/signup\n// Creates a new account (or claims an existing contact). Sets HttpOnly JWT cookie on success.\n// Returns {} on success or { error } on failure.\nasync function handleSignup(request: Request, NR: NextResponseLike): Promise<Response> {\n const body = await request.json().catch(() => ({})) as Record<string, string>;\n const { email, phone, password, password_confirmation, first_name, last_name } = body;\n\n if (!email && !phone) return NR.json({ error: 'Email or phone is required.' }, { status: 422 });\n\n const res = await fetch(`${getApiUrl()}/consumer/auth/signup`, {\n method: 'POST',\n headers: apiHeaders(request),\n body: JSON.stringify({\n email: email || undefined,\n phone: phone || undefined,\n password,\n password_confirmation,\n first_name: first_name || undefined,\n last_name: last_name || undefined,\n }),\n });\n\n const json = await res.json().catch(() => ({}));\n if (!res.ok) {\n return NR.json({ error: json.error || 'Signup failed. Please try again.' }, { status: res.status });\n }\n\n const token = json.data?.token;\n if (!token) return NR.json({ error: 'No token received.' }, { status: 500 });\n\n const response = NR.json({ claimed: json.data?.claimed ?? false });\n response.cookies.set(CONSUMER_TOKEN_COOKIE, token, {\n httpOnly: true,\n secure: process.env.NODE_ENV === 'production',\n sameSite: 'lax',\n path: '/',\n maxAge: COOKIE_MAX_AGE,\n });\n return response;\n}\n\n// POST /api/consumer/send_code\n// Sends a 4-digit SMS verification code for passwordless login/signup.\nasync function handleSendCode(request: Request, NR: NextResponseLike): Promise<Response> {\n const body = await request.json().catch(() => ({})) as Record<string, string>;\n const { phone } = body;\n if (!phone) return NR.json({ error: 'Phone is required.' }, { status: 422 });\n\n const res = await fetch(`${getApiUrl()}/consumer/auth/send_code`, {\n method: 'POST',\n headers: apiHeaders(request),\n body: JSON.stringify({ phone }),\n });\n\n const json = await res.json().catch(() => ({}));\n if (!res.ok) {\n return NR.json(\n {\n error: json.error || 'Failed to send verification code. Please try again.',\n code: json.code,\n retry_in_seconds: json.retry_in_seconds,\n },\n { status: res.status }\n );\n }\n\n return NR.json({\n resend_available_at: json.data?.resend_available_at ?? null,\n });\n}\n\n// POST /api/consumer/verify_code\n// Verifies the SMS code and returns a short-lived verification token.\nasync function handleVerifyCode(request: Request, NR: NextResponseLike): Promise<Response> {\n const body = await request.json().catch(() => ({})) as Record<string, string>;\n const { phone, code } = body;\n if (!phone || !code) return NR.json({ error: 'Phone and code are required.' }, { status: 422 });\n\n const res = await fetch(`${getApiUrl()}/consumer/auth/verify_code`, {\n method: 'POST',\n headers: apiHeaders(request),\n body: JSON.stringify({ phone, code }),\n });\n\n const json = await res.json().catch(() => ({}));\n if (!res.ok) {\n return NR.json(\n { error: json.error || 'Verification failed. Please try again.', code: json.code },\n { status: res.status }\n );\n }\n\n return NR.json({\n verification_token: json.data?.verification_token,\n first_name: json.data?.first_name ?? '',\n last_name: json.data?.last_name ?? '',\n email: json.data?.email ?? '',\n });\n}\n\n// POST /api/consumer/passwordless_auth\n// Completes passwordless auth and sets HttpOnly JWT cookie.\nasync function handlePasswordlessAuth(request: Request, NR: NextResponseLike): Promise<Response> {\n const body = await request.json().catch(() => ({})) as Record<string, string>;\n const { phone, verification_token, first_name, last_name, email } = body;\n\n if (!phone) return NR.json({ error: 'Phone is required.' }, { status: 422 });\n if (!verification_token) return NR.json({ error: 'Verification token is required.' }, { status: 422 });\n if (!first_name || !last_name || !email) {\n return NR.json({ error: 'First name, last name, and email are required.' }, { status: 422 });\n }\n\n const res = await fetch(`${getApiUrl()}/consumer/auth/passwordless_auth`, {\n method: 'POST',\n headers: apiHeaders(request),\n body: JSON.stringify({\n phone,\n verification_token,\n first_name,\n last_name,\n email,\n }),\n });\n\n const json = await res.json().catch(() => ({}));\n if (!res.ok) {\n return NR.json({ error: json.error || 'Authentication failed. Please try again.' }, { status: res.status });\n }\n\n const token = json.data?.token;\n if (!token) return NR.json({ error: 'No token received.' }, { status: 500 });\n\n const response = NR.json({});\n response.cookies.set(CONSUMER_TOKEN_COOKIE, token, {\n httpOnly: true,\n secure: process.env.NODE_ENV === 'production',\n sameSite: 'lax',\n path: '/',\n maxAge: COOKIE_MAX_AGE,\n });\n return response;\n}\n\n// POST /api/consumer/logout\n// Clears the JWT cookie.\nasync function handleLogout(_request: Request, NR: NextResponseLike): Promise<Response> {\n const response = NR.json({ success: true });\n response.cookies.delete(CONSUMER_TOKEN_COOKIE);\n return response;\n}\n\n/**\n * Creates a single POST handler that routes to the correct auth action based on\n * the dynamic `[action]` path segment.\n */\nexport function createConsumerAuthHandlers({ NextResponse }: { NextResponse: NextResponseLike }) {\n return {\n POST: async (\n request: Request,\n context: { params: Promise<{ action: string }> }\n ): Promise<Response> => {\n const { action } = await context.params;\n if (action === 'initiate') return handleInitiate(request, NextResponse);\n if (action === 'login') return handleLogin(request, NextResponse);\n if (action === 'signup') return handleSignup(request, NextResponse);\n if (action === 'send_code') return handleSendCode(request, NextResponse);\n if (action === 'verify_code') return handleVerifyCode(request, NextResponse);\n if (action === 'passwordless_auth') return handlePasswordlessAuth(request, NextResponse);\n if (action === 'logout') return handleLogout(request, NextResponse);\n return NextResponse.json({ error: 'Not found' }, { status: 404 });\n },\n };\n}\n"],"mappings":"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","names":[]}
@@ -1,37 +0,0 @@
1
- /**
2
- * Form submission proxy route handler for Next.js App Router.
3
- *
4
- * Usage in a site/template:
5
- * // app/api/form/route.ts
6
- * export { POST } from 'keystone-design-bootstrap/next/routes/form';
7
- *
8
- * Env (server-side only):
9
- * - API_URL (default: http://localhost:3000/api/v1)
10
- * - API_KEY
11
- *
12
- * ## Meta Pixel + CAPI tracking for custom forms
13
- *
14
- * POST body must include `formType: 'lead'` for conversion tracking to fire:
15
- * - Server-side: the API automatically fires a CAPI Lead event (no extra work needed).
16
- * - Client-side: the response includes `eventId` for browser/server deduplication.
17
- * After a successful response, call these two functions from 'keystone-design-bootstrap/tracking':
18
- *
19
- * const result = await response.json();
20
- * if (result.success) {
21
- * await setPixelUserData({ email, phone }); // hash + store identity for the session
22
- * firePixelEvent('Lead', undefined, result.eventId); // fire fbq('track', 'Lead') with server event ID for dedup
23
- * }
24
- *
25
- * Both tracking calls are silent no-ops when no Meta Pixel is configured for the site.
26
- * Non-lead form types (e.g. 'job_application') do not fire any tracking events.
27
- */
28
- type JsonResponder = (body: unknown, init?: ResponseInit) => Response;
29
- declare function createFormRouteHandlers(deps?: {
30
- NextResponse?: {
31
- json: JsonResponder;
32
- };
33
- }): {
34
- POST: (request: Request) => Promise<Response>;
35
- };
36
-
37
- export { createFormRouteHandlers };