@topolo/sdk 0.2.4 → 0.2.6

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.js CHANGED
@@ -60,14 +60,20 @@ var TopoloHttpError = class extends TopoloSdkError {
60
60
  var SERVICES = {
61
61
  agent: "https://topolo-agent-worker.topolo.workers.dev",
62
62
  auth: "https://auth.topolo.app",
63
+ books: "https://books.topolo.app",
63
64
  bugfix: "https://bugfix.topolo.app",
64
65
  bytes: "https://r2-media-manager-worker.topolo.workers.dev",
65
66
  calendar: "https://calendar.topolo.app",
66
67
  chat: "https://chat.topolo.app",
67
68
  commerce: "https://topolo-commerce-api.topolo.workers.dev",
68
69
  crm: "https://crm-api.topolo.app",
70
+ customer_success: "https://customer-success.topolo.app",
69
71
  feed: "https://topolo-feed-api.topolo.app",
72
+ flow: "https://flow.topolo.app",
70
73
  forecast: "https://forecast-worker-production.topolo.workers.dev",
74
+ forms: "https://forms.topolo.app",
75
+ insights: "https://insights.topolo.app",
76
+ inventory: "https://inventory.topolo.app",
71
77
  learn: "https://topololearn-api.topolo.workers.dev",
72
78
  mail: "https://mail.topolo.app",
73
79
  mdm: "https://topolo-mdm-api.topolo.app",
@@ -75,16 +81,30 @@ var SERVICES = {
75
81
  nexus: "https://topolo-nexus-gateway.topolo.workers.dev",
76
82
  one: "https://one.topolo.app",
77
83
  pay: "https://topolo-pay.topolo.workers.dev",
84
+ people: "https://people.topolo.app",
78
85
  "quro.api": "https://api.ol0.me",
79
86
  "quro.redirect": "https://ol0.me",
80
87
  roadmapper: "https://roadmapper-api.topolo.app",
88
+ sign: "https://sign.topolo.app",
81
89
  social_studio: "https://topolo-social-studio-api.topolo.workers.dev",
82
90
  socialize: "https://socialize-prod-api.topolo.workers.dev",
83
91
  support: "https://support.topolo.app",
92
+ survey: "https://survey.topolo.app",
93
+ voice: "https://voice.topolo.app",
84
94
  web: "https://web-api.topolo.app"
85
95
  };
86
96
  var PLATFORM_SERVICE_IDS = {
87
- crm: "srv_iCwM4jGXcwlj"
97
+ books: "srv_topolo_books",
98
+ crm: "srv_iCwM4jGXcwlj",
99
+ customer_success: "srv_topolo_customer_success",
100
+ flow: "srv_topolo_flow",
101
+ forms: "srv_topolo_forms",
102
+ insights: "srv_topolo_insights",
103
+ inventory: "srv_topolo_inventory",
104
+ people: "srv_topolo_people",
105
+ sign: "srv_topolo_sign",
106
+ survey: "srv_topolo_survey",
107
+ voice: "srv_topolo_voice"
88
108
  };
89
109
 
90
110
  // src/applications.generated.ts
@@ -159,6 +179,30 @@ var APPLICATIONS = {
159
179
  }
160
180
  ]
161
181
  },
182
+ "books": {
183
+ "id": "books",
184
+ "appDir": "TopoloBooks",
185
+ "name": "topolo-books",
186
+ "packageName": "topolo-books",
187
+ "productionUrl": "https://books.topolo.app",
188
+ "services": [
189
+ "books"
190
+ ],
191
+ "deployTargets": [
192
+ {
193
+ "name": "topolo-books",
194
+ "kind": "worker",
195
+ "apiUrl": "https://books.topolo.app",
196
+ "domains": [
197
+ "books.topolo.app"
198
+ ],
199
+ "routes": [
200
+ "books.topolo.app"
201
+ ],
202
+ "serviceId": "books"
203
+ }
204
+ ]
205
+ },
162
206
  "bugfix": {
163
207
  "id": "bugfix",
164
208
  "appDir": "TopoloBugFix",
@@ -360,6 +404,30 @@ var APPLICATIONS = {
360
404
  }
361
405
  ]
