@topolo/sdk 0.2.5 → 0.2.7

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.d.ts CHANGED
@@ -38,8 +38,10 @@ declare const SERVICES: {
38
38
  readonly bugfix: "https://bugfix.topolo.app";
39
39
  readonly bytes: "https://r2-media-manager-worker.topolo.workers.dev";
40
40
  readonly calendar: "https://calendar.topolo.app";
41
+ readonly capacity: "https://topolo-capacity.topolo.workers.dev";
41
42
  readonly chat: "https://chat.topolo.app";
42
43
  readonly commerce: "https://topolo-commerce-api.topolo.workers.dev";
44
+ readonly compose: "https://compose.topolo.app";
43
45
  readonly crm: "https://crm-api.topolo.app";
44
46
  readonly customer_success: "https://customer-success.topolo.app";
45
47
  readonly feed: "https://topolo-feed-api.topolo.app";
@@ -53,6 +55,7 @@ declare const SERVICES: {
53
55
  readonly mdm: "https://topolo-mdm-api.topolo.app";
54
56
  readonly messaging: "https://messages.topolo.app";
55
57
  readonly nexus: "https://topolo-nexus-gateway.topolo.workers.dev";
58
+ readonly notify: "https://notify.topolo.app";
56
59
  readonly one: "https://one.topolo.app";
57
60
  readonly pay: "https://topolo-pay.topolo.workers.dev";
58
61
  readonly people: "https://people.topolo.app";
@@ -197,6 +200,22 @@ declare const APPLICATIONS: {
197
200
  readonly serviceId: "calendar";
198
201
  }];
199
202
  };
203
+ readonly capacity: {
204
+ readonly id: "capacity";
205
+ readonly appDir: "TopoloCapacity";
206
+ readonly name: "topolo-capacity";
207
+ readonly packageName: "topolo-capacity";
208
+ readonly productionUrl: "https://capacity.topolo.app";
209
+ readonly services: readonly ["capacity"];
210
+ readonly deployTargets: readonly [{
211
+ readonly name: "topolo-capacity";
212
+ readonly kind: "worker";
213
+ readonly apiUrl: "https://topolo-capacity.topolo.workers.dev";
214
+ readonly domains: readonly ["capacity.topolo.app", "topolo-capacity.topolo.workers.dev"];
215
+ readonly routes: readonly [];
216
+ readonly serviceId: "capacity";
217
+ }];
218
+ };
200
219
  readonly chat: {
201
220
  readonly id: "chat";
202
221
  readonly appDir: "TopoloChat";
@@ -268,6 +287,22 @@ declare const APPLICATIONS: {
268
287
  readonly serviceId: null;
269
288
  }];
270
289
  };
290
+ readonly compose: {
291
+ readonly id: "compose";
292
+ readonly appDir: "TopoloCompose";
293
+ readonly name: "topolo-compose";
294
+ readonly packageName: "@topolo/compose";
295
+ readonly productionUrl: "https://compose.topolo.app";
296
+ readonly services: readonly ["compose"];
297
+ readonly deployTargets: readonly [{
298
+ readonly name: "topolo-compose";
299
+ readonly kind: "worker";
300
+ readonly apiUrl: "https://compose.topolo.app";
301
+ readonly domains: readonly ["compose.topolo.app"];
302
+ readonly routes: readonly ["compose.topolo.app"];
303
+ readonly serviceId: "compose";
304
+ }];
305
+ };
271
306
  readonly crm: {
272
307
  readonly id: "crm";
273
308
  readonly appDir: "TopoloCRM";
@@ -566,6 +601,22 @@ declare const APPLICATIONS: {
566
601
  readonly serviceId: "nexus";
567
602
  }];
568
603
  };
