@agent-native/core 0.98.2 → 0.98.3

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 (64) hide show
  1. package/corpus/README.md +2 -2
  2. package/corpus/core/CHANGELOG.md +10 -0
  3. package/corpus/core/package.json +1 -1
  4. package/corpus/core/src/agent/production-agent.ts +2 -2
  5. package/corpus/core/src/client/index.ts +2 -0
  6. package/corpus/core/src/client/settings/DemoModeSection.tsx +6 -6
  7. package/corpus/core/src/client/settings/SettingsPanel.tsx +31 -211
  8. package/corpus/core/src/client/settings/agent-settings-search.ts +219 -0
  9. package/corpus/core/src/client/settings/index.ts +4 -0
  10. package/corpus/core/src/demo/actions/toggle-demo-mode.ts +2 -2
  11. package/corpus/core/src/demo/config.ts +6 -6
  12. package/corpus/core/src/demo/redact.ts +18 -76
  13. package/corpus/templates/analytics/.agents/skills/session-replay/SKILL.md +21 -4
  14. package/corpus/templates/analytics/AGENTS.md +6 -6
  15. package/corpus/templates/analytics/app/components/layout/CommandPalette.tsx +429 -244
  16. package/corpus/templates/analytics/app/components/layout/command-palette-search.ts +93 -0
  17. package/corpus/templates/analytics/app/hooks/use-replay-storage-status.ts +2 -1
  18. package/corpus/templates/analytics/app/lib/demo-chart-trend.ts +46 -33
  19. package/corpus/templates/analytics/app/pages/Settings.tsx +8 -45
  20. package/corpus/templates/analytics/app/pages/sessions/SessionDetailPage.tsx +205 -70
  21. package/corpus/templates/analytics/app/pages/sessions/SessionsPage.tsx +32 -16
  22. package/corpus/templates/analytics/app/pages/settings/settings-search.ts +126 -0
  23. package/corpus/templates/analytics/changelog/2026-07-12-command-menu-loading-placeholders-now-stay-below-available-r.md +6 -0
  24. package/corpus/templates/analytics/changelog/2026-07-12-command-menu-search-now-prioritizes-the-best-match.md +6 -0
  25. package/corpus/templates/analytics/changelog/2026-07-12-demo-charts-preserve-source-movement.md +6 -0
  26. package/corpus/templates/analytics/changelog/2026-07-12-replay-storage-settings-stay-readable-at-narrow-widths.md +6 -0
  27. package/corpus/templates/analytics/changelog/2026-07-12-session-replays-preserve-recorded-styling-and-keep-malformed.md +6 -0
  28. package/dist/agent/production-agent.js +2 -2
  29. package/dist/agent/production-agent.js.map +1 -1
  30. package/dist/client/index.d.ts +1 -1
  31. package/dist/client/index.d.ts.map +1 -1
  32. package/dist/client/index.js +1 -1
  33. package/dist/client/index.js.map +1 -1
  34. package/dist/client/settings/DemoModeSection.d.ts +3 -3
  35. package/dist/client/settings/DemoModeSection.js +4 -4
  36. package/dist/client/settings/DemoModeSection.js.map +1 -1
  37. package/dist/client/settings/SettingsPanel.d.ts.map +1 -1
  38. package/dist/client/settings/SettingsPanel.js +41 -191
  39. package/dist/client/settings/SettingsPanel.js.map +1 -1
  40. package/dist/client/settings/agent-settings-search.d.ts +16 -0
  41. package/dist/client/settings/agent-settings-search.d.ts.map +1 -0
  42. package/dist/client/settings/agent-settings-search.js +178 -0
  43. package/dist/client/settings/agent-settings-search.js.map +1 -0
  44. package/dist/client/settings/index.d.ts +1 -0
  45. package/dist/client/settings/index.d.ts.map +1 -1
  46. package/dist/client/settings/index.js +1 -0
  47. package/dist/client/settings/index.js.map +1 -1
  48. package/dist/collab/routes.d.ts +2 -2
  49. package/dist/collab/struct-routes.d.ts +1 -1
  50. package/dist/demo/actions/toggle-demo-mode.js +2 -2
  51. package/dist/demo/actions/toggle-demo-mode.js.map +1 -1
  52. package/dist/demo/config.js +6 -6
  53. package/dist/demo/config.js.map +1 -1
  54. package/dist/demo/redact.d.ts +7 -5
  55. package/dist/demo/redact.d.ts.map +1 -1
  56. package/dist/demo/redact.js +19 -54
  57. package/dist/demo/redact.js.map +1 -1
  58. package/dist/notifications/routes.d.ts +1 -1
  59. package/dist/progress/routes.d.ts +1 -1
  60. package/dist/provider-api/corpus-jobs.d.ts +2 -2
  61. package/dist/resources/handlers.d.ts +3 -3
  62. package/dist/server/agent-engine-api-key-route.d.ts +1 -1
  63. package/dist/server/transcribe-voice.d.ts +1 -1
  64. package/package.json +2 -2
