keystone-design-bootstrap 1.0.100 → 1.0.102

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 (62) hide show
  1. package/README.md +4 -0
  2. package/package.json +1 -1
  3. package/src/next/routes/consumer-auth.ts +41 -20
  4. package/dist/blog-post-vWzW8yFb.d.ts +0 -50
  5. package/dist/contexts/index.d.ts +0 -13
  6. package/dist/contexts/index.js +0 -173
  7. package/dist/contexts/index.js.map +0 -1
  8. package/dist/design_system/components/DynamicFormFields.d.ts +0 -15
  9. package/dist/design_system/components/DynamicFormFields.js +0 -5176
  10. package/dist/design_system/components/DynamicFormFields.js.map +0 -1
  11. package/dist/design_system/elements/index.d.ts +0 -383
  12. package/dist/design_system/elements/index.js +0 -4007
  13. package/dist/design_system/elements/index.js.map +0 -1
  14. package/dist/design_system/logo/keystone-logo.d.ts +0 -6
  15. package/dist/design_system/logo/keystone-logo.js +0 -145
  16. package/dist/design_system/logo/keystone-logo.js.map +0 -1
  17. package/dist/design_system/sections/index.d.ts +0 -233
  18. package/dist/design_system/sections/index.js +0 -20048
  19. package/dist/design_system/sections/index.js.map +0 -1
  20. package/dist/form-C94A_PX_.d.ts +0 -36
  21. package/dist/index.d.ts +0 -70
  22. package/dist/index.js +0 -20608
  23. package/dist/index.js.map +0 -1
  24. package/dist/lib/component-registry.d.ts +0 -13
  25. package/dist/lib/component-registry.js +0 -36
  26. package/dist/lib/component-registry.js.map +0 -1
  27. package/dist/lib/hooks/index.d.ts +0 -83
  28. package/dist/lib/hooks/index.js +0 -182
  29. package/dist/lib/hooks/index.js.map +0 -1
  30. package/dist/lib/server-api.d.ts +0 -67
  31. package/dist/lib/server-api.js +0 -195
  32. package/dist/lib/server-api.js.map +0 -1
  33. package/dist/package-DeHKpQp7.d.ts +0 -121
  34. package/dist/photos-CmBdWiuZ.d.ts +0 -27
  35. package/dist/themes/index.d.ts +0 -17
  36. package/dist/themes/index.js +0 -29
  37. package/dist/themes/index.js.map +0 -1
  38. package/dist/tracking/index.d.ts +0 -254
  39. package/dist/tracking/index.js +0 -550
  40. package/dist/tracking/index.js.map +0 -1
  41. package/dist/types/index.d.ts +0 -313
  42. package/dist/types/index.js +0 -1
  43. package/dist/types/index.js.map +0 -1
  44. package/dist/utils/cx.d.ts +0 -15
  45. package/dist/utils/cx.js +0 -18
  46. package/dist/utils/cx.js.map +0 -1
  47. package/dist/utils/gradient-placeholder.d.ts +0 -7
  48. package/dist/utils/gradient-placeholder.js +0 -59
  49. package/dist/utils/gradient-placeholder.js.map +0 -1
  50. package/dist/utils/is-react-component.d.ts +0 -21
  51. package/dist/utils/is-react-component.js +0 -20
  52. package/dist/utils/is-react-component.js.map +0 -1
  53. package/dist/utils/markdown-toc.d.ts +0 -14
  54. package/dist/utils/markdown-toc.js +0 -29
  55. package/dist/utils/markdown-toc.js.map +0 -1
  56. package/dist/utils/phone-helpers.d.ts +0 -24
  57. package/dist/utils/phone-helpers.js +0 -26
  58. package/dist/utils/phone-helpers.js.map +0 -1
  59. package/dist/utils/photo-helpers.d.ts +0 -38
  60. package/dist/utils/photo-helpers.js +0 -41
  61. package/dist/utils/photo-helpers.js.map +0 -1
  62. package/dist/website-photos-Cl1YqAno.d.ts +0 -21
package/README.md CHANGED
@@ -27,6 +27,9 @@ The shared design system and runtime package powering all Keystone customer webs
27
27
  # .env.local
28
28
  API_URL=http://localhost:3000/api/v1
29
29
  API_KEY=your-api-key-here