604
+ readonly notify: {
605
+ readonly id: "notify";
606
+ readonly appDir: "TopoloNotify";
607
+ readonly name: "topolo-notify";
608
+ readonly packageName: "@topolo/notify";
609
+ readonly productionUrl: "https://notify.topolo.app";
610
+ readonly services: readonly ["notify"];
611
+ readonly deployTargets: readonly [{
612
+ readonly name: "topolo-notify";
613
+ readonly kind: "worker";
614
+ readonly apiUrl: "https://notify.topolo.app";
615
+ readonly domains: readonly ["notify.topolo.app"];
616
+ readonly routes: readonly ["notify.topolo.app"];
617
+ readonly serviceId: "notify";
618
+ }];
619
+ };
569
620
  readonly one: {
570
621
  readonly id: "one";
571
622
  readonly appDir: "TopoloOne";
@@ -847,7 +898,7 @@ type ApplicationId = keyof typeof APPLICATIONS;
847
898
  type ApplicationCatalogEntry = (typeof APPLICATIONS)[ApplicationId];
848
899
  type ApplicationDeployTarget = ApplicationCatalogEntry['deployTargets'][number];
849
900
 
850
- declare const APPLICATION_REQUIREMENTS_VERSION = "2026-04-22.1";
901
+ declare const APPLICATION_REQUIREMENTS_VERSION = "2026-04-25.1";
851
902
  type ApplicationRequirementScope = 'all' | 'browser' | 'api' | 'tooling' | 'agent_surface';
852
903
  interface ApplicationRequirement {
853
904
  id: string;
@@ -951,6 +1002,13 @@ declare const APPLICATION_REQUIREMENTS: readonly [{
951
1002
  readonly appliesTo: readonly ["api", "tooling", "agent_surface"];
952
1003
  readonly evidence: readonly ["Read operations have typed SDK/CLI/MCP surfaces once their contract stabilizes", "Mutating generic calls require --confirm or confirm:true", "MCP tools never accept orgId and advertise only appropriate scope-gated tools"];
953
1004
  readonly implementation: readonly ["Add SDK types first, then CLI commands and MCP tools for durable workflows", "Use generic API passthrough only as a temporary escape hatch", "Keep command output JSON-stable for agents and human-readable with --no-json"];
1005
+ }, {
1006
+ readonly id: "native-dashboard-widget";
1007
+ readonly title: "Expose a native dashboard widget contract";
1008
+ readonly summary: "Launchable first-party applications must populate TopoloOne live workspace through an app-owned /api/widget endpoint using the SDK widget response contract.";
1009
+ readonly appliesTo: readonly ["api"];
1010
+ readonly evidence: readonly ["The app-owned API exposes GET /api/widget", "The endpoint returns TopoloWidgetApiResponse from @topolo/sdk", "The endpoint derives organization/user context from the app auth boundary"];
1011
+ readonly implementation: readonly ["Import createTopoloWidgetResponse from @topolo/sdk in the app backend", "Return native app metrics or action widgets instead of generic launch-card fallbacks", "Add a route-level test that validates the response with validateTopoloWidgetResponse"];
954
1012
  }, {
955
1013
  readonly id: "observability-and-audit";
956
1014
  readonly title: "Emit platform audit and debugging signals";
@@ -1235,6 +1293,128 @@ declare class TopoloOAuth {
1235
1293
  }): Promise<TokenResponse>;
1236
1294
  }
1237
1295
 
1296
+ declare const TOPOLO_WIDGET_ENDPOINT = "/api/widget";
1297
+ declare const TOPOLO_WIDGET_REFRESH_INTERVAL_MS = 60000;
1298
+ type TopoloWidgetType = "stats" | "recent-activity" | "quick-actions" | "notifications" | "chart";
1299
+ interface TopoloWidgetBase {
1300
+ serviceId: string;
1301
+ serviceName: string;
1302
+ serviceIcon?: string;
1303
+ type: TopoloWidgetType;
1304
+ lastUpdated: string;
1305
+ snapshot?: TopoloWidgetSnapshotMetadata;
1306
+ }
1307
+ interface TopoloWidgetMetric {
1308
+ label: string;
1309
+ value: string | number;
1310
+ change?: number;
1311
+ changeLabel?: string;
1312
+ icon?: string;
1313
+ }
1314
+ interface TopoloWidgetSnapshotMetric {
1315
+ key: string;
1316
+ label: string;
1317
+ value: number;
1318
+ unit?: string;
1319
+ change?: number;
1320
+ changeLabel?: string;
1321
+ }
1322
+ interface TopoloWidgetSnapshotMetadata {
1323
+ presetKey?: string;
1324
+ audience?: string;
1325
+ scope?: string;
1326
+ scopeLabel?: string;
1327
+ generatedAt?: string;
1328
+ summary?: string;
1329
+ defaultMetricKeys?: string[];
1330
+ availableMetrics?: TopoloWidgetSnapshotMetric[];
1331
+ highlights?: string[];
1332
+ }
1333
+ interface TopoloStatsWidget extends TopoloWidgetBase {
1334
+ type: "stats";
1335
+ stats: TopoloWidgetMetric[];
1336
+ }
1337
+ interface TopoloWidgetActivityItem {
1338
+ id: string;
1339
+ title: string;
1340
+ description?: string;
1341
+ timestamp: string;
1342
+ icon?: string;
1343
+ link?: string;
1344
+ }
1345
+ interface TopoloRecentActivityWidget extends TopoloWidgetBase {
1346
+ type: "recent-activity";
1347
+ activities: TopoloWidgetActivityItem[];
1348
+ }
1349
+ interface TopoloWidgetActionItem {
1350
+ id: string;
1351
+ label: string;
1352
+ icon?: string;
1353
+ link: string;
1354
+ primary?: boolean;
1355
+ }
1356
+ interface TopoloQuickActionsWidget extends TopoloWidgetBase {
1357
+ type: "quick-actions";
1358
+ actions: TopoloWidgetActionItem[];
1359
+ }
1360
+ interface TopoloWidgetNotificationItem {
1361
+ id: string;
1362
+ title: string;
1363
+ message: string;
1364
+ type: "info" | "warning" | "error" | "success";
1365
+ timestamp: string;
1366
+ read: boolean;
1367
+ link?: string;
1368
+ }
1369
+ interface TopoloNotificationsWidget extends TopoloWidgetBase {
1370
+ type: "notifications";
1371
+ notifications: TopoloWidgetNotificationItem[];
1372
+ unreadCount: number;
1373
+ }
1374
+ interface TopoloChartWidget extends TopoloWidgetBase {
1375
+ type: "chart";
1376
+ chartType: "line" | "bar" | "pie" | "donut";
1377
+ title: string;
1378
+ data: {
1379
+ labels: string[];
1380
+ values: number[];
1381
+ };
1382
+ }
1383
+ type TopoloWidget = TopoloStatsWidget | TopoloRecentActivityWidget | TopoloQuickActionsWidget | TopoloNotificationsWidget | TopoloChartWidget;
1384
+ type TopoloWidgetWithOptionalMetadata<T extends TopoloWidget> = Omit<T, "serviceId" | "serviceName" | "lastUpdated"> & Partial<Pick<TopoloWidgetBase, "serviceId" | "serviceName" | "lastUpdated">>;
1385
+ type TopoloWidgetDraft = TopoloWidget extends infer Widget ? Widget extends TopoloWidget ? TopoloWidgetWithOptionalMetadata<Widget> : never : never;
1386
+ interface TopoloWidgetApiResponse {
1387
+ success: boolean;
1388
+ widgets: TopoloWidget[];
1389
+ error?: string;
1390
+ }
1391
+ interface TopoloWidgetResponseOptions {
1392
+ serviceId: string;
1393
+ serviceName: string;
1394
+ widgets: TopoloWidgetDraft[];
1395
+ now?: Date | string;
1396
+ }
1397
+ interface TopoloWidgetValidationResult {
1398
+ ok: boolean;
1399
+ errors: string[];
1400
+ }
1401
+ interface TopoloWidgetConfig {
1402
+ serviceId: string;
1403
+ serviceName: string;
1404
+ baseUrl: string;
1405
+ widgetEndpoint: string;
1406
+ enabled: boolean;
1407
+ refreshInterval: number;
1408
+ }
1409
+ declare function defineTopoloStatsWidget(widget: Omit<TopoloStatsWidget, "type">): TopoloStatsWidget;
1410
+ declare function defineTopoloRecentActivityWidget(widget: Omit<TopoloRecentActivityWidget, "type">): TopoloRecentActivityWidget;
1411
+ declare function defineTopoloQuickActionsWidget(widget: Omit<TopoloQuickActionsWidget, "type">): TopoloQuickActionsWidget;
1412
+ declare function defineTopoloNotificationsWidget(widget: Omit<TopoloNotificationsWidget, "type">): TopoloNotificationsWidget;
1413
+ declare function defineTopoloChartWidget(widget: Omit<TopoloChartWidget, "type">): TopoloChartWidget;
1414
+ declare function createTopoloWidgetResponse({ serviceId, serviceName, widgets, now, }: TopoloWidgetResponseOptions): TopoloWidgetApiResponse;
1415
+ declare function createTopoloWidgetError(error: string): TopoloWidgetApiResponse;
1416
+ declare function validateTopoloWidgetResponse(response: unknown): TopoloWidgetValidationResult;
1417
+
1238
1418
  /**
1239
1419
  * Convenience factory that returns a ready-to-use typed Topolo client plus
1240
1420
  * domain module surfaces (identity, crm, ...).
@@ -1249,4 +1429,4 @@ declare function createTopolo(options: TopoloClientOptions): {
1249
1429
  };
1250
1430
  type Topolo = ReturnType<typeof createTopolo>;
1251
1431
 
1252
- export { APPLICATIONS, APPLICATION_REQUIREMENTS, APPLICATION_REQUIREMENTS_VERSION, type AgentIdentity, 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_SERVICE_URLS, type DeviceAuthorizationResponse, IdentityModule, type ListContactsOptions, type ListContactsResult, type OAuthHelperOptions, PLATFORM_SERVICE_IDS, type RequestOptions, type ServiceId, type TokenResponse, type Topolo, TopoloAuthError, TopoloClient, type TopoloClientOptions, type TopoloCredential, type TopoloDebugEvent, TopoloHttpError, TopoloOAuth, TopoloPermissionError, TopoloSdkError, applicationRequirementScopes, auditAllApplicationRequirements, auditApplicationRequirements, createTopolo, requirementsForApplication, resolveServiceUrl };
1432
+ export { APPLICATIONS, APPLICATION_REQUIREMENTS, APPLICATION_REQUIREMENTS_VERSION, type AgentIdentity, 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_SERVICE_URLS, type DeviceAuthorizationResponse, IdentityModule, type ListContactsOptions, type ListContactsResult, type OAuthHelperOptions, PLATFORM_SERVICE_IDS, type RequestOptions, type ServiceId, TOPOLO_WIDGET_ENDPOINT, TOPOLO_WIDGET_REFRESH_INTERVAL_MS, type TokenResponse, type Topolo, TopoloAuthError, type TopoloChartWidget, TopoloClient, type TopoloClientOptions, type TopoloCredential, type TopoloDebugEvent, TopoloHttpError, type TopoloNotificationsWidget, TopoloOAuth, TopoloPermissionError, type TopoloQuickActionsWidget, type TopoloRecentActivityWidget, TopoloSdkError, 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, resolveServiceUrl, validateTopoloWidgetResponse };
package/dist/index.js CHANGED
@@ -64,8 +64,10 @@ var SERVICES = {
64
64
  bugfix: "https://bugfix.topolo.app",
65
65
  bytes: "https://r2-media-manager-worker.topolo.workers.dev",
66
66
  calendar: "https://calendar.topolo.app",
67
+ capacity: "https://topolo-capacity.topolo.workers.dev",
67
68
  chat: "https://chat.topolo.app",
68
69
  commerce: "https://topolo-commerce-api.topolo.workers.dev",
70
+ compose: "https://compose.topolo.app",
69
71
  crm: "https://crm-api.topolo.app",
70
72
  customer_success: "https://customer-success.topolo.app",
71
73
  feed: "https://topolo-feed-api.topolo.app",
@@ -79,6 +81,7 @@ var SERVICES = {
79
81
  mdm: "https://topolo-mdm-api.topolo.app",
80
82
  messaging: "https://messages.topolo.app",
81
83
  nexus: "https://topolo-nexus-gateway.topolo.workers.dev",
84
+ notify: "https://notify.topolo.app",
82
85
  one: "https://one.topolo.app",
83
86
  pay: "https://topolo-pay.topolo.workers.dev",
84
87
  people: "https://people.topolo.app",
@@ -95,12 +98,14 @@ var SERVICES = {
95
98
  };
96
99
  var PLATFORM_SERVICE_IDS = {
97
100
  books: "srv_topolo_books",
101
+ compose: "srv_topolo_compose",
98
102
  crm: "srv_iCwM4jGXcwlj",
99
103
  customer_success: "srv_topolo_customer_success",
100
104
  flow: "srv_topolo_flow",
101
105
  forms: "srv_topolo_forms",
102
106
  insights: "srv_topolo_insights",
103
107
  inventory: "srv_topolo_inventory",
108
+ notify: "svc_topolo_notify",
104
109
  people: "srv_topolo_people",
105
110
  sign: "srv_topolo_sign",
106
111
  survey: "srv_topolo_survey",
@@ -279,6 +284,29 @@ var APPLICATIONS = {
279
284
  }
280
285
  ]
281
286
  },
287
+ "capacity": {
288
+ "id": "capacity",
289
+ "appDir": "TopoloCapacity",
290
+ "name": "topolo-capacity",
291
+ "packageName": "topolo-capacity",
292
+ "productionUrl": "https://capacity.topolo.app",
293
+ "services": [
294
+ "capacity"
295
+ ],
296
+ "deployTargets": [
297
+ {
298
+ "name": "topolo-capacity",
299
+ "kind": "worker",
300
+ "apiUrl": "https://topolo-capacity.topolo.workers.dev",
301
+ "domains": [
302
+ "capacity.topolo.app",
303
+ "topolo-capacity.topolo.workers.dev"
304
+ ],
305
+ "routes": [],
306
+ "serviceId": "capacity"
307
+ }
308
+ ]
309
+ },
282
310
  "chat": {
283
311
  "id": "chat",
284
312
  "appDir": "TopoloChat",
@@ -376,6 +404,30 @@ var APPLICATIONS = {
376
404
  }
377
405
  ]
378
406
  },
407
+ "compose": {
408
+ "id": "compose",
409
+ "appDir": "TopoloCompose",
410
+ "name": "topolo-compose",
411
+ "packageName": "@topolo/compose",
412
+ "productionUrl": "https://compose.topolo.app",
413
+ "services": [
414
+ "compose"
415
+ ],
416
+ "deployTargets": [
417
+ {
418
+ "name": "topolo-compose",
419
+ "kind": "worker",
420
+ "apiUrl": "https://compose.topolo.app",
421
+ "domains": [
422
+ "compose.topolo.app"
423
+ ],
424
+ "routes": [
425
+ "compose.topolo.app"
426
+ ],
427
+ "serviceId": "compose"
428
+ }
429
+ ]
430
+ },
379
431
  "crm": {
380
432
  "id": "crm",
381
433
  "appDir": "TopoloCRM",
@@ -793,6 +845,30 @@ var APPLICATIONS = {
793
845
  }
794
846
  ]
795
847
  },
848
+ "notify": {
849
+ "id": "notify",
850
+ "appDir": "TopoloNotify",
851
+ "name": "topolo-notify",
852
+ "packageName": "@topolo/notify",
853
+ "productionUrl": "https://notify.topolo.app",
854
+ "services": [
855
+ "notify"
856
+ ],
857
+ "deployTargets": [
858
+ {
859
+ "name": "topolo-notify",
860
+ "kind": "worker",
861
+ "apiUrl": "https://notify.topolo.app",
862
+ "domains": [
863
+ "notify.topolo.app"
864
+ ],
865
+ "routes": [
866
+ "notify.topolo.app"
867
+ ],
868
+ "serviceId": "notify"
869
+ }
870
+ ]
871
+ },
796
872
  "one": {
797
873
  "id": "one",
798
874
  "appDir": "TopoloOne",
@@ -1175,7 +1251,7 @@ var APPLICATIONS = {
1175
1251
  };
1176
1252
 
1177
1253
  // src/application-requirements.ts
1178
- var APPLICATION_REQUIREMENTS_VERSION = "2026-04-22.1";
1254
+ var APPLICATION_REQUIREMENTS_VERSION = "2026-04-25.1";
1179
1255
  var APPLICATION_REQUIREMENTS = [
1180
1256
  {
1181
1257
  id: "platform-metadata",
@@ -1307,6 +1383,22 @@ var APPLICATION_REQUIREMENTS = [
1307
1383
  "Keep command output JSON-stable for agents and human-readable with --no-json"
1308
1384
  ]
1309
1385
  },
1386
+ {
1387
+ id: "native-dashboard-widget",
1388
+ title: "Expose a native dashboard widget contract",
1389
+ summary: "Launchable first-party applications must populate TopoloOne live workspace through an app-owned /api/widget endpoint using the SDK widget response contract.",
1390
+ appliesTo: ["api"],
1391
+ evidence: [
1392
+ "The app-owned API exposes GET /api/widget",
1393
+ "The endpoint returns TopoloWidgetApiResponse from @topolo/sdk",
1394
+ "The endpoint derives organization/user context from the app auth boundary"
1395
+ ],
1396
+ implementation: [
1397
+ "Import createTopoloWidgetResponse from @topolo/sdk in the app backend",
1398
+ "Return native app metrics or action widgets instead of generic launch-card fallbacks",
1399
+ "Add a route-level test that validates the response with validateTopoloWidgetResponse"
1400
+ ]
1401
+ },
1310
1402
  {
1311
1403
  id: "observability-and-audit",
1312
1404
  title: "Emit platform audit and debugging signals",
@@ -1478,6 +1570,13 @@ function evaluateRequirement(application, requirement) {
1478
1570
  }
1479
1571
  return finding(requirement, "missing", "No SDK service or tooling surface is registered.", evidence);
1480
1572
  }
1573
+ case "native-dashboard-widget":
1574
+ return finding(
1575
+ requirement,
1576
+ "needs_review",
1577
+ "Catalog metadata cannot verify app-owned /api/widget implementation details.",
1578
+ evidence
1579
+ );
1481
1580
  case "observability-and-audit":
1482
1581
  return finding(
1483
1582
  requirement,
@@ -1876,6 +1975,161 @@ var TopoloOAuth = class {
1876
1975
  }
1877
1976
  };
1878
1977
 
1978
+ // src/widgets.ts
1979
+ var TOPOLO_WIDGET_ENDPOINT = "/api/widget";
1980
+ var TOPOLO_WIDGET_REFRESH_INTERVAL_MS = 6e4;
1981
+ function defineTopoloStatsWidget(widget) {
1982
+ return { ...widget, type: "stats" };
1983
+ }
1984
+ function defineTopoloRecentActivityWidget(widget) {
1985
+ return { ...widget, type: "recent-activity" };
1986
+ }
1987
+ function defineTopoloQuickActionsWidget(widget) {
1988
+ return { ...widget, type: "quick-actions" };
1989
+ }
1990
+ function defineTopoloNotificationsWidget(widget) {
1991
+ return { ...widget, type: "notifications" };
1992
+ }
1993
+ function defineTopoloChartWidget(widget) {
1994
+ return { ...widget, type: "chart" };
1995
+ }
1996
+ function createTopoloWidgetResponse({
1997
+ serviceId,
1998
+ serviceName,
1999
+ widgets,
2000
+ now
2001
+ }) {
2002
+ const lastUpdated = toIsoTimestamp(now);
2003
+ return {
2004
+ success: true,
2005
+ widgets: widgets.map((widget) => ({
2006
+ ...widget,
2007
+ serviceId: widget.serviceId?.trim() || serviceId,
2008
+ serviceName: widget.serviceName?.trim() || serviceName,
2009
+ lastUpdated: widget.lastUpdated?.trim() || lastUpdated
2010
+ }))
2011
+ };
2012
+ }
2013
+ function createTopoloWidgetError(error) {
2014
+ return {
2015
+ success: false,
2016
+ widgets: [],
2017
+ error
2018
+ };
2019
+ }
2020
+ function validateTopoloWidgetResponse(response) {
2021
+ const errors = [];
2022
+ if (!isRecord(response)) {
2023
+ return { ok: false, errors: ["response must be an object"] };
2024
+ }
2025
+ if (typeof response.success !== "boolean") {
2026
+ errors.push("success must be a boolean");
2027
+ }
2028
+ if (!Array.isArray(response.widgets)) {
2029
+ errors.push("widgets must be an array");
2030
+ return { ok: errors.length === 0, errors };
2031
+ }
2032
+ response.widgets.forEach((widget, index) => {
2033
+ validateWidget(widget, `widgets[${index}]`, errors);
2034
+ });
2035
+ if (response.success === false && response.error !== void 0 && typeof response.error !== "string") {
2036
+ errors.push("error must be a string when provided");
2037
+ }
2038
+ return { ok: errors.length === 0, errors };
2039
+ }
2040
+ function validateWidget(widget, path, errors) {
2041
+ if (!isRecord(widget)) {
2042
+ errors.push(`${path} must be an object`);
2043
+ return;
2044
+ }
2045
+ validateNonEmptyString(widget.serviceId, `${path}.serviceId`, errors);
2046
+ validateNonEmptyString(widget.serviceName, `${path}.serviceName`, errors);
2047
+ validateNonEmptyString(widget.lastUpdated, `${path}.lastUpdated`, errors);
2048
+ validateSnapshotMetadata(widget.snapshot, `${path}.snapshot`, errors);
2049
+ switch (widget.type) {
2050
+ case "stats":
2051
+ validateArray(widget.stats, `${path}.stats`, errors);
2052
+ break;
2053
+ case "recent-activity":
2054
+ validateArray(widget.activities, `${path}.activities`, errors);
2055
+ break;
2056
+ case "quick-actions":
2057
+ validateArray(widget.actions, `${path}.actions`, errors);
2058
+ break;
2059
+ case "notifications":
2060
+ validateArray(widget.notifications, `${path}.notifications`, errors);
2061
+ if (typeof widget.unreadCount !== "number") {
2062
+ errors.push(`${path}.unreadCount must be a number`);
2063
+ }
2064
+ break;
2065
+ case "chart":
2066
+ validateNonEmptyString(widget.chartType, `${path}.chartType`, errors);
2067
+ validateNonEmptyString(widget.title, `${path}.title`, errors);
2068
+ if (!isRecord(widget.data)) {
2069
+ errors.push(`${path}.data must be an object`);
2070
+ } else {
2071
+ validateArray(widget.data.labels, `${path}.data.labels`, errors);
2072
+ validateArray(widget.data.values, `${path}.data.values`, errors);
2073
+ }
2074
+ break;
2075
+ default:
2076
+ errors.push(`${path}.type must be a supported Topolo widget type`);
2077
+ }
2078
+ }
2079
+ function validateSnapshotMetadata(snapshot, path, errors) {
2080
+ if (snapshot === void 0) {
2081
+ return;
2082
+ }
2083
+ if (!isRecord(snapshot)) {
2084
+ errors.push(`${path} must be an object when provided`);
2085
+ return;
2086
+ }
2087
+ if (snapshot.defaultMetricKeys !== void 0 && !Array.isArray(snapshot.defaultMetricKeys)) {
2088
+ errors.push(`${path}.defaultMetricKeys must be an array when provided`);
2089
+ }
2090
+ if (snapshot.highlights !== void 0 && !Array.isArray(snapshot.highlights)) {
2091
+ errors.push(`${path}.highlights must be an array when provided`);
2092
+ }
2093
+ if (snapshot.availableMetrics === void 0) {
2094
+ return;
2095
+ }
2096
+ if (!Array.isArray(snapshot.availableMetrics)) {
2097
+ errors.push(`${path}.availableMetrics must be an array when provided`);
2098
+ return;
2099
+ }
2100
+ snapshot.availableMetrics.forEach((metric, index) => {
2101
+ const metricPath = `${path}.availableMetrics[${index}]`;
2102
+ if (!isRecord(metric)) {
2103
+ errors.push(`${metricPath} must be an object`);
2104
+ return;
2105
+ }
2106
+ validateNonEmptyString(metric.key, `${metricPath}.key`, errors);
2107
+ validateNonEmptyString(metric.label, `${metricPath}.label`, errors);
2108
+ if (typeof metric.value !== "number" || Number.isNaN(metric.value)) {
2109
+ errors.push(`${metricPath}.value must be a number`);
2110
+ }
2111
+ });
2112
+ }
2113
+ function validateNonEmptyString(value, path, errors) {
2114
+ if (typeof value !== "string" || value.trim().length === 0) {
2115
+ errors.push(`${path} must be a non-empty string`);
2116
+ }
2117
+ }
2118
+ function validateArray(value, path, errors) {
2119
+ if (!Array.isArray(value)) {
2120
+ errors.push(`${path} must be an array`);
2121
+ }
2122
+ }
2123
+ function isRecord(value) {
2124
+ return typeof value === "object" && value !== null && !Array.isArray(value);
2125
+ }
2126
+ function toIsoTimestamp(input) {
2127
+ if (input instanceof Date) {
2128
+ return input.toISOString();
2129
+ }
2130
+ return input ?? (/* @__PURE__ */ new Date()).toISOString();
2131
+ }
2132
+
1879
2133
  // src/index.ts
