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.
- package/README.md +4 -0
- package/package.json +1 -1
- package/src/next/routes/consumer-auth.ts +41 -20
- package/dist/blog-post-vWzW8yFb.d.ts +0 -50
- package/dist/contexts/index.d.ts +0 -13
- package/dist/contexts/index.js +0 -173
- package/dist/contexts/index.js.map +0 -1
- package/dist/design_system/components/DynamicFormFields.d.ts +0 -15
- package/dist/design_system/components/DynamicFormFields.js +0 -5176
- package/dist/design_system/components/DynamicFormFields.js.map +0 -1
- package/dist/design_system/elements/index.d.ts +0 -383
- package/dist/design_system/elements/index.js +0 -4007
- package/dist/design_system/elements/index.js.map +0 -1
- package/dist/design_system/logo/keystone-logo.d.ts +0 -6
- package/dist/design_system/logo/keystone-logo.js +0 -145
- package/dist/design_system/logo/keystone-logo.js.map +0 -1
- package/dist/design_system/sections/index.d.ts +0 -233
- package/dist/design_system/sections/index.js +0 -20048
- package/dist/design_system/sections/index.js.map +0 -1
- package/dist/form-C94A_PX_.d.ts +0 -36
- package/dist/index.d.ts +0 -70
- package/dist/index.js +0 -20608
- package/dist/index.js.map +0 -1
- package/dist/lib/component-registry.d.ts +0 -13
- package/dist/lib/component-registry.js +0 -36
- package/dist/lib/component-registry.js.map +0 -1
- package/dist/lib/hooks/index.d.ts +0 -83
- package/dist/lib/hooks/index.js +0 -182
- package/dist/lib/hooks/index.js.map +0 -1
- package/dist/lib/server-api.d.ts +0 -67
- package/dist/lib/server-api.js +0 -195
- package/dist/lib/server-api.js.map +0 -1
- package/dist/package-DeHKpQp7.d.ts +0 -121
- package/dist/photos-CmBdWiuZ.d.ts +0 -27
- package/dist/themes/index.d.ts +0 -17
- package/dist/themes/index.js +0 -29
- package/dist/themes/index.js.map +0 -1
- package/dist/tracking/index.d.ts +0 -254
- package/dist/tracking/index.js +0 -550
- package/dist/tracking/index.js.map +0 -1
- package/dist/types/index.d.ts +0 -313
- package/dist/types/index.js +0 -1
- package/dist/types/index.js.map +0 -1
- package/dist/utils/cx.d.ts +0 -15
- package/dist/utils/cx.js +0 -18
- package/dist/utils/cx.js.map +0 -1
- package/dist/utils/gradient-placeholder.d.ts +0 -7
- package/dist/utils/gradient-placeholder.js +0 -59
- package/dist/utils/gradient-placeholder.js.map +0 -1
- package/dist/utils/is-react-component.d.ts +0 -21
- package/dist/utils/is-react-component.js +0 -20
- package/dist/utils/is-react-component.js.map +0 -1
- package/dist/utils/markdown-toc.d.ts +0 -14
- package/dist/utils/markdown-toc.js +0 -29
- package/dist/utils/markdown-toc.js.map +0 -1
- package/dist/utils/phone-helpers.d.ts +0 -24
- package/dist/utils/phone-helpers.js +0 -26
- package/dist/utils/phone-helpers.js.map +0 -1
- package/dist/utils/photo-helpers.d.ts +0 -38
- package/dist/utils/photo-helpers.js +0 -41
- package/dist/utils/photo-helpers.js.map +0 -1
- 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
|
@@ -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
|
|
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(`${
|
|
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:
|
|
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(`${
|
|
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
|
-
{
|
|
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:
|
|
207
|
-
first_name:
|
|
208
|
-
last_name:
|
|
209
|
-
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(`${
|
|
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(
|
|
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 =
|
|
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:
|
|
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 };
|
package/dist/contexts/index.d.ts
DELETED
|
@@ -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 };
|
package/dist/contexts/index.js
DELETED
|
@@ -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 };
|