@agent-native/core 0.133.2 → 0.134.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (213) hide show
  1. package/corpus/README.md +2 -2
  2. package/corpus/core/CHANGELOG.md +62 -0
  3. package/corpus/core/docs/content/observability.mdx +41 -1
  4. package/corpus/core/docs/content/tracking.mdx +25 -0
  5. package/corpus/core/package.json +1 -1
  6. package/corpus/core/src/agent/run-manager.ts +7 -0
  7. package/corpus/core/src/client/agent-chat-adapter.ts +10 -0
  8. package/corpus/core/src/client/analytics.ts +105 -1
  9. package/corpus/core/src/client/use-action.ts +6 -0
  10. package/corpus/core/src/deploy/build.ts +38 -1
  11. package/corpus/core/src/observability/posthog-ai.ts +294 -0
  12. package/corpus/core/src/observability/routes.ts +29 -6
  13. package/corpus/core/src/observability/traces.ts +287 -12
  14. package/corpus/core/src/observability/types.ts +11 -0
  15. package/corpus/core/src/secrets/register-framework-secrets.ts +16 -0
  16. package/corpus/core/src/server/agent-run-context.ts +21 -0
  17. package/corpus/core/src/server/capture-error.ts +8 -0
  18. package/corpus/core/src/server/core-routes-plugin.ts +75 -4
  19. package/corpus/core/src/server/deploy-environment.ts +57 -0
  20. package/corpus/core/src/server/error-noise-filter.ts +268 -0
  21. package/corpus/core/src/server/posthog-config.ts +75 -0
  22. package/corpus/core/src/server/request-context.ts +6 -0
  23. package/corpus/core/src/server/sentry-config.ts +4 -8
  24. package/corpus/core/src/server/sentry-plugin.ts +13 -29
  25. package/corpus/core/src/server/sentry.ts +13 -156
  26. package/corpus/core/src/server/ssr-handler.ts +6 -1
  27. package/corpus/core/src/shared/mcp-embed-headers.ts +1 -1
  28. package/corpus/core/src/templates/workspace-core/.agents/skills/observability/SKILL.md +36 -10
  29. package/corpus/core/src/templates/workspace-core/.agents/skills/tracking/SKILL.md +55 -1
  30. package/corpus/core/src/tracking/error-capture.ts +44 -109
  31. package/corpus/core/src/tracking/index.ts +11 -0
  32. package/corpus/core/src/tracking/posthog-exception.ts +305 -0
  33. package/corpus/core/src/tracking/providers.ts +91 -14
  34. package/corpus/core/src/tracking/redaction.ts +105 -0
  35. package/corpus/templates/content/actions/_batch-utils.ts +33 -0
  36. package/corpus/templates/content/actions/_builder-cms-read-client.ts +173 -81
  37. package/corpus/templates/content/actions/_content-files.ts +31 -21
  38. package/corpus/templates/content/actions/_database-source-utils.ts +653 -155
  39. package/corpus/templates/content/actions/_database-utils.ts +535 -41
  40. package/corpus/templates/content/actions/add-content-database-source-field-property.ts +291 -240
  41. package/corpus/templates/content/actions/add-database-item.ts +15 -1
  42. package/corpus/templates/content/actions/attach-content-database-source.ts +156 -58
  43. package/corpus/templates/content/actions/bind-content-database-source-field.ts +2 -2
  44. package/corpus/templates/content/actions/cancel-prepared-builder-source-update.ts +4 -1
  45. package/corpus/templates/content/actions/delete-database-items.ts +8 -2
  46. package/corpus/templates/content/actions/disconnect-content-database-source.ts +2 -2
  47. package/corpus/templates/content/actions/duplicate-database-item.ts +15 -1
  48. package/corpus/templates/content/actions/duplicate-database-items.ts +19 -1
  49. package/corpus/templates/content/actions/execute-builder-source-execution.ts +2 -1
  50. package/corpus/templates/content/actions/get-content-database.ts +12 -64
  51. package/corpus/templates/content/actions/move-database-item.ts +4 -1
  52. package/corpus/templates/content/actions/prepare-builder-source-execution.ts +1 -1
  53. package/corpus/templates/content/actions/prepare-builder-source-review.ts +4 -8
  54. package/corpus/templates/content/actions/preview-content-database-source-attach.ts +92 -0
  55. package/corpus/templates/content/actions/process-builder-body-hydration.ts +2 -1
  56. package/corpus/templates/content/actions/query-content-database-items.ts +64 -0
  57. package/corpus/templates/content/actions/refresh-content-database-source.ts +7 -0
  58. package/corpus/templates/content/actions/review-content-database-source-change-set.ts +1 -1
  59. package/corpus/templates/content/actions/set-content-database-source-write-mode.ts +1 -1
  60. package/corpus/templates/content/actions/stage-builder-revision.ts +1 -1
  61. package/corpus/templates/content/actions/update-content-database-personal-view.ts +29 -3
  62. package/corpus/templates/content/actions/update-content-database-view.ts +1 -1
  63. package/corpus/templates/content/actions/validate-builder-source-execution.ts +1 -1
  64. package/corpus/templates/content/app/components/editor/DocumentProperties.tsx +3 -22
  65. package/corpus/templates/content/app/components/editor/database/DatabaseView.tsx +267 -105
  66. package/corpus/templates/content/app/components/sidebar/DocumentSidebar.tsx +82 -1
  67. package/corpus/templates/content/app/hooks/use-content-database.ts +285 -24
  68. package/corpus/templates/content/app/hooks/use-document-properties.ts +7 -6
  69. package/corpus/templates/content/app/i18n-data.ts +10 -0
  70. package/corpus/templates/content/changelog/2026-07-29-large-databases-keep-useful-rows-visible.md +6 -0
  71. package/corpus/templates/content/changelog/2026-07-30-builder-source-columns-now-appear-immediately-when-connected.md +6 -0
  72. package/corpus/templates/content/changelog/2026-07-30-large-builder-backed-tables-show-useful-rows-sooner-and-fini.md +6 -0
  73. package/corpus/templates/content/changelog/2026-08-01-large-builder-databases-now-show-rows-immediately-and-finish.md +6 -0
  74. package/corpus/templates/content/parity/matrix.md +2 -1
  75. package/corpus/templates/content/parity/matrix.ts +25 -0
  76. package/corpus/templates/content/shared/api.ts +54 -4
  77. package/corpus/templates/content/shared/database-query.ts +359 -0
  78. package/dist/agent/run-manager.d.ts.map +1 -1
  79. package/dist/agent/run-manager.js +7 -0
  80. package/dist/agent/run-manager.js.map +1 -1
  81. package/dist/client/agent-chat-adapter.d.ts.map +1 -1
  82. package/dist/client/agent-chat-adapter.js +12 -0
  83. package/dist/client/agent-chat-adapter.js.map +1 -1
  84. package/dist/client/analytics.d.ts +8 -0
  85. package/dist/client/analytics.d.ts.map +1 -1
  86. package/dist/client/analytics.js +95 -1
  87. package/dist/client/analytics.js.map +1 -1
  88. package/dist/client/use-action.d.ts.map +1 -1
  89. package/dist/client/use-action.js +6 -0
  90. package/dist/client/use-action.js.map +1 -1
  91. package/dist/collab/routes.d.ts +1 -1
  92. package/dist/collab/struct-routes.d.ts +1 -1
  93. package/dist/deploy/build.d.ts.map +1 -1
  94. package/dist/deploy/build.js +38 -1
  95. package/dist/deploy/build.js.map +1 -1
  96. package/dist/file-upload/actions/upload-image.d.ts +1 -1
  97. package/dist/notifications/routes.d.ts +3 -3
  98. package/dist/observability/posthog-ai.d.ts +126 -0
  99. package/dist/observability/posthog-ai.d.ts.map +1 -0
  100. package/dist/observability/posthog-ai.js +190 -0
  101. package/dist/observability/posthog-ai.js.map +1 -0
  102. package/dist/observability/routes.d.ts +1 -1
  103. package/dist/observability/routes.d.ts.map +1 -1
  104. package/dist/observability/routes.js +26 -6
  105. package/dist/observability/routes.js.map +1 -1
  106. package/dist/observability/traces.d.ts +9 -0
  107. package/dist/observability/traces.d.ts.map +1 -1
  108. package/dist/observability/traces.js +219 -10
  109. package/dist/observability/traces.js.map +1 -1
  110. package/dist/observability/types.d.ts +10 -0
  111. package/dist/observability/types.d.ts.map +1 -1
  112. package/dist/observability/types.js +1 -0
  113. package/dist/observability/types.js.map +1 -1
  114. package/dist/secrets/register-framework-secrets.d.ts.map +1 -1
  115. package/dist/secrets/register-framework-secrets.js +14 -0
  116. package/dist/secrets/register-framework-secrets.js.map +1 -1
  117. package/dist/server/agent-run-context.d.ts +8 -0
  118. package/dist/server/agent-run-context.d.ts.map +1 -1
  119. package/dist/server/agent-run-context.js +18 -0
  120. package/dist/server/agent-run-context.js.map +1 -1
  121. package/dist/server/capture-error.d.ts +8 -0
  122. package/dist/server/capture-error.d.ts.map +1 -1
  123. package/dist/server/capture-error.js.map +1 -1
  124. package/dist/server/core-routes-plugin.d.ts +0 -23
  125. package/dist/server/core-routes-plugin.d.ts.map +1 -1
  126. package/dist/server/core-routes-plugin.js +71 -7
  127. package/dist/server/core-routes-plugin.js.map +1 -1
  128. package/dist/server/deploy-environment.d.ts +17 -0
  129. package/dist/server/deploy-environment.d.ts.map +1 -0
  130. package/dist/server/deploy-environment.js +47 -0
  131. package/dist/server/deploy-environment.js.map +1 -0
  132. package/dist/server/error-noise-filter.d.ts +80 -0
  133. package/dist/server/error-noise-filter.d.ts.map +1 -0
  134. package/dist/server/error-noise-filter.js +173 -0
  135. package/dist/server/error-noise-filter.js.map +1 -0
  136. package/dist/server/posthog-config.d.ts +28 -0
  137. package/dist/server/posthog-config.d.ts.map +1 -0
  138. package/dist/server/posthog-config.js +53 -0
  139. package/dist/server/posthog-config.js.map +1 -0
  140. package/dist/server/request-context.d.ts +6 -0
  141. package/dist/server/request-context.d.ts.map +1 -1
  142. package/dist/server/request-context.js.map +1 -1
  143. package/dist/server/sentry-config.d.ts +1 -0
  144. package/dist/server/sentry-config.d.ts.map +1 -1
  145. package/dist/server/sentry-config.js +3 -1
  146. package/dist/server/sentry-config.js.map +1 -1
  147. package/dist/server/sentry-plugin.d.ts.map +1 -1
  148. package/dist/server/sentry-plugin.js +12 -27
  149. package/dist/server/sentry-plugin.js.map +1 -1
  150. package/dist/server/sentry.d.ts.map +1 -1
  151. package/dist/server/sentry.js +8 -124
  152. package/dist/server/sentry.js.map +1 -1
  153. package/dist/server/ssr-handler.d.ts.map +1 -1
  154. package/dist/server/ssr-handler.js +6 -1
  155. package/dist/server/ssr-handler.js.map +1 -1
  156. package/dist/shared/mcp-embed-headers.d.ts +1 -1
  157. package/dist/shared/mcp-embed-headers.d.ts.map +1 -1
  158. package/dist/shared/mcp-embed-headers.js +1 -1
  159. package/dist/shared/mcp-embed-headers.js.map +1 -1
  160. package/dist/templates/workspace-core/.agents/skills/observability/SKILL.md +36 -10
  161. package/dist/templates/workspace-core/.agents/skills/tracking/SKILL.md +55 -1
  162. package/dist/tracking/error-capture.d.ts +7 -0
  163. package/dist/tracking/error-capture.d.ts.map +1 -1
  164. package/dist/tracking/error-capture.js +10 -73
  165. package/dist/tracking/error-capture.js.map +1 -1
  166. package/dist/tracking/index.d.ts +1 -0
  167. package/dist/tracking/index.d.ts.map +1 -1
  168. package/dist/tracking/index.js +1 -0
  169. package/dist/tracking/index.js.map +1 -1
  170. package/dist/tracking/posthog-exception.d.ts +103 -0
  171. package/dist/tracking/posthog-exception.d.ts.map +1 -0
  172. package/dist/tracking/posthog-exception.js +181 -0
  173. package/dist/tracking/posthog-exception.js.map +1 -0
  174. package/dist/tracking/providers.d.ts +14 -0
  175. package/dist/tracking/providers.d.ts.map +1 -1
  176. package/dist/tracking/providers.js +63 -11
  177. package/dist/tracking/providers.js.map +1 -1
  178. package/dist/tracking/redaction.d.ts +25 -0
  179. package/dist/tracking/redaction.d.ts.map +1 -0
  180. package/dist/tracking/redaction.js +85 -0
  181. package/dist/tracking/redaction.js.map +1 -0
  182. package/docs/content/observability.mdx +41 -1
  183. package/docs/content/tracking.mdx +25 -0
  184. package/package.json +1 -1
  185. package/src/agent/run-manager.ts +7 -0
  186. package/src/client/agent-chat-adapter.ts +10 -0
  187. package/src/client/analytics.ts +105 -1
  188. package/src/client/use-action.ts +6 -0
  189. package/src/deploy/build.ts +38 -1
  190. package/src/observability/posthog-ai.ts +294 -0
  191. package/src/observability/routes.ts +29 -6
  192. package/src/observability/traces.ts +287 -12
  193. package/src/observability/types.ts +11 -0
  194. package/src/secrets/register-framework-secrets.ts +16 -0
  195. package/src/server/agent-run-context.ts +21 -0
  196. package/src/server/capture-error.ts +8 -0
  197. package/src/server/core-routes-plugin.ts +75 -4
  198. package/src/server/deploy-environment.ts +57 -0
  199. package/src/server/error-noise-filter.ts +268 -0
  200. package/src/server/posthog-config.ts +75 -0
  201. package/src/server/request-context.ts +6 -0
  202. package/src/server/sentry-config.ts +4 -8
  203. package/src/server/sentry-plugin.ts +13 -29
  204. package/src/server/sentry.ts +13 -156
  205. package/src/server/ssr-handler.ts +6 -1
  206. package/src/shared/mcp-embed-headers.ts +1 -1
  207. package/src/templates/workspace-core/.agents/skills/observability/SKILL.md +36 -10
  208. package/src/templates/workspace-core/.agents/skills/tracking/SKILL.md +55 -1
  209. package/src/tracking/error-capture.ts +44 -109
  210. package/src/tracking/index.ts +11 -0
  211. package/src/tracking/posthog-exception.ts +305 -0
  212. package/src/tracking/providers.ts +91 -14
  213. package/src/tracking/redaction.ts +105 -0