@@ -0,0 +1,16 @@
1
+ import type { SettingsSearchEntry } from "./SettingsTabsPage.js";
2
+ export type SettingsSectionId = "account" | "llm" | "app-models" | "limits" | "voice" | "demo-mode" | "automations" | "secrets" | "hosting" | "database" | "uploads" | "auth" | "email" | "browser" | "background" | "integrations" | "usage" | "a2a";
3
+ export declare const SETTINGS_SECTION_IDS: Set<SettingsSectionId>;
4
+ export declare const ALL_SETTINGS_SECTIONS: readonly SettingsSectionId[];
5
+ export declare const AGENT_SETTINGS_SECTIONS: readonly SettingsSectionId[];
6
+ export declare const CONNECTION_SETTINGS_SECTIONS: readonly SettingsSectionId[];
7
+ export declare const WORKSPACE_SETTINGS_SECTIONS: readonly SettingsSectionId[];
8
+ export declare function buildSectionSearchEntries(sections: readonly SettingsSectionId[]): SettingsSearchEntry[];
9
+ export interface AgentSettingsSearchTab {
10
+ id: string;
11
+ label: string;
12
+ keywords: string;
13
+ searchEntries?: SettingsSearchEntry[];
14
+ }
15
+ export declare function getAgentSettingsSearchTabs(): AgentSettingsSearchTab[];
16
+ //# sourceMappingURL=agent-settings-search.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"agent-settings-search.d.ts","sourceRoot":"","sources":["../../../src/client/settings/agent-settings-search.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAC;AAEjE,MAAM,MAAM,iBAAiB,GACzB,SAAS,GACT,KAAK,GACL,YAAY,GACZ,QAAQ,GACR,OAAO,GACP,WAAW,GACX,aAAa,GACb,SAAS,GACT,SAAS,GACT,UAAU,GACV,SAAS,GACT,MAAM,GACN,OAAO,GACP,SAAS,GACT,YAAY,GACZ,cAAc,GACd,OAAO,GACP,KAAK,CAAC;AAEV,eAAO,MAAM,oBAAoB,wBAmB/B,CAAC;AAEH,eAAO,MAAM,qBAAqB,EAAE,SAAS,iBAAiB,EAmB7D,CAAC;AAEF,eAAO,MAAM,uBAAuB,EAAE,SAAS,iBAAiB,EAQ/D,CAAC;AAEF,eAAO,MAAM,4BAA4B,EAAE,SAAS,iBAAiB,EAMpE,CAAC;AAEF,eAAO,MAAM,2BAA2B,EAAE,SAAS,iBAAiB,EAOnE,CAAC;AAiFF,wBAAgB,yBAAyB,CACvC,QAAQ,EAAE,SAAS,iBAAiB,EAAE,GACrC,mBAAmB,EAAE,CAWvB;AAED,MAAM,WAAW,sBAAsB;IACrC,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,aAAa,CAAC,EAAE,mBAAmB,EAAE,CAAC;CACvC;AAED,wBAAgB,0BAA0B,IAAI,sBAAsB,EAAE,CA0BrE"}
@@ -0,0 +1,178 @@
1
+ export const SETTINGS_SECTION_IDS = new Set([
2
+ "account",
3
+ "llm",
4
+ "app-models",
5
+ "limits",
6
+ "voice",
7
+ "demo-mode",
8
+ "automations",
9
+ "secrets",
10
+ "hosting",
11
+ "database",
12
+ "uploads",
13
+ "auth",
14
+ "email",
15
+ "browser",
16
+ "background",
17
+ "integrations",
18
+ "usage",
19
+ "a2a",
20
+ ]);
21
+ export const ALL_SETTINGS_SECTIONS = [
22
+ "account",
23
+ "llm",
24
+ "app-models",
25
+ "limits",
26
+ "voice",
27
+ "demo-mode",
28
+ "automations",
29
+ "secrets",
30
+ "hosting",
31
+ "database",
32
+ "uploads",
33
+ "auth",
34
+ "email",
35
+ "browser",
36
+ "background",
37
+ "integrations",
38
+ "usage",
39
+ "a2a",
40
+ ];
41
+ export const AGENT_SETTINGS_SECTIONS = [
42
+ "llm",
43
+ "app-models",
44
+ "limits",
45
+ "voice",
46
+ "automations",
47
+ "background",
48
+ "a2a",
49
+ ];
50
+ export const CONNECTION_SETTINGS_SECTIONS = [
51
+ "secrets",
52
+ "integrations",
53
+ "email",
54
+ "browser",
55
+ "usage",
56
+ ];
57
+ export const WORKSPACE_SETTINGS_SECTIONS = [
58
+ "account",
59
+ "demo-mode",
60
+ "hosting",
61
+ "database",
62
+ "uploads",
63
+ "auth",
64
+ ];
65
+ const SETTINGS_SECTION_SEARCH_META = {
66
+ account: {
67
+ label: "Account",
68
+ keywords: "profile photo avatar identity signed in email name",
69
+ },
70
+ llm: {
71
+ label: "LLM",
72
+ keywords: "model claude gpt openai anthropic gemini api key provider ai engine llm",
73
+ },
74
+ "app-models": {
75
+ label: "App Default Model",
76
+ keywords: "default model provider app template composer",
77
+ },
78
+ limits: {
79
+ label: "Agent Limits",
80
+ keywords: "max iterations budget loop timeout runtime",
81
+ },
82
+ voice: {
83
+ label: "Voice Transcription",
84
+ keywords: "microphone dictation speech to text whisper",
85
+ },
86
+ "demo-mode": {
87
+ label: "Demo mode",
88
+ keywords: "fake data anonymize redact screenshot privacy mask",
89
+ },
90
+ automations: {
91
+ label: "Automations",
92
+ keywords: "triggers scheduled events cron jobs",
93
+ },
94
+ secrets: {
95
+ label: "API Keys & Connections",
96
+ keywords: "secrets credentials tokens api keys environment variables",
97
+ },
98
+ hosting: {
99
+ label: "Hosting",
100
+ keywords: "deploy netlify vercel cloudflare builder nitro",
101
+ },
102
+ database: {
103
+ label: "Database",
104
+ keywords: "postgres sqlite neon supabase turso storage sql pglite",
105
+ },
106
+ uploads: {
107
+ label: "File uploads",
108
+ keywords: "files storage s3 avatars attachments bucket blob",
109
+ },
110
+ auth: {
111
+ label: "Authentication",
112
+ keywords: "login signup oauth google github better auth access sso",
113
+ },
114
+ email: {
115
+ label: "Email",
116
+ keywords: "resend sendgrid smtp transactional notifications reports",
117
+ },
118
+ browser: {
119
+ label: "Browser Automation",
120
+ keywords: "web scraping playwright chrome headless",
121
+ },
122
+ background: {
123
+ label: "Background Agent",
124
+ keywords: "code changes branches builder production async",
125
+ },
126
+ integrations: {
127
+ label: "Integrations",
128
+ keywords: "slack telegram whatsapp discord messaging connect",
129
+ },
130
+ usage: {
131
+ label: "Usage",
132
+ keywords: "tokens cost spend billing consumption",
133
+ },
134
+ a2a: {
135
+ label: "Connected Agents (A2A)",
136
+ keywords: "remote agents protocol a2a connected",
137
+ },
138
+ };
139
+ export function buildSectionSearchEntries(sections) {
140
+ return sections.map((section) => {
141
+ const meta = SETTINGS_SECTION_SEARCH_META[section];
142
+ return {
143
+ id: `section:${section}`,
144
+ label: meta.label,
145
+ keywords: meta.keywords,
146
+ description: meta.description,
147
+ hash: section,
148
+ };
149
+ });
150
+ }
151
+ export function getAgentSettingsSearchTabs() {
152
+ return [
153
+ {
154
+ id: "agent",
155
+ label: "Agent",
156
+ keywords: "agent model llm limits voice automations",
157
+ searchEntries: buildSectionSearchEntries(AGENT_SETTINGS_SECTIONS),
158
+ },
159
+ {
160
+ id: "connections",
161
+ label: "Connections",
162
+ keywords: "connections secrets integrations email browser usage",
163
+ searchEntries: buildSectionSearchEntries(CONNECTION_SETTINGS_SECTIONS),
164
+ },
165
+ {
166
+ id: "organization",
167
+ label: "Organization",
168
+ keywords: "organization org team members invites collaborators",
169
+ },
170
+ {
171
+ id: "workspace",
172
+ label: "Workspace",
173
+ keywords: "workspace account hosting database uploads auth",
174
+ searchEntries: buildSectionSearchEntries(WORKSPACE_SETTINGS_SECTIONS),
175
+ },
176
+ ];
177
+ }
178
+ //# sourceMappingURL=agent-settings-search.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"agent-settings-search.js","sourceRoot":"","sources":["../../../src/client/settings/agent-settings-search.ts"],"names":[],"mappings":"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","sourcesContent":["import type { SettingsSearchEntry } from \"./SettingsTabsPage.js\";\n\nexport type SettingsSectionId =\n | \"account\"\n | \"llm\"\n | \"app-models\"\n | \"limits\"\n | \"voice\"\n | \"demo-mode\"\n | \"automations\"\n | \"secrets\"\n | \"hosting\"\n | \"database\"\n | \"uploads\"\n | \"auth\"\n | \"email\"\n | \"browser\"\n | \"background\"\n | \"integrations\"\n | \"usage\"\n | \"a2a\";\n\nexport const SETTINGS_SECTION_IDS = new Set<SettingsSectionId>([\n \"account\",\n \"llm\",\n \"app-models\",\n \"limits\",\n \"voice\",\n \"demo-mode\",\n \"automations\",\n \"secrets\",\n \"hosting\",\n \"database\",\n \"uploads\",\n \"auth\",\n \"email\",\n \"browser\",\n \"background\",\n \"integrations\",\n \"usage\",\n \"a2a\",\n]);\n\nexport const ALL_SETTINGS_SECTIONS: readonly SettingsSectionId[] = [\n \"account\",\n \"llm\",\n \"app-models\",\n \"limits\",\n \"voice\",\n \"demo-mode\",\n \"automations\",\n \"secrets\",\n \"hosting\",\n \"database\",\n \"uploads\",\n \"auth\",\n \"email\",\n \"browser\",\n \"background\",\n \"integrations\",\n \"usage\",\n \"a2a\",\n];\n\nexport const AGENT_SETTINGS_SECTIONS: readonly SettingsSectionId[] = [\n \"llm\",\n \"app-models\",\n \"limits\",\n \"voice\",\n \"automations\",\n \"background\",\n \"a2a\",\n];\n\nexport const CONNECTION_SETTINGS_SECTIONS: readonly SettingsSectionId[] = [\n \"secrets\",\n \"integrations\",\n \"email\",\n \"browser\",\n \"usage\",\n];\n\nexport const WORKSPACE_SETTINGS_SECTIONS: readonly SettingsSectionId[] = [\n \"account\",\n \"demo-mode\",\n \"hosting\",\n \"database\",\n \"uploads\",\n \"auth\",\n];\n\nconst SETTINGS_SECTION_SEARCH_META: Record<\n SettingsSectionId,\n { label: string; keywords: string; description?: string }\n> = {\n account: {\n label: \"Account\",\n keywords: \"profile photo avatar identity signed in email name\",\n },\n llm: {\n label: \"LLM\",\n keywords:\n \"model claude gpt openai anthropic gemini api key provider ai engine llm\",\n },\n \"app-models\": {\n label: \"App Default Model\",\n keywords: \"default model provider app template composer\",\n },\n limits: {\n label: \"Agent Limits\",\n keywords: \"max iterations budget loop timeout runtime\",\n },\n voice: {\n label: \"Voice Transcription\",\n keywords: \"microphone dictation speech to text whisper\",\n },\n \"demo-mode\": {\n label: \"Demo mode\",\n keywords: \"fake data anonymize redact screenshot privacy mask\",\n },\n automations: {\n label: \"Automations\",\n keywords: \"triggers scheduled events cron jobs\",\n },\n secrets: {\n label: \"API Keys & Connections\",\n keywords: \"secrets credentials tokens api keys environment variables\",\n },\n hosting: {\n label: \"Hosting\",\n keywords: \"deploy netlify vercel cloudflare builder nitro\",\n },\n database: {\n label: \"Database\",\n keywords: \"postgres sqlite neon supabase turso storage sql pglite\",\n },\n uploads: {\n label: \"File uploads\",\n keywords: \"files storage s3 avatars attachments bucket blob\",\n },\n auth: {\n label: \"Authentication\",\n keywords: \"login signup oauth google github better auth access sso\",\n },\n email: {\n label: \"Email\",\n keywords: \"resend sendgrid smtp transactional notifications reports\",\n },\n browser: {\n label: \"Browser Automation\",\n keywords: \"web scraping playwright chrome headless\",\n },\n background: {\n label: \"Background Agent\",\n keywords: \"code changes branches builder production async\",\n },\n integrations: {\n label: \"Integrations\",\n keywords: \"slack telegram whatsapp discord messaging connect\",\n },\n usage: {\n label: \"Usage\",\n keywords: \"tokens cost spend billing consumption\",\n },\n a2a: {\n label: \"Connected Agents (A2A)\",\n keywords: \"remote agents protocol a2a connected\",\n },\n};\n\nexport function buildSectionSearchEntries(\n sections: readonly SettingsSectionId[],\n): SettingsSearchEntry[] {\n return sections.map((section) => {\n const meta = SETTINGS_SECTION_SEARCH_META[section];\n return {\n id: `section:${section}`,\n label: meta.label,\n keywords: meta.keywords,\n description: meta.description,\n hash: section,\n };\n });\n}\n\nexport interface AgentSettingsSearchTab {\n id: string;\n label: string;\n keywords: string;\n searchEntries?: SettingsSearchEntry[];\n}\n\nexport function getAgentSettingsSearchTabs(): AgentSettingsSearchTab[] {\n return [\n {\n id: \"agent\",\n label: \"Agent\",\n keywords: \"agent model llm limits voice automations\",\n searchEntries: buildSectionSearchEntries(AGENT_SETTINGS_SECTIONS),\n },\n {\n id: \"connections\",\n label: \"Connections\",\n keywords: \"connections secrets integrations email browser usage\",\n searchEntries: buildSectionSearchEntries(CONNECTION_SETTINGS_SECTIONS),\n },\n {\n id: \"organization\",\n label: \"Organization\",\n keywords: \"organization org team members invites collaborators\",\n },\n {\n id: \"workspace\",\n label: \"Workspace\",\n keywords: \"workspace account hosting database uploads auth\",\n searchEntries: buildSectionSearchEntries(WORKSPACE_SETTINGS_SECTIONS),\n },\n ];\n}\n"]}
@@ -1,4 +1,5 @@
1
1
  export { SettingsPanel, useAgentSettingsTabs, type SettingsPanelProps, } from "./SettingsPanel.js";
