@topolo/sdk 0.21.3 → 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;
@@ -470,7 +550,8 @@ async function resolveActionSecrets(value, store, secrets) {
470
550
  if (isActionSecretReference(value)) {
471
551
  if (!store) throw new TopoloSdkError("action_secret_store_required", "Protected action references require a secret store.");
472
552
  const resolved = await store.load(value);
473
- if (typeof resolved === "string" && resolved) secrets.set(resolved, value);
553
+ if (typeof resolved !== "string" || !resolved) throw new TopoloSdkError("action_secret_unsupported_type", "Protected action handoff requires a nonempty string credential.");
554
+ secrets.set(resolved, value);
474
555
  return resolved;
475
556
  }
476
557
  if (Array.isArray(value)) return Promise.all(value.map((item) => resolveActionSecrets(item, store, secrets)));
@@ -891,8 +972,8 @@ function inspectSchema(schema, path, root, depth) {
891
972
  );
892
973
  for (const [key, child] of children) {
893
974
  if (!isRecord2(child)) continue;
894
- const issue = inspectSchema(child, `${path}.${key}`, root, depth + 1);
895
- if (issue) return issue;
975
+ const issue2 = inspectSchema(child, `${path}.${key}`, root, depth + 1);
976
+ if (issue2) return issue2;
896
977
  }
897
978
  return null;
898
979
  }
@@ -2232,7 +2313,7 @@ var TopoloClient = class _TopoloClient {
2232
2313
  input: selectedInput,
2233
2314
  inputSource: input ? "provided" : example ? "example" : "empty",
2234
2315
  missingFields: [...new Set(
2235
- 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)
2236
2317
  )],
2237
2318
  plan
2238
2319
  };
@@ -2297,7 +2378,7 @@ var TopoloClient = class _TopoloClient {
2297
2378
  if (!validation.valid) {
2298
2379
  throw new TopoloSdkError(
2299
2380
  "invalid_action_input",
2300
- `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("; ")}`
2301
2382
  );
2302
2383
  }
2303
2384
  const resourceIssue = validateActionResource(entry, options.resource);
@@ -5073,6 +5154,7 @@ function createTopolo(options) {
5073
5154
  canonicalTopoloRequestId,
5074
5155
  canonicalTopoloRequired,
5075
5156
  canonicalTopoloRetryAfter,
5157
+ canonicalTopoloServiceErrorCode,
5076
5158
  canonicalizeActorEnvelope,
5077
5159
  compactActionCatalogEntry,
5078
5160
  compactActionPlan,
@@ -5096,6 +5178,7 @@ function createTopolo(options) {
5096
5178
  enrichActionContract,
5097
5179
  extractTopoloServiceErrorCode,
5098
5180
  extractTopoloServiceErrorDetails,
5181
+ extractTopoloServiceErrorMessage,
5099
5182
  formatDirectoryApplicationIds,
5100
5183
  friendlyAppId,
5101
5184
  isTopoloWidgetOutputSchema,
@@ -5110,6 +5193,7 @@ function createTopolo(options) {
5110
5193
  resolveApplicationDirectoryEntry,
5111
5194
  resolveCatalogServiceUrl,
5112
5195
  resolveServiceUrl,
5196
+ sanitizeTopoloServiceMessage,
5113
5197
  sha256CanonicalValue,
5114
5198
  topoloErrorHint,
5115
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;
@@ -371,7 +448,8 @@ async function resolveActionSecrets(value, store, secrets) {
371
448
  if (isActionSecretReference(value)) {
372
449
  if (!store) throw new TopoloSdkError("action_secret_store_required", "Protected action references require a secret store.");
373
450
  const resolved = await store.load(value);
374
- if (typeof resolved === "string" && resolved) secrets.set(resolved, value);
451
+ if (typeof resolved !== "string" || !resolved) throw new TopoloSdkError("action_secret_unsupported_type", "Protected action handoff requires a nonempty string credential.");
452
+ secrets.set(resolved, value);
375
453
  return resolved;
376
454
  }
377
455
  if (Array.isArray(value)) return Promise.all(value.map((item) => resolveActionSecrets(item, store, secrets)));
@@ -792,8 +870,8 @@ function inspectSchema(schema, path, root, depth) {
792
870
  );
793
871
  for (const [key, child] of children) {
794
872
  if (!isRecord2(child)) continue;
795
- const issue = inspectSchema(child, `${path}.${key}`, root, depth + 1);
796
- if (issue) return issue;
873
+ const issue2 = inspectSchema(child, `${path}.${key}`, root, depth + 1);
874
+ if (issue2) return issue2;
797
875
  }
798
876
  return null;
799
877
  }
@@ -2133,7 +2211,7 @@ var TopoloClient = class _TopoloClient {
2133
2211
  input: selectedInput,
2134
2212
  inputSource: input ? "provided" : example ? "example" : "empty",
2135
2213
  missingFields: [...new Set(
2136
- 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)
2137
2215
  )],
2138
2216
  plan
2139
2217
  };
@@ -2198,7 +2276,7 @@ var TopoloClient = class _TopoloClient {
2198
2276
  if (!validation.valid) {
2199
2277
  throw new TopoloSdkError(
2200
2278
  "invalid_action_input",
2201
- `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("; ")}`
2202
2280
  );
2203
2281
  }
2204
2282
  const resourceIssue = validateActionResource(entry, options.resource);
@@ -4973,6 +5051,7 @@ export {
4973
5051
  canonicalTopoloRequestId,
4974
5052
  canonicalTopoloRequired,
4975
5053
  canonicalTopoloRetryAfter,
5054
+ canonicalTopoloServiceErrorCode,
4976
5055
  canonicalizeActorEnvelope,
4977
5056
  compactActionCatalogEntry,
4978
5057
  compactActionPlan,
@@ -4996,6 +5075,7 @@ export {
4996
5075
  enrichActionContract,
4997
5076
  extractTopoloServiceErrorCode,
4998
5077
  extractTopoloServiceErrorDetails,
5078
+ extractTopoloServiceErrorMessage,
4999
5079
  formatDirectoryApplicationIds,
5000
5080
  friendlyAppId,
5001
5081
  isTopoloWidgetOutputSchema,
@@ -5010,6 +5090,7 @@ export {
5010
5090
  resolveApplicationDirectoryEntry,
5011
5091
  resolveCatalogServiceUrl,
5012
5092
  resolveServiceUrl,
5093
+ sanitizeTopoloServiceMessage,
5013
5094
  sha256CanonicalValue,
5014
5095
  topoloErrorHint,
5015
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.3",
5
- "topoloPublishedVersion": "0.21.3",
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",