@topolo/sdk 0.21.4 → 0.22.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.
package/dist/index.cjs CHANGED
@@ -52,6 +52,7 @@ __export(index_exports, {
52
52
  canonicalTopoloRequestId: () => canonicalTopoloRequestId,
53
53
  canonicalTopoloRequired: () => canonicalTopoloRequired,
54
54
  canonicalTopoloRetryAfter: () => canonicalTopoloRetryAfter,
55
+ canonicalTopoloServiceErrorCode: () => canonicalTopoloServiceErrorCode,
55
56
  canonicalizeActorEnvelope: () => canonicalizeActorEnvelope,
56
57
  compactActionCatalogEntry: () => compactActionCatalogEntry,
57
58
  compactActionPlan: () => compactActionPlan,
@@ -75,6 +76,7 @@ __export(index_exports, {
75
76
  enrichActionContract: () => enrichActionContract,
76
77
  extractTopoloServiceErrorCode: () => extractTopoloServiceErrorCode,
77
78
  extractTopoloServiceErrorDetails: () => extractTopoloServiceErrorDetails,
79
+ extractTopoloServiceErrorMessage: () => extractTopoloServiceErrorMessage,
78
80
  formatDirectoryApplicationIds: () => formatDirectoryApplicationIds,
79
81
  friendlyAppId: () => friendlyAppId,
80
82
  isTopoloWidgetOutputSchema: () => isTopoloWidgetOutputSchema,
@@ -89,6 +91,7 @@ __export(index_exports, {
89
91
  resolveApplicationDirectoryEntry: () => resolveApplicationDirectoryEntry,
90
92
  resolveCatalogServiceUrl: () => resolveCatalogServiceUrl,
91
93
  resolveServiceUrl: () => resolveServiceUrl,
94
+ sanitizeTopoloServiceMessage: () => sanitizeTopoloServiceMessage,
92
95
  sha256CanonicalValue: () => sha256CanonicalValue,
93
96
  topoloErrorHint: () => topoloErrorHint,
94
97
  topoloServiceOrigins: () => topoloServiceOrigins,
@@ -173,6 +176,9 @@ var PUBLIC_ERROR_CODES = /* @__PURE__ */ new Set([
173
176
  "unknown_service"
174
177
  ]);
175
178
  var ERROR_CODE_PATTERN = /^[a-z][a-z0-9_]{0,63}$/;
179
+ var SERVICE_ERROR_CODE_PATTERN = /^[a-z][a-z0-9]*(?:_[a-z][a-z0-9]*){1,9}$/;
180
+ var SERVICE_MESSAGE_MAX_LENGTH = 300;
181
+ var SERVICE_ISSUE_LIMIT = 32;
176
182
  var TOPOLO_REQUEST_ID_PATTERN = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
177
183
  var CLOUDFLARE_RAY_ID_PATTERN = /^[0-9a-f]{16}-[A-Z]{3}$/;
178
184
  var PERMISSION_PATTERN = /^[a-z][a-z0-9_-]{0,63}(?:\.[a-z][a-z0-9_-]{0,63})*:(?:[a-z][a-z0-9_-]{0,63}|\*)$/;
@@ -197,6 +203,24 @@ function canonicalTopoloErrorCode(value) {
197
203
  if (!ERROR_CODE_PATTERN.test(candidate) || !PUBLIC_ERROR_CODES.has(candidate)) return null;
198
204
  return candidate;
199
205
  }
206
+ function canonicalTopoloServiceErrorCode(value) {
207
+ const platform = canonicalTopoloErrorCode(value);
208
+ if (platform) return platform;
209
+ if (typeof value !== "string") return null;
210
+ const candidate = value.trim();
211
+ if (candidate.length > 64 || !SERVICE_ERROR_CODE_PATTERN.test(candidate)) return null;
212
+ const wordLike = candidate.split("_").every((segment) => {
213
+ const digits = segment.replace(/[a-z]/g, "").length;
214
+ return digits === 0 || digits < segment.length - digits && segment.length <= 8;
215
+ });
216
+ return wordLike ? candidate : null;
217
+ }
218
+ function sanitizeTopoloServiceMessage(value) {
219
+ if (typeof value !== "string") return void 0;
220
+ const text2 = value.replace(/[\u0000-\u001f\u007f-\u009f\u200b-\u200f\u2028-\u202e\u2066-\u2069\ufeff]/g, " ").replace(/\b[a-z][a-z0-9+.-]*:\/\/\S+/gi, "[url]").replace(/[^\s@<>()[\],;:"']+@[^\s@<>()[\],;:"']+\.[a-z]{2,}/gi, "[email]").replace(/[A-Za-z0-9_\-+/=.]{20,}/g, (run) => /[0-9]/.test(run) && /[A-Za-z]/.test(run) ? "[redacted]" : run).replace(/\s+/g, " ").trim();
221
+ if (!text2) return void 0;
222
+ return text2.length > SERVICE_MESSAGE_MAX_LENGTH ? `${text2.slice(0, SERVICE_MESSAGE_MAX_LENGTH - 1).trimEnd()}\u2026` : text2;
223
+ }
200
224
  function canonicalTopoloRequestId(value) {
201
225
  if (typeof value !== "string") return void 0;
202
226
  const candidate = value.trim();
@@ -221,7 +245,7 @@ var TopoloAuthError = class extends TopoloSdkError {
221
245
  retryAfter;
222
246
  details;
223
247
  constructor(message, code = "auth_error", options = {}) {
224
- super(canonicalTopoloErrorCode(code) ?? "auth_error", message);
248
+ super(canonicalTopoloServiceErrorCode(code) ?? "auth_error", message);
225
249
  this.name = "TopoloAuthError";
226
250
  this.status = options.status ?? 401;
227
251
  this.body = options.body;
@@ -245,7 +269,7 @@ var TopoloPermissionError = class extends TopoloSdkError {
245
269
  details;
246
270
  constructor(message, required, options = {}) {
247
271
  super(
248
- canonicalTopoloErrorCode(options.code) ?? serviceErrorCode(options.body, "permission_denied"),
272
+ canonicalTopoloServiceErrorCode(options.code) ?? serviceErrorCode(options.body, "permission_denied"),
249
273
  message
250
274
  );
251
275
  this.name = "TopoloPermissionError";
@@ -264,18 +288,34 @@ var TopoloPermissionError = class extends TopoloSdkError {
264
288
  function extractTopoloServiceErrorCode(body) {
265
289
  if (!body || typeof body !== "object" || Array.isArray(body)) return null;
266
290
  const record2 = body;
267
- const topLevel = canonicalTopoloErrorCode(record2.code);
291
+ const topLevel = canonicalTopoloServiceErrorCode(record2.code);
268
292
  if (topLevel) return topLevel;
269
293
  const nested = record2.error;
270
- const nestedString = canonicalTopoloErrorCode(nested);
294
+ const nestedString = canonicalTopoloServiceErrorCode(nested);
271
295
  if (nestedString) return nestedString;
272
296
  if (nested && typeof nested === "object" && !Array.isArray(nested)) {
273
297
  const code = nested.code;
274
- const nestedCode = canonicalTopoloErrorCode(code);
298
+ const nestedCode = canonicalTopoloServiceErrorCode(code);
275
299
  if (nestedCode) return nestedCode;
276
300
  }
277
301
  return null;
278
302
  }
303
+ function extractTopoloServiceErrorMessage(body) {
304
+ if (!body || typeof body !== "object" || Array.isArray(body)) return void 0;
305
+ const record2 = body;
306
+ const nested = record2.error;
307
+ const candidates = [];
308
+ if (nested && typeof nested === "object" && !Array.isArray(nested)) {
309
+ candidates.push(nested.message);
310
+ }
311
+ candidates.push(record2.message, record2.error_description);
312
+ if (typeof nested === "string" && !canonicalTopoloServiceErrorCode(nested)) candidates.push(nested);
313
+ for (const candidate of candidates) {
314
+ const message = sanitizeTopoloServiceMessage(candidate);
315
+ if (message) return message;
316
+ }
317
+ return void 0;
318
+ }
279
319
  function serviceErrorCode(body, fallback) {
280
320
  return extractTopoloServiceErrorCode(body) ?? fallback;
281
321
  }
@@ -289,10 +329,7 @@ function extractTopoloServiceErrorDetails(body) {
289
329
  if (candidate === void 0) candidate = nestedRecord.details ?? nestedRecord;
290
330
  }
291
331
  if (candidate === void 0) candidate = record2;
292
- if (Array.isArray(candidate)) {
293
- const paths = canonicalTopoloValidationPaths(candidate);
294
- return paths.length ? { paths } : void 0;
295
- }
332
+ if (Array.isArray(candidate)) return validationIssueDetails(canonicalTopoloValidationIssues(candidate)) ?? void 0;
296
333
  if (!candidate || typeof candidate !== "object") return void 0;
297
334
  const source = candidate;
298
335
  const safe = {};
@@ -334,18 +371,59 @@ function extractTopoloServiceErrorDetails(body) {
334
371
  if (paths.length) safe[key] = paths;
335
372
  }
336
373
  }
374
+ const issues = [
375
+ ...Array.isArray(source.issues) ? canonicalTopoloValidationIssues(source.issues) : [],
376
+ ...flattenedValidationIssues(source.formErrors, source.fieldErrors)
377
+ ].slice(0, SERVICE_ISSUE_LIMIT);
378
+ Object.assign(safe, validationIssueDetails(issues));
337
379
  return Object.keys(safe).length ? safe : void 0;
338
380
  }
339
- function canonicalTopoloValidationPaths(issues) {
381
+ function validationIssueDetails(issues) {
382
+ if (!issues.length) return null;
340
383
  const paths = [];
341
- for (const issue of issues) {
342
- if (!issue || typeof issue !== "object" || Array.isArray(issue)) continue;
343
- const record2 = issue;
384
+ for (const issue2 of issues) {
385
+ if (issue2.path && !paths.includes(issue2.path)) paths.push(issue2.path);
386
+ }
387
+ return paths.length ? { paths, issues } : { issues };
388
+ }
389
+ function issue(path, message) {
390
+ const text2 = sanitizeTopoloServiceMessage(message);
391
+ if (!path && !text2) return null;
392
+ return { ...path ? { path } : {}, ...text2 ? { message: text2 } : {} };
393
+ }
394
+ function canonicalTopoloValidationIssues(values) {
395
+ const issues = [];
396
+ for (const value of values) {
397
+ if (!value || typeof value !== "object" || Array.isArray(value)) continue;
398
+ const record2 = value;
344
399
  const path = canonicalTopoloValidationPath(record2.field) ?? canonicalTopoloValidationPath(record2.path);
345
- if (path && !paths.includes(path)) paths.push(path);
346
- if (paths.length === 32) break;
400
+ if (!path) continue;
401
+ const projected = issue(path, record2.message);
402
+ if (projected) issues.push(projected);
403
+ if (issues.length === SERVICE_ISSUE_LIMIT) break;
404
+ }
405
+ return issues;
406
+ }
407
+ function flattenedValidationIssues(formErrors, fieldErrors) {
408
+ const issues = [];
409
+ if (Array.isArray(formErrors)) {
410
+ for (const message of formErrors) {
411
+ const projected = issue(void 0, message);
412
+ if (projected) issues.push(projected);
413
+ }
414
+ }
415
+ if (fieldErrors && typeof fieldErrors === "object" && !Array.isArray(fieldErrors)) {
416
+ for (const [key, messages] of Object.entries(fieldErrors)) {
417
+ const path = canonicalTopoloValidationPath(key);
418
+ if (!path) continue;
419
+ const list = Array.isArray(messages) && messages.length ? messages : [void 0];
420
+ for (const message of list) {
421
+ const projected = issue(path, message);
422
+ if (projected) issues.push(projected);
423
+ }
424
+ }
347
425
  }
348
- return paths;
426
+ return issues;
349
427
  }
350
428
  function canonicalTopoloValidationPath(value) {
351
429
  if (typeof value === "string") {
@@ -367,7 +445,9 @@ function canonicalTopoloValidationPath(value) {
367
445
  return PUBLIC_FIELD_PATH_PATTERN.test(path) ? path : void 0;
368
446
  }
369
447
  function publicTopoloErrorMessage(error) {
370
- const code = canonicalTopoloErrorCode(
448
+ const serviceMessage = typeof error === "string" ? void 0 : extractTopoloServiceErrorMessage(error.body);
449
+ if (serviceMessage) return serviceMessage;
450
+ const code = canonicalTopoloServiceErrorCode(
371
451
  typeof error === "string" ? error : error.code ?? extractTopoloServiceErrorCode(error.body)
372
452
  ) ?? "request_failed";
373
453
  if (/(?:organization|org).*(?:enroll|membership|member|admission)/.test(code)) {
@@ -384,7 +464,7 @@ function publicTopoloErrorMessage(error) {
384
464
  return `Topolo request failed (${code}).`;
385
465
  }
386
466
  function topoloErrorHint(error) {
387
- const code = canonicalTopoloErrorCode(
467
+ const code = canonicalTopoloServiceErrorCode(
388
468
  typeof error === "string" ? error : error.code ?? extractTopoloServiceErrorCode(error.body)
389
469
  );
390
470
  if (!code) return void 0;
@@ -892,8 +972,8 @@ function inspectSchema(schema, path, root, depth) {
892
972
  );
893
973
  for (const [key, child] of children) {
894
974
  if (!isRecord2(child)) continue;
895
- const issue = inspectSchema(child, `${path}.${key}`, root, depth + 1);
896
- if (issue) return issue;
975
+ const issue2 = inspectSchema(child, `${path}.${key}`, root, depth + 1);
976
+ if (issue2) return issue2;
897
977
  }
898
978
  return null;
899
979
  }
@@ -2233,7 +2313,7 @@ var TopoloClient = class _TopoloClient {
2233
2313
  input: selectedInput,
2234
2314
  inputSource: input ? "provided" : example ? "example" : "empty",
2235
2315
  missingFields: [...new Set(
2236
- plan.validation.errors.filter((issue) => issue.code === "required").map((issue) => issue.path)
2316
+ plan.validation.errors.filter((issue2) => issue2.code === "required").map((issue2) => issue2.path)
2237
2317
  )],
2238
2318
  plan
2239
2319
  };
@@ -2298,7 +2378,7 @@ var TopoloClient = class _TopoloClient {
2298
2378
  if (!validation.valid) {
2299
2379
  throw new TopoloSdkError(
2300
2380
  "invalid_action_input",
2301
- `Topolo action "${entry.actionId}" input is invalid: ${validation.errors.map((issue) => `${issue.path} ${issue.message}`).join("; ")}`
2381
+ `Topolo action "${entry.actionId}" input is invalid: ${validation.errors.map((issue2) => `${issue2.path} ${issue2.message}`).join("; ")}`
2302
2382
  );
2303
2383
  }
2304
2384
  const resourceIssue = validateActionResource(entry, options.resource);
@@ -5074,6 +5154,7 @@ function createTopolo(options) {
5074
5154
  canonicalTopoloRequestId,
5075
5155
  canonicalTopoloRequired,
5076
5156
  canonicalTopoloRetryAfter,
5157
+ canonicalTopoloServiceErrorCode,
5077
5158
  canonicalizeActorEnvelope,
5078
5159
  compactActionCatalogEntry,
5079
5160
  compactActionPlan,
@@ -5097,6 +5178,7 @@ function createTopolo(options) {
5097
5178
  enrichActionContract,
5098
5179
  extractTopoloServiceErrorCode,
5099
5180
  extractTopoloServiceErrorDetails,
5181
+ extractTopoloServiceErrorMessage,
5100
5182
  formatDirectoryApplicationIds,
5101
5183
  friendlyAppId,
5102
5184
  isTopoloWidgetOutputSchema,
@@ -5111,6 +5193,7 @@ function createTopolo(options) {
5111
5193
  resolveApplicationDirectoryEntry,
5112
5194
  resolveCatalogServiceUrl,
5113
5195
  resolveServiceUrl,
5196
+ sanitizeTopoloServiceMessage,
5114
5197
  sha256CanonicalValue,
5115
5198
  topoloErrorHint,
5116
5199
  topoloServiceOrigins,
package/dist/index.d.cts CHANGED
@@ -922,6 +922,18 @@ declare class TopoloSdkError extends Error {
922
922
  constructor(code: string, message: string);
923
923
  }
924
924
  declare function canonicalTopoloErrorCode(value: unknown): string | null;
925
+ /**
926
+ * Canonical code for a service's own error body: a platform code, or a
927
+ * service-published enum identifier that cannot carry identity or secret
928
+ * values. Everything else falls back to the caller's generic code.
929
+ */
930
+ declare function canonicalTopoloServiceErrorCode(value: unknown): string | null;
931
+ /**
932
+ * One line of service-authored error text that is safe to show the caller:
933
+ * control and bidirectional characters removed, emails, URLs and token-like
934
+ * runs redacted, and bounded length.
935
+ */
936
+ declare function sanitizeTopoloServiceMessage(value: unknown): string | undefined;
925
937
  declare function canonicalTopoloRequestId(value: unknown): string | undefined;
926
938
  declare function canonicalTopoloRetryAfter(value: unknown): string | undefined;
927
939
  declare function canonicalTopoloRequired(value: unknown): string[];
@@ -957,7 +969,18 @@ interface HttpErrorContext {
957
969
  details?: unknown;
958
970
  }
959
971
  declare function extractTopoloServiceErrorCode(body: unknown): string | null;
972
+ /**
973
+ * The service's own error message from a JSON error body (`error.message`,
974
+ * `message`, a prose `error` string, or OAuth `error_description`), sanitized
975
+ * for display. Non-object bodies such as HTML error pages yield nothing.
976
+ */
977
+ declare function extractTopoloServiceErrorMessage(body: unknown): string | undefined;
960
978
  declare function extractTopoloServiceErrorDetails(body: unknown): unknown;
979
+ /**
980
+ * Caller-facing message: the service's own sanitized message when its error
981
+ * body carries one, otherwise a fixed message derived from the code. The
982
+ * thrown error's `message` is never projected.
983
+ */
961
984
  declare function publicTopoloErrorMessage(error: string | {
962
985
  code?: string;
963
986
  body?: unknown;
@@ -1746,4 +1769,4 @@ declare function createTopolo(options: TopoloClientOptions): {
1746
1769
  };
1747
1770
  type Topolo = ReturnType<typeof createTopolo>;
1748
1771
 
1749
- export { ACTION_CATALOG_DIGEST_ALGORITHM, ACTOR_AUDIT_PROJECTION_VERSION, ACTOR_ENVELOPE_VERSION, type AccountableSubject, type AccountableSubjectType, type ActionContractManifest, type ActionContractSource, type ActorAssurance, type ActorAuditEventRole, type ActorAuditProjection, type ActorChannel, type ActorDelegationHop, type ActorEnvelope, ActorEnvelopeValidationError, type ActorIdentity, type ActorPrincipalType, type AgentIdentity, type AppApiId, type ApplicationCatalogEntry, type ApplicationDeployTarget, type ApplicationDirectory, type ApplicationDirectoryApplication, type ApplicationDirectoryClient, type ApplicationDirectorySource, type ApplicationId, type CredentialIntrospection, type CrmContactSummary, CrmModule, DEFAULT_APP_URLS, type DeviceAuthorizationResponse, type ExternalAgentCredentialIssueInput, type ExternalAgentCredentialIssueResult, IdentityModule, type ListContactsOptions, type ListContactsResult, type OAuthHelperOptions, type P2PActionDetail, type P2PActionRequestInput, type P2PActionRequestResult, type P2PActionRow, type P2PActionRun, type P2PCapability, type P2PConnection, type P2PHold, type P2PLedgerEntry, P2PModule, type P2PPolicy, type P2PPricingModel, type P2PSettlementBatch, type P2PSettlementGroup, type PublishCapabilityInput, type RequestOptions, type ServiceCatalogUrlEntry, TOPOLO_ACTOR_ENVELOPE_HEADER, TOPOLO_ENVIRONMENT_SERVICE_URLS, TOPOLO_RUNTIME_ENVIRONMENTS, TOPOLO_WIDGET_CONTRACT_VERSION, TOPOLO_WIDGET_ENDPOINT, TOPOLO_WIDGET_OUTPUT_SCHEMA, TOPOLO_WIDGET_REFRESH_INTERVAL_MS, type TokenResponse, type Topolo, type TopoloActionAgentContract, type TopoloActionCatalogEntry, type TopoloActionCatalogSummary, type TopoloActionDigestInput, type TopoloActionPlan, type TopoloActionPreparation, type TopoloActionSecretStore, type TopoloActionUploadOptions, type TopoloActionValidationIssue, type TopoloActionValidationResult, type TopoloActionsWidget, type TopoloActivityWidget, type TopoloAgentExecutionContext, type TopoloApiKeyResourceMetadata, TopoloAuthError, type TopoloBinaryResponse, type TopoloBindableResource, type TopoloBindableResourceCatalog, type TopoloChartWidget, TopoloClient, type TopoloClientOptions, TopoloConfirmationRequiredError, type TopoloCredential, type TopoloCredentialRequestContext, type TopoloDebugEvent, TopoloHttpError, type TopoloInlineBase64UploadContract, type TopoloJsonSchema, type TopoloNotificationsWidget, TopoloOAuth, TopoloPermissionError, type TopoloRuntimeEnvironment, TopoloSdkError, type TopoloServiceCatalogEntry, type TopoloStatsWidget, type TopoloWidget, type TopoloWidgetAccessibility, type TopoloWidgetActionBinding, type TopoloWidgetActionRecovery, type TopoloWidgetActivityItem, type TopoloWidgetApiError, type TopoloWidgetApiErrorResponse, type TopoloWidgetApiResponse, type TopoloWidgetApiSuccessResponse, type TopoloWidgetBase, type TopoloWidgetConfig, type TopoloWidgetConfiguration, type TopoloWidgetConfigurationField, type TopoloWidgetConfigurationOption, type TopoloWidgetContext, type TopoloWidgetContribution, type TopoloWidgetDatasetDefinition, type TopoloWidgetDimension, type TopoloWidgetDimensionDefinition, type TopoloWidgetDraft, type TopoloWidgetDrilldown, type TopoloWidgetErrorResponseOptions, type TopoloWidgetEventDefinition, type TopoloWidgetLifecycleStage, type TopoloWidgetLocalization, type TopoloWidgetMetric, type TopoloWidgetMetricAggregation, type TopoloWidgetMetricComparison, type TopoloWidgetMetricDefinition, type TopoloWidgetMetricSemantic, type TopoloWidgetNotificationItem, type TopoloWidgetPeriod, type TopoloWidgetPresentation, type TopoloWidgetRefreshPolicy, type TopoloWidgetResourceBinding, type TopoloWidgetResponseOptions, type TopoloWidgetSeries, type TopoloWidgetSeriesDefinition, type TopoloWidgetSeriesPoint, type TopoloWidgetSize, type TopoloWidgetState, type TopoloWidgetStatus, type TopoloWidgetType, type TopoloWidgetValidationResult, type TopoloWidgetVisualizationFamily, type TopoloWidgetWorkspaceSelector, type TopoloWorkspace, type TopoloWorkspaceListResult, type TopoloWorkspaceMutationResult, type TopoloWorkspacePolicy, WorkspacesModule, actionContractCompleteness, applicationEntryFromCatalog, assertTopoloServiceUrlEnvironment, calculateDpopJkt, canonicalJson, canonicalTopoloErrorCode, canonicalTopoloRequestId, canonicalTopoloRequired, canonicalTopoloRetryAfter, canonicalizeActorEnvelope, compactActionCatalogEntry, compactActionPlan, compactActionPreparation, compactActionResult, compactActionValidation, createDpopProof, createTopolo, createTopoloAgentExecutionContext, createTopoloWidgetError, createTopoloWidgetResponse, decodeActorEnvelopeHeader, defineTopoloActionsWidget, defineTopoloActivityWidget, defineTopoloChartWidget, defineTopoloNotificationsWidget, defineTopoloStatsWidget, digestTopoloActionCatalog, encodeActorEnvelopeHeader, encodeTopoloActionBase64, enrichActionContract, extractTopoloServiceErrorCode, extractTopoloServiceErrorDetails, formatDirectoryApplicationIds, friendlyAppId, isTopoloWidgetOutputSchema, listApplicationDirectory, parseActorEnvelope, parseTopoloActionUploadContract, preferExactActionMatches, prepareTopoloActionBase64UploadInput, prepareTopoloActionUploadInput, projectActorAuditEvent, publicTopoloErrorMessage, resolveApplicationDirectoryEntry, resolveCatalogServiceUrl, resolveServiceUrl, sha256CanonicalValue, topoloErrorHint, topoloServiceOrigins, validateTopoloActionInput, validateTopoloWidgetResponse };
1772
+ export { ACTION_CATALOG_DIGEST_ALGORITHM, ACTOR_AUDIT_PROJECTION_VERSION, ACTOR_ENVELOPE_VERSION, type AccountableSubject, type AccountableSubjectType, type ActionContractManifest, type ActionContractSource, type ActorAssurance, type ActorAuditEventRole, type ActorAuditProjection, type ActorChannel, type ActorDelegationHop, type ActorEnvelope, ActorEnvelopeValidationError, type ActorIdentity, type ActorPrincipalType, type AgentIdentity, type AppApiId, type ApplicationCatalogEntry, type ApplicationDeployTarget, type ApplicationDirectory, type ApplicationDirectoryApplication, type ApplicationDirectoryClient, type ApplicationDirectorySource, type ApplicationId, type CredentialIntrospection, type CrmContactSummary, CrmModule, DEFAULT_APP_URLS, type DeviceAuthorizationResponse, type ExternalAgentCredentialIssueInput, type ExternalAgentCredentialIssueResult, IdentityModule, type ListContactsOptions, type ListContactsResult, type OAuthHelperOptions, type P2PActionDetail, type P2PActionRequestInput, type P2PActionRequestResult, type P2PActionRow, type P2PActionRun, type P2PCapability, type P2PConnection, type P2PHold, type P2PLedgerEntry, P2PModule, type P2PPolicy, type P2PPricingModel, type P2PSettlementBatch, type P2PSettlementGroup, type PublishCapabilityInput, type RequestOptions, type ServiceCatalogUrlEntry, TOPOLO_ACTOR_ENVELOPE_HEADER, TOPOLO_ENVIRONMENT_SERVICE_URLS, TOPOLO_RUNTIME_ENVIRONMENTS, TOPOLO_WIDGET_CONTRACT_VERSION, TOPOLO_WIDGET_ENDPOINT, TOPOLO_WIDGET_OUTPUT_SCHEMA, TOPOLO_WIDGET_REFRESH_INTERVAL_MS, type TokenResponse, type Topolo, type TopoloActionAgentContract, type TopoloActionCatalogEntry, type TopoloActionCatalogSummary, type TopoloActionDigestInput, type TopoloActionPlan, type TopoloActionPreparation, type TopoloActionSecretStore, type TopoloActionUploadOptions, type TopoloActionValidationIssue, type TopoloActionValidationResult, type TopoloActionsWidget, type TopoloActivityWidget, type TopoloAgentExecutionContext, type TopoloApiKeyResourceMetadata, TopoloAuthError, type TopoloBinaryResponse, type TopoloBindableResource, type TopoloBindableResourceCatalog, type TopoloChartWidget, TopoloClient, type TopoloClientOptions, TopoloConfirmationRequiredError, type TopoloCredential, type TopoloCredentialRequestContext, type TopoloDebugEvent, TopoloHttpError, type TopoloInlineBase64UploadContract, type TopoloJsonSchema, type TopoloNotificationsWidget, TopoloOAuth, TopoloPermissionError, type TopoloRuntimeEnvironment, TopoloSdkError, type TopoloServiceCatalogEntry, type TopoloStatsWidget, type TopoloWidget, type TopoloWidgetAccessibility, type TopoloWidgetActionBinding, type TopoloWidgetActionRecovery, type TopoloWidgetActivityItem, type TopoloWidgetApiError, type TopoloWidgetApiErrorResponse, type TopoloWidgetApiResponse, type TopoloWidgetApiSuccessResponse, type TopoloWidgetBase, type TopoloWidgetConfig, type TopoloWidgetConfiguration, type TopoloWidgetConfigurationField, type TopoloWidgetConfigurationOption, type TopoloWidgetContext, type TopoloWidgetContribution, type TopoloWidgetDatasetDefinition, type TopoloWidgetDimension, type TopoloWidgetDimensionDefinition, type TopoloWidgetDraft, type TopoloWidgetDrilldown, type TopoloWidgetErrorResponseOptions, type TopoloWidgetEventDefinition, type TopoloWidgetLifecycleStage, type TopoloWidgetLocalization, type TopoloWidgetMetric, type TopoloWidgetMetricAggregation, type TopoloWidgetMetricComparison, type TopoloWidgetMetricDefinition, type TopoloWidgetMetricSemantic, type TopoloWidgetNotificationItem, type TopoloWidgetPeriod, type TopoloWidgetPresentation, type TopoloWidgetRefreshPolicy, type TopoloWidgetResourceBinding, type TopoloWidgetResponseOptions, type TopoloWidgetSeries, type TopoloWidgetSeriesDefinition, type TopoloWidgetSeriesPoint, type TopoloWidgetSize, type TopoloWidgetState, type TopoloWidgetStatus, type TopoloWidgetType, type TopoloWidgetValidationResult, type TopoloWidgetVisualizationFamily, type TopoloWidgetWorkspaceSelector, type TopoloWorkspace, type TopoloWorkspaceListResult, type TopoloWorkspaceMutationResult, type TopoloWorkspacePolicy, WorkspacesModule, actionContractCompleteness, applicationEntryFromCatalog, assertTopoloServiceUrlEnvironment, calculateDpopJkt, canonicalJson, canonicalTopoloErrorCode, canonicalTopoloRequestId, canonicalTopoloRequired, canonicalTopoloRetryAfter, canonicalTopoloServiceErrorCode, canonicalizeActorEnvelope, compactActionCatalogEntry, compactActionPlan, compactActionPreparation, compactActionResult, compactActionValidation, createDpopProof, createTopolo, createTopoloAgentExecutionContext, createTopoloWidgetError, createTopoloWidgetResponse, decodeActorEnvelopeHeader, defineTopoloActionsWidget, defineTopoloActivityWidget, defineTopoloChartWidget, defineTopoloNotificationsWidget, defineTopoloStatsWidget, digestTopoloActionCatalog, encodeActorEnvelopeHeader, encodeTopoloActionBase64, enrichActionContract, extractTopoloServiceErrorCode, extractTopoloServiceErrorDetails, extractTopoloServiceErrorMessage, formatDirectoryApplicationIds, friendlyAppId, isTopoloWidgetOutputSchema, listApplicationDirectory, parseActorEnvelope, parseTopoloActionUploadContract, preferExactActionMatches, prepareTopoloActionBase64UploadInput, prepareTopoloActionUploadInput, projectActorAuditEvent, publicTopoloErrorMessage, resolveApplicationDirectoryEntry, resolveCatalogServiceUrl, resolveServiceUrl, sanitizeTopoloServiceMessage, sha256CanonicalValue, topoloErrorHint, topoloServiceOrigins, validateTopoloActionInput, validateTopoloWidgetResponse };
package/dist/index.d.ts CHANGED
@@ -922,6 +922,18 @@ declare class TopoloSdkError extends Error {
922
922
  constructor(code: string, message: string);
923
923
  }
924
924
  declare function canonicalTopoloErrorCode(value: unknown): string | null;
925
+ /**
926
+ * Canonical code for a service's own error body: a platform code, or a
927
+ * service-published enum identifier that cannot carry identity or secret
928
+ * values. Everything else falls back to the caller's generic code.
929
+ */
930
+ declare function canonicalTopoloServiceErrorCode(value: unknown): string | null;
931
+ /**
932
+ * One line of service-authored error text that is safe to show the caller:
933
+ * control and bidirectional characters removed, emails, URLs and token-like
934
+ * runs redacted, and bounded length.
935
+ */
936
+ declare function sanitizeTopoloServiceMessage(value: unknown): string | undefined;
925
937
  declare function canonicalTopoloRequestId(value: unknown): string | undefined;
926
938
  declare function canonicalTopoloRetryAfter(value: unknown): string | undefined;
927
939
  declare function canonicalTopoloRequired(value: unknown): string[];
@@ -957,7 +969,18 @@ interface HttpErrorContext {
957
969
  details?: unknown;
958
970
  }
959
971
  declare function extractTopoloServiceErrorCode(body: unknown): string | null;
972
+ /**
973
+ * The service's own error message from a JSON error body (`error.message`,
974
+ * `message`, a prose `error` string, or OAuth `error_description`), sanitized
975
+ * for display. Non-object bodies such as HTML error pages yield nothing.
976
+ */
977
+ declare function extractTopoloServiceErrorMessage(body: unknown): string | undefined;
960
978
  declare function extractTopoloServiceErrorDetails(body: unknown): unknown;
979
+ /**
980
+ * Caller-facing message: the service's own sanitized message when its error
981
+ * body carries one, otherwise a fixed message derived from the code. The
982
+ * thrown error's `message` is never projected.
983
+ */
961
984
  declare function publicTopoloErrorMessage(error: string | {
962
985
  code?: string;
963
986
  body?: unknown;
@@ -1746,4 +1769,4 @@ declare function createTopolo(options: TopoloClientOptions): {
1746
1769
  };
1747
1770
  type Topolo = ReturnType<typeof createTopolo>;
1748
1771
 
1749
- export { ACTION_CATALOG_DIGEST_ALGORITHM, ACTOR_AUDIT_PROJECTION_VERSION, ACTOR_ENVELOPE_VERSION, type AccountableSubject, type AccountableSubjectType, type ActionContractManifest, type ActionContractSource, type ActorAssurance, type ActorAuditEventRole, type ActorAuditProjection, type ActorChannel, type ActorDelegationHop, type ActorEnvelope, ActorEnvelopeValidationError, type ActorIdentity, type ActorPrincipalType, type AgentIdentity, type AppApiId, type ApplicationCatalogEntry, type ApplicationDeployTarget, type ApplicationDirectory, type ApplicationDirectoryApplication, type ApplicationDirectoryClient, type ApplicationDirectorySource, type ApplicationId, type CredentialIntrospection, type CrmContactSummary, CrmModule, DEFAULT_APP_URLS, type DeviceAuthorizationResponse, type ExternalAgentCredentialIssueInput, type ExternalAgentCredentialIssueResult, IdentityModule, type ListContactsOptions, type ListContactsResult, type OAuthHelperOptions, type P2PActionDetail, type P2PActionRequestInput, type P2PActionRequestResult, type P2PActionRow, type P2PActionRun, type P2PCapability, type P2PConnection, type P2PHold, type P2PLedgerEntry, P2PModule, type P2PPolicy, type P2PPricingModel, type P2PSettlementBatch, type P2PSettlementGroup, type PublishCapabilityInput, type RequestOptions, type ServiceCatalogUrlEntry, TOPOLO_ACTOR_ENVELOPE_HEADER, TOPOLO_ENVIRONMENT_SERVICE_URLS, TOPOLO_RUNTIME_ENVIRONMENTS, TOPOLO_WIDGET_CONTRACT_VERSION, TOPOLO_WIDGET_ENDPOINT, TOPOLO_WIDGET_OUTPUT_SCHEMA, TOPOLO_WIDGET_REFRESH_INTERVAL_MS, type TokenResponse, type Topolo, type TopoloActionAgentContract, type TopoloActionCatalogEntry, type TopoloActionCatalogSummary, type TopoloActionDigestInput, type TopoloActionPlan, type TopoloActionPreparation, type TopoloActionSecretStore, type TopoloActionUploadOptions, type TopoloActionValidationIssue, type TopoloActionValidationResult, type TopoloActionsWidget, type TopoloActivityWidget, type TopoloAgentExecutionContext, type TopoloApiKeyResourceMetadata, TopoloAuthError, type TopoloBinaryResponse, type TopoloBindableResource, type TopoloBindableResourceCatalog, type TopoloChartWidget, TopoloClient, type TopoloClientOptions, TopoloConfirmationRequiredError, type TopoloCredential, type TopoloCredentialRequestContext, type TopoloDebugEvent, TopoloHttpError, type TopoloInlineBase64UploadContract, type TopoloJsonSchema, type TopoloNotificationsWidget, TopoloOAuth, TopoloPermissionError, type TopoloRuntimeEnvironment, TopoloSdkError, type TopoloServiceCatalogEntry, type TopoloStatsWidget, type TopoloWidget, type TopoloWidgetAccessibility, type TopoloWidgetActionBinding, type TopoloWidgetActionRecovery, type TopoloWidgetActivityItem, type TopoloWidgetApiError, type TopoloWidgetApiErrorResponse, type TopoloWidgetApiResponse, type TopoloWidgetApiSuccessResponse, type TopoloWidgetBase, type TopoloWidgetConfig, type TopoloWidgetConfiguration, type TopoloWidgetConfigurationField, type TopoloWidgetConfigurationOption, type TopoloWidgetContext, type TopoloWidgetContribution, type TopoloWidgetDatasetDefinition, type TopoloWidgetDimension, type TopoloWidgetDimensionDefinition, type TopoloWidgetDraft, type TopoloWidgetDrilldown, type TopoloWidgetErrorResponseOptions, type TopoloWidgetEventDefinition, type TopoloWidgetLifecycleStage, type TopoloWidgetLocalization, type TopoloWidgetMetric, type TopoloWidgetMetricAggregation, type TopoloWidgetMetricComparison, type TopoloWidgetMetricDefinition, type TopoloWidgetMetricSemantic, type TopoloWidgetNotificationItem, type TopoloWidgetPeriod, type TopoloWidgetPresentation, type TopoloWidgetRefreshPolicy, type TopoloWidgetResourceBinding, type TopoloWidgetResponseOptions, type TopoloWidgetSeries, type TopoloWidgetSeriesDefinition, type TopoloWidgetSeriesPoint, type TopoloWidgetSize, type TopoloWidgetState, type TopoloWidgetStatus, type TopoloWidgetType, type TopoloWidgetValidationResult, type TopoloWidgetVisualizationFamily, type TopoloWidgetWorkspaceSelector, type TopoloWorkspace, type TopoloWorkspaceListResult, type TopoloWorkspaceMutationResult, type TopoloWorkspacePolicy, WorkspacesModule, actionContractCompleteness, applicationEntryFromCatalog, assertTopoloServiceUrlEnvironment, calculateDpopJkt, canonicalJson, canonicalTopoloErrorCode, canonicalTopoloRequestId, canonicalTopoloRequired, canonicalTopoloRetryAfter, canonicalizeActorEnvelope, compactActionCatalogEntry, compactActionPlan, compactActionPreparation, compactActionResult, compactActionValidation, createDpopProof, createTopolo, createTopoloAgentExecutionContext, createTopoloWidgetError, createTopoloWidgetResponse, decodeActorEnvelopeHeader, defineTopoloActionsWidget, defineTopoloActivityWidget, defineTopoloChartWidget, defineTopoloNotificationsWidget, defineTopoloStatsWidget, digestTopoloActionCatalog, encodeActorEnvelopeHeader, encodeTopoloActionBase64, enrichActionContract, extractTopoloServiceErrorCode, extractTopoloServiceErrorDetails, formatDirectoryApplicationIds, friendlyAppId, isTopoloWidgetOutputSchema, listApplicationDirectory, parseActorEnvelope, parseTopoloActionUploadContract, preferExactActionMatches, prepareTopoloActionBase64UploadInput, prepareTopoloActionUploadInput, projectActorAuditEvent, publicTopoloErrorMessage, resolveApplicationDirectoryEntry, resolveCatalogServiceUrl, resolveServiceUrl, sha256CanonicalValue, topoloErrorHint, topoloServiceOrigins, validateTopoloActionInput, validateTopoloWidgetResponse };
1772
+ export { ACTION_CATALOG_DIGEST_ALGORITHM, ACTOR_AUDIT_PROJECTION_VERSION, ACTOR_ENVELOPE_VERSION, type AccountableSubject, type AccountableSubjectType, type ActionContractManifest, type ActionContractSource, type ActorAssurance, type ActorAuditEventRole, type ActorAuditProjection, type ActorChannel, type ActorDelegationHop, type ActorEnvelope, ActorEnvelopeValidationError, type ActorIdentity, type ActorPrincipalType, type AgentIdentity, type AppApiId, type ApplicationCatalogEntry, type ApplicationDeployTarget, type ApplicationDirectory, type ApplicationDirectoryApplication, type ApplicationDirectoryClient, type ApplicationDirectorySource, type ApplicationId, type CredentialIntrospection, type CrmContactSummary, CrmModule, DEFAULT_APP_URLS, type DeviceAuthorizationResponse, type ExternalAgentCredentialIssueInput, type ExternalAgentCredentialIssueResult, IdentityModule, type ListContactsOptions, type ListContactsResult, type OAuthHelperOptions, type P2PActionDetail, type P2PActionRequestInput, type P2PActionRequestResult, type P2PActionRow, type P2PActionRun, type P2PCapability, type P2PConnection, type P2PHold, type P2PLedgerEntry, P2PModule, type P2PPolicy, type P2PPricingModel, type P2PSettlementBatch, type P2PSettlementGroup, type PublishCapabilityInput, type RequestOptions, type ServiceCatalogUrlEntry, TOPOLO_ACTOR_ENVELOPE_HEADER, TOPOLO_ENVIRONMENT_SERVICE_URLS, TOPOLO_RUNTIME_ENVIRONMENTS, TOPOLO_WIDGET_CONTRACT_VERSION, TOPOLO_WIDGET_ENDPOINT, TOPOLO_WIDGET_OUTPUT_SCHEMA, TOPOLO_WIDGET_REFRESH_INTERVAL_MS, type TokenResponse, type Topolo, type TopoloActionAgentContract, type TopoloActionCatalogEntry, type TopoloActionCatalogSummary, type TopoloActionDigestInput, type TopoloActionPlan, type TopoloActionPreparation, type TopoloActionSecretStore, type TopoloActionUploadOptions, type TopoloActionValidationIssue, type TopoloActionValidationResult, type TopoloActionsWidget, type TopoloActivityWidget, type TopoloAgentExecutionContext, type TopoloApiKeyResourceMetadata, TopoloAuthError, type TopoloBinaryResponse, type TopoloBindableResource, type TopoloBindableResourceCatalog, type TopoloChartWidget, TopoloClient, type TopoloClientOptions, TopoloConfirmationRequiredError, type TopoloCredential, type TopoloCredentialRequestContext, type TopoloDebugEvent, TopoloHttpError, type TopoloInlineBase64UploadContract, type TopoloJsonSchema, type TopoloNotificationsWidget, TopoloOAuth, TopoloPermissionError, type TopoloRuntimeEnvironment, TopoloSdkError, type TopoloServiceCatalogEntry, type TopoloStatsWidget, type TopoloWidget, type TopoloWidgetAccessibility, type TopoloWidgetActionBinding, type TopoloWidgetActionRecovery, type TopoloWidgetActivityItem, type TopoloWidgetApiError, type TopoloWidgetApiErrorResponse, type TopoloWidgetApiResponse, type TopoloWidgetApiSuccessResponse, type TopoloWidgetBase, type TopoloWidgetConfig, type TopoloWidgetConfiguration, type TopoloWidgetConfigurationField, type TopoloWidgetConfigurationOption, type TopoloWidgetContext, type TopoloWidgetContribution, type TopoloWidgetDatasetDefinition, type TopoloWidgetDimension, type TopoloWidgetDimensionDefinition, type TopoloWidgetDraft, type TopoloWidgetDrilldown, type TopoloWidgetErrorResponseOptions, type TopoloWidgetEventDefinition, type TopoloWidgetLifecycleStage, type TopoloWidgetLocalization, type TopoloWidgetMetric, type TopoloWidgetMetricAggregation, type TopoloWidgetMetricComparison, type TopoloWidgetMetricDefinition, type TopoloWidgetMetricSemantic, type TopoloWidgetNotificationItem, type TopoloWidgetPeriod, type TopoloWidgetPresentation, type TopoloWidgetRefreshPolicy, type TopoloWidgetResourceBinding, type TopoloWidgetResponseOptions, type TopoloWidgetSeries, type TopoloWidgetSeriesDefinition, type TopoloWidgetSeriesPoint, type TopoloWidgetSize, type TopoloWidgetState, type TopoloWidgetStatus, type TopoloWidgetType, type TopoloWidgetValidationResult, type TopoloWidgetVisualizationFamily, type TopoloWidgetWorkspaceSelector, type TopoloWorkspace, type TopoloWorkspaceListResult, type TopoloWorkspaceMutationResult, type TopoloWorkspacePolicy, WorkspacesModule, actionContractCompleteness, applicationEntryFromCatalog, assertTopoloServiceUrlEnvironment, calculateDpopJkt, canonicalJson, canonicalTopoloErrorCode, canonicalTopoloRequestId, canonicalTopoloRequired, canonicalTopoloRetryAfter, canonicalTopoloServiceErrorCode, canonicalizeActorEnvelope, compactActionCatalogEntry, compactActionPlan, compactActionPreparation, compactActionResult, compactActionValidation, createDpopProof, createTopolo, createTopoloAgentExecutionContext, createTopoloWidgetError, createTopoloWidgetResponse, decodeActorEnvelopeHeader, defineTopoloActionsWidget, defineTopoloActivityWidget, defineTopoloChartWidget, defineTopoloNotificationsWidget, defineTopoloStatsWidget, digestTopoloActionCatalog, encodeActorEnvelopeHeader, encodeTopoloActionBase64, enrichActionContract, extractTopoloServiceErrorCode, extractTopoloServiceErrorDetails, extractTopoloServiceErrorMessage, formatDirectoryApplicationIds, friendlyAppId, isTopoloWidgetOutputSchema, listApplicationDirectory, parseActorEnvelope, parseTopoloActionUploadContract, preferExactActionMatches, prepareTopoloActionBase64UploadInput, prepareTopoloActionUploadInput, projectActorAuditEvent, publicTopoloErrorMessage, resolveApplicationDirectoryEntry, resolveCatalogServiceUrl, resolveServiceUrl, sanitizeTopoloServiceMessage, sha256CanonicalValue, topoloErrorHint, topoloServiceOrigins, validateTopoloActionInput, validateTopoloWidgetResponse };
package/dist/index.js CHANGED
@@ -74,6 +74,9 @@ var PUBLIC_ERROR_CODES = /* @__PURE__ */ new Set([
74
74
  "unknown_service"
75
75
  ]);
76
76
  var ERROR_CODE_PATTERN = /^[a-z][a-z0-9_]{0,63}$/;
77
+ var SERVICE_ERROR_CODE_PATTERN = /^[a-z][a-z0-9]*(?:_[a-z][a-z0-9]*){1,9}$/;
78
+ var SERVICE_MESSAGE_MAX_LENGTH = 300;
79
+ var SERVICE_ISSUE_LIMIT = 32;
77
80
  var TOPOLO_REQUEST_ID_PATTERN = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
78
81
  var CLOUDFLARE_RAY_ID_PATTERN = /^[0-9a-f]{16}-[A-Z]{3}$/;
79
82
  var PERMISSION_PATTERN = /^[a-z][a-z0-9_-]{0,63}(?:\.[a-z][a-z0-9_-]{0,63})*:(?:[a-z][a-z0-9_-]{0,63}|\*)$/;
@@ -98,6 +101,24 @@ function canonicalTopoloErrorCode(value) {
98
101
  if (!ERROR_CODE_PATTERN.test(candidate) || !PUBLIC_ERROR_CODES.has(candidate)) return null;
99
102
  return candidate;
100
103
  }
104
+ function canonicalTopoloServiceErrorCode(value) {
105
+ const platform = canonicalTopoloErrorCode(value);
106
+ if (platform) return platform;
107
+ if (typeof value !== "string") return null;
108
+ const candidate = value.trim();
109
+ if (candidate.length > 64 || !SERVICE_ERROR_CODE_PATTERN.test(candidate)) return null;
110
+ const wordLike = candidate.split("_").every((segment) => {
111
+ const digits = segment.replace(/[a-z]/g, "").length;
112
+ return digits === 0 || digits < segment.length - digits && segment.length <= 8;
113
+ });
114
+ return wordLike ? candidate : null;
115
+ }
116
+ function sanitizeTopoloServiceMessage(value) {
117
+ if (typeof value !== "string") return void 0;
118
+ const text2 = value.replace(/[\u0000-\u001f\u007f-\u009f\u200b-\u200f\u2028-\u202e\u2066-\u2069\ufeff]/g, " ").replace(/\b[a-z][a-z0-9+.-]*:\/\/\S+/gi, "[url]").replace(/[^\s@<>()[\],;:"']+@[^\s@<>()[\],;:"']+\.[a-z]{2,}/gi, "[email]").replace(/[A-Za-z0-9_\-+/=.]{20,}/g, (run) => /[0-9]/.test(run) && /[A-Za-z]/.test(run) ? "[redacted]" : run).replace(/\s+/g, " ").trim();
119
+ if (!text2) return void 0;
120
+ return text2.length > SERVICE_MESSAGE_MAX_LENGTH ? `${text2.slice(0, SERVICE_MESSAGE_MAX_LENGTH - 1).trimEnd()}\u2026` : text2;
121
+ }
101
122
  function canonicalTopoloRequestId(value) {
102
123
  if (typeof value !== "string") return void 0;
103
124
  const candidate = value.trim();
@@ -122,7 +143,7 @@ var TopoloAuthError = class extends TopoloSdkError {
122
143
  retryAfter;
123
144
  details;
124
145
  constructor(message, code = "auth_error", options = {}) {
125
- super(canonicalTopoloErrorCode(code) ?? "auth_error", message);
146
+ super(canonicalTopoloServiceErrorCode(code) ?? "auth_error", message);
126
147
  this.name = "TopoloAuthError";
127
148
  this.status = options.status ?? 401;
128
149
  this.body = options.body;
@@ -146,7 +167,7 @@ var TopoloPermissionError = class extends TopoloSdkError {
146
167
  details;
147
168
  constructor(message, required, options = {}) {
148
169
  super(
149
- canonicalTopoloErrorCode(options.code) ?? serviceErrorCode(options.body, "permission_denied"),
170
+ canonicalTopoloServiceErrorCode(options.code) ?? serviceErrorCode(options.body, "permission_denied"),
150
171
  message
151
172
  );
152
173
  this.name = "TopoloPermissionError";
@@ -165,18 +186,34 @@ var TopoloPermissionError = class extends TopoloSdkError {
165
186
  function extractTopoloServiceErrorCode(body) {
166
187
  if (!body || typeof body !== "object" || Array.isArray(body)) return null;
167
188
  const record2 = body;
168
- const topLevel = canonicalTopoloErrorCode(record2.code);
189
+ const topLevel = canonicalTopoloServiceErrorCode(record2.code);
169
190
  if (topLevel) return topLevel;
170
191
  const nested = record2.error;
171
- const nestedString = canonicalTopoloErrorCode(nested);
192
+ const nestedString = canonicalTopoloServiceErrorCode(nested);
172
193
  if (nestedString) return nestedString;
173
194
  if (nested && typeof nested === "object" && !Array.isArray(nested)) {
174
195
  const code = nested.code;
175
- const nestedCode = canonicalTopoloErrorCode(code);
196
+ const nestedCode = canonicalTopoloServiceErrorCode(code);
176
197
  if (nestedCode) return nestedCode;
177
198
  }
178
199
  return null;
179
200
  }
201
+ function extractTopoloServiceErrorMessage(body) {
202
+ if (!body || typeof body !== "object" || Array.isArray(body)) return void 0;
203
+ const record2 = body;
204
+ const nested = record2.error;
205
+ const candidates = [];
206
+ if (nested && typeof nested === "object" && !Array.isArray(nested)) {
207
+ candidates.push(nested.message);
208
+ }
209
+ candidates.push(record2.message, record2.error_description);
210
+ if (typeof nested === "string" && !canonicalTopoloServiceErrorCode(nested)) candidates.push(nested);
211
+ for (const candidate of candidates) {
212
+ const message = sanitizeTopoloServiceMessage(candidate);
213
+ if (message) return message;
214
+ }
215
+ return void 0;
216
+ }
180
217
  function serviceErrorCode(body, fallback) {
181
218
  return extractTopoloServiceErrorCode(body) ?? fallback;
182
219
  }
@@ -190,10 +227,7 @@ function extractTopoloServiceErrorDetails(body) {
190
227
  if (candidate === void 0) candidate = nestedRecord.details ?? nestedRecord;
191
228
  }
192
229
  if (candidate === void 0) candidate = record2;
193
- if (Array.isArray(candidate)) {
194
- const paths = canonicalTopoloValidationPaths(candidate);
195
- return paths.length ? { paths } : void 0;
196
- }
230
+ if (Array.isArray(candidate)) return validationIssueDetails(canonicalTopoloValidationIssues(candidate)) ?? void 0;
197
231
  if (!candidate || typeof candidate !== "object") return void 0;
198
232
  const source = candidate;
199
233
  const safe = {};
@@ -235,18 +269,59 @@ function extractTopoloServiceErrorDetails(body) {
235
269
  if (paths.length) safe[key] = paths;
236
270
  }
237
271
  }
272
+ const issues = [
273
+ ...Array.isArray(source.issues) ? canonicalTopoloValidationIssues(source.issues) : [],
274
+ ...flattenedValidationIssues(source.formErrors, source.fieldErrors)
275
+ ].slice(0, SERVICE_ISSUE_LIMIT);
276
+ Object.assign(safe, validationIssueDetails(issues));
238
277
  return Object.keys(safe).length ? safe : void 0;
239
278
  }
240
- function canonicalTopoloValidationPaths(issues) {
279
+ function validationIssueDetails(issues) {
280
+ if (!issues.length) return null;
241
281
  const paths = [];
242
- for (const issue of issues) {
243
- if (!issue || typeof issue !== "object" || Array.isArray(issue)) continue;
244
- const record2 = issue;
282
+ for (const issue2 of issues) {
283
+ if (issue2.path && !paths.includes(issue2.path)) paths.push(issue2.path);
284
+ }
285
+ return paths.length ? { paths, issues } : { issues };
286
+ }
287
+ function issue(path, message) {
288
+ const text2 = sanitizeTopoloServiceMessage(message);
289
+ if (!path && !text2) return null;
290
+ return { ...path ? { path } : {}, ...text2 ? { message: text2 } : {} };
291
+ }
292
+ function canonicalTopoloValidationIssues(values) {
293
+ const issues = [];
294
+ for (const value of values) {
295
+ if (!value || typeof value !== "object" || Array.isArray(value)) continue;
296
+ const record2 = value;
245
297
  const path = canonicalTopoloValidationPath(record2.field) ?? canonicalTopoloValidationPath(record2.path);
246
- if (path && !paths.includes(path)) paths.push(path);
247
- if (paths.length === 32) break;
298
+ if (!path) continue;
299
+ const projected = issue(path, record2.message);
300
+ if (projected) issues.push(projected);
301
+ if (issues.length === SERVICE_ISSUE_LIMIT) break;
302
+ }
303
+ return issues;
304
+ }
305
+ function flattenedValidationIssues(formErrors, fieldErrors) {
306
+ const issues = [];
307
+ if (Array.isArray(formErrors)) {
308
+ for (const message of formErrors) {
309
+ const projected = issue(void 0, message);
310
+ if (projected) issues.push(projected);
311
+ }
312
+ }
313
+ if (fieldErrors && typeof fieldErrors === "object" && !Array.isArray(fieldErrors)) {
314
+ for (const [key, messages] of Object.entries(fieldErrors)) {
315
+ const path = canonicalTopoloValidationPath(key);
316
+ if (!path) continue;
317
+ const list = Array.isArray(messages) && messages.length ? messages : [void 0];
318
+ for (const message of list) {
319
+ const projected = issue(path, message);
320
+ if (projected) issues.push(projected);
321
+ }
322
+ }
248
323
  }
249
- return paths;
324
+ return issues;
250
325
  }
251
326
  function canonicalTopoloValidationPath(value) {
252
327
  if (typeof value === "string") {
@@ -268,7 +343,9 @@ function canonicalTopoloValidationPath(value) {
268
343
  return PUBLIC_FIELD_PATH_PATTERN.test(path) ? path : void 0;
269
344
  }
270
345
  function publicTopoloErrorMessage(error) {
271
- const code = canonicalTopoloErrorCode(
346
+ const serviceMessage = typeof error === "string" ? void 0 : extractTopoloServiceErrorMessage(error.body);
347
+ if (serviceMessage) return serviceMessage;
348
+ const code = canonicalTopoloServiceErrorCode(
272
349
  typeof error === "string" ? error : error.code ?? extractTopoloServiceErrorCode(error.body)
273
350
  ) ?? "request_failed";
274
351
  if (/(?:organization|org).*(?:enroll|membership|member|admission)/.test(code)) {
@@ -285,7 +362,7 @@ function publicTopoloErrorMessage(error) {
285
362
  return `Topolo request failed (${code}).`;
286
363
  }
287
364
  function topoloErrorHint(error) {
288
- const code = canonicalTopoloErrorCode(
365
+ const code = canonicalTopoloServiceErrorCode(
289
366
  typeof error === "string" ? error : error.code ?? extractTopoloServiceErrorCode(error.body)
290
367
  );
291
368
  if (!code) return void 0;
@@ -793,8 +870,8 @@ function inspectSchema(schema, path, root, depth) {
793
870
  );
794
871
  for (const [key, child] of children) {
795
872
  if (!isRecord2(child)) continue;
796
- const issue = inspectSchema(child, `${path}.${key}`, root, depth + 1);
797
- if (issue) return issue;
873
+ const issue2 = inspectSchema(child, `${path}.${key}`, root, depth + 1);
874
+ if (issue2) return issue2;
798
875
  }
799
876
  return null;
800
877
  }
@@ -2134,7 +2211,7 @@ var TopoloClient = class _TopoloClient {
2134
2211
  input: selectedInput,
2135
2212
  inputSource: input ? "provided" : example ? "example" : "empty",
2136
2213
  missingFields: [...new Set(
2137
- plan.validation.errors.filter((issue) => issue.code === "required").map((issue) => issue.path)
2214
+ plan.validation.errors.filter((issue2) => issue2.code === "required").map((issue2) => issue2.path)
2138
2215
  )],
2139
2216
  plan
2140
2217
  };
@@ -2199,7 +2276,7 @@ var TopoloClient = class _TopoloClient {
2199
2276
  if (!validation.valid) {
2200
2277
  throw new TopoloSdkError(
2201
2278
  "invalid_action_input",
2202
- `Topolo action "${entry.actionId}" input is invalid: ${validation.errors.map((issue) => `${issue.path} ${issue.message}`).join("; ")}`
2279
+ `Topolo action "${entry.actionId}" input is invalid: ${validation.errors.map((issue2) => `${issue2.path} ${issue2.message}`).join("; ")}`
2203
2280
  );
2204
2281
  }
2205
2282
  const resourceIssue = validateActionResource(entry, options.resource);
@@ -4974,6 +5051,7 @@ export {
4974
5051
  canonicalTopoloRequestId,
4975
5052
  canonicalTopoloRequired,
4976
5053
  canonicalTopoloRetryAfter,
5054
+ canonicalTopoloServiceErrorCode,
4977
5055
  canonicalizeActorEnvelope,
4978
5056
  compactActionCatalogEntry,
4979
5057
  compactActionPlan,
@@ -4997,6 +5075,7 @@ export {
4997
5075
  enrichActionContract,
4998
5076
  extractTopoloServiceErrorCode,
4999
5077
  extractTopoloServiceErrorDetails,
5078
+ extractTopoloServiceErrorMessage,
5000
5079
  formatDirectoryApplicationIds,
5001
5080
  friendlyAppId,
5002
5081
  isTopoloWidgetOutputSchema,
@@ -5011,6 +5090,7 @@ export {
5011
5090
  resolveApplicationDirectoryEntry,
5012
5091
  resolveCatalogServiceUrl,
5013
5092
  resolveServiceUrl,
5093
+ sanitizeTopoloServiceMessage,
5014
5094
  sha256CanonicalValue,
5015
5095
  topoloErrorHint,
5016
5096
  topoloServiceOrigins,
@@ -114,6 +114,9 @@ var PUBLIC_ERROR_CODES = /* @__PURE__ */ new Set([
114
114
  "unknown_service"
115
115
  ]);
116
116
  var ERROR_CODE_PATTERN = /^[a-z][a-z0-9_]{0,63}$/;
117
+ var SERVICE_ERROR_CODE_PATTERN = /^[a-z][a-z0-9]*(?:_[a-z][a-z0-9]*){1,9}$/;
118
+ var SERVICE_MESSAGE_MAX_LENGTH = 300;
119
+ var SERVICE_ISSUE_LIMIT = 32;
117
120
  var TOPOLO_REQUEST_ID_PATTERN = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
118
121
  var CLOUDFLARE_RAY_ID_PATTERN = /^[0-9a-f]{16}-[A-Z]{3}$/;
119
122
  var PERMISSION_PATTERN = /^[a-z][a-z0-9_-]{0,63}(?:\.[a-z][a-z0-9_-]{0,63})*:(?:[a-z][a-z0-9_-]{0,63}|\*)$/;
@@ -138,6 +141,24 @@ function canonicalTopoloErrorCode(value) {
138
141
  if (!ERROR_CODE_PATTERN.test(candidate) || !PUBLIC_ERROR_CODES.has(candidate)) return null;
139
142
  return candidate;
140
143
  }
144
+ function canonicalTopoloServiceErrorCode(value) {
145
+ const platform2 = canonicalTopoloErrorCode(value);
146
+ if (platform2) return platform2;
147
+ if (typeof value !== "string") return null;
148
+ const candidate = value.trim();
149
+ if (candidate.length > 64 || !SERVICE_ERROR_CODE_PATTERN.test(candidate)) return null;
150
+ const wordLike = candidate.split("_").every((segment) => {
151
+ const digits = segment.replace(/[a-z]/g, "").length;
152
+ return digits === 0 || digits < segment.length - digits && segment.length <= 8;
153
+ });
154
+ return wordLike ? candidate : null;
155
+ }
156
+ function sanitizeTopoloServiceMessage(value) {
157
+ if (typeof value !== "string") return void 0;
158
+ const text = value.replace(/[\u0000-\u001f\u007f-\u009f\u200b-\u200f\u2028-\u202e\u2066-\u2069\ufeff]/g, " ").replace(/\b[a-z][a-z0-9+.-]*:\/\/\S+/gi, "[url]").replace(/[^\s@<>()[\],;:"']+@[^\s@<>()[\],;:"']+\.[a-z]{2,}/gi, "[email]").replace(/[A-Za-z0-9_\-+/=.]{20,}/g, (run) => /[0-9]/.test(run) && /[A-Za-z]/.test(run) ? "[redacted]" : run).replace(/\s+/g, " ").trim();
159
+ if (!text) return void 0;
160
+ return text.length > SERVICE_MESSAGE_MAX_LENGTH ? `${text.slice(0, SERVICE_MESSAGE_MAX_LENGTH - 1).trimEnd()}\u2026` : text;
161
+ }
141
162
  function canonicalTopoloRequestId(value) {
142
163
  if (typeof value !== "string") return void 0;
143
164
  const candidate = value.trim();
@@ -162,7 +183,7 @@ var TopoloAuthError = class extends TopoloSdkError {
162
183
  retryAfter;
163
184
  details;
164
185
  constructor(message, code = "auth_error", options = {}) {
165
- super(canonicalTopoloErrorCode(code) ?? "auth_error", message);
186
+ super(canonicalTopoloServiceErrorCode(code) ?? "auth_error", message);
166
187
  this.name = "TopoloAuthError";
167
188
  this.status = options.status ?? 401;
168
189
  this.body = options.body;
@@ -178,14 +199,14 @@ var TopoloAuthError = class extends TopoloSdkError {
178
199
  function extractTopoloServiceErrorCode(body) {
179
200
  if (!body || typeof body !== "object" || Array.isArray(body)) return null;
180
201
  const record = body;
181
- const topLevel = canonicalTopoloErrorCode(record.code);
202
+ const topLevel = canonicalTopoloServiceErrorCode(record.code);
182
203
  if (topLevel) return topLevel;
183
204
  const nested = record.error;
184
- const nestedString = canonicalTopoloErrorCode(nested);
205
+ const nestedString = canonicalTopoloServiceErrorCode(nested);
185
206
  if (nestedString) return nestedString;
186
207
  if (nested && typeof nested === "object" && !Array.isArray(nested)) {
187
208
  const code = nested.code;
188
- const nestedCode = canonicalTopoloErrorCode(code);
209
+ const nestedCode = canonicalTopoloServiceErrorCode(code);
189
210
  if (nestedCode) return nestedCode;
190
211
  }
191
212
  return null;
@@ -203,10 +224,7 @@ function extractTopoloServiceErrorDetails(body) {
203
224
  if (candidate === void 0) candidate = nestedRecord.details ?? nestedRecord;
204
225
  }
205
226
  if (candidate === void 0) candidate = record;
206
- if (Array.isArray(candidate)) {
207
- const paths = canonicalTopoloValidationPaths(candidate);
208
- return paths.length ? { paths } : void 0;
209
- }
227
+ if (Array.isArray(candidate)) return validationIssueDetails(canonicalTopoloValidationIssues(candidate)) ?? void 0;
210
228
  if (!candidate || typeof candidate !== "object") return void 0;
211
229
  const source = candidate;
212
230
  const safe = {};
@@ -248,18 +266,59 @@ function extractTopoloServiceErrorDetails(body) {
248
266
  if (paths.length) safe[key] = paths;
249
267
  }
250
268
  }
269
+ const issues = [
270
+ ...Array.isArray(source.issues) ? canonicalTopoloValidationIssues(source.issues) : [],
271
+ ...flattenedValidationIssues(source.formErrors, source.fieldErrors)
272
+ ].slice(0, SERVICE_ISSUE_LIMIT);
273
+ Object.assign(safe, validationIssueDetails(issues));
251
274
  return Object.keys(safe).length ? safe : void 0;
252
275
  }
253
- function canonicalTopoloValidationPaths(issues) {
276
+ function validationIssueDetails(issues) {
277
+ if (!issues.length) return null;
254
278
  const paths = [];
255
- for (const issue of issues) {
256
- if (!issue || typeof issue !== "object" || Array.isArray(issue)) continue;
257
- const record = issue;
279
+ for (const issue2 of issues) {
280
+ if (issue2.path && !paths.includes(issue2.path)) paths.push(issue2.path);
281
+ }
282
+ return paths.length ? { paths, issues } : { issues };
283
+ }
284
+ function issue(path, message) {
285
+ const text = sanitizeTopoloServiceMessage(message);
286
+ if (!path && !text) return null;
287
+ return { ...path ? { path } : {}, ...text ? { message: text } : {} };
288
+ }
289
+ function canonicalTopoloValidationIssues(values) {
290
+ const issues = [];
291
+ for (const value of values) {
292
+ if (!value || typeof value !== "object" || Array.isArray(value)) continue;
293
+ const record = value;
258
294
  const path = canonicalTopoloValidationPath(record.field) ?? canonicalTopoloValidationPath(record.path);
259
- if (path && !paths.includes(path)) paths.push(path);
260
- if (paths.length === 32) break;
295
+ if (!path) continue;
296
+ const projected = issue(path, record.message);
297
+ if (projected) issues.push(projected);
298
+ if (issues.length === SERVICE_ISSUE_LIMIT) break;
299
+ }
300
+ return issues;
301
+ }
302
+ function flattenedValidationIssues(formErrors, fieldErrors) {
303
+ const issues = [];
304
+ if (Array.isArray(formErrors)) {
305
+ for (const message of formErrors) {
306
+ const projected = issue(void 0, message);
307
+ if (projected) issues.push(projected);
308
+ }
309
+ }
310
+ if (fieldErrors && typeof fieldErrors === "object" && !Array.isArray(fieldErrors)) {
311
+ for (const [key, messages] of Object.entries(fieldErrors)) {
312
+ const path = canonicalTopoloValidationPath(key);
313
+ if (!path) continue;
314
+ const list = Array.isArray(messages) && messages.length ? messages : [void 0];
315
+ for (const message of list) {
316
+ const projected = issue(path, message);
317
+ if (projected) issues.push(projected);
318
+ }
319
+ }
261
320
  }
262
- return paths;
321
+ return issues;
263
322
  }
264
323
  function canonicalTopoloValidationPath(value) {
265
324
  if (typeof value === "string") {
@@ -60,6 +60,9 @@ var PUBLIC_ERROR_CODES = /* @__PURE__ */ new Set([
60
60
  "unknown_service"
61
61
  ]);
62
62
  var ERROR_CODE_PATTERN = /^[a-z][a-z0-9_]{0,63}$/;
63
+ var SERVICE_ERROR_CODE_PATTERN = /^[a-z][a-z0-9]*(?:_[a-z][a-z0-9]*){1,9}$/;
64
+ var SERVICE_MESSAGE_MAX_LENGTH = 300;
65
+ var SERVICE_ISSUE_LIMIT = 32;
63
66
  var TOPOLO_REQUEST_ID_PATTERN = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
64
67
  var CLOUDFLARE_RAY_ID_PATTERN = /^[0-9a-f]{16}-[A-Z]{3}$/;
65
68
  var PERMISSION_PATTERN = /^[a-z][a-z0-9_-]{0,63}(?:\.[a-z][a-z0-9_-]{0,63})*:(?:[a-z][a-z0-9_-]{0,63}|\*)$/;
@@ -84,6 +87,24 @@ function canonicalTopoloErrorCode(value) {
84
87
  if (!ERROR_CODE_PATTERN.test(candidate) || !PUBLIC_ERROR_CODES.has(candidate)) return null;
85
88
  return candidate;
86
89
  }
90
+ function canonicalTopoloServiceErrorCode(value) {
91
+ const platform2 = canonicalTopoloErrorCode(value);
92
+ if (platform2) return platform2;
93
+ if (typeof value !== "string") return null;
94
+ const candidate = value.trim();
95
+ if (candidate.length > 64 || !SERVICE_ERROR_CODE_PATTERN.test(candidate)) return null;
96
+ const wordLike = candidate.split("_").every((segment) => {
97
+ const digits = segment.replace(/[a-z]/g, "").length;
98
+ return digits === 0 || digits < segment.length - digits && segment.length <= 8;
99
+ });
100
+ return wordLike ? candidate : null;
101
+ }
102
+ function sanitizeTopoloServiceMessage(value) {
103
+ if (typeof value !== "string") return void 0;
104
+ const text = value.replace(/[\u0000-\u001f\u007f-\u009f\u200b-\u200f\u2028-\u202e\u2066-\u2069\ufeff]/g, " ").replace(/\b[a-z][a-z0-9+.-]*:\/\/\S+/gi, "[url]").replace(/[^\s@<>()[\],;:"']+@[^\s@<>()[\],;:"']+\.[a-z]{2,}/gi, "[email]").replace(/[A-Za-z0-9_\-+/=.]{20,}/g, (run) => /[0-9]/.test(run) && /[A-Za-z]/.test(run) ? "[redacted]" : run).replace(/\s+/g, " ").trim();
105
+ if (!text) return void 0;
106
+ return text.length > SERVICE_MESSAGE_MAX_LENGTH ? `${text.slice(0, SERVICE_MESSAGE_MAX_LENGTH - 1).trimEnd()}\u2026` : text;
107
+ }
87
108
  function canonicalTopoloRequestId(value) {
88
109
  if (typeof value !== "string") return void 0;
89
110
  const candidate = value.trim();
@@ -108,7 +129,7 @@ var TopoloAuthError = class extends TopoloSdkError {
108
129
  retryAfter;
109
130
  details;
110
131
  constructor(message, code = "auth_error", options = {}) {
111
- super(canonicalTopoloErrorCode(code) ?? "auth_error", message);
132
+ super(canonicalTopoloServiceErrorCode(code) ?? "auth_error", message);
112
133
  this.name = "TopoloAuthError";
113
134
  this.status = options.status ?? 401;
114
135
  this.body = options.body;
@@ -124,14 +145,14 @@ var TopoloAuthError = class extends TopoloSdkError {
124
145
  function extractTopoloServiceErrorCode(body) {
125
146
  if (!body || typeof body !== "object" || Array.isArray(body)) return null;
126
147
  const record = body;
127
- const topLevel = canonicalTopoloErrorCode(record.code);
148
+ const topLevel = canonicalTopoloServiceErrorCode(record.code);
128
149
  if (topLevel) return topLevel;
129
150
  const nested = record.error;
130
- const nestedString = canonicalTopoloErrorCode(nested);
151
+ const nestedString = canonicalTopoloServiceErrorCode(nested);
131
152
  if (nestedString) return nestedString;
132
153
  if (nested && typeof nested === "object" && !Array.isArray(nested)) {
133
154
  const code = nested.code;
134
- const nestedCode = canonicalTopoloErrorCode(code);
155
+ const nestedCode = canonicalTopoloServiceErrorCode(code);
135
156
  if (nestedCode) return nestedCode;
136
157
  }
137
158
  return null;
@@ -149,10 +170,7 @@ function extractTopoloServiceErrorDetails(body) {
149
170
  if (candidate === void 0) candidate = nestedRecord.details ?? nestedRecord;
150
171
  }
151
172
  if (candidate === void 0) candidate = record;
152
- if (Array.isArray(candidate)) {
153
- const paths = canonicalTopoloValidationPaths(candidate);
154
- return paths.length ? { paths } : void 0;
155
- }
173
+ if (Array.isArray(candidate)) return validationIssueDetails(canonicalTopoloValidationIssues(candidate)) ?? void 0;
156
174
  if (!candidate || typeof candidate !== "object") return void 0;
157
175
  const source = candidate;
158
176
  const safe = {};
@@ -194,18 +212,59 @@ function extractTopoloServiceErrorDetails(body) {
194
212
  if (paths.length) safe[key] = paths;
195
213
  }
196
214
  }
215
+ const issues = [
216
+ ...Array.isArray(source.issues) ? canonicalTopoloValidationIssues(source.issues) : [],
217
+ ...flattenedValidationIssues(source.formErrors, source.fieldErrors)
218
+ ].slice(0, SERVICE_ISSUE_LIMIT);
219
+ Object.assign(safe, validationIssueDetails(issues));
197
220
  return Object.keys(safe).length ? safe : void 0;
198
221
  }
199
- function canonicalTopoloValidationPaths(issues) {
222
+ function validationIssueDetails(issues) {
223
+ if (!issues.length) return null;
200
224
  const paths = [];
201
- for (const issue of issues) {
202
- if (!issue || typeof issue !== "object" || Array.isArray(issue)) continue;
203
- const record = issue;
225
+ for (const issue2 of issues) {
226
+ if (issue2.path && !paths.includes(issue2.path)) paths.push(issue2.path);
227
+ }
228
+ return paths.length ? { paths, issues } : { issues };
229
+ }
230
+ function issue(path, message) {
231
+ const text = sanitizeTopoloServiceMessage(message);
232
+ if (!path && !text) return null;
233
+ return { ...path ? { path } : {}, ...text ? { message: text } : {} };
234
+ }
235
+ function canonicalTopoloValidationIssues(values) {
236
+ const issues = [];
237
+ for (const value of values) {
238
+ if (!value || typeof value !== "object" || Array.isArray(value)) continue;
239
+ const record = value;
204
240
  const path = canonicalTopoloValidationPath(record.field) ?? canonicalTopoloValidationPath(record.path);
205
- if (path && !paths.includes(path)) paths.push(path);
206
- if (paths.length === 32) break;
241
+ if (!path) continue;
242
+ const projected = issue(path, record.message);
243
+ if (projected) issues.push(projected);
244
+ if (issues.length === SERVICE_ISSUE_LIMIT) break;
245
+ }
246
+ return issues;
247
+ }
248
+ function flattenedValidationIssues(formErrors, fieldErrors) {
249
+ const issues = [];
250
+ if (Array.isArray(formErrors)) {
251
+ for (const message of formErrors) {
252
+ const projected = issue(void 0, message);
253
+ if (projected) issues.push(projected);
254
+ }
255
+ }
256
+ if (fieldErrors && typeof fieldErrors === "object" && !Array.isArray(fieldErrors)) {
257
+ for (const [key, messages] of Object.entries(fieldErrors)) {
258
+ const path = canonicalTopoloValidationPath(key);
259
+ if (!path) continue;
260
+ const list = Array.isArray(messages) && messages.length ? messages : [void 0];
261
+ for (const message of list) {
262
+ const projected = issue(path, message);
263
+ if (projected) issues.push(projected);
264
+ }
265
+ }
207
266
  }
208
- return paths;
267
+ return issues;
209
268
  }
210
269
  function canonicalTopoloValidationPath(value) {
211
270
  if (typeof value === "string") {
package/package.json CHANGED
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "name": "@topolo/sdk",
3
3
  "packageManager": "pnpm@10.17.1",
4
- "version": "0.21.4",
5
- "topoloPublishedVersion": "0.21.4",
4
+ "version": "0.22.0",
5
+ "topoloPublishedVersion": "0.22.0",
6
6
  "description": "Typed client SDK for the Topolo platform. Used by TopoloCli, TopoloMCP, and third-party agents.",
7
7
  "license": "UNLICENSED",
8
8
  "author": "Topolo",