362
406
  },
407
+ "customer_success": {
408
+ "id": "customer_success",
409
+ "appDir": "TopoloCustomerSuccess",
410
+ "name": "topolo-customer-success",
411
+ "packageName": "topolo-customer-success",
412
+ "productionUrl": "https://customer-success.topolo.app",
413
+ "services": [
414
+ "customer_success"
415
+ ],
416
+ "deployTargets": [
417
+ {
418
+ "name": "topolo-customer-success",
419
+ "kind": "worker",
420
+ "apiUrl": "https://customer-success.topolo.app",
421
+ "domains": [
422
+ "customer-success.topolo.app"
423
+ ],
424
+ "routes": [
425
+ "customer-success.topolo.app"
426
+ ],
427
+ "serviceId": "customer_success"
428
+ }
429
+ ]
430
+ },
363
431
  "developers": {
364
432
  "id": "developers",
365
433
  "appDir": "TopoloDevelopers",
@@ -436,6 +504,30 @@ var APPLICATIONS = {
436
504
  }
437
505
  ]
438
506
  },
507
+ "flow": {
508
+ "id": "flow",
509
+ "appDir": "TopoloFlow",
510
+ "name": "topolo-flow",
511
+ "packageName": "topolo-flow",
512
+ "productionUrl": "https://flow.topolo.app",
513
+ "services": [
514
+ "flow"
515
+ ],
516
+ "deployTargets": [
517
+ {
518
+ "name": "topolo-flow",
519
+ "kind": "worker",
520
+ "apiUrl": "https://flow.topolo.app",
521
+ "domains": [
522
+ "flow.topolo.app"
523
+ ],
524
+ "routes": [
525
+ "flow.topolo.app"
526
+ ],
527
+ "serviceId": "flow"
528
+ }
529
+ ]
530
+ },
439
531
  "forecast": {
440
532
  "id": "forecast",
441
533
  "appDir": "TopoloForecast",
@@ -464,6 +556,78 @@ var APPLICATIONS = {
464
556
  }
465
557
  ]
466
558
  },
559
+ "forms": {
560
+ "id": "forms",
561
+ "appDir": "TopoloForms",
562
+ "name": "topolo-forms",
563
+ "packageName": "topolo-forms",
564
+ "productionUrl": "https://forms.topolo.app",
565
+ "services": [
566
+ "forms"
567
+ ],
568
+ "deployTargets": [
569
+ {
570
+ "name": "topolo-forms",
571
+ "kind": "worker",
572
+ "apiUrl": "https://forms.topolo.app",
573
+ "domains": [
574
+ "forms.topolo.app"
575
+ ],
576
+ "routes": [
577
+ "forms.topolo.app"
578
+ ],
579
+ "serviceId": "forms"
580
+ }
581
+ ]
582
+ },
583
+ "insights": {
584
+ "id": "insights",
585
+ "appDir": "TopoloInsights",
586
+ "name": "topolo-insights",
587
+ "packageName": "topolo-insights",
588
+ "productionUrl": "https://insights.topolo.app",
589
+ "services": [
590
+ "insights"
591
+ ],
592
+ "deployTargets": [
593
+ {
594
+ "name": "topolo-insights",
595
+ "kind": "worker",
596
+ "apiUrl": "https://insights.topolo.app",
597
+ "domains": [
598
+ "insights.topolo.app"
599
+ ],
600
+ "routes": [
601
+ "insights.topolo.app"
602
+ ],
603
+ "serviceId": "insights"
604
+ }
605
+ ]
606
+ },
607
+ "inventory": {
608
+ "id": "inventory",
609
+ "appDir": "TopoloInventory",
610
+ "name": "topolo-inventory",
611
+ "packageName": "topolo-inventory",
612
+ "productionUrl": "https://inventory.topolo.app",
613
+ "services": [
614
+ "inventory"
615
+ ],
616
+ "deployTargets": [
617
+ {
618
+ "name": "topolo-inventory",
619
+ "kind": "worker",
620
+ "apiUrl": "https://inventory.topolo.app",
621
+ "domains": [
622
+ "inventory.topolo.app"
623
+ ],
624
+ "routes": [
625
+ "inventory.topolo.app"
626
+ ],
627
+ "serviceId": "inventory"
628
+ }
629
+ ]
630
+ },
467
631
  "learn": {
468
632
  "id": "learn",
469
633
  "appDir": "TopoloLearn",
@@ -664,7 +828,9 @@ var APPLICATIONS = {
664
828
  "kind": "worker",
665
829
  "apiUrl": null,
666
830
  "domains": [
667
- "one.topolo.io"
831
+ "one.topolo.io",
832
+ "topolo.io",
833
+ "www.topolo.io"
668
834
  ],
669
835
  "routes": [],
670
836
  "serviceId": null
@@ -701,6 +867,30 @@ var APPLICATIONS = {
701
867
  }
702
868
  ]
703
869
  },