2
+ export { getAgentSettingsSearchTabs, type AgentSettingsSearchTab, } from "./agent-settings-search.js";
2
3
  export { SettingsTabsPage, type SettingsSearchEntry, type SettingsTabItem, type SettingsTabsPageProps, } from "./SettingsTabsPage.js";
3
4
  export { openBuilderConnectPopup, useBuilderConnectFlow, useBuilderStatus, withBuilderConnectTrackingParams, type BuilderConnectFlow, type BuilderConnectFlowOptions, type BuilderConnectStartOptions, type BuilderStatus, type OpenBuilderConnectPopupOptions, } from "./useBuilderStatus.js";
4
5
  export { SecretsSection, type SecretsSectionProps } from "./SecretsSection.js";
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/client/settings/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,aAAa,EACb,oBAAoB,EACpB,KAAK,kBAAkB,GACxB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EACL,gBAAgB,EAChB,KAAK,mBAAmB,EACxB,KAAK,eAAe,EACpB,KAAK,qBAAqB,GAC3B,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EACL,uBAAuB,EACvB,qBAAqB,EACrB,gBAAgB,EAChB,gCAAgC,EAChC,KAAK,kBAAkB,EACvB,KAAK,yBAAyB,EAC9B,KAAK,0BAA0B,EAC/B,KAAK,aAAa,EAClB,KAAK,8BAA8B,GACpC,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EAAE,cAAc,EAAE,KAAK,mBAAmB,EAAE,MAAM,qBAAqB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/client/settings/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,aAAa,EACb,oBAAoB,EACpB,KAAK,kBAAkB,GACxB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EACL,0BAA0B,EAC1B,KAAK,sBAAsB,GAC5B,MAAM,4BAA4B,CAAC;AACpC,OAAO,EACL,gBAAgB,EAChB,KAAK,mBAAmB,EACxB,KAAK,eAAe,EACpB,KAAK,qBAAqB,GAC3B,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EACL,uBAAuB,EACvB,qBAAqB,EACrB,gBAAgB,EAChB,gCAAgC,EAChC,KAAK,kBAAkB,EACvB,KAAK,yBAAyB,EAC9B,KAAK,0BAA0B,EAC/B,KAAK,aAAa,EAClB,KAAK,8BAA8B,GACpC,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EAAE,cAAc,EAAE,KAAK,mBAAmB,EAAE,MAAM,qBAAqB,CAAC"}
@@ -1,4 +1,5 @@
1
1
  export { SettingsPanel, useAgentSettingsTabs, } from "./SettingsPanel.js";