30
+ # Optional: override passwordless OTP route base used by
31
+ # /api/consumer/send_code|verify_code|passwordless_auth proxy handlers.
32
+ CONSUMER_AUTH_URL=https://www.keystone.app/api/consumer
30
33
  ```
31
34
 
32
35
  ### 2. Config
@@ -192,6 +195,7 @@ Data fetching works the same as any other site. All functions are server-only (u
192
195
  ```
193
196
  API_URL=http://localhost:3000/api/v1
194
197
  API_KEY=your-api-key-here
198
+ CONSUMER_AUTH_URL=https://www.keystone.app/api/consumer
195
199
  ```
196
200
 
197
201
  **Fetch data for a page — always use `Promise.all` to avoid waterfall requests:**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "keystone-design-bootstrap",
3
- "version": "1.0.100",
3
+ "version": "1.0.102",
4
4
  "description": "Keystone Design Bootstrap - Sections, Elements, and Theme System for customer websites",
5
5
  "type": "module",
6
6
  "main": "./src/index.ts",
@@ -12,6 +12,8 @@
12
12
  * Env (server-side only):
13
13
  * - API_URL (default: http://localhost:3000/api/v1)
14
14
  * - API_KEY
15
+ * - CONSUMER_AUTH_URL (optional; overrides passwordless routes base, e.g.
16
+ * https://www.keystone.app/api/consumer)
15
17
  */
16
18
 
17
19
  import { CONSUMER_TOKEN_COOKIE } from '../../lib/consumer-session';
@@ -30,6 +32,12 @@ function getApiKey(): string {
30
32
  return process.env.API_KEY || '';
31
33
  }
32
34
 
35
+ function getPasswordlessBaseUrl(): string {
36
+ const override = (process.env.CONSUMER_AUTH_URL || '').trim();
37
+ if (override) return override.replace(/\/+$/, '');
38
+ return `${getApiUrl().replace(/\/+$/, '')}/consumer/auth`;
39
+ }
40
+
33
41
  function apiHeaders(request?: Request): Record<string, string> {
34
42
  const key = getApiKey();
35
43
  return {
@@ -39,6 +47,10 @@ function apiHeaders(request?: Request): Record<string, string> {
39
47
  };
40
48
  }
41
49
 
50
+ function responseData(json: Record<string, unknown>): Record<string, unknown> {
51
+ return (json.data as Record<string, unknown>) || json;
52
+ }
53
+
42
54
  // POST /api/consumer/initiate
43
55
  // Looks up an existing user by email or phone, creating a Contact if needed.
44
56
  // Returns { exists, firstName, hasPassword }.
@@ -60,8 +72,8 @@ async function handleInitiate(request: Request, NR: NextResponseLike): Promise<R
60
72
  if (res.status === 404) return NR.json({ exists: false });
61
73
  if (!res.ok) return NR.json({ exists: null });
62
74
 
63
- const json = await res.json().catch(() => ({}));
64
- const data = json.data as Record<string, unknown> | undefined;
75
+ const json = await res.json().catch(() => ({})) as Record<string, unknown>;
76
+ const data = responseData(json);
65
77
  return NR.json({
66
78
  exists: true,
67
79
  firstName: data?.first_name ?? undefined,
@@ -158,26 +170,27 @@ async function handleSendCode(request: Request, NR: NextResponseLike): Promise<R
158
170
  const { phone } = body;
159
171
  if (!phone) return NR.json({ error: 'Phone is required.' }, { status: 422 });
160
172
 
161
- const res = await fetch(`${getApiUrl()}/consumer/auth/send_code`, {
173
+ const res = await fetch(`${getPasswordlessBaseUrl()}/send_code`, {
162
174
  method: 'POST',
163
175
  headers: apiHeaders(request),
164
176
  body: JSON.stringify({ phone }),
165
177
  });
166
178
 
167
- const json = await res.json().catch(() => ({}));
179
+ const json = await res.json().catch(() => ({})) as Record<string, unknown>;
180
+ const data = responseData(json);
168
181
  if (!res.ok) {
169
182
  return NR.json(
170
183
  {
171
- error: json.error || 'Failed to send verification code. Please try again.',
172
- code: json.code,
173
- retry_in_seconds: json.retry_in_seconds,
184
+ error: (json as Record<string, unknown>).error || 'Failed to send verification code. Please try again.',
185
+ code: (json as Record<string, unknown>).code,
186
+ retry_in_seconds: (json as Record<string, unknown>).retry_in_seconds,
174
187
  },
175
188
  { status: res.status }
176
189
  );
177
190
  }
178
191
 
179
192
  return NR.json({
180
- resend_available_at: json.data?.resend_available_at ?? null,
193
+ resend_available_at: data?.resend_available_at ?? null,
181
194
  });
182
195
  }
183
196
 
@@ -188,25 +201,29 @@ async function handleVerifyCode(request: Request, NR: NextResponseLike): Promise
188
201
  const { phone, code } = body;
189
202
  if (!phone || !code) return NR.json({ error: 'Phone and code are required.' }, { status: 422 });
190
203
 
191
- const res = await fetch(`${getApiUrl()}/consumer/auth/verify_code`, {
204
+ const res = await fetch(`${getPasswordlessBaseUrl()}/verify_code`, {
192
205
  method: 'POST',
193
206
  headers: apiHeaders(request),
194
207
  body: JSON.stringify({ phone, code }),
195
208
  });
196
209
 
197
- const json = await res.json().catch(() => ({}));
210
+ const json = await res.json().catch(() => ({})) as Record<string, unknown>;
211
+ const data = responseData(json);
198
212
  if (!res.ok) {
199
213
  return NR.json(
200
- { error: json.error || 'Verification failed. Please try again.', code: json.code },
214
+ {
215
+ error: (json as Record<string, unknown>).error || 'Verification failed. Please try again.',
216
+ code: (json as Record<string, unknown>).code,
217
+ },
201
218
  { status: res.status }
202
219
  );
203
220
  }
204
221
 
205
222
  return NR.json({
206
- verification_token: json.data?.verification_token,
207
- first_name: json.data?.first_name ?? '',
208
- last_name: json.data?.last_name ?? '',
209
- email: json.data?.email ?? '',
223
+ verification_token: data?.verification_token,
224
+ first_name: data?.first_name ?? '',
225
+ last_name: data?.last_name ?? '',
226
+ email: data?.email ?? '',
210
227
  });
211
228
  }
212
229
 
@@ -222,7 +239,7 @@ async function handlePasswordlessAuth(request: Request, NR: NextResponseLike): P
222
239
  return NR.json({ error: 'First name, last name, and email are required.' }, { status: 422 });
223
240
  }
224
241
 
225
- const res = await fetch(`${getApiUrl()}/consumer/auth/passwordless_auth`, {
242
+ const res = await fetch(`${getPasswordlessBaseUrl()}/passwordless_auth`, {
226
243
  method: 'POST',
227
244
  headers: apiHeaders(request),
228
245
  body: JSON.stringify({
@@ -234,17 +251,21 @@ async function handlePasswordlessAuth(request: Request, NR: NextResponseLike): P
234
251
  }),
235
252
  });
236
253
 
237
- const json = await res.json().catch(() => ({}));
254
+ const json = await res.json().catch(() => ({})) as Record<string, unknown>;
255
+ const data = responseData(json);
238
256
  if (!res.ok) {
239
- return NR.json({ error: json.error || 'Authentication failed. Please try again.' }, { status: res.status });
257
+ return NR.json(
258
+ { error: (json as Record<string, unknown>).error || 'Authentication failed. Please try again.' },
259
+ { status: res.status }
260
+ );
240
261
  }
241
262
 
242
- const token = json.data?.token;
263
+ const token = data?.token;
243
264
  if (!token) return NR.json({ error: 'No token received.' }, { status: 500 });
244
265
 
245
266
  // Surface the server-side Lead event_id so the browser can fire a single deduped
246
267
  // Lead (fbq track with { eventID }) that Meta matches against the CAPI Lead event.
247
- const response = NR.json({ eventId: json.data?.event_id ?? undefined });
268
+ const response = NR.json({ eventId: data?.event_id ?? undefined });
248
269
  response.cookies.set(CONSUMER_TOKEN_COOKIE, token, {
249
270
  httpOnly: true,
250
271
  secure: process.env.NODE_ENV === 'production',
@@ -1,50 +0,0 @@
1
- import { P as PhotoAttachment } from './photos-CmBdWiuZ.js';
2
-
3
- interface BlogPost {
4
- id: number;
5
- title: string;
6
- slug: string;
7
- status: string;
8
- published_at?: string;
9
- excerpt_markdown?: string;
10
- content_markdown: string;
11
- featured: boolean;
12
- seo_title?: string;
13
- seo_description?: string;
14
- seo_keywords?: string;
15
- created_at: string;
16
- updated_at: string;
17
- photo_attachments?: PhotoAttachment[];
18
- blog_post_authors?: BlogPostAuthor[];
19
- blog_post_tags?: BlogPostTag[];
20
- }
21
- interface BlogPostParams {
22
- status?: string;
23
- author_id?: number;
24
- tag_id?: number;
25
- q?: string;
26
- page?: number;
27
- per_page?: number;
28
- featured?: boolean;
29
- }
30
- type BlogPostResponse = BlogPost[];
31
- interface BlogPostAuthor {
32
- id: number;
33
- name: string;
34
- slug: string;
35
- bio_markdown?: string;
36
- active: boolean;
37
- created_at: string;
38
- updated_at: string;
39
- photo_attachments?: PhotoAttachment[];
40
- }
41
- interface BlogPostTag {
42
- id: number;
43
- name: string;
44
- slug: string;
45
- description?: string;
46
- created_at: string;
47
- updated_at: string;
48
- }
49
-
50
- export type { BlogPost as B, BlogPostAuthor as a, BlogPostParams as b, BlogPostResponse as c, BlogPostTag as d };
@@ -1,13 +0,0 @@
1
- import * as React$1 from 'react';
2
- import { Theme } from '../themes/index.js';
3
-
4
- interface ThemeContextValue {
5
- theme: Theme;
6
- }
7
- declare function ThemeProvider({ theme, children }: {
8
- theme: Theme;
9
- children: React.ReactNode;
10
- }): React$1.JSX.Element;
11
- declare function useTheme(): ThemeContextValue;
12
-
13
- export { ThemeProvider, useTheme };
@@ -1,173 +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/contexts/ThemeContext.tsx
19
- import { createContext, useContext } from "react";
20
-
21
- // src/themes/index.ts
22
- var THEME_CONFIG = {
23
- classic: "",
24
- // Base files with no suffix (hero-home.tsx)
25
- aman: ".aman",
26
- // Aman Hotels variant files (hero-home.aman.tsx)
27
- barelux: ".barelux",
28
- // Bare Lux Studio variant files (hero-home.barelux.tsx)
29
- balance: ".balance",
30
- // Balance Aesthetics variant files (hero-home.balance.tsx)
31
- custom: ""
32
- // Fully custom sites — no design-system CSS loaded, all styling built in the site itself
33
- };
34
- function isValidTheme(theme) {
35
- return theme in THEME_CONFIG;
36
- }
37
-
38
- // src/tracking/logging.ts
39
- import { logs } from "@opentelemetry/api-logs";
40
- import { OTLPLogExporter } from "@opentelemetry/exporter-logs-otlp-http";
41
- import { resourceFromAttributes } from "@opentelemetry/resources";
42
- import { BatchLogRecordProcessor, LoggerProvider } from "@opentelemetry/sdk-logs";
43
- var BUILD_CONSOLE_DISABLED = process.env.NEXT_PUBLIC_LOGGING_DISABLED === "1";
44
- var BUILD_POSTHOG_DISABLED = process.env.NEXT_PUBLIC_POSTHOG_LOGGING_DISABLED === "1";
45
- var MAX_PENDING_POSTHOG_LOGS = 500;
46
- var otelLogger = null;
47
- var pendingPostHogLogs = [];
48
- var browserConsole = globalThis == null ? void 0 : globalThis["console"];
49
- var CHANNEL_COLORS = {
50
- // Shared diagnostics
51
- "global-client": "#d2a8ff",
52
- // Section pins (desktop)
53
- "every-channel-pin": "#9febd7",
54
- "hero-pin": "#6ecc8b",
55
- "pricing-pin": "#399587",
56
- "product-screens-pin": "#4fafa0",
57
- "social-proof-pin": "#ffbb8a",
58
- "value-props-pin": "#e0a733",
59
- "work-pin": "#f57e56",
60
- // Section pins (mobile)
61
- "mobile-every-channel-pin": "#7ed9c6",
62
- "mobile-hero-pin": "#f0eee6",
63
- "mobile-pricing-pin": "#80d4ff",
64
- "mobile-product-screens-pin": "#3a9085",
65
- "mobile-social-proof-pin": "#ffd580",
66
- "mobile-value-props-pin": "#4fafa0"
67
- };
68
- function flattenAttributes(input, prefix = "") {
69
- const output = {};
70
- for (const [key, value] of Object.entries(input)) {
71
- const nextKey = prefix ? `${prefix}.${key}` : key;
72
- if (value === null || value === void 0) continue;
73
- if (typeof value === "string" || typeof value === "number" || typeof value === "boolean") {
74
- output[nextKey] = value;
75
- continue;
76
- }
77
- if (Array.isArray(value)) {
78
- output[nextKey] = JSON.stringify(value);
79
- continue;
80
- }
81
- if (typeof value === "object") {
82
- Object.assign(output, flattenAttributes(value, nextKey));
83
- continue;
84
- }
85
- output[nextKey] = String(value);
86
- }
87
- return output;
88
- }
89
- function enqueuePendingPostHogLog(entry) {
90
- if (pendingPostHogLogs.length >= MAX_PENDING_POSTHOG_LOGS) {
91
- pendingPostHogLogs.shift();
92
- }
93
- pendingPostHogLogs.push(entry);
94
- }
95
- function isConsoleEnabled() {
96
- if (BUILD_CONSOLE_DISABLED) return false;
97
- if (typeof window === "undefined") return true;
98
- return window.__loggingDisabled !== true;
99
- }
100
- function isPostHogShippingEnabled() {
101
- if (BUILD_POSTHOG_DISABLED) return false;
102
- if (typeof window === "undefined") return false;
103
- return window.__posthogLoggingDisabled !== true;
104
- }
105
- function formatDetail(detail) {
106
- return Object.entries(detail).map(([k, v]) => `${k}=${typeof v === "number" ? v.toFixed(4) : String(v)}`).join(" ");
107
- }
108
- function emitConsole(level, channel, event, detail) {
109
- var _a, _b, _c, _d;
110
- const color = (_a = CHANNEL_COLORS[channel]) != null ? _a : "#aaa";
111
- const detailStr = formatDetail(detail);
112
- const message = `%c[${channel}] %c${event}%c ${detailStr}`;
113
- const channelStyle = `color:${color}; font-weight:bold`;
114
- const eventStyle = level === "error" ? "color:#e94e4e; font-weight:bold" : level === "warn" ? "color:#f5a623; font-weight:bold" : "color:#fff; font-weight:bold";
115
- const detailStyle = "color:#999; font-weight:normal";
116
- if (level === "error") {
117
- (_b = browserConsole == null ? void 0 : browserConsole.error) == null ? void 0 : _b.call(browserConsole, message, channelStyle, eventStyle, detailStyle);
118
- return;
119
- }
120
- if (level === "warn") {
121
- (_c = browserConsole == null ? void 0 : browserConsole.warn) == null ? void 0 : _c.call(browserConsole, message, channelStyle, eventStyle, detailStyle);
122
- return;
123
- }
124
- (_d = browserConsole == null ? void 0 : browserConsole.log) == null ? void 0 : _d.call(browserConsole, message, channelStyle, eventStyle, detailStyle);
125
- }
126
- function emitToPostHog(level, channel, event, detail) {
127
- if (!otelLogger) return false;
128
- const severityText = level === "warn" ? "WARNING" : level === "error" ? "ERROR" : "INFO";
129
- const attributes = flattenAttributes(__spreadValues({ channel }, detail));
130
- otelLogger.emit({
131
- severityText,
132
- body: event,
133
- attributes
134
- });
135
- return true;
136
- }
137
- function emit(level, channel, event, detail, options) {
138
- var _a;
139
- const shouldShip = ((_a = options == null ? void 0 : options.shipToPostHog) != null ? _a : level !== "info") && isPostHogShippingEnabled();
140
- if (level !== "info" || isConsoleEnabled()) {
141
- emitConsole(level, channel, event, detail);
142
- }
143
- if (shouldShip) {
144
- const shipped = emitToPostHog(level, channel, event, detail);
145
- if (!shipped) {
146
- enqueuePendingPostHogLog({ level, channel, event, detail });
147
- }
148
- }
149
- }
150
- function warn(channel, event, detail = {}, options) {
151
- emit("warn", channel, event, detail, options);
152
- }
153
-
154
- // src/contexts/ThemeContext.tsx
155
- var ThemeContext = createContext({ theme: "classic" });
156
- function ThemeProvider({
157
- theme,
158
- children
159
- }) {
160
- if (!isValidTheme(theme)) {
161
- warn("theme", "INVALID_THEME_FALLBACK", { theme });
162
- theme = "classic";
163
- }
164
- return /* @__PURE__ */ React.createElement(ThemeContext.Provider, { value: { theme } }, children);
165
- }
166
- function useTheme() {
167
- return useContext(ThemeContext);
168
- }
169
- export {
170
- ThemeProvider,
171
- useTheme
172
- };
173
- //# sourceMappingURL=index.js.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../../src/contexts/ThemeContext.tsx","../../src/themes/index.ts","../../src/tracking/logging.ts"],"sourcesContent":["'use client';\n\nimport { createContext, useContext } from 'react';\nimport { Theme, isValidTheme } from '../themes';\nimport { warn } from '../tracking/logging';\n\ninterface ThemeContextValue {\n theme: Theme;\n}\n\nconst ThemeContext = createContext<ThemeContextValue>({ theme: 'classic' });\n\nexport function ThemeProvider({ \n theme, \n children \n}: { \n theme: Theme; \n children: React.ReactNode;\n}) {\n // Validate theme at runtime\n if (!isValidTheme(theme)) {\n warn('theme', 'INVALID_THEME_FALLBACK', { theme });\n theme = 'classic';\n }\n \n return (\n <ThemeContext.Provider value={{ theme }}>\n {children}\n </ThemeContext.Provider>\n );\n}\n\nexport function useTheme() {\n return useContext(ThemeContext);\n}\n","/**\n * Theme Configuration\n * Single source of truth for all themes\n */\n\nexport const THEME_CONFIG = {\n classic: '', // Base files with no suffix (hero-home.tsx)\n aman: '.aman', // Aman Hotels variant files (hero-home.aman.tsx)\n barelux: '.barelux', // Bare Lux Studio variant files (hero-home.barelux.tsx)\n balance: '.balance', // Balance Aesthetics variant files (hero-home.balance.tsx)\n custom: '', // Fully custom sites — no design-system CSS loaded, all styling built in the site itself\n} as const;\n\nexport type Theme = keyof typeof THEME_CONFIG;\n\nexport function getAvailableThemes(): Theme[] {\n return Object.keys(THEME_CONFIG) as Theme[];\n}\n\nexport function getThemeSuffix(theme: Theme): string {\n return THEME_CONFIG[theme] || '';\n}\n\nexport function isValidTheme(theme: string): theme is Theme {\n return theme in THEME_CONFIG;\n}\n","'use client';\n\nimport { logs } from '@opentelemetry/api-logs';\nimport { OTLPLogExporter } from '@opentelemetry/exporter-logs-otlp-http';\nimport { resourceFromAttributes } from '@opentelemetry/resources';\nimport { BatchLogRecordProcessor, LoggerProvider } from '@opentelemetry/sdk-logs';\n\nconst BUILD_CONSOLE_DISABLED = process.env.NEXT_PUBLIC_LOGGING_DISABLED === '1';\nconst BUILD_POSTHOG_DISABLED = process.env.NEXT_PUBLIC_POSTHOG_LOGGING_DISABLED === '1';\ninterface LoggingWindow extends Window {\n __loggingDisabled?: boolean;\n __posthogLoggingDisabled?: boolean;\n}\n\nexport type LogLevel = 'info' | 'warn' | 'error';\n\nexport type LogOptions = {\n /** Send this log payload to PostHog Logs product. */\n shipToPostHog?: boolean;\n};\n\ntype OTelInitOptions = {\n apiKey: string;\n apiHost?: string;\n serviceName?: string;\n environment?: string;\n accountId?: number;\n accountName?: string;\n};\n\ntype PendingShipLog = {\n level: LogLevel;\n channel: string;\n event: string;\n detail: Record<string, unknown>;\n};\n\nconst MAX_PENDING_POSTHOG_LOGS = 500;\nlet otelProvider: LoggerProvider | null = null;\nlet otelLogger: ReturnType<typeof logs.getLogger> | null = null;\nlet otelInitFingerprint = '';\nconst pendingPostHogLogs: PendingShipLog[] = [];\nconst browserConsole = globalThis?.['console'];\n\n/**\n * Channel → accent colour. Unregistered channels fall through to gray.\n */\nexport const CHANNEL_COLORS: Record<string, string> = {\n // Shared diagnostics\n 'global-client': '#d2a8ff',\n\n // Section pins (desktop)\n 'every-channel-pin': '#9febd7',\n 'hero-pin': '#6ecc8b',\n 'pricing-pin': '#399587',\n 'product-screens-pin': '#4fafa0',\n 'social-proof-pin': '#ffbb8a',\n 'value-props-pin': '#e0a733',\n 'work-pin': '#f57e56',\n\n // Section pins (mobile)\n 'mobile-every-channel-pin': '#7ed9c6',\n 'mobile-hero-pin': '#f0eee6',\n 'mobile-pricing-pin': '#80d4ff',\n 'mobile-product-screens-pin': '#3a9085',\n 'mobile-social-proof-pin': '#ffd580',\n 'mobile-value-props-pin': '#4fafa0',\n};\n\nfunction flattenAttributes(input: Record<string, unknown>, prefix = ''): Record<string, string | number | boolean> {\n const output: Record<string, string | number | boolean> = {};\n\n for (const [key, value] of Object.entries(input)) {\n const nextKey = prefix ? `${prefix}.${key}` : key;\n if (value === null || value === undefined) continue;\n\n if (typeof value === 'string' || typeof value === 'number' || typeof value === 'boolean') {\n output[nextKey] = value;\n continue;\n }\n\n if (Array.isArray(value)) {\n output[nextKey] = JSON.stringify(value);\n continue;\n }\n\n if (typeof value === 'object') {\n Object.assign(output, flattenAttributes(value as Record<string, unknown>, nextKey));\n continue;\n }\n\n output[nextKey] = String(value);\n }\n\n return output;\n}\n\nfunction stripTrailingSlash(host: string): string {\n return host.replace(/\\/+$/, '');\n}\n\nfunction enqueuePendingPostHogLog(entry: PendingShipLog): void {\n if (pendingPostHogLogs.length >= MAX_PENDING_POSTHOG_LOGS) {\n pendingPostHogLogs.shift();\n }\n pendingPostHogLogs.push(entry);\n}\n\nfunction flushPendingPostHogLogs(): void {\n if (!otelLogger || pendingPostHogLogs.length === 0) return;\n\n while (pendingPostHogLogs.length > 0) {\n const entry = pendingPostHogLogs.shift();\n if (!entry) break;\n emitToPostHog(entry.level, entry.channel, entry.event, entry.detail);\n }\n}\n\nexport function initializePostHogLogging(options: OTelInitOptions): void {\n if (typeof window === 'undefined') return;\n if (!options.apiKey?.trim()) return;\n\n const apiHost = stripTrailingSlash(options.apiHost?.trim() || 'https://us.i.posthog.com');\n const serviceName = options.serviceName?.trim() || 'keystone-customer-site';\n const environment = options.environment?.trim() || 'production';\n const fingerprint = `${apiHost}|${options.apiKey}|${serviceName}|${environment}|${options.accountId ?? ''}|${options.accountName ?? ''}`;\n if (otelLogger && otelInitFingerprint === fingerprint) return;\n\n if (otelProvider) {\n // Cleanly replace logger provider when config changes.\n void otelProvider.shutdown().catch(() => {});\n otelProvider = null;\n otelLogger = null;\n }\n\n const baseAttributes: Record<string, string | number | boolean> = {\n 'service.name': serviceName,\n environment,\n site_domain: window.location.hostname,\n };\n if (options.accountId !== undefined) baseAttributes.account_id = options.accountId;\n if (options.accountName) baseAttributes.account_name = options.accountName;\n\n const exporter = new OTLPLogExporter({\n url: `${apiHost}/i/v1/logs?token=${encodeURIComponent(options.apiKey)}`,\n headers: {\n // Keep request \"simple\" to avoid CORS preflight in browser.\n 'Content-Type': 'text/plain',\n },\n });\n\n otelProvider = new LoggerProvider({\n resource: resourceFromAttributes(baseAttributes),\n processors: [new BatchLogRecordProcessor(exporter)],\n });\n\n logs.setGlobalLoggerProvider(otelProvider);\n otelLogger = logs.getLogger(serviceName);\n otelInitFingerprint = fingerprint;\n flushPendingPostHogLogs();\n}\n\nfunction isConsoleEnabled(): boolean {\n if (BUILD_CONSOLE_DISABLED) return false;\n if (typeof window === 'undefined') return true;\n return (window as LoggingWindow).__loggingDisabled !== true;\n}\n\nfunction isPostHogShippingEnabled(): boolean {\n if (BUILD_POSTHOG_DISABLED) return false;\n if (typeof window === 'undefined') return false;\n return (window as LoggingWindow).__posthogLoggingDisabled !== true;\n}\n\nfunction formatDetail(detail: Record<string, unknown>): string {\n return Object.entries(detail)\n .map(([k, v]) => `${k}=${typeof v === 'number' ? v.toFixed(4) : String(v)}`)\n .join(' ');\n}\n\nfunction emitConsole(\n level: LogLevel,\n channel: string,\n event: string,\n detail: Record<string, unknown>,\n): void {\n const color = CHANNEL_COLORS[channel] ?? '#aaa';\n const detailStr = formatDetail(detail);\n const message = `%c[${channel}] %c${event}%c ${detailStr}`;\n const channelStyle = `color:${color}; font-weight:bold`;\n const eventStyle = level === 'error'\n ? 'color:#e94e4e; font-weight:bold'\n : level === 'warn'\n ? 'color:#f5a623; font-weight:bold'\n : 'color:#fff; font-weight:bold';\n const detailStyle = 'color:#999; font-weight:normal';\n\n if (level === 'error') {\n browserConsole?.error?.(message, channelStyle, eventStyle, detailStyle);\n return;\n }\n if (level === 'warn') {\n browserConsole?.warn?.(message, channelStyle, eventStyle, detailStyle);\n return;\n }\n browserConsole?.log?.(message, channelStyle, eventStyle, detailStyle);\n}\n\nfunction emitToPostHog(level: LogLevel, channel: string, event: string, detail: Record<string, unknown>): boolean {\n if (!otelLogger) return false;\n\n const severityText = level === 'warn' ? 'WARNING' : level === 'error' ? 'ERROR' : 'INFO';\n const attributes = flattenAttributes({ channel, ...detail });\n\n otelLogger.emit({\n severityText,\n body: event,\n attributes,\n });\n return true;\n}\n\nfunction emit(level: LogLevel, channel: string, event: string, detail: Record<string, unknown>, options?: LogOptions): void {\n const shouldShip = (options?.shipToPostHog ?? level !== 'info') && isPostHogShippingEnabled();\n // Keep warn/error visible even when regular logs are muted.\n if (level !== 'info' || isConsoleEnabled()) {\n emitConsole(level, channel, event, detail);\n }\n if (shouldShip) {\n const shipped = emitToPostHog(level, channel, event, detail);\n if (!shipped) {\n enqueuePendingPostHogLog({ level, channel, event, detail });\n }\n }\n}\n\nexport function log(channel: string, event: string, detail: Record<string, unknown> = {}, options?: LogOptions): void {\n emit('info', channel, event, detail, options);\n}\n\nexport function warn(channel: string, event: string, detail: Record<string, unknown> = {}, options?: LogOptions): void {\n emit('warn', channel, event, detail, options);\n}\n\nexport function error(channel: string, event: string, detail: Record<string, unknown> = {}, options?: LogOptions): void {\n emit('error', channel, event, detail, options);\n}\n"],"mappings":"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","names":[]}
@@ -1,15 +0,0 @@
1
- import React__default from 'react';
2
- import { F as FormDefinition } from '../../form-C94A_PX_.js';
3
-
4
- interface DynamicFormFieldsProps {
5
- /** Form definition from API (fields array + optional settings). */
6
- form: FormDefinition;
7
- /** For job_application forms: add hidden jobSlug input. */
8
- jobSlug?: string;
9
- /** Optional URLs for ToS/Privacy links in consent checkbox label. */
10
- privacyPolicyUrl?: string;
11
- termsOfServiceUrl?: string;
12
- }
13
- declare function DynamicFormFields({ form, jobSlug, privacyPolicyUrl, termsOfServiceUrl }: DynamicFormFieldsProps): React__default.JSX.Element;
14
-
15
- export { DynamicFormFields, type DynamicFormFieldsProps };