@@ -13,6 +13,7 @@
13
13
  * automatically by the core-routes plugin).
14
14
  */
15
15
 
16
+ import { reshapeTrackedExceptionProperties } from "./posthog-exception.js";
16
17
  import { registerTrackingProvider } from "./registry.js";
17
18
  import type { TrackingProvider, TrackingEvent } from "./types.js";
18
19
 
@@ -162,27 +163,61 @@ function isPostHogAiObservabilityEvent(eventName: string): boolean {
162
163
  return eventName.startsWith("$ai_");
163
164
  }
164
165
 
165
- function createPostHogProvider(apiKey: string, host: string): TrackingProvider {
166
+ /**
167
+ * `$ai_*` and `$exception` are ingested through PostHog's dedicated endpoint
168
+ * rather than `/capture/`, and `$exception` additionally has to carry
169
+ * `$exception_list` — the framework's own `captureException()` emits camelCase
170
+ * fields that PostHog would otherwise render as an empty, ungroupable issue.
171
+ */
172
+ function createPostHogProvider(
173
+ apiKey: string,
174
+ host: string,
175
+ errorTracking: boolean,
176
+ ): TrackingProvider {
177
+ const sendToEventsEndpoint = (
178
+ event: TrackingEvent,
179
+ properties: Record<string, unknown> | undefined,
180
+ distinctId: string,
181
+ ): void => {
182
+ enqueue(
183
+ `${host}/i/v0/e/`,
184
+ JSON.stringify({
185
+ api_key: apiKey,
186
+ event: event.name,
187
+ properties: {
188
+ distinct_id: distinctId,
189
+ ...properties,
190
+ timestamp: event.timestamp,
191
+ },
192
+ }),
193
+ );
194
+ };
195
+
166
196
  return {
167
197
  name: "posthog",
168
198
  track(event: TrackingEvent) {
169
199
  const distinctId = event.userId || "anonymous";
170
200
  if (isPostHogAiObservabilityEvent(event.name)) {
171
- enqueue(
172
- `${host}/i/v0/e/`,
173
- JSON.stringify({
174
- api_key: apiKey,
175
- event: event.name,
176
- properties: {
177
- distinct_id: distinctId,
178
- ...event.properties,
179
- timestamp: event.timestamp,
180
- },
181
- }),
182
- );
201
+ sendToEventsEndpoint(event, event.properties, distinctId);
183
202
  return;
184
203
  }
185
204
 
205
+ if (event.name === "$exception") {
206
+ // `POSTHOG_ERROR_TRACKING=false` keeps product analytics flowing while
207
+ // another backend owns crashes. Drop rather than downgrade to
208
+ // `/capture/`: a malformed exception is what this branch exists to
209
+ // prevent.
210
+ if (!errorTracking) return;
211
+ const reshaped = reshapeTrackedExceptionProperties(event.properties);
212
+ if (reshaped) {
213
+ sendToEventsEndpoint(event, reshaped, distinctId);
214
+ return;
215
+ }
216
+ // No recognizable exception fields. Fall through to `/capture/` so the
217
+ // event is still recorded as-is rather than becoming an issue with
218
+ // nothing in it.
219
+ }
220
+
186
221
  enqueue(
187
222
  `${host}/capture/`,
188
223
  JSON.stringify({
@@ -213,6 +248,42 @@ function createPostHogProvider(apiKey: string, host: string): TrackingProvider {
213
248
  };
214
249
  }
215
250
 
251
+ /**
252
+ * Send one event to PostHog only, bypassing the provider fan-out.
253
+ *
254
+ * For payloads whose *shape* is PostHog-specific and whose *content* other
255
+ * backends must not receive. `track()` broadcasts to every configured provider,
256
+ * so a PostHog-only integration (e.g. enabling a survey id) would otherwise
257
+ * start exporting that integration's content — including user-authored text —
258
+ * to Mixpanel, Amplitude, webhooks, and Agent Native Analytics as a side
259
+ * effect nobody opted into.
260
+ *
261
+ * Returns `false` when PostHog is not configured, so callers can tell "not
262
+ * sent" from "sent".
263
+ */
264
+ export function sendPostHogEvent(
265
+ name: string,
266
+ properties: Record<string, unknown>,
267
+ distinctId: string,
268
+ ): boolean {
269
+ const apiKey = process.env.POSTHOG_API_KEY;
270
+ if (!apiKey) return false;
271
+ const host = (process.env.POSTHOG_HOST || POSTHOG_DEFAULT_HOST).replace(
272
+ /\/+$/,
273
+ "",
274
+ );
275
+ enqueue(
276
+ `${host}/capture/`,
277
+ JSON.stringify({
278
+ api_key: apiKey,
279
+ event: name,
280
+ distinct_id: distinctId,
281
+ properties: { ...properties, timestamp: new Date().toISOString() },
282
+ }),
283
+ );
284
+ return true;
285
+ }
286
+
216
287
  // ─── Mixpanel ──────────────────────────────────────────────────────────────
217
288
 
218
289
  function createMixpanelProvider(token: string): TrackingProvider {
@@ -383,7 +454,13 @@ export function registerBuiltinProviders(): void {
383
454
  /\/+$/,
384
455
  "",
385
456
  );
386
- registerTrackingProvider(createPostHogProvider(posthogKey, host));
457
+ registerTrackingProvider(
458
+ createPostHogProvider(
459
+ posthogKey,
460
+ host,
461
+ process.env.POSTHOG_ERROR_TRACKING?.trim().toLowerCase() !== "false",
462
+ ),
463
+ );
387
464
  }
388
465
 
389
466
  const mixpanelToken = process.env.MIXPANEL_TOKEN;
@@ -0,0 +1,105 @@
1
+ /**
2
+ * Bounding and redaction helpers shared by every exception emitter.
3
+ *
4
+ * Kept free of `process.env` and Node built-ins so the browser bundle can use
5
+ * the same rules — an exception shaped one way on the server and another way
6
+ * in the client is how a leak ships in only one of them.
7
+ */
8
+
9
+ export const MAX_MESSAGE_LENGTH = 1000;
10
+ export const MAX_STACK_LENGTH = 8000;
11
+ export const MAX_TAGS = 30;
12
+ export const MAX_EXTRA_KEYS = 30;
13
+ export const MAX_EXTRA_VALUE_LENGTH = 1000;
14
+
15
+ const SECRET_RE = /\b(?:bearer|basic)\s+[^\s]+/gi;
16
+
17
+ export const SECRET_KEY_RE =
18
+ /(?:authorization|cookie|set[-_]?cookie|token|secret|password|passwd|pwd|api[-_]?key|apikey|credential)/i;
19
+
20
+ export function redact(value: string): string {
21
+ return value
22
+ .replace(SECRET_RE, (match) => `${match.split(/\s+/, 1)[0]} <redacted>`)
23
+ .replace(
24
+ /([A-Za-z0-9_$.-]*(?:authorization|cookie|token|secret|password|passwd|pwd|api[-_]?key|apikey|credential)[A-Za-z0-9_$.-]*\s*[:=]\s*)([^\s,;}]+)/gi,
25
+ "$1<redacted>",
26
+ );
27
+ }
28
+
29
+ export function boundedText(value: unknown, max: number): string {
30
+ const text = typeof value === "string" ? value : String(value ?? "");
31
+ const safe = redact(text);
32
+ return safe.length > max ? safe.slice(0, max) : safe;
33
+ }
34
+
35
+ export function safeValue(value: unknown, depth = 2): unknown {
36
+ if (
37
+ value == null ||
38
+ typeof value === "boolean" ||
39
+ typeof value === "number"
40
+ ) {
41
+ return value;
42
+ }
43
+ if (typeof value === "string")
44
+ return boundedText(value, MAX_EXTRA_VALUE_LENGTH);
45
+ if (depth <= 0) return boundedText(value, MAX_EXTRA_VALUE_LENGTH);
46
+ if (Array.isArray(value)) {
47
+ return value.slice(0, 20).map((item) => safeValue(item, depth - 1));
48
+ }
49
+ if (typeof value === "object") {
50
+ const out: Record<string, unknown> = {};
51
+ for (const [key, child] of Object.entries(value)) {
52
+ if (Object.keys(out).length >= MAX_EXTRA_KEYS) break;
53
+ const safeKey = boundedText(key, 100);
54
+ out[safeKey] = SECRET_KEY_RE.test(safeKey)
55
+ ? "<redacted>"
56
+ : safeValue(child, depth - 1);
57
+ }
58
+ return out;
59
+ }
60
+ return boundedText(value, MAX_EXTRA_VALUE_LENGTH);
61
+ }
62
+
63
+ export function safeTags(
64
+ tags: Record<string, string | undefined> | undefined,
65
+ ): Record<string, string> {
66
+ const out: Record<string, string> = {};
67
+ for (const [key, value] of Object.entries(tags ?? {})) {
68
+ if (Object.keys(out).length >= MAX_TAGS) break;
69
+ // Skip, don't stop: callers build tag objects with optional entries
70
+ // (`{ ...tags, route, method, userAgent }`), so breaking on the first
71
+ // undefined dropped every tag after it depending on key order.
72
+ if (value == null) continue;
73
+ const safeKey = boundedText(key, 100);
74
+ out[safeKey] = SECRET_KEY_RE.test(safeKey)
75
+ ? "<redacted>"
76
+ : boundedText(value, 200);
77
+ }
78
+ return out;
79
+ }
80
+
81
+ export interface ExceptionParts {
82
+ type: string;
83
+ message: string;
84
+ stack?: string;
85
+ }
86
+
87
+ /** Split an unknown thrown value into bounded, redacted type/message/stack. */
88
+ export function exceptionParts(error: unknown): ExceptionParts {
89
+ if (error instanceof Error) {
90
+ return {
91
+ type: boundedText(error.name || "Error", 200),
92
+ message: boundedText(
93
+ error.message || error.name || "Error",
94
+ MAX_MESSAGE_LENGTH,
95
+ ),
96
+ ...(error.stack
97
+ ? { stack: boundedText(error.stack, MAX_STACK_LENGTH) }
98
+ : {}),
99
+ };
100
+ }
101
+ return {
102
+ type: "Error",
103
+ message: boundedText(error, MAX_MESSAGE_LENGTH),
104
+ };
105
+ }