870
+ "people": {
871
+ "id": "people",
872
+ "appDir": "TopoloPeople",
873
+ "name": "topolo-people",
874
+ "packageName": "topolo-people",
875
+ "productionUrl": "https://people.topolo.app",
876
+ "services": [
877
+ "people"
878
+ ],
879
+ "deployTargets": [
880
+ {
881
+ "name": "topolo-people",
882
+ "kind": "worker",
883
+ "apiUrl": "https://people.topolo.app",
884
+ "domains": [
885
+ "people.topolo.app"
886
+ ],
887
+ "routes": [
888
+ "people.topolo.app"
889
+ ],
890
+ "serviceId": "people"
891
+ }
892
+ ]
893
+ },
704
894
  "quro": {
705
895
  "id": "quro",
706
896
  "appDir": "TopoloQuro",
@@ -772,6 +962,30 @@ var APPLICATIONS = {
772
962
  }
773
963
  ]
774
964
  },
965
+ "sign": {
966
+ "id": "sign",
967
+ "appDir": "TopoloSign",
968
+ "name": "topolo-sign",
969
+ "packageName": "topolo-sign",
970
+ "productionUrl": "https://sign.topolo.app",
971
+ "services": [
972
+ "sign"
973
+ ],
974
+ "deployTargets": [
975
+ {
976
+ "name": "topolo-sign",
977
+ "kind": "worker",
978
+ "apiUrl": "https://sign.topolo.app",
979
+ "domains": [
980
+ "sign.topolo.app"
981
+ ],
982
+ "routes": [
983
+ "sign.topolo.app"
984
+ ],
985
+ "serviceId": "sign"
986
+ }
987
+ ]
988
+ },
775
989
  "social_studio": {
776
990
  "id": "social_studio",
777
991
  "appDir": "TopoloSocialStudio",
@@ -868,6 +1082,54 @@ var APPLICATIONS = {
868
1082
  }
869
1083
  ]
870
1084
  },
