@topolo/sdk 0.8.0 → 0.8.1

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
@@ -20,6 +20,7 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
20
20
  // src/index.ts
21
21
  var index_exports = {};
22
22
  __export(index_exports, {
23
+ ACTION_CATALOG_DIGEST_ALGORITHM: () => ACTION_CATALOG_DIGEST_ALGORITHM,
23
24
  APPLICATIONS: () => APPLICATIONS,
24
25
  APPLICATION_REQUIREMENTS: () => APPLICATION_REQUIREMENTS,
25
26
  APPLICATION_REQUIREMENTS_VERSION: () => APPLICATION_REQUIREMENTS_VERSION,
@@ -47,6 +48,7 @@ __export(index_exports, {
47
48
  defineTopoloQuickActionsWidget: () => defineTopoloQuickActionsWidget,
48
49
  defineTopoloRecentActivityWidget: () => defineTopoloRecentActivityWidget,
49
50
  defineTopoloStatsWidget: () => defineTopoloStatsWidget,
51
+ digestTopoloActionCatalog: () => digestTopoloActionCatalog,
50
52
  requirementsForApplication: () => requirementsForApplication,
51
53
  resolveCatalogServiceUrl: () => resolveCatalogServiceUrl,
52
54
  resolveServiceUrl: () => resolveServiceUrl,
@@ -2507,6 +2509,31 @@ var TopoloClient = class _TopoloClient {
2507
2509
  )
2508
2510
  };
2509
2511
  }
2512
+ async getActionCatalogSummary(service) {
2513
+ const boundedService = service.trim();
2514
+ if (!boundedService) {
2515
+ throw new TopoloSdkError("service_required", "service is required for bounded action discovery");
2516
+ }
2517
+ const res = await this.request({
2518
+ service: "developers",
2519
+ method: "GET",
2520
+ path: "/api/actions/catalog",
2521
+ query: { service: boundedService, summary: "true" }
2522
+ });
2523
+ const raw = res.data?.summary ?? res.summary;
2524
+ if (!raw || typeof raw !== "object" || Array.isArray(raw)) {
2525
+ throw new TopoloSdkError("action_catalog_summary_unavailable", "Action catalog summary is unavailable.");
2526
+ }
2527
+ const record = raw;
2528
+ if (record.algorithm !== "sha256-v1" || typeof record.digest !== "string" || !/^[a-f0-9]{64}$/.test(record.digest) || !Number.isSafeInteger(record.actionCount) || Number(record.actionCount) < 0) {
2529
+ throw new TopoloSdkError("action_catalog_summary_unavailable", "Action catalog summary is invalid.");
2530
+ }
2531
+ return {
2532
+ algorithm: "sha256-v1",
2533
+ digest: record.digest,
2534
+ actionCount: Number(record.actionCount)
2535
+ };
2536
+ }
2510
2537
  /** @deprecated Prefer searchActions() so callers retain the continuation cursor. */
2511
2538
  async listActions(options) {
2512
2539
  if (!options) {
@@ -2522,15 +2549,23 @@ var TopoloClient = class _TopoloClient {
2522
2549
  "action id is required"
2523
2550
  );
2524
2551
  }
2525
- const res = await this.request({
2526
- service: "developers",
2527
- method: "GET",
2528
- path: "/api/actions/catalog",
2529
- query: { actionId }
2530
- });
2552
+ let res;
2553
+ try {
2554
+ res = await this.request({
2555
+ service: "developers",
2556
+ method: "GET",
2557
+ path: "/api/actions/catalog",
2558
+ query: { actionId }
2559
+ });
2560
+ } catch (error) {
2561
+ if (error instanceof TopoloHttpError && error.status === 404) {
2562
+ throw new TopoloSdkError("unknown_action", `Unknown or unavailable Topolo action "${action}".`);
2563
+ }
2564
+ throw error;
2565
+ }
2531
2566
  const raw = res.data?.action ?? res.action;
2532
2567
  const match = normalizeActionCatalogEntry(raw);
2533
- if (!match) throw new TopoloSdkError("unknown_action", `Unknown Topolo action "${action}".`);
2568
+ if (!match) throw new TopoloSdkError("unknown_action", `Unknown or unavailable Topolo action "${action}".`);
2534
2569
  return match;
2535
2570
  }
2536
2571
  async callAction(action, input = {}, options = {}) {
@@ -2903,6 +2938,40 @@ function mergeSignals(a, b) {
2903
2938
  return controller.signal;
2904
2939
  }
2905
2940
 
2941
+ // src/action-catalog-digest.ts
2942
+ var ACTION_CATALOG_DIGEST_ALGORITHM = "sha256-v1";
2943
+ function canonicalPermission(value, appId) {
2944
+ let permission = String(value || "").trim().toLowerCase().replace(/\s+/g, "");
2945
+ const prefix = `${String(appId || "").trim().toLowerCase()}.`;
2946
+ if (prefix !== "." && permission.startsWith(prefix)) permission = permission.slice(prefix.length);
2947
+ return permission.replace(/\./g, ":");
2948
+ }
2949
+ function stableJson(value) {
2950
+ if (Array.isArray(value)) return `[${value.map(stableJson).join(",")}]`;
2951
+ if (value && typeof value === "object") {
2952
+ const record = value;
2953
+ return `{${Object.keys(record).sort().map((key) => `${JSON.stringify(key)}:${stableJson(record[key])}`).join(",")}}`;
2954
+ }
2955
+ return JSON.stringify(value);
2956
+ }
2957
+ async function digestTopoloActionCatalog(actions, appId) {
2958
+ const canonical = actions.filter((action) => action.agentAccess !== "off").map((action) => ({
2959
+ actionId: action.actionId || `${appId}.${action.name}`,
2960
+ authorizationMode: action.authorizationMode === "runtime" ? "runtime" : "static",
2961
+ inputSchema: action.inputSchema,
2962
+ method: action.method,
2963
+ outputSchema: action.outputSchema,
2964
+ path: action.path,
2965
+ permission: canonicalPermission(action.permission ?? action.permissionName ?? "", appId),
2966
+ readOnly: action.readOnly,
2967
+ requiresConfirmation: action.requiresConfirmation,
2968
+ target: action.target ?? ""
2969
+ })).sort((left, right) => left.actionId.localeCompare(right.actionId));
2970
+ const bytes = new TextEncoder().encode(canonical.map(stableJson).join("\n"));
2971
+ const digest = await crypto.subtle.digest("SHA-256", bytes);
2972
+ return [...new Uint8Array(digest)].map((value) => value.toString(16).padStart(2, "0")).join("");
2973
+ }
2974
+
2906
2975
  // src/modules/crm.ts
2907
2976
  var CrmModule = class {
2908
2977
  constructor(client) {
@@ -3428,6 +3497,7 @@ function createTopolo(options) {
3428
3497
  }
3429
3498
  // Annotate the CommonJS export names for ESM import in node:
3430
3499
  0 && (module.exports = {
3500
+ ACTION_CATALOG_DIGEST_ALGORITHM,
3431
3501
  APPLICATIONS,
3432
3502
  APPLICATION_REQUIREMENTS,
3433
3503
  APPLICATION_REQUIREMENTS_VERSION,
@@ -3455,6 +3525,7 @@ function createTopolo(options) {
3455
3525
  defineTopoloQuickActionsWidget,
3456
3526
  defineTopoloRecentActivityWidget,
3457
3527
  defineTopoloStatsWidget,
3528
+ digestTopoloActionCatalog,
3458
3529
  requirementsForApplication,
3459
3530
  resolveCatalogServiceUrl,
3460
3531
  resolveServiceUrl,
package/dist/index.d.cts CHANGED
@@ -174,6 +174,11 @@ interface TopoloActionCatalogPage {
174
174
  actions: TopoloActionCatalogEntry[];
175
175
  page: TopoloCatalogPage;
176
176
  }
177
+ interface TopoloActionCatalogSummary {
178
+ algorithm: 'sha256-v1';
179
+ digest: string;
180
+ actionCount: number;
181
+ }
177
182
  interface TopoloCatalogSearchOptions {
178
183
  query?: string;
179
184
  cursor?: string;
@@ -249,6 +254,7 @@ declare class TopoloClient {
249
254
  searchActions(options: TopoloCatalogSearchOptions & {
250
255
  service: string;
251
256
  }): Promise<TopoloActionCatalogPage>;
257
+ getActionCatalogSummary(service: string): Promise<TopoloActionCatalogSummary>;
252
258
  /** @deprecated Prefer searchActions() so callers retain the continuation cursor. */
253
259
  listActions(options?: TopoloCatalogSearchOptions & {
254
260
  service: string;
@@ -293,6 +299,24 @@ interface CredentialIntrospection {
293
299
  } | null;
294
300
  }
295
301
 
302
+ declare const ACTION_CATALOG_DIGEST_ALGORITHM: "sha256-v1";
303
+ interface TopoloActionDigestInput {
304
+ actionId?: string;
305
+ name: string;
306
+ method: string;
307
+ path: string;
308
+ permission?: string | null;
309
+ permissionName?: string | null;
310
+ authorizationMode?: string | null;
311
+ target?: string | null;
312
+ readOnly: boolean;
313
+ requiresConfirmation: boolean;
314
+ agentAccess?: string | null;
315
+ inputSchema: Record<string, unknown>;
316
+ outputSchema: Record<string, unknown>;
317
+ }
318
+ declare function digestTopoloActionCatalog(actions: TopoloActionDigestInput[], appId: string): Promise<string>;
319
+
296
320
  declare const APP_API_URLS: {
297
321
  readonly agent: "https://agent.topolo.app";
298
322
  readonly auth: "https://auth.topolo.app";
@@ -2136,4 +2160,4 @@ declare function createTopolo(options: TopoloClientOptions): {
2136
2160
  };
2137
2161
  type Topolo = ReturnType<typeof createTopolo>;
2138
2162
 
2139
- export { APPLICATIONS, APPLICATION_REQUIREMENTS, APPLICATION_REQUIREMENTS_VERSION, type AgentIdentity, type AppApiId, type ApplicationCatalogEntry, type ApplicationDeployTarget, type ApplicationId, type ApplicationRequirement, type ApplicationRequirementAudit, type ApplicationRequirementFinding, type ApplicationRequirementMigrationItem, type ApplicationRequirementScope, type ApplicationRequirementScore, type ApplicationRequirementStatus, type ApplicationRequirementsAuditReport, type CredentialIntrospection, type CrmContactSummary, CrmModule, DEFAULT_APP_URLS, type DeviceAuthorizationResponse, 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_WIDGET_ENDPOINT, TOPOLO_WIDGET_REFRESH_INTERVAL_MS, type TokenResponse, type Topolo, type TopoloActionCatalogEntry, type TopoloApiKeyResourceMetadata, TopoloAuthError, type TopoloChartWidget, TopoloClient, type TopoloClientOptions, TopoloConfirmationRequiredError, type TopoloCredential, type TopoloDebugEvent, TopoloHttpError, type TopoloNotificationsWidget, TopoloOAuth, TopoloPermissionError, type TopoloQuickActionsWidget, type TopoloRecentActivityWidget, TopoloSdkError, type TopoloServiceCatalogEntry, type TopoloStatsWidget, type TopoloWidget, type TopoloWidgetActionItem, type TopoloWidgetActivityItem, type TopoloWidgetApiResponse, type TopoloWidgetBase, type TopoloWidgetConfig, type TopoloWidgetDraft, type TopoloWidgetMetric, type TopoloWidgetNotificationItem, type TopoloWidgetResponseOptions, type TopoloWidgetSnapshotMetadata, type TopoloWidgetSnapshotMetric, type TopoloWidgetType, type TopoloWidgetValidationResult, applicationRequirementScopes, auditAllApplicationRequirements, auditApplicationRequirements, createTopolo, createTopoloWidgetError, createTopoloWidgetResponse, defineTopoloChartWidget, defineTopoloNotificationsWidget, defineTopoloQuickActionsWidget, defineTopoloRecentActivityWidget, defineTopoloStatsWidget, requirementsForApplication, resolveCatalogServiceUrl, resolveServiceUrl, validateTopoloWidgetResponse };
2163
+ export { ACTION_CATALOG_DIGEST_ALGORITHM, APPLICATIONS, APPLICATION_REQUIREMENTS, APPLICATION_REQUIREMENTS_VERSION, type AgentIdentity, type AppApiId, type ApplicationCatalogEntry, type ApplicationDeployTarget, type ApplicationId, type ApplicationRequirement, type ApplicationRequirementAudit, type ApplicationRequirementFinding, type ApplicationRequirementMigrationItem, type ApplicationRequirementScope, type ApplicationRequirementScore, type ApplicationRequirementStatus, type ApplicationRequirementsAuditReport, type CredentialIntrospection, type CrmContactSummary, CrmModule, DEFAULT_APP_URLS, type DeviceAuthorizationResponse, 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_WIDGET_ENDPOINT, TOPOLO_WIDGET_REFRESH_INTERVAL_MS, type TokenResponse, type Topolo, type TopoloActionCatalogEntry, type TopoloActionCatalogSummary, type TopoloActionDigestInput, type TopoloApiKeyResourceMetadata, TopoloAuthError, type TopoloChartWidget, TopoloClient, type TopoloClientOptions, TopoloConfirmationRequiredError, type TopoloCredential, type TopoloDebugEvent, TopoloHttpError, type TopoloNotificationsWidget, TopoloOAuth, TopoloPermissionError, type TopoloQuickActionsWidget, type TopoloRecentActivityWidget, TopoloSdkError, type TopoloServiceCatalogEntry, type TopoloStatsWidget, type TopoloWidget, type TopoloWidgetActionItem, type TopoloWidgetActivityItem, type TopoloWidgetApiResponse, type TopoloWidgetBase, type TopoloWidgetConfig, type TopoloWidgetDraft, type TopoloWidgetMetric, type TopoloWidgetNotificationItem, type TopoloWidgetResponseOptions, type TopoloWidgetSnapshotMetadata, type TopoloWidgetSnapshotMetric, type TopoloWidgetType, type TopoloWidgetValidationResult, applicationRequirementScopes, auditAllApplicationRequirements, auditApplicationRequirements, createTopolo, createTopoloWidgetError, createTopoloWidgetResponse, defineTopoloChartWidget, defineTopoloNotificationsWidget, defineTopoloQuickActionsWidget, defineTopoloRecentActivityWidget, defineTopoloStatsWidget, digestTopoloActionCatalog, requirementsForApplication, resolveCatalogServiceUrl, resolveServiceUrl, validateTopoloWidgetResponse };
package/dist/index.d.ts CHANGED
@@ -174,6 +174,11 @@ interface TopoloActionCatalogPage {
174
174
  actions: TopoloActionCatalogEntry[];
175
175
  page: TopoloCatalogPage;
176
176
  }
177
+ interface TopoloActionCatalogSummary {
178
+ algorithm: 'sha256-v1';
179
+ digest: string;
180
+ actionCount: number;
181
+ }
177
182
  interface TopoloCatalogSearchOptions {
178
183
  query?: string;
179
184
  cursor?: string;
@@ -249,6 +254,7 @@ declare class TopoloClient {
249
254
  searchActions(options: TopoloCatalogSearchOptions & {
250
255
  service: string;
251
256
  }): Promise<TopoloActionCatalogPage>;
257
+ getActionCatalogSummary(service: string): Promise<TopoloActionCatalogSummary>;
252
258
  /** @deprecated Prefer searchActions() so callers retain the continuation cursor. */
253
259
  listActions(options?: TopoloCatalogSearchOptions & {
254
260
  service: string;
@@ -293,6 +299,24 @@ interface CredentialIntrospection {
293
299
  } | null;
294
300
  }
295
301
 
302
+ declare const ACTION_CATALOG_DIGEST_ALGORITHM: "sha256-v1";
303
+ interface TopoloActionDigestInput {
304
+ actionId?: string;
305
+ name: string;
306
+ method: string;
307
+ path: string;
308
+ permission?: string | null;
309
+ permissionName?: string | null;
310
+ authorizationMode?: string | null;
311
+ target?: string | null;
312
+ readOnly: boolean;
313
+ requiresConfirmation: boolean;
314
+ agentAccess?: string | null;
315
+ inputSchema: Record<string, unknown>;
316
+ outputSchema: Record<string, unknown>;
317
+ }
318
+ declare function digestTopoloActionCatalog(actions: TopoloActionDigestInput[], appId: string): Promise<string>;
319
+
296
320
  declare const APP_API_URLS: {
297
321
  readonly agent: "https://agent.topolo.app";
298
322
  readonly auth: "https://auth.topolo.app";
@@ -2136,4 +2160,4 @@ declare function createTopolo(options: TopoloClientOptions): {
2136
2160
  };
2137
2161
  type Topolo = ReturnType<typeof createTopolo>;
2138
2162
 
2139
- export { APPLICATIONS, APPLICATION_REQUIREMENTS, APPLICATION_REQUIREMENTS_VERSION, type AgentIdentity, type AppApiId, type ApplicationCatalogEntry, type ApplicationDeployTarget, type ApplicationId, type ApplicationRequirement, type ApplicationRequirementAudit, type ApplicationRequirementFinding, type ApplicationRequirementMigrationItem, type ApplicationRequirementScope, type ApplicationRequirementScore, type ApplicationRequirementStatus, type ApplicationRequirementsAuditReport, type CredentialIntrospection, type CrmContactSummary, CrmModule, DEFAULT_APP_URLS, type DeviceAuthorizationResponse, 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_WIDGET_ENDPOINT, TOPOLO_WIDGET_REFRESH_INTERVAL_MS, type TokenResponse, type Topolo, type TopoloActionCatalogEntry, type TopoloApiKeyResourceMetadata, TopoloAuthError, type TopoloChartWidget, TopoloClient, type TopoloClientOptions, TopoloConfirmationRequiredError, type TopoloCredential, type TopoloDebugEvent, TopoloHttpError, type TopoloNotificationsWidget, TopoloOAuth, TopoloPermissionError, type TopoloQuickActionsWidget, type TopoloRecentActivityWidget, TopoloSdkError, type TopoloServiceCatalogEntry, type TopoloStatsWidget, type TopoloWidget, type TopoloWidgetActionItem, type TopoloWidgetActivityItem, type TopoloWidgetApiResponse, type TopoloWidgetBase, type TopoloWidgetConfig, type TopoloWidgetDraft, type TopoloWidgetMetric, type TopoloWidgetNotificationItem, type TopoloWidgetResponseOptions, type TopoloWidgetSnapshotMetadata, type TopoloWidgetSnapshotMetric, type TopoloWidgetType, type TopoloWidgetValidationResult, applicationRequirementScopes, auditAllApplicationRequirements, auditApplicationRequirements, createTopolo, createTopoloWidgetError, createTopoloWidgetResponse, defineTopoloChartWidget, defineTopoloNotificationsWidget, defineTopoloQuickActionsWidget, defineTopoloRecentActivityWidget, defineTopoloStatsWidget, requirementsForApplication, resolveCatalogServiceUrl, resolveServiceUrl, validateTopoloWidgetResponse };
2163
+ export { ACTION_CATALOG_DIGEST_ALGORITHM, APPLICATIONS, APPLICATION_REQUIREMENTS, APPLICATION_REQUIREMENTS_VERSION, type AgentIdentity, type AppApiId, type ApplicationCatalogEntry, type ApplicationDeployTarget, type ApplicationId, type ApplicationRequirement, type ApplicationRequirementAudit, type ApplicationRequirementFinding, type ApplicationRequirementMigrationItem, type ApplicationRequirementScope, type ApplicationRequirementScore, type ApplicationRequirementStatus, type ApplicationRequirementsAuditReport, type CredentialIntrospection, type CrmContactSummary, CrmModule, DEFAULT_APP_URLS, type DeviceAuthorizationResponse, 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_WIDGET_ENDPOINT, TOPOLO_WIDGET_REFRESH_INTERVAL_MS, type TokenResponse, type Topolo, type TopoloActionCatalogEntry, type TopoloActionCatalogSummary, type TopoloActionDigestInput, type TopoloApiKeyResourceMetadata, TopoloAuthError, type TopoloChartWidget, TopoloClient, type TopoloClientOptions, TopoloConfirmationRequiredError, type TopoloCredential, type TopoloDebugEvent, TopoloHttpError, type TopoloNotificationsWidget, TopoloOAuth, TopoloPermissionError, type TopoloQuickActionsWidget, type TopoloRecentActivityWidget, TopoloSdkError, type TopoloServiceCatalogEntry, type TopoloStatsWidget, type TopoloWidget, type TopoloWidgetActionItem, type TopoloWidgetActivityItem, type TopoloWidgetApiResponse, type TopoloWidgetBase, type TopoloWidgetConfig, type TopoloWidgetDraft, type TopoloWidgetMetric, type TopoloWidgetNotificationItem, type TopoloWidgetResponseOptions, type TopoloWidgetSnapshotMetadata, type TopoloWidgetSnapshotMetric, type TopoloWidgetType, type TopoloWidgetValidationResult, applicationRequirementScopes, auditAllApplicationRequirements, auditApplicationRequirements, createTopolo, createTopoloWidgetError, createTopoloWidgetResponse, defineTopoloChartWidget, defineTopoloNotificationsWidget, defineTopoloQuickActionsWidget, defineTopoloRecentActivityWidget, defineTopoloStatsWidget, digestTopoloActionCatalog, requirementsForApplication, resolveCatalogServiceUrl, resolveServiceUrl, validateTopoloWidgetResponse };
package/dist/index.js CHANGED
@@ -2451,6 +2451,31 @@ var TopoloClient = class _TopoloClient {
2451
2451
  )
2452
2452
  };
2453
2453
  }
2454
+ async getActionCatalogSummary(service) {
2455
+ const boundedService = service.trim();
2456
+ if (!boundedService) {
2457
+ throw new TopoloSdkError("service_required", "service is required for bounded action discovery");
2458
+ }
2459
+ const res = await this.request({
2460
+ service: "developers",
2461
+ method: "GET",
2462
+ path: "/api/actions/catalog",
2463
+ query: { service: boundedService, summary: "true" }
2464
+ });
2465
+ const raw = res.data?.summary ?? res.summary;
2466
+ if (!raw || typeof raw !== "object" || Array.isArray(raw)) {
2467
+ throw new TopoloSdkError("action_catalog_summary_unavailable", "Action catalog summary is unavailable.");
2468
+ }
2469
+ const record = raw;
2470
+ if (record.algorithm !== "sha256-v1" || typeof record.digest !== "string" || !/^[a-f0-9]{64}$/.test(record.digest) || !Number.isSafeInteger(record.actionCount) || Number(record.actionCount) < 0) {
2471
+ throw new TopoloSdkError("action_catalog_summary_unavailable", "Action catalog summary is invalid.");
2472
+ }
2473
+ return {
2474
+ algorithm: "sha256-v1",
2475
+ digest: record.digest,
2476
+ actionCount: Number(record.actionCount)
2477
+ };
2478
+ }
2454
2479
  /** @deprecated Prefer searchActions() so callers retain the continuation cursor. */
2455
2480
  async listActions(options) {
2456
2481
  if (!options) {
@@ -2466,15 +2491,23 @@ var TopoloClient = class _TopoloClient {
2466
2491
  "action id is required"
2467
2492
  );
2468
2493
  }
2469
- const res = await this.request({
2470
- service: "developers",
2471
- method: "GET",
2472
- path: "/api/actions/catalog",
2473
- query: { actionId }
2474
- });
2494
+ let res;
2495
+ try {
2496
+ res = await this.request({
2497
+ service: "developers",
2498
+ method: "GET",
2499
+ path: "/api/actions/catalog",
2500
+ query: { actionId }
2501
+ });
2502
+ } catch (error) {
2503
+ if (error instanceof TopoloHttpError && error.status === 404) {
2504
+ throw new TopoloSdkError("unknown_action", `Unknown or unavailable Topolo action "${action}".`);
2505
+ }
2506
+ throw error;
2507
+ }
2475
2508
  const raw = res.data?.action ?? res.action;
2476
2509
  const match = normalizeActionCatalogEntry(raw);
2477
- if (!match) throw new TopoloSdkError("unknown_action", `Unknown Topolo action "${action}".`);
2510
+ if (!match) throw new TopoloSdkError("unknown_action", `Unknown or unavailable Topolo action "${action}".`);
2478
2511
  return match;
2479
2512
  }
2480
2513
  async callAction(action, input = {}, options = {}) {
@@ -2847,6 +2880,40 @@ function mergeSignals(a, b) {
2847
2880
  return controller.signal;
2848
2881
  }
2849
2882
 
2883
+ // src/action-catalog-digest.ts
2884
+ var ACTION_CATALOG_DIGEST_ALGORITHM = "sha256-v1";
2885
+ function canonicalPermission(value, appId) {
2886
+ let permission = String(value || "").trim().toLowerCase().replace(/\s+/g, "");
2887
+ const prefix = `${String(appId || "").trim().toLowerCase()}.`;
2888
+ if (prefix !== "." && permission.startsWith(prefix)) permission = permission.slice(prefix.length);
2889
+ return permission.replace(/\./g, ":");
2890
+ }
2891
+ function stableJson(value) {
2892
+ if (Array.isArray(value)) return `[${value.map(stableJson).join(",")}]`;
2893
+ if (value && typeof value === "object") {
2894
+ const record = value;
2895
+ return `{${Object.keys(record).sort().map((key) => `${JSON.stringify(key)}:${stableJson(record[key])}`).join(",")}}`;
2896
+ }
2897
+ return JSON.stringify(value);
2898
+ }
2899
+ async function digestTopoloActionCatalog(actions, appId) {
2900
+ const canonical = actions.filter((action) => action.agentAccess !== "off").map((action) => ({
2901
+ actionId: action.actionId || `${appId}.${action.name}`,
2902
+ authorizationMode: action.authorizationMode === "runtime" ? "runtime" : "static",
2903
+ inputSchema: action.inputSchema,
2904
+ method: action.method,
2905
+ outputSchema: action.outputSchema,
2906
+ path: action.path,
2907
+ permission: canonicalPermission(action.permission ?? action.permissionName ?? "", appId),
2908
+ readOnly: action.readOnly,
2909
+ requiresConfirmation: action.requiresConfirmation,
2910
+ target: action.target ?? ""
2911
+ })).sort((left, right) => left.actionId.localeCompare(right.actionId));
2912
+ const bytes = new TextEncoder().encode(canonical.map(stableJson).join("\n"));
2913
+ const digest = await crypto.subtle.digest("SHA-256", bytes);
2914
+ return [...new Uint8Array(digest)].map((value) => value.toString(16).padStart(2, "0")).join("");
2915
+ }
2916
+
2850
2917
  // src/modules/crm.ts
2851
2918
  var CrmModule = class {
2852
2919
  constructor(client) {
@@ -3371,6 +3438,7 @@ function createTopolo(options) {
3371
3438
  };
3372
3439
  }
3373
3440
  export {
3441
+ ACTION_CATALOG_DIGEST_ALGORITHM,
3374
3442
  APPLICATIONS,
3375
3443
  APPLICATION_REQUIREMENTS,
3376
3444
  APPLICATION_REQUIREMENTS_VERSION,
@@ -3398,6 +3466,7 @@ export {
3398
3466
  defineTopoloQuickActionsWidget,
3399
3467
  defineTopoloRecentActivityWidget,
3400
3468
  defineTopoloStatsWidget,
3469
+ digestTopoloActionCatalog,
3401
3470
  requirementsForApplication,
3402
3471
  resolveCatalogServiceUrl,
3403
3472
  resolveServiceUrl,