1880
2134
  function createTopolo(options) {
1881
2135
  const client = new TopoloClient(options);
@@ -1893,6 +2147,8 @@ export {
1893
2147
  DEFAULT_SERVICE_URLS,
1894
2148
  IdentityModule,
1895
2149
  PLATFORM_SERVICE_IDS,
2150
+ TOPOLO_WIDGET_ENDPOINT,
2151
+ TOPOLO_WIDGET_REFRESH_INTERVAL_MS,
1896
2152
  TopoloAuthError,
1897
2153
  TopoloClient,
1898
2154
  TopoloHttpError,
@@ -1903,6 +2159,14 @@ export {
1903
2159
  auditAllApplicationRequirements,
1904
2160
  auditApplicationRequirements,
1905
2161
  createTopolo,
2162
+ createTopoloWidgetError,
2163
+ createTopoloWidgetResponse,
2164
+ defineTopoloChartWidget,
2165
+ defineTopoloNotificationsWidget,
2166
+ defineTopoloQuickActionsWidget,
2167
+ defineTopoloRecentActivityWidget,
2168
+ defineTopoloStatsWidget,
1906
2169
  requirementsForApplication,
1907
- resolveServiceUrl
2170
+ resolveServiceUrl,
2171
+ validateTopoloWidgetResponse
1908
2172
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@topolo/sdk",
3
- "version": "0.2.5",
3
+ "version": "0.2.7",
4
4
  "description": "Typed client SDK for the Topolo platform. Used by TopoloCli, TopoloMCP, and third-party agents.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -4,7 +4,7 @@ import {
4
4
  type ApplicationId,
5
5
  } from './applications.generated.js';
6
6
 
7
- export const APPLICATION_REQUIREMENTS_VERSION = '2026-04-22.1';
7
+ export const APPLICATION_REQUIREMENTS_VERSION = '2026-04-25.1';
8
8
 
9
9
  export type ApplicationRequirementScope =
10
10
  | 'all'
@@ -205,6 +205,23 @@ export const APPLICATION_REQUIREMENTS = [
205
205
  'Keep command output JSON-stable for agents and human-readable with --no-json',
206
206
  ],
207
207
  },
208
+ {
209
+ id: 'native-dashboard-widget',
210
+ title: 'Expose a native dashboard widget contract',
211
+ summary:
212
+ 'Launchable first-party applications must populate TopoloOne live workspace through an app-owned /api/widget endpoint using the SDK widget response contract.',
213
+ appliesTo: ['api'],
214
+ evidence: [
215
+ 'The app-owned API exposes GET /api/widget',
216
+ 'The endpoint returns TopoloWidgetApiResponse from @topolo/sdk',
217
+ 'The endpoint derives organization/user context from the app auth boundary',
218
+ ],
219
+ implementation: [
220
+ 'Import createTopoloWidgetResponse from @topolo/sdk in the app backend',
221
+ 'Return native app metrics or action widgets instead of generic launch-card fallbacks',
222
+ 'Add a route-level test that validates the response with validateTopoloWidgetResponse',
223
+ ],
224
+ },
208
225
  {
209
226
  id: 'observability-and-audit',
210
227
  title: 'Emit platform audit and debugging signals',
@@ -411,6 +428,13 @@ function evaluateRequirement(
411
428
  }
412
429
  return finding(requirement, 'missing', 'No SDK service or tooling surface is registered.', evidence);
413
430
  }
431
+ case 'native-dashboard-widget':
432
+ return finding(
433
+ requirement,
434
+ 'needs_review',
435
+ 'Catalog metadata cannot verify app-owned /api/widget implementation details.',
436
+ evidence,
437
+ );
414
438
  case 'observability-and-audit':
415
439
  return finding(
416
440
  requirement,