2
+ export { getAgentSettingsSearchTabs, } from "./agent-settings-search.js";
2
3
  export { SettingsTabsPage, } from "./SettingsTabsPage.js";
3
4
  export { openBuilderConnectPopup, useBuilderConnectFlow, useBuilderStatus, withBuilderConnectTrackingParams, } from "./useBuilderStatus.js";
4
5
  export { SecretsSection } from "./SecretsSection.js";
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/client/settings/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,aAAa,EACb,oBAAoB,GAErB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EACL,gBAAgB,GAIjB,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EACL,uBAAuB,EACvB,qBAAqB,EACrB,gBAAgB,EAChB,gCAAgC,GAMjC,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EAAE,cAAc,EAA4B,MAAM,qBAAqB,CAAC","sourcesContent":["export {\n SettingsPanel,\n useAgentSettingsTabs,\n type SettingsPanelProps,\n} from \"./SettingsPanel.js\";\nexport {\n SettingsTabsPage,\n type SettingsSearchEntry,\n type SettingsTabItem,\n type SettingsTabsPageProps,\n} from \"./SettingsTabsPage.js\";\nexport {\n openBuilderConnectPopup,\n useBuilderConnectFlow,\n useBuilderStatus,\n withBuilderConnectTrackingParams,\n type BuilderConnectFlow,\n type BuilderConnectFlowOptions,\n type BuilderConnectStartOptions,\n type BuilderStatus,\n type OpenBuilderConnectPopupOptions,\n} from \"./useBuilderStatus.js\";\nexport { SecretsSection, type SecretsSectionProps } from \"./SecretsSection.js\";\n"]}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/client/settings/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,aAAa,EACb,oBAAoB,GAErB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EACL,0BAA0B,GAE3B,MAAM,4BAA4B,CAAC;AACpC,OAAO,EACL,gBAAgB,GAIjB,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EACL,uBAAuB,EACvB,qBAAqB,EACrB,gBAAgB,EAChB,gCAAgC,GAMjC,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EAAE,cAAc,EAA4B,MAAM,qBAAqB,CAAC","sourcesContent":["export {\n SettingsPanel,\n useAgentSettingsTabs,\n type SettingsPanelProps,\n} from \"./SettingsPanel.js\";\nexport {\n getAgentSettingsSearchTabs,\n type AgentSettingsSearchTab,\n} from \"./agent-settings-search.js\";\nexport {\n SettingsTabsPage,\n type SettingsSearchEntry,\n type SettingsTabItem,\n type SettingsTabsPageProps,\n} from \"./SettingsTabsPage.js\";\nexport {\n openBuilderConnectPopup,\n useBuilderConnectFlow,\n useBuilderStatus,\n withBuilderConnectTrackingParams,\n type BuilderConnectFlow,\n type BuilderConnectFlowOptions,\n type BuilderConnectStartOptions,\n type BuilderStatus,\n type OpenBuilderConnectPopupOptions,\n} from \"./useBuilderStatus.js\";\nexport { SecretsSection, type SecretsSectionProps } from \"./SecretsSection.js\";\n"]}
@@ -26,8 +26,8 @@ export declare const getCollabState: import("h3").EventHandlerWithFetch<import("
26
26
  * Body: { update: string (base64), requestSource?: string }
27
27
  */
28
28
  export declare const postCollabUpdate: import("h3").EventHandlerWithFetch<import("h3").EventHandlerRequest, Promise<{
29
- ok?: undefined;
30
29
  error: string;
30
+ ok?: undefined;
31
31
  } | {
32
32
  error?: undefined;
33
33
  ok: boolean;
@@ -42,8 +42,8 @@ export declare const postCollabUpdate: import("h3").EventHandlerWithFetch<import
42
42
  */
43
43
  export declare const postCollabText: import("h3").EventHandlerWithFetch<import("h3").EventHandlerRequest, Promise<{
44
44
  ok?: undefined;
45
- text?: undefined;
46
45
  error: string;
46
+ text?: undefined;
47
47
  } | {
48
48
  error?: undefined;
49
49
  ok: boolean;
@@ -13,8 +13,8 @@
13
13
  * Body: { json: any, fieldName?: string, type?: "map"|"array", requestSource?: string }
14
14
  */
15
15
  export declare const postCollabJson: import("h3").EventHandlerWithFetch<import("h3").EventHandlerRequest, Promise<{
16
- error: string;
17
16
  ok?: undefined;
17
+ error: string;
18
18
  } | {
19
19
  error?: undefined;
20
20
  ok: boolean;
@@ -2,7 +2,7 @@ import { z } from "zod";
2
2
  import { defineAction } from "../../action.js";
3
3
  import { writeAppState } from "../../application-state/script-helpers.js";
4
4
  export default defineAction({
5
- description: "Turn demo mode on or off. When demo mode is on, the app replaces contact/free-text names, email addresses, and numbers with realistic fake data everywhere — in the UI and in what you (the agent) see — while keeping labels, IDs, dates, and structure intact so everything still works. Use when the user asks to 'hide my data', 'turn on demo mode', 'anonymize this for a screen share / recording', or similar. This is the same toggle as the Demo mode switch in settings.",
5
+ description: "Turn demo mode on or off. When demo mode is on, the app replaces email addresses and numbers with realistic fake data everywhere — in the UI and in what you (the agent) see — while keeping names, free text, labels, IDs, dates, and structure intact so everything still works. Use when the user asks to 'hide my data', 'turn on demo mode', 'anonymize this for a screen share / recording', or similar. This is the same toggle as the Demo mode switch in settings.",
6
6
  schema: z.object({
7
7
  enabled: z
8
8
  .boolean()
@@ -13,7 +13,7 @@ export default defineAction({
13
13
  return {
14
14
  enabled,
15
15
  message: enabled
16
- ? "Demo mode is ON — contact/free-text names, emails, and numbers are now replaced with deterministic fake data everywhere (UI and agent). Labels, IDs, and structure are preserved so everything keeps working."
16
+ ? "Demo mode is ON — emails and numbers are now replaced with deterministic fake data everywhere (UI and agent). Names, free text, labels, IDs, and structure are preserved so everything keeps working."
17
17
  : "Demo mode is OFF — real data is shown again.",
18
18
  };
19
19
  },
@@ -1 +1 @@
1
- {"version":3,"file":"toggle-demo-mode.js","sourceRoot":"","sources":["../../../src/demo/actions/toggle-demo-mode.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAC/C,OAAO,EAAE,aAAa,EAAE,MAAM,2CAA2C,CAAC;AAE1E,eAAe,YAAY,CAAC;IAC1B,WAAW,EACT,qdAAqd;IACvd,MAAM,EAAE,CAAC,CAAC,MAAM,CAAC;QACf,OAAO,EAAE,CAAC;aACP,OAAO,EAAE;aACT,QAAQ,CAAC,kDAAkD,CAAC;KAChE,CAAC;IACF,GAAG,EAAE,KAAK,EAAE,EAAE,OAAO,EAAE,EAAE,EAAE;QACzB,MAAM,aAAa,CAAC,WAAW,EAAE,EAAE,OAAO,EAAE,CAAC,CAAC;QAC9C,OAAO;YACL,OAAO;YACP,OAAO,EAAE,OAAO;gBACd,CAAC,CAAC,+MAA+M;gBACjN,CAAC,CAAC,8CAA8C;SACnD,CAAC;IACJ,CAAC;CACF,CAAC,CAAC","sourcesContent":["import { z } from \"zod\";\n\nimport { defineAction } from \"../../action.js\";\nimport { writeAppState } from \"../../application-state/script-helpers.js\";\n\nexport default defineAction({\n description:\n \"Turn demo mode on or off. When demo mode is on, the app replaces contact/free-text names, email addresses, and numbers with realistic fake data everywhere — in the UI and in what you (the agent) see — while keeping labels, IDs, dates, and structure intact so everything still works. Use when the user asks to 'hide my data', 'turn on demo mode', 'anonymize this for a screen share / recording', or similar. This is the same toggle as the Demo mode switch in settings.\",\n schema: z.object({\n enabled: z\n .boolean()\n .describe(\"true to turn demo mode on, false to turn it off.\"),\n }),\n run: async ({ enabled }) => {\n await writeAppState(\"demo-mode\", { enabled });\n return {\n enabled,\n message: enabled\n ? \"Demo mode is ON — contact/free-text names, emails, and numbers are now replaced with deterministic fake data everywhere (UI and agent). Labels, IDs, and structure are preserved so everything keeps working.\"\n : \"Demo mode is OFF — real data is shown again.\",\n };\n },\n});\n"]}
1
+ {"version":3,"file":"toggle-demo-mode.js","sourceRoot":"","sources":["../../../src/demo/actions/toggle-demo-mode.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAC/C,OAAO,EAAE,aAAa,EAAE,MAAM,2CAA2C,CAAC;AAE1E,eAAe,YAAY,CAAC;IAC1B,WAAW,EACT,6cAA6c;IAC/c,MAAM,EAAE,CAAC,CAAC,MAAM,CAAC;QACf,OAAO,EAAE,CAAC;aACP,OAAO,EAAE;aACT,QAAQ,CAAC,kDAAkD,CAAC;KAChE,CAAC;IACF,GAAG,EAAE,KAAK,EAAE,EAAE,OAAO,EAAE,EAAE,EAAE;QACzB,MAAM,aAAa,CAAC,WAAW,EAAE,EAAE,OAAO,EAAE,CAAC,CAAC;QAC9C,OAAO;YACL,OAAO;YACP,OAAO,EAAE,OAAO;gBACd,CAAC,CAAC,uMAAuM;gBACzM,CAAC,CAAC,8CAA8C;SACnD,CAAC;IACJ,CAAC;CACF,CAAC,CAAC","sourcesContent":["import { z } from \"zod\";\n\nimport { defineAction } from \"../../action.js\";\nimport { writeAppState } from \"../../application-state/script-helpers.js\";\n\nexport default defineAction({\n description:\n \"Turn demo mode on or off. When demo mode is on, the app replaces email addresses and numbers with realistic fake data everywhere — in the UI and in what you (the agent) see — while keeping names, free text, labels, IDs, dates, and structure intact so everything still works. Use when the user asks to 'hide my data', 'turn on demo mode', 'anonymize this for a screen share / recording', or similar. This is the same toggle as the Demo mode switch in settings.\",\n schema: z.object({\n enabled: z\n .boolean()\n .describe(\"true to turn demo mode on, false to turn it off.\"),\n }),\n run: async ({ enabled }) => {\n await writeAppState(\"demo-mode\", { enabled });\n return {\n enabled,\n message: enabled\n ? \"Demo mode is ON — emails and numbers are now replaced with deterministic fake data everywhere (UI and agent). Names, free text, labels, IDs, and structure are preserved so everything keeps working.\"\n : \"Demo mode is OFF — real data is shown again.\",\n };\n },\n});\n"]}
@@ -1,12 +1,12 @@
1
1
  /**
2
2
  * Demo mode gate.
3
3
  *
4
- * Demo mode replaces contact/free-text names, email addresses, and numbers in every action
5
- * result with deterministic fake data — for both the UI and what the agent
6
- * sees while preserving labels, IDs, dates, URLs, and structure so the app
7
- * keeps working. The redaction WALK (see ./redact.ts) is expensive on large
8
- * payloads, so callers MUST gate it behind this function and only walk when it
9
- * returns true.
4
+ * Demo mode replaces email addresses and numbers in every action result with
5
+ * deterministic fake data — for both the UI and what the agent sees — while
6
+ * preserving names, free text, labels, IDs, dates, URLs, and structure so the
7
+ * app keeps working. The redaction WALK (see ./redact.ts) is expensive on
8
+ * large payloads, so callers MUST gate it behind this function and only walk
9
+ * when it returns true.
10
10
  *
11
11
  * This gate itself is intentionally cheap:
12
12
  * - An env-forced deployment (a hosted demo site) short-circuits with zero
@@ -1 +1 @@
1
- {"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/demo/config.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AACH,OAAO,EAAE,YAAY,EAAE,MAAM,wCAAwC,CAAC;AAEtE,MAAM,MAAM,GAAG,KAAK,CAAC;AACrB,MAAM,KAAK,GAAG,IAAI,GAAG,EAA0C,CAAC;AAEhE,oEAAoE;AACpE,MAAM,UAAU,gBAAgB;IAC9B,OAAO,OAAO,CAAC,GAAG,CAAC,SAAS,KAAK,MAAM,CAAC;AAC1C,CAAC;AAED;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,iBAAiB;IACrC,IAAI,gBAAgB,EAAE;QAAE,OAAO,IAAI,CAAC;IACpC,IAAI,CAAC;QACH,IAAI,UAAU,GAAG,GAAG,CAAC;QACrB,IAAI,CAAC;YACH,MAAM,EAAE,mBAAmB,EAAE,GAC3B,MAAM,MAAM,CAAC,8BAA8B,CAAC,CAAC;YAC/C,UAAU,GAAG,mBAAmB,EAAE,IAAI,OAAO,CAAC,GAAG,CAAC,gBAAgB,IAAI,GAAG,CAAC;QAC5E,CAAC;QAAC,MAAM,CAAC;YACP,mEAAmE;QACrE,CAAC;QACD,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QACvB,MAAM,GAAG,GAAG,KAAK,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC;QAClC,IAAI,GAAG,IAAI,GAAG,GAAG,GAAG,CAAC,EAAE,GAAG,MAAM;YAAE,OAAO,GAAG,CAAC,KAAK,CAAC;QACnD,MAAM,KAAK,GAAG,MAAM,YAAY,CAAC,WAAW,CAAC,CAAC;QAC9C,MAAM,OAAO,GAAG,KAAK,EAAE,OAAO,KAAK,IAAI,CAAC;QACxC,KAAK,CAAC,GAAG,CAAC,UAAU,EAAE,EAAE,KAAK,EAAE,OAAO,EAAE,EAAE,EAAE,GAAG,EAAE,CAAC,CAAC;QACnD,OAAO,OAAO,CAAC;IACjB,CAAC;IAAC,MAAM,CAAC;QACP,oEAAoE;QACpE,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC","sourcesContent":["/**\n * Demo mode gate.\n *\n * Demo mode replaces contact/free-text names, email addresses, and numbers in every action\n * result with deterministic fake data — for both the UI and what the agent\n * sees — while preserving labels, IDs, dates, URLs, and structure so the app\n * keeps working. The redaction WALK (see ./redact.ts) is expensive on large\n * payloads, so callers MUST gate it behind this function and only walk when it\n * returns true.\n *\n * This gate itself is intentionally cheap:\n * - An env-forced deployment (a hosted demo site) short-circuits with zero\n * I/O — `DEMO_MODE=true`.\n * - The per-user runtime toggle lives in `application_state` under the\n * `demo-mode` key (`{ enabled: boolean }`), written by the settings UI and\n * the `toggle-demo-mode` agent action. It's read behind a short in-process\n * TTL cache keyed by user, so a tight agent tool-call loop doesn't hit the\n * DB on every result.\n */\nimport { readAppState } from \"../application-state/script-helpers.js\";\n\nconst TTL_MS = 3_000;\nconst cache = new Map<string, { value: boolean; at: number }>();\n\n/** Deployment-wide force (hosted demo site). Zero cost — no I/O. */\nexport function isDemoModeForced(): boolean {\n return process.env.DEMO_MODE === \"true\";\n}\n\n/**\n * Whether demo-mode redaction should run for the current request/user.\n * Cheap by design — safe to call before every action result; the expensive\n * walk only happens when this is true.\n */\nexport async function isDemoModeEnabled(): Promise<boolean> {\n if (isDemoModeForced()) return true;\n try {\n let sessionKey = \"_\";\n try {\n const { getRequestUserEmail } =\n await import(\"../server/request-context.js\");\n sessionKey = getRequestUserEmail() ?? process.env.AGENT_USER_EMAIL ?? \"_\";\n } catch {\n // request-context unavailable (CLI / non-server) — use default key\n }\n const now = Date.now();\n const hit = cache.get(sessionKey);\n if (hit && now - hit.at < TTL_MS) return hit.value;\n const state = await readAppState(\"demo-mode\");\n const enabled = state?.enabled === true;\n cache.set(sessionKey, { value: enabled, at: now });\n return enabled;\n } catch {\n // No request context / DB unavailable — fail closed (no redaction).\n return false;\n }\n}\n"]}
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/demo/config.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AACH,OAAO,EAAE,YAAY,EAAE,MAAM,wCAAwC,CAAC;AAEtE,MAAM,MAAM,GAAG,KAAK,CAAC;AACrB,MAAM,KAAK,GAAG,IAAI,GAAG,EAA0C,CAAC;AAEhE,oEAAoE;AACpE,MAAM,UAAU,gBAAgB;IAC9B,OAAO,OAAO,CAAC,GAAG,CAAC,SAAS,KAAK,MAAM,CAAC;AAC1C,CAAC;AAED;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,iBAAiB;IACrC,IAAI,gBAAgB,EAAE;QAAE,OAAO,IAAI,CAAC;IACpC,IAAI,CAAC;QACH,IAAI,UAAU,GAAG,GAAG,CAAC;QACrB,IAAI,CAAC;YACH,MAAM,EAAE,mBAAmB,EAAE,GAC3B,MAAM,MAAM,CAAC,8BAA8B,CAAC,CAAC;YAC/C,UAAU,GAAG,mBAAmB,EAAE,IAAI,OAAO,CAAC,GAAG,CAAC,gBAAgB,IAAI,GAAG,CAAC;QAC5E,CAAC;QAAC,MAAM,CAAC;YACP,mEAAmE;QACrE,CAAC;QACD,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QACvB,MAAM,GAAG,GAAG,KAAK,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC;QAClC,IAAI,GAAG,IAAI,GAAG,GAAG,GAAG,CAAC,EAAE,GAAG,MAAM;YAAE,OAAO,GAAG,CAAC,KAAK,CAAC;QACnD,MAAM,KAAK,GAAG,MAAM,YAAY,CAAC,WAAW,CAAC,CAAC;QAC9C,MAAM,OAAO,GAAG,KAAK,EAAE,OAAO,KAAK,IAAI,CAAC;QACxC,KAAK,CAAC,GAAG,CAAC,UAAU,EAAE,EAAE,KAAK,EAAE,OAAO,EAAE,EAAE,EAAE,GAAG,EAAE,CAAC,CAAC;QACnD,OAAO,OAAO,CAAC;IACjB,CAAC;IAAC,MAAM,CAAC;QACP,oEAAoE;QACpE,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC","sourcesContent":["/**\n * Demo mode gate.\n *\n * Demo mode replaces email addresses and numbers in every action result with\n * deterministic fake data — for both the UI and what the agent sees — while\n * preserving names, free text, labels, IDs, dates, URLs, and structure so the\n * app keeps working. The redaction WALK (see ./redact.ts) is expensive on\n * large payloads, so callers MUST gate it behind this function and only walk\n * when it returns true.\n *\n * This gate itself is intentionally cheap:\n * - An env-forced deployment (a hosted demo site) short-circuits with zero\n * I/O — `DEMO_MODE=true`.\n * - The per-user runtime toggle lives in `application_state` under the\n * `demo-mode` key (`{ enabled: boolean }`), written by the settings UI and\n * the `toggle-demo-mode` agent action. It's read behind a short in-process\n * TTL cache keyed by user, so a tight agent tool-call loop doesn't hit the\n * DB on every result.\n */\nimport { readAppState } from \"../application-state/script-helpers.js\";\n\nconst TTL_MS = 3_000;\nconst cache = new Map<string, { value: boolean; at: number }>();\n\n/** Deployment-wide force (hosted demo site). Zero cost — no I/O. */\nexport function isDemoModeForced(): boolean {\n return process.env.DEMO_MODE === \"true\";\n}\n\n/**\n * Whether demo-mode redaction should run for the current request/user.\n * Cheap by design — safe to call before every action result; the expensive\n * walk only happens when this is true.\n */\nexport async function isDemoModeEnabled(): Promise<boolean> {\n if (isDemoModeForced()) return true;\n try {\n let sessionKey = \"_\";\n try {\n const { getRequestUserEmail } =\n await import(\"../server/request-context.js\");\n sessionKey = getRequestUserEmail() ?? process.env.AGENT_USER_EMAIL ?? \"_\";\n } catch {\n // request-context unavailable (CLI / non-server) — use default key\n }\n const now = Date.now();\n const hit = cache.get(sessionKey);\n if (hit && now - hit.at < TTL_MS) return hit.value;\n const state = await readAppState(\"demo-mode\");\n const enabled = state?.enabled === true;\n cache.set(sessionKey, { value: enabled, at: now });\n return enabled;\n } catch {\n // No request context / DB unavailable — fail closed (no redaction).\n return false;\n }\n}\n"]}
@@ -1,13 +1,15 @@
1
1
  /**
2
2
  * Pure, dependency-free, deterministic demo-mode redactor.
3
3
  *
4
- * Replaces sensitive values (names, emails, and free numbers) with stable fake
4
+ * Replaces sensitive values (emails and free numbers) with stable fake
5
5
  * substitutes so a demo looks coherent — the same input always maps to the
6
6
  * same fake. Crucially, it NEVER rewrites identifiers, structural tokens, or
7
- * timestamps: under-redaction is safe, corrupting an ID is not. The string
8
- * redactor uses a protect-first strategy (mask IDs with opaque placeholders
9
- * before any transform runs, restore them byte-identical afterwards), and the
10
- * structure-aware walker additionally protects leaf values by key name.
7
+ * timestamps. Names and other free text are deliberately left alone because
8
+ * guessing whether arbitrary text is a person's name is too inaccurate. The
9
+ * string redactor uses a protect-first strategy (mask IDs with opaque
10
+ * placeholders before any transform runs, restore them byte-identical
11
+ * afterwards), and the structure-aware walker additionally protects leaf
12
+ * values by key name.
11
13
  */
12
14
  export interface RedactOptions {
13
15
  salt?: string;
@@ -1 +1 @@
1
- {"version":3,"file":"redact.d.ts","sourceRoot":"","sources":["../../src/demo/redact.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,MAAM,WAAW,aAAa;IAC5B,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAsiBD,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,aAAa,GAAG,MAAM,CAE3E;AA4ID,wBAAgB,cAAc,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,IAAI,CAAC,EAAE,aAAa,GAAG,CAAC,CAGnE;AAED;;;;GAIG;AACH,wBAAgB,8BAA8B,IAAI,IAAI,CAGrD"}
1
+ {"version":3,"file":"redact.d.ts","sourceRoot":"","sources":["../../src/demo/redact.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,MAAM,WAAW,aAAa;IAC5B,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAghBD,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,aAAa,GAAG,MAAM,CAE3E;AAsGD,wBAAgB,cAAc,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,IAAI,CAAC,EAAE,aAAa,GAAG,CAAC,CAGnE;AAED;;;;GAIG;AACH,wBAAgB,8BAA8B,IAAI,IAAI,CAGrD"}
@@ -1,13 +1,15 @@
1
1
  /**
2
2
  * Pure, dependency-free, deterministic demo-mode redactor.
3
3
  *
4
- * Replaces sensitive values (names, emails, and free numbers) with stable fake
4
+ * Replaces sensitive values (emails and free numbers) with stable fake
5
5
  * substitutes so a demo looks coherent — the same input always maps to the
6
6
  * same fake. Crucially, it NEVER rewrites identifiers, structural tokens, or
7
- * timestamps: under-redaction is safe, corrupting an ID is not. The string
8
- * redactor uses a protect-first strategy (mask IDs with opaque placeholders
9
- * before any transform runs, restore them byte-identical afterwards), and the
10
- * structure-aware walker additionally protects leaf values by key name.
7
+ * timestamps. Names and other free text are deliberately left alone because
8
+ * guessing whether arbitrary text is a person's name is too inaccurate. The
9
+ * string redactor uses a protect-first strategy (mask IDs with opaque
10
+ * placeholders before any transform runs, restore them byte-identical
11
+ * afterwards), and the structure-aware walker additionally protects leaf
12
+ * values by key name.
11
13
  */
12
14
  /* ------------------------------------------------------------------ *
13
15
  * Seeded hash + PRNG (xmur3 seed → mulberry32 stream)
@@ -56,7 +58,7 @@ function pick(rng, pool) {
56
58
  * round-trips back through redaction (e.g. you edit a draft that's
57
59
  * already showing fake text, it autosaves, then refetches) it is passed
58
60
  * through UNCHANGED instead of being re-faked into something new. This
59
- * is what stops names/emails drifting on every edit.
61
+ * is what stops emails drifting on every edit.
60
62
  *
61
63
  * Leak-free by construction: no timers, a hard size cap, and lazy TTL purge
62
64
  * on write. Works the same per-tab in the browser and per-process on the
@@ -223,14 +225,6 @@ const LAST_NAMES = [
223
225
  /* ------------------------------------------------------------------ *
224
226
  * Fake value generators (deterministic in value + salt)
225
227
  * ------------------------------------------------------------------ */
226
- function fakeName(original, salt) {
227
- return memoFake("name", original, salt, () => {
228
- const rng = seededRng(`name:${original}`, salt);
229
- const first = pick(rng, FIRST_NAMES);
230
- const last = pick(rng, LAST_NAMES);
231
- return `${first} ${last}`;
232
- });
233
- }
234
228
  // Realistic-looking but safe stand-in domains: real consumer providers (the
235
229
  // local part is fake, so no real mailbox is implied) plus the canonical
236
230
  // reserved fictional-company domains (Contoso/Fabrikam/Northwind), which read
@@ -427,9 +421,6 @@ function unprotect(text, restore) {
427
421
  * Transforms (run only on protected text)
428
422
  * ------------------------------------------------------------------ */
429
423
  const EMAIL_RE = /\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}\b/g;
430
- // 2+ capitalized words (each starts uppercase, allows internal lowercase /
431
- // apostrophes / hyphens). Single-letter middle initials allowed: `Sarah J Connor`.
432
- const FULL_NAME_RE = /\b[A-Z][a-zA-Z'’-]*(?:\s+[A-Z](?:[a-zA-Z'’-]*)?){1,3}\b/g;
433
424
  // A standalone numeric token: optional currency + sign, digits with optional
434
425
  // comma grouping and a single optional decimal part. Bounded so it is NOT
435
426
  // adjacent to a letter (placeholders already removed letter-mixed tokens, but
@@ -438,9 +429,6 @@ const NUMBER_RE = /(^|[^A-Za-z0-9_])([$€£]?)([+-]?)(\d[\d,]*(?:\.\d+)?)(?![A-
438
429
  function transformEmails(text, salt) {
439
430
  return text.replace(EMAIL_RE, (match) => fakeEmail(match, salt));
440
431
  }
441
- function transformNames(text, salt) {
442
- return text.replace(FULL_NAME_RE, (match) => fakeName(match, salt));
443
- }
444
432
  function isProbablyYear(digits) {
445
433
  if (digits.length !== 4)
446
434
  return false;
@@ -475,19 +463,17 @@ function transformNumbers(text, salt) {
475
463
  /* ------------------------------------------------------------------ *
476
464
  * Public: string redactor
477
465
  * ------------------------------------------------------------------ */
478
- function redactDemoStringInternal(text, salt, redactNames) {
466
+ function redactDemoStringInternal(text, salt) {
479
467
  if (typeof text !== "string" || text.length === 0)
480
468
  return text;
481
469
  const { text: masked, restore } = protect(text);
482
470
  let out = masked;
483
471
  out = transformEmails(out, salt);
484
- if (redactNames)
485
- out = transformNames(out, salt);
486
472
  out = transformNumbers(out, salt);
487
473
  return unprotect(out, restore);
488
474
  }
489
475
  export function redactDemoString(text, opts) {
490
- return redactDemoStringInternal(text, opts?.salt ?? "", true);
476
+ return redactDemoStringInternal(text, opts?.salt ?? "");
491
477
  }
492
478
  /* ------------------------------------------------------------------ *
493
479
  * Public: structure-aware redactor
@@ -495,29 +481,11 @@ export function redactDemoString(text, opts) {
495
481
  // Keys whose leaf values must NEVER be transformed (still recurse into nested
496
482
  // objects/arrays under them). Besides ids/urls/timestamps this also covers
497
483
  // code/query-bearing keys (`sql`, `query`, `expression`, `formula`, `code`):
498
- // prose-redacting a SQL string injects fake emails/numbers into it and rewrites
499
- // its leading tokens, producing `syntax error at or near "Henry"` /
500
- // `queries must start with SELECT or WITH`. The query must run untouched; its
501
- // RESULTS are what get redacted so the chart still shows fake values.
484
+ // redacting a SQL string mutates literals and can make the query semantically
485
+ // wrong or invalid. The query must run untouched; its RESULTS are what get
486
+ // redacted so the chart still shows fake values.
502
487
  const PROTECTED_KEY_RE = /^id$|(^|_)id$|Id$|Ids$|uuid|guid|slug|token|secret|password|passwd|apikey|api_key|hash|sha\d*|etag|cursor|nonce|sessionid|messageid|threadid|nodeid|(^|_)key$|keyid|(^|_)ref$|url$|uri$|href$|src$|path$|filename$|mimetype|mime|^sql$|sql$|query|expression|formula|^code$|createdat|updatedat|deletedat|expiresat|timestamp|.+at$|.+_at$/i;
503
- // UI labels and chart/dashboard titles often look like person names ("Maya
504
- // Davis (First-party)", "Clicks by Henry Moore") but are structural labels. Keep
505
- // them stable while still redacting free-text and contact-style person fields.
506
- const LABEL_TEXT_KEY_RE = /^(name|title|label)$/i;
507
488
  const MAX_DEPTH = 64;
508
- function isStandalonePersonNameLabel(text) {
509
- const trimmed = text.trim();
510
- if (!trimmed)
511
- return false;
512
- return /^[A-Z][a-zA-Z'’-]+(?:\s+[A-Z]\.?)?\s+[A-Z][a-zA-Z'’-]+$/.test(trimmed);
513
- }
514
- function shouldRedactNamesForChild(key, entry) {
515
- if (!LABEL_TEXT_KEY_RE.test(key))
516
- return true;
517
- // Preserve structural labels/titles, but do not let common contact-shaped
518
- // fields like `{ name: "Olivia Parker" }` leak real person names.
519
- return typeof entry === "string" ? isStandalonePersonNameLabel(entry) : true;
520
- }
521
489
  function isPlainObject(value) {
522
490
  if (value === null || typeof value !== "object")
523
491
  return false;
@@ -528,9 +496,6 @@ function isPlainObject(value) {
528
496
  const proto = Object.getPrototypeOf(value);
529
497
  return proto === Object.prototype || proto === null;
530
498
  }
531
- function redactDemoStringWithSalt(text, salt, redactNames) {
532
- return redactDemoStringInternal(text, salt, redactNames);
533
- }
534
499
  function redactNumberLeaf(value, salt) {
535
500
  if (!Number.isFinite(value))
536
501
  return value;
@@ -545,14 +510,14 @@ function redactNumberLeaf(value, salt) {
545
510
  return value;
546
511
  return n;
547
512
  }
548
- function walk(value, salt, depth, seen, redactNames) {
513
+ function walk(value, salt, depth, seen) {
549
514
  if (depth > MAX_DEPTH)
550
515
  return value;
551
516
  if (value === null || value === undefined)
552
517
  return value;
553
518
  const t = typeof value;
554
519
  if (t === "string") {
555
- return redactDemoStringWithSalt(value, salt, redactNames);
520
+ return redactDemoStringInternal(value, salt);
556
521
  }
557
522
  if (t === "number") {
558
523
  return redactNumberLeaf(value, salt);
@@ -566,7 +531,7 @@ function walk(value, salt, depth, seen, redactNames) {
566
531
  if (seen.has(value))
567
532
  return value;
568
533
  seen.add(value);
569
- const out = value.map((item) => walk(item, salt, depth + 1, seen, redactNames));
534
+ const out = value.map((item) => walk(item, salt, depth + 1, seen));
570
535
  seen.delete(value);
571
536
  return out;
572
537
  }
@@ -583,7 +548,7 @@ function walk(value, salt, depth, seen, redactNames) {
583
548
  !(entry instanceof Date)) {
584
549
  // Still recurse into nested structures, but the protected key does
585
550
  // not transform its own leaf value.
586
- out[key] = walk(entry, salt, depth + 1, seen, redactNames);
551
+ out[key] = walk(entry, salt, depth + 1, seen);
587
552
  }
588
553
  else {
589
554
  // Leaf under a protected key: pass through completely untouched.
@@ -591,7 +556,7 @@ function walk(value, salt, depth, seen, redactNames) {
591
556
  }
592
557
  continue;
593
558
  }
594
- out[key] = walk(entry, salt, depth + 1, seen, redactNames && shouldRedactNamesForChild(key, entry));
559
+ out[key] = walk(entry, salt, depth + 1, seen);
595
560
  }
596
561
  seen.delete(value);
597
562
  return out;
@@ -601,7 +566,7 @@ function walk(value, salt, depth, seen, redactNames) {
601
566
  }
602
567
  export function redactDemoData(value, opts) {
603
568
  const salt = opts?.salt ?? "";
604
- return walk(value, salt, 0, new WeakSet(), true);
569
+ return walk(value, salt, 0, new WeakSet());
605
570
  }
606
571
  /**
607
572
  * Clear the stable-mapping caches. Test-only — the caches are process-global