1085
+ "survey": {
1086
+ "id": "survey",
1087
+ "appDir": "TopoloSurvey",
1088
+ "name": "topolo-survey",
1089
+ "packageName": "topolo-survey",
1090
+ "productionUrl": "https://survey.topolo.app",
1091
+ "services": [
1092
+ "survey"
1093
+ ],
1094
+ "deployTargets": [
1095
+ {
1096
+ "name": "topolo-survey",
1097
+ "kind": "worker",
1098
+ "apiUrl": "https://survey.topolo.app",
1099
+ "domains": [
1100
+ "survey.topolo.app"
1101
+ ],
1102
+ "routes": [
1103
+ "survey.topolo.app"
1104
+ ],
1105
+ "serviceId": "survey"
1106
+ }
1107
+ ]
1108
+ },
1109
+ "voice": {
1110
+ "id": "voice",
1111
+ "appDir": "TopoloVoice",
1112
+ "name": "topolo-voice",
1113
+ "packageName": "topolo-voice",
1114
+ "productionUrl": "https://voice.topolo.app",
1115
+ "services": [
1116
+ "voice"
1117
+ ],
1118
+ "deployTargets": [
1119
+ {
1120
+ "name": "topolo-voice",
1121
+ "kind": "worker",
1122
+ "apiUrl": "https://voice.topolo.app",
1123
+ "domains": [
1124
+ "voice.topolo.app"
1125
+ ],
1126
+ "routes": [
1127
+ "voice.topolo.app"
1128
+ ],
1129
+ "serviceId": "voice"
1130
+ }
1131
+ ]
1132
+ },
871
1133
  "web": {
872
1134
  "id": "web",
873
1135
  "appDir": "TopoloWeb",
@@ -913,7 +1175,7 @@ var APPLICATIONS = {
913
1175
  };
914
1176
 
915
1177
  // src/application-requirements.ts
916
- var APPLICATION_REQUIREMENTS_VERSION = "2026-04-22.1";
1178
+ var APPLICATION_REQUIREMENTS_VERSION = "2026-04-25.1";
917
1179
  var APPLICATION_REQUIREMENTS = [
918
1180
  {
919
1181
  id: "platform-metadata",
@@ -1045,6 +1307,22 @@ var APPLICATION_REQUIREMENTS = [
1045
1307
  "Keep command output JSON-stable for agents and human-readable with --no-json"
1046
1308
  ]
1047
1309
  },
1310
+ {
1311
+ id: "native-dashboard-widget",
1312
+ title: "Expose a native dashboard widget contract",
1313
+ summary: "Launchable first-party applications must populate TopoloOne live workspace through an app-owned /api/widget endpoint using the SDK widget response contract.",
1314
+ appliesTo: ["api"],
1315
+ evidence: [
1316
+ "The app-owned API exposes GET /api/widget",
1317
+ "The endpoint returns TopoloWidgetApiResponse from @topolo/sdk",
1318
+ "The endpoint derives organization/user context from the app auth boundary"
1319
+ ],
1320
+ implementation: [
1321
+ "Import createTopoloWidgetResponse from @topolo/sdk in the app backend",
1322
+ "Return native app metrics or action widgets instead of generic launch-card fallbacks",
1323
+ "Add a route-level test that validates the response with validateTopoloWidgetResponse"
1324
+ ]
1325
+ },
1048
1326
  {
1049
1327
  id: "observability-and-audit",
1050
1328
  title: "Emit platform audit and debugging signals",
@@ -1080,9 +1358,8 @@ var APPLICATION_REQUIREMENTS = [
1080
1358
  ];
1081
1359
  function applicationRequirementScopes(application) {
1082
1360
  const scopes = /* @__PURE__ */ new Set(["all"]);
1083
- const deployTargets = application.deployTargets;
1084
- const hasBrowserSurface = Boolean(application.productionUrl) || deployTargets.some((target) => target.kind === "pages");
1085
- const hasApiSurface = application.services.length > 0 || deployTargets.some((target) => Boolean(target.apiUrl));
1361
+ const hasBrowserSurface = Boolean(application.productionUrl) || application.deployTargets.some((target) => target.kind === "pages");
1362
+ const hasApiSurface = application.services.length > 0 || application.deployTargets.some((target) => Boolean(target.apiUrl));
1086
1363
  if (hasBrowserSurface) scopes.add("browser");
1087
1364
  if (hasApiSurface) scopes.add("api");
1088
1365
  if (application.id === "cli" || application.id === "mcp" || application.id === "cloudcontrol") {
@@ -1217,6 +1494,13 @@ function evaluateRequirement(application, requirement) {
1217
1494
  }
1218
1495
  return finding(requirement, "missing", "No SDK service or tooling surface is registered.", evidence);
1219
1496
  }
1497
+ case "native-dashboard-widget":
1498
+ return finding(
1499
+ requirement,
1500
+ "needs_review",
1501
+ "Catalog metadata cannot verify app-owned /api/widget implementation details.",
1502
+ evidence
1503
+ );
1220
1504
  case "observability-and-audit":
1221
1505
  return finding(
1222
1506
  requirement,
@@ -1270,11 +1554,10 @@ function statusRank(status) {
1270
1554
  // src/services.ts
1271
1555
  var DEFAULT_SERVICE_URLS = SERVICES;
1272
1556
  function resolveServiceUrl(service, overrides) {
1273
- var _a;
1274
- const override = overrides == null ? void 0 : overrides[service];
1557
+ const override = overrides?.[service];
1275
1558
  if (override) return override;
1276
1559
  const envKey = `TOPOLO_SERVICE_URL_${service.replace(/\./g, "_").toUpperCase()}`;
1277
- const envValue = typeof process !== "undefined" ? (_a = process.env) == null ? void 0 : _a[envKey] : void 0;
1560
+ const envValue = typeof process !== "undefined" ? process.env?.[envKey] : void 0;
1278
1561
  if (envValue) return envValue;
1279
1562
  return DEFAULT_SERVICE_URLS[service];
1280
1563
  }
@@ -1290,9 +1573,8 @@ var TopoloClient = class {
1290
1573
  fetchImpl;
1291
1574
  debug;
1292
1575
  constructor(options) {
1293
- var _a;
1294
1576
  if (!options.credential) throw new TopoloAuthError("credential is required");
1295
- if (!((_a = options.agent) == null ? void 0 : _a.clientName)) throw new TopoloAuthError("agent.clientName is required");
1577
+ if (!options.agent?.clientName) throw new TopoloAuthError("agent.clientName is required");
1296
1578
  this.credential = options.credential;
1297
1579
  this.agent = options.agent;
1298
1580
  this.serviceUrls = options.serviceUrls;
@@ -1482,7 +1764,6 @@ var CrmModule = class {
1482
1764
  }
1483
1765
  client;
1484
1766
  async listContacts(options = {}) {
1485
- var _a, _b, _c;
1486
1767
  const res = await this.client.request({
1487
1768
  service: "crm",
1488
1769
  path: "/api/contacts",
@@ -1492,12 +1773,12 @@ var CrmModule = class {
1492
1773
  pageSize: options.pageSize
1493
1774
  }
1494
1775
  });
1495
- const rows = Array.isArray(res == null ? void 0 : res.contacts) ? res.contacts : Array.isArray(res == null ? void 0 : res.data) ? res.data : [];
1776
+ const rows = Array.isArray(res?.contacts) ? res.contacts : Array.isArray(res?.data) ? res.data : [];
1496
1777
  return {
1497
1778
  contacts: rows.map(toSummary),
1498
- total: (res == null ? void 0 : res.total) ?? ((_a = res == null ? void 0 : res.pagination) == null ? void 0 : _a.total) ?? rows.length,
1499
- page: (res == null ? void 0 : res.page) ?? ((_b = res == null ? void 0 : res.pagination) == null ? void 0 : _b.page) ?? options.page ?? 1,
1500
- pageSize: (res == null ? void 0 : res.pageSize) ?? ((_c = res == null ? void 0 : res.pagination) == null ? void 0 : _c.pageSize) ?? options.pageSize ?? rows.length
1779
+ total: res?.total ?? res?.pagination?.total ?? rows.length,
1780
+ page: res?.page ?? res?.pagination?.page ?? options.page ?? 1,
1781
+ pageSize: res?.pageSize ?? res?.pagination?.pageSize ?? options.pageSize ?? rows.length
1501
1782
  };
1502
1783
  }
1503
1784
  async getContact(contactId) {
@@ -1618,6 +1899,126 @@ var TopoloOAuth = class {
1618
1899
  }
1619
1900
  };
1620
1901
 
1902
+ // src/widgets.ts
1903
+ var TOPOLO_WIDGET_ENDPOINT = "/api/widget";
1904
+ var TOPOLO_WIDGET_REFRESH_INTERVAL_MS = 6e4;
1905
+ function defineTopoloStatsWidget(widget) {
1906
+ return { ...widget, type: "stats" };
1907
+ }
1908
+ function defineTopoloRecentActivityWidget(widget) {
1909
+ return { ...widget, type: "recent-activity" };
1910
+ }
1911
+ function defineTopoloQuickActionsWidget(widget) {
1912
+ return { ...widget, type: "quick-actions" };
1913
+ }
1914
+ function defineTopoloNotificationsWidget(widget) {
1915
+ return { ...widget, type: "notifications" };
1916
+ }
1917
+ function defineTopoloChartWidget(widget) {
1918
+ return { ...widget, type: "chart" };
1919
+ }
1920
+ function createTopoloWidgetResponse({
1921
+ serviceId,
1922
+ serviceName,
1923
+ widgets,
1924
+ now
1925
+ }) {
1926
+ const lastUpdated = toIsoTimestamp(now);
1927
+ return {
1928
+ success: true,
1929
+ widgets: widgets.map((widget) => ({
1930
+ ...widget,
1931
+ serviceId: widget.serviceId?.trim() || serviceId,
1932
+ serviceName: widget.serviceName?.trim() || serviceName,
1933
+ lastUpdated: widget.lastUpdated?.trim() || lastUpdated
1934
+ }))
1935
+ };
1936
+ }
1937
+ function createTopoloWidgetError(error) {
1938
+ return {
1939
+ success: false,
1940
+ widgets: [],
1941
+ error
1942
+ };
1943
+ }
1944
+ function validateTopoloWidgetResponse(response) {
1945
+ const errors = [];
1946
+ if (!isRecord(response)) {
1947
+ return { ok: false, errors: ["response must be an object"] };
1948
+ }
1949
+ if (typeof response.success !== "boolean") {
1950
+ errors.push("success must be a boolean");
1951
+ }
1952
+ if (!Array.isArray(response.widgets)) {
1953
+ errors.push("widgets must be an array");
1954
+ return { ok: errors.length === 0, errors };
1955
+ }
1956
+ response.widgets.forEach((widget, index) => {
1957
+ validateWidget(widget, `widgets[${index}]`, errors);
1958
+ });
1959
+ if (response.success === false && response.error !== void 0 && typeof response.error !== "string") {
1960
+ errors.push("error must be a string when provided");
1961
+ }
1962
+ return { ok: errors.length === 0, errors };
1963
+ }
1964
+ function validateWidget(widget, path, errors) {
1965
+ if (!isRecord(widget)) {
1966
+ errors.push(`${path} must be an object`);
1967
+ return;
1968
+ }
1969
+ validateNonEmptyString(widget.serviceId, `${path}.serviceId`, errors);
1970
+ validateNonEmptyString(widget.serviceName, `${path}.serviceName`, errors);
1971
+ validateNonEmptyString(widget.lastUpdated, `${path}.lastUpdated`, errors);
1972
+ switch (widget.type) {
1973
+ case "stats":
1974
+ validateArray(widget.stats, `${path}.stats`, errors);
1975
+ break;
1976
+ case "recent-activity":
1977
+ validateArray(widget.activities, `${path}.activities`, errors);
1978
+ break;
1979
+ case "quick-actions":
1980
+ validateArray(widget.actions, `${path}.actions`, errors);
1981
+ break;
1982
+ case "notifications":
1983
+ validateArray(widget.notifications, `${path}.notifications`, errors);
1984
+ if (typeof widget.unreadCount !== "number") {
1985
+ errors.push(`${path}.unreadCount must be a number`);
1986
+ }
1987
+ break;
1988
+ case "chart":
1989
+ validateNonEmptyString(widget.chartType, `${path}.chartType`, errors);
1990
+ validateNonEmptyString(widget.title, `${path}.title`, errors);
1991
+ if (!isRecord(widget.data)) {
1992
+ errors.push(`${path}.data must be an object`);
1993
+ } else {
1994
+ validateArray(widget.data.labels, `${path}.data.labels`, errors);
1995
+ validateArray(widget.data.values, `${path}.data.values`, errors);
1996
+ }
1997
+ break;
1998
+ default:
1999
+ errors.push(`${path}.type must be a supported Topolo widget type`);
2000
+ }
2001
+ }
2002
+ function validateNonEmptyString(value, path, errors) {
2003
+ if (typeof value !== "string" || value.trim().length === 0) {
2004
+ errors.push(`${path} must be a non-empty string`);
2005
+ }
2006
+ }
2007
+ function validateArray(value, path, errors) {
2008
+ if (!Array.isArray(value)) {
2009
+ errors.push(`${path} must be an array`);
2010
+ }
2011
+ }
2012
+ function isRecord(value) {
2013
+ return typeof value === "object" && value !== null && !Array.isArray(value);
2014
+ }
2015
+ function toIsoTimestamp(input) {
2016
+ if (input instanceof Date) {
2017
+ return input.toISOString();
2018
+ }
2019
+ return input ?? (/* @__PURE__ */ new Date()).toISOString();
2020
+ }
2021
+
1621
2022
  // src/index.ts
1622
2023
  function createTopolo(options) {
1623
2024
  const client = new TopoloClient(options);
@@ -1635,6 +2036,8 @@ export {
1635
2036
  DEFAULT_SERVICE_URLS,
1636
2037
  IdentityModule,
1637
2038
  PLATFORM_SERVICE_IDS,
2039
+ TOPOLO_WIDGET_ENDPOINT,
2040
+ TOPOLO_WIDGET_REFRESH_INTERVAL_MS,
1638
2041
  TopoloAuthError,
1639
2042
  TopoloClient,
1640
2043
  TopoloHttpError,
@@ -1645,6 +2048,14 @@ export {
1645
2048
  auditAllApplicationRequirements,
1646
2049
  auditApplicationRequirements,
1647
2050
  createTopolo,
2051
+ createTopoloWidgetError,
2052
+ createTopoloWidgetResponse,
2053
+ defineTopoloChartWidget,
2054
+ defineTopoloNotificationsWidget,
2055
+ defineTopoloQuickActionsWidget,
2056
+ defineTopoloRecentActivityWidget,
2057
+ defineTopoloStatsWidget,
1648
2058
  requirementsForApplication,
1649
- resolveServiceUrl
2059
+ resolveServiceUrl,
2060
+ validateTopoloWidgetResponse
1650
2061
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@topolo/sdk",
3
- "version": "0.2.4",
3
+ "version": "0.2.6",
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",
@@ -1,11 +1,10 @@
1
1
  import {
2
2
  APPLICATIONS,
3
3
  type ApplicationCatalogEntry,
4
- type ApplicationDeployTarget,
5
4
  type ApplicationId,
6
5
  } from './applications.generated.js';
7
6
 
8
- export const APPLICATION_REQUIREMENTS_VERSION = '2026-04-22.1';
7
+ export const APPLICATION_REQUIREMENTS_VERSION = '2026-04-25.1';
9
8
 
10
9
  export type ApplicationRequirementScope =
11
10
  | 'all'
@@ -206,6 +205,23 @@ export const APPLICATION_REQUIREMENTS = [
206
205
  'Keep command output JSON-stable for agents and human-readable with --no-json',
207
206
  ],
208
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
+ },
209
225
  {
210
226
  id: 'observability-and-audit',
211
227
  title: 'Emit platform audit and debugging signals',
@@ -246,12 +262,11 @@ export function applicationRequirementScopes(
246
262
  application: ApplicationCatalogEntry,
247
263
  ): ApplicationRequirementScope[] {
248
264
  const scopes = new Set<ApplicationRequirementScope>(['all']);
249
- const deployTargets = application.deployTargets as readonly ApplicationDeployTarget[];
250
265
  const hasBrowserSurface =
251
- Boolean(application.productionUrl) || deployTargets.some((target) => target.kind === 'pages');
266
+ Boolean(application.productionUrl) || application.deployTargets.some((target) => target.kind === 'pages');
252
267
  const hasApiSurface =
253
268
  application.services.length > 0 ||
254
- deployTargets.some((target) => Boolean(target.apiUrl));
269
+ application.deployTargets.some((target) => Boolean(target.apiUrl));
255
270
 
256
271
  if (hasBrowserSurface) scopes.add('browser');
257
272
  if (hasApiSurface) scopes.add('api');
@@ -413,6 +428,13 @@ function evaluateRequirement(
413
428
  }
414
429
  return finding(requirement, 'missing', 'No SDK service or tooling surface is registered.', evidence);
415
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
+ );
416
438
  case 'observability-and-audit':
417
439
  return finding(
418
440
  requirement,