@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/README.md +23 -0
- package/dist/index.cjs +440 -18
- package/dist/index.d.cts +338 -59
- package/dist/index.d.ts +338 -59
- package/dist/index.js +428 -17
- package/package.json +1 -1
- package/src/application-requirements.ts +27 -5
- package/src/applications.generated.ts +243 -1
- package/src/index.ts +29 -0
- package/src/services.generated.ts +20 -0
- package/src/services.test.ts +27 -0
- package/src/widgets.test.ts +123 -0
- package/src/widgets.ts +288 -0
package/README.md
CHANGED
|
@@ -94,6 +94,29 @@ that contract into catalog-backed conformance reports and migration-queue items.
|
|
|
94
94
|
Catalog-visible evidence is marked directly; implementation details that require
|
|
95
95
|
code or docs inspection are deliberately marked `needs_review`.
|
|
96
96
|
|
|
97
|
+
## Native dashboard widgets
|
|
98
|
+
|
|
99
|
+
Launchable first-party applications populate the TopoloOne live workspace through
|
|
100
|
+
their own `GET /api/widget` endpoint. The SDK owns the shared payload contract:
|
|
101
|
+
|
|
102
|
+
```ts
|
|
103
|
+
import { createTopoloWidgetResponse } from '@topolo/sdk';
|
|
104
|
+
|
|
105
|
+
return Response.json(createTopoloWidgetResponse({
|
|
106
|
+
serviceId: 'srv_topolo_example',
|
|
107
|
+
serviceName: 'Example',
|
|
108
|
+
widgets: [
|
|
109
|
+
{
|
|
110
|
+
type: 'stats',
|
|
111
|
+
stats: [{ label: 'Open items', value: 3 }],
|
|
112
|
+
},
|
|
113
|
+
],
|
|
114
|
+
}));
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
Use `validateTopoloWidgetResponse()` in endpoint tests to prevent app-local
|
|
118
|
+
payload drift.
|
|
119
|
+
|
|
97
120
|
## Escape hatch
|
|
98
121
|
|
|
99
122
|
```ts
|
package/dist/index.cjs
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
"use strict";
|
|
1
2
|
var __defProp = Object.defineProperty;
|
|
2
3
|
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
3
4
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
@@ -26,6 +27,8 @@ __export(index_exports, {
|
|
|
26
27
|
DEFAULT_SERVICE_URLS: () => DEFAULT_SERVICE_URLS,
|
|
27
28
|
IdentityModule: () => IdentityModule,
|
|
28
29
|
PLATFORM_SERVICE_IDS: () => PLATFORM_SERVICE_IDS,
|
|
30
|
+
TOPOLO_WIDGET_ENDPOINT: () => TOPOLO_WIDGET_ENDPOINT,
|
|
31
|
+
TOPOLO_WIDGET_REFRESH_INTERVAL_MS: () => TOPOLO_WIDGET_REFRESH_INTERVAL_MS,
|
|
29
32
|
TopoloAuthError: () => TopoloAuthError,
|
|
30
33
|
TopoloClient: () => TopoloClient,
|
|
31
34
|
TopoloHttpError: () => TopoloHttpError,
|
|
@@ -36,8 +39,16 @@ __export(index_exports, {
|
|
|
36
39
|
auditAllApplicationRequirements: () => auditAllApplicationRequirements,
|
|
37
40
|
auditApplicationRequirements: () => auditApplicationRequirements,
|
|
38
41
|
createTopolo: () => createTopolo,
|
|
42
|
+
createTopoloWidgetError: () => createTopoloWidgetError,
|
|
43
|
+
createTopoloWidgetResponse: () => createTopoloWidgetResponse,
|
|
44
|
+
defineTopoloChartWidget: () => defineTopoloChartWidget,
|
|
45
|
+
defineTopoloNotificationsWidget: () => defineTopoloNotificationsWidget,
|
|
46
|
+
defineTopoloQuickActionsWidget: () => defineTopoloQuickActionsWidget,
|
|
47
|
+
defineTopoloRecentActivityWidget: () => defineTopoloRecentActivityWidget,
|
|
48
|
+
defineTopoloStatsWidget: () => defineTopoloStatsWidget,
|
|
39
49
|
requirementsForApplication: () => requirementsForApplication,
|
|
40
|
-
resolveServiceUrl: () => resolveServiceUrl
|
|
50
|
+
resolveServiceUrl: () => resolveServiceUrl,
|
|
51
|
+
validateTopoloWidgetResponse: () => validateTopoloWidgetResponse
|
|
41
52
|
});
|
|
42
53
|
module.exports = __toCommonJS(index_exports);
|
|
43
54
|
|
|
@@ -103,14 +114,20 @@ var TopoloHttpError = class extends TopoloSdkError {
|
|
|
103
114
|
var SERVICES = {
|
|
104
115
|
agent: "https://topolo-agent-worker.topolo.workers.dev",
|
|
105
116
|
auth: "https://auth.topolo.app",
|
|
117
|
+
books: "https://books.topolo.app",
|
|
106
118
|
bugfix: "https://bugfix.topolo.app",
|
|
107
119
|
bytes: "https://r2-media-manager-worker.topolo.workers.dev",
|
|
108
120
|
calendar: "https://calendar.topolo.app",
|
|
109
121
|
chat: "https://chat.topolo.app",
|
|
110
122
|
commerce: "https://topolo-commerce-api.topolo.workers.dev",
|
|
111
123
|
crm: "https://crm-api.topolo.app",
|
|
124
|
+
customer_success: "https://customer-success.topolo.app",
|
|
112
125
|
feed: "https://topolo-feed-api.topolo.app",
|
|
126
|
+
flow: "https://flow.topolo.app",
|
|
113
127
|
forecast: "https://forecast-worker-production.topolo.workers.dev",
|
|
128
|
+
forms: "https://forms.topolo.app",
|
|
129
|
+
insights: "https://insights.topolo.app",
|
|
130
|
+
inventory: "https://inventory.topolo.app",
|
|
114
131
|
learn: "https://topololearn-api.topolo.workers.dev",
|
|
115
132
|
mail: "https://mail.topolo.app",
|
|
116
133
|
mdm: "https://topolo-mdm-api.topolo.app",
|
|
@@ -118,16 +135,30 @@ var SERVICES = {
|
|
|
118
135
|
nexus: "https://topolo-nexus-gateway.topolo.workers.dev",
|
|
119
136
|
one: "https://one.topolo.app",
|
|
120
137
|
pay: "https://topolo-pay.topolo.workers.dev",
|
|
138
|
+
people: "https://people.topolo.app",
|
|
121
139
|
"quro.api": "https://api.ol0.me",
|
|
122
140
|
"quro.redirect": "https://ol0.me",
|
|
123
141
|
roadmapper: "https://roadmapper-api.topolo.app",
|
|
142
|
+
sign: "https://sign.topolo.app",
|
|
124
143
|
social_studio: "https://topolo-social-studio-api.topolo.workers.dev",
|
|
125
144
|
socialize: "https://socialize-prod-api.topolo.workers.dev",
|
|
126
145
|
support: "https://support.topolo.app",
|
|
146
|
+
survey: "https://survey.topolo.app",
|
|
147
|
+
voice: "https://voice.topolo.app",
|
|
127
148
|
web: "https://web-api.topolo.app"
|
|
128
149
|
};
|
|
129
150
|
var PLATFORM_SERVICE_IDS = {
|
|
130
|
-
|
|
151
|
+
books: "srv_topolo_books",
|
|
152
|
+
crm: "srv_iCwM4jGXcwlj",
|
|
153
|
+
customer_success: "srv_topolo_customer_success",
|
|
154
|
+
flow: "srv_topolo_flow",
|
|
155
|
+
forms: "srv_topolo_forms",
|
|
156
|
+
insights: "srv_topolo_insights",
|
|
157
|
+
inventory: "srv_topolo_inventory",
|
|
158
|
+
people: "srv_topolo_people",
|
|
159
|
+
sign: "srv_topolo_sign",
|
|
160
|
+
survey: "srv_topolo_survey",
|
|
161
|
+
voice: "srv_topolo_voice"
|
|
131
162
|
};
|
|
132
163
|
|
|
133
164
|
// src/applications.generated.ts
|
|
@@ -202,6 +233,30 @@ var APPLICATIONS = {
|
|
|
202
233
|
}
|
|
203
234
|
]
|
|
204
235
|
},
|
|
236
|
+
"books": {
|
|
237
|
+
"id": "books",
|
|
238
|
+
"appDir": "TopoloBooks",
|
|
239
|
+
"name": "topolo-books",
|
|
240
|
+
"packageName": "topolo-books",
|
|
241
|
+
"productionUrl": "https://books.topolo.app",
|
|
242
|
+
"services": [
|
|
243
|
+
"books"
|
|
244
|
+
],
|
|
245
|
+
"deployTargets": [
|
|
246
|
+
{
|
|
247
|
+
"name": "topolo-books",
|
|
248
|
+
"kind": "worker",
|
|
249
|
+
"apiUrl": "https://books.topolo.app",
|
|
250
|
+
"domains": [
|
|
251
|
+
"books.topolo.app"
|
|
252
|
+
],
|
|
253
|
+
"routes": [
|
|
254
|
+
"books.topolo.app"
|
|
255
|
+
],
|
|
256
|
+
"serviceId": "books"
|
|
257
|
+
}
|
|
258
|
+
]
|
|
259
|
+
},
|
|
205
260
|
"bugfix": {
|
|
206
261
|
"id": "bugfix",
|
|
207
262
|
"appDir": "TopoloBugFix",
|
|
@@ -403,6 +458,30 @@ var APPLICATIONS = {
|
|
|
403
458
|
}
|
|
404
459
|
]
|
|
405
460
|
},
|
|
461
|
+
"customer_success": {
|
|
462
|
+
"id": "customer_success",
|
|
463
|
+
"appDir": "TopoloCustomerSuccess",
|
|
464
|
+
"name": "topolo-customer-success",
|
|
465
|
+
"packageName": "topolo-customer-success",
|
|
466
|
+
"productionUrl": "https://customer-success.topolo.app",
|
|
467
|
+
"services": [
|
|
468
|
+
"customer_success"
|
|
469
|
+
],
|
|
470
|
+
"deployTargets": [
|
|
471
|
+
{
|
|
472
|
+
"name": "topolo-customer-success",
|
|
473
|
+
"kind": "worker",
|
|
474
|
+
"apiUrl": "https://customer-success.topolo.app",
|
|
475
|
+
"domains": [
|
|
476
|
+
"customer-success.topolo.app"
|
|
477
|
+
],
|
|
478
|
+
"routes": [
|
|
479
|
+
"customer-success.topolo.app"
|
|
480
|
+
],
|
|
481
|
+
"serviceId": "customer_success"
|
|
482
|
+
}
|
|
483
|
+
]
|
|
484
|
+
},
|
|
406
485
|
"developers": {
|
|
407
486
|
"id": "developers",
|
|
408
487
|
"appDir": "TopoloDevelopers",
|
|
@@ -479,6 +558,30 @@ var APPLICATIONS = {
|
|
|
479
558
|
}
|
|
480
559
|
]
|
|
481
560
|
},
|
|
561
|
+
"flow": {
|
|
562
|
+
"id": "flow",
|
|
563
|
+
"appDir": "TopoloFlow",
|
|
564
|
+
"name": "topolo-flow",
|
|
565
|
+
"packageName": "topolo-flow",
|
|
566
|
+
"productionUrl": "https://flow.topolo.app",
|
|
567
|
+
"services": [
|
|
568
|
+
"flow"
|
|
569
|
+
],
|
|
570
|
+
"deployTargets": [
|
|
571
|
+
{
|
|
572
|
+
"name": "topolo-flow",
|
|
573
|
+
"kind": "worker",
|
|
574
|
+
"apiUrl": "https://flow.topolo.app",
|
|
575
|
+
"domains": [
|
|
576
|
+
"flow.topolo.app"
|
|
577
|
+
],
|
|
578
|
+
"routes": [
|
|
579
|
+
"flow.topolo.app"
|
|
580
|
+
],
|
|
581
|
+
"serviceId": "flow"
|
|
582
|
+
}
|
|
583
|
+
]
|
|
584
|
+
},
|
|
482
585
|
"forecast": {
|
|
483
586
|
"id": "forecast",
|
|
484
587
|
"appDir": "TopoloForecast",
|
|
@@ -507,6 +610,78 @@ var APPLICATIONS = {
|
|
|
507
610
|
}
|
|
508
611
|
]
|
|
509
612
|
},
|
|
613
|
+
"forms": {
|
|
614
|
+
"id": "forms",
|
|
615
|
+
"appDir": "TopoloForms",
|
|
616
|
+
"name": "topolo-forms",
|
|
617
|
+
"packageName": "topolo-forms",
|
|
618
|
+
"productionUrl": "https://forms.topolo.app",
|
|
619
|
+
"services": [
|
|
620
|
+
"forms"
|
|
621
|
+
],
|
|
622
|
+
"deployTargets": [
|
|
623
|
+
{
|
|
624
|
+
"name": "topolo-forms",
|
|
625
|
+
"kind": "worker",
|
|
626
|
+
"apiUrl": "https://forms.topolo.app",
|
|
627
|
+
"domains": [
|
|
628
|
+
"forms.topolo.app"
|
|
629
|
+
],
|
|
630
|
+
"routes": [
|
|
631
|
+
"forms.topolo.app"
|
|
632
|
+
],
|
|
633
|
+
"serviceId": "forms"
|
|
634
|
+
}
|
|
635
|
+
]
|
|
636
|
+
},
|
|
637
|
+
"insights": {
|
|
638
|
+
"id": "insights",
|
|
639
|
+
"appDir": "TopoloInsights",
|
|
640
|
+
"name": "topolo-insights",
|
|
641
|
+
"packageName": "topolo-insights",
|
|
642
|
+
"productionUrl": "https://insights.topolo.app",
|
|
643
|
+
"services": [
|
|
644
|
+
"insights"
|
|
645
|
+
],
|
|
646
|
+
"deployTargets": [
|
|
647
|
+
{
|
|
648
|
+
"name": "topolo-insights",
|
|
649
|
+
"kind": "worker",
|
|
650
|
+
"apiUrl": "https://insights.topolo.app",
|
|
651
|
+
"domains": [
|
|
652
|
+
"insights.topolo.app"
|
|
653
|
+
],
|
|
654
|
+
"routes": [
|
|
655
|
+
"insights.topolo.app"
|
|
656
|
+
],
|
|
657
|
+
"serviceId": "insights"
|
|
658
|
+
}
|
|
659
|
+
]
|
|
660
|
+
},
|
|
661
|
+
"inventory": {
|
|
662
|
+
"id": "inventory",
|
|
663
|
+
"appDir": "TopoloInventory",
|
|
664
|
+
"name": "topolo-inventory",
|
|
665
|
+
"packageName": "topolo-inventory",
|
|
666
|
+
"productionUrl": "https://inventory.topolo.app",
|
|
667
|
+
"services": [
|
|
668
|
+
"inventory"
|
|
669
|
+
],
|
|
670
|
+
"deployTargets": [
|
|
671
|
+
{
|
|
672
|
+
"name": "topolo-inventory",
|
|
673
|
+
"kind": "worker",
|
|
674
|
+
"apiUrl": "https://inventory.topolo.app",
|
|
675
|
+
"domains": [
|
|
676
|
+
"inventory.topolo.app"
|
|
677
|
+
],
|
|
678
|
+
"routes": [
|
|
679
|
+
"inventory.topolo.app"
|
|
680
|
+
],
|
|
681
|
+
"serviceId": "inventory"
|
|
682
|
+
}
|
|
683
|
+
]
|
|
684
|
+
},
|
|
510
685
|
"learn": {
|
|
511
686
|
"id": "learn",
|
|
512
687
|
"appDir": "TopoloLearn",
|
|
@@ -707,7 +882,9 @@ var APPLICATIONS = {
|
|
|
707
882
|
"kind": "worker",
|
|
708
883
|
"apiUrl": null,
|
|
709
884
|
"domains": [
|
|
710
|
-
"one.topolo.io"
|
|
885
|
+
"one.topolo.io",
|
|
886
|
+
"topolo.io",
|
|
887
|
+
"www.topolo.io"
|
|
711
888
|
],
|
|
712
889
|
"routes": [],
|
|
713
890
|
"serviceId": null
|
|
@@ -744,6 +921,30 @@ var APPLICATIONS = {
|
|
|
744
921
|
}
|
|
745
922
|
]
|
|
746
923
|
},
|
|
924
|
+
"people": {
|
|
925
|
+
"id": "people",
|
|
926
|
+
"appDir": "TopoloPeople",
|
|
927
|
+
"name": "topolo-people",
|
|
928
|
+
"packageName": "topolo-people",
|
|
929
|
+
"productionUrl": "https://people.topolo.app",
|
|
930
|
+
"services": [
|
|
931
|
+
"people"
|
|
932
|
+
],
|
|
933
|
+
"deployTargets": [
|
|
934
|
+
{
|
|
935
|
+
"name": "topolo-people",
|
|
936
|
+
"kind": "worker",
|
|
937
|
+
"apiUrl": "https://people.topolo.app",
|
|
938
|
+
"domains": [
|
|
939
|
+
"people.topolo.app"
|
|
940
|
+
],
|
|
941
|
+
"routes": [
|
|
942
|
+
"people.topolo.app"
|
|
943
|
+
],
|
|
944
|
+
"serviceId": "people"
|
|
945
|
+
}
|
|
946
|
+
]
|
|
947
|
+
},
|
|
747
948
|
"quro": {
|
|
748
949
|
"id": "quro",
|
|
749
950
|
"appDir": "TopoloQuro",
|
|
@@ -815,6 +1016,30 @@ var APPLICATIONS = {
|
|
|
815
1016
|
}
|
|
816
1017
|
]
|
|
817
1018
|
},
|
|
1019
|
+
"sign": {
|
|
1020
|
+
"id": "sign",
|
|
1021
|
+
"appDir": "TopoloSign",
|
|
1022
|
+
"name": "topolo-sign",
|
|
1023
|
+
"packageName": "topolo-sign",
|
|
1024
|
+
"productionUrl": "https://sign.topolo.app",
|
|
1025
|
+
"services": [
|
|
1026
|
+
"sign"
|
|
1027
|
+
],
|
|
1028
|
+
"deployTargets": [
|
|
1029
|
+
{
|
|
1030
|
+
"name": "topolo-sign",
|
|
1031
|
+
"kind": "worker",
|
|
1032
|
+
"apiUrl": "https://sign.topolo.app",
|
|
1033
|
+
"domains": [
|
|
1034
|
+
"sign.topolo.app"
|
|
1035
|
+
],
|
|
1036
|
+
"routes": [
|
|
1037
|
+
"sign.topolo.app"
|
|
1038
|
+
],
|
|
1039
|
+
"serviceId": "sign"
|
|
1040
|
+
}
|
|
1041
|
+
]
|
|
1042
|
+
},
|
|
818
1043
|
"social_studio": {
|
|
819
1044
|
"id": "social_studio",
|
|
820
1045
|
"appDir": "TopoloSocialStudio",
|
|
@@ -911,6 +1136,54 @@ var APPLICATIONS = {
|
|
|
911
1136
|
}
|
|
912
1137
|
]
|
|
913
1138
|
},
|
|
1139
|
+
"survey": {
|
|
1140
|
+
"id": "survey",
|
|
1141
|
+
"appDir": "TopoloSurvey",
|
|
1142
|
+
"name": "topolo-survey",
|
|
1143
|
+
"packageName": "topolo-survey",
|
|
1144
|
+
"productionUrl": "https://survey.topolo.app",
|
|
1145
|
+
"services": [
|
|
1146
|
+
"survey"
|
|
1147
|
+
],
|
|
1148
|
+
"deployTargets": [
|
|
1149
|
+
{
|
|
1150
|
+
"name": "topolo-survey",
|
|
1151
|
+
"kind": "worker",
|
|
1152
|
+
"apiUrl": "https://survey.topolo.app",
|
|
1153
|
+
"domains": [
|
|
1154
|
+
"survey.topolo.app"
|
|
1155
|
+
],
|
|
1156
|
+
"routes": [
|
|
1157
|
+
"survey.topolo.app"
|
|
1158
|
+
],
|
|
1159
|
+
"serviceId": "survey"
|
|
1160
|
+
}
|
|
1161
|
+
]
|
|
1162
|
+
},
|
|
1163
|
+
"voice": {
|
|
1164
|
+
"id": "voice",
|
|
1165
|
+
"appDir": "TopoloVoice",
|
|
1166
|
+
"name": "topolo-voice",
|
|
1167
|
+
"packageName": "topolo-voice",
|
|
1168
|
+
"productionUrl": "https://voice.topolo.app",
|
|
1169
|
+
"services": [
|
|
1170
|
+
"voice"
|
|
1171
|
+
],
|
|
1172
|
+
"deployTargets": [
|
|
1173
|
+
{
|
|
1174
|
+
"name": "topolo-voice",
|
|
1175
|
+
"kind": "worker",
|
|
1176
|
+
"apiUrl": "https://voice.topolo.app",
|
|
1177
|
+
"domains": [
|
|
1178
|
+
"voice.topolo.app"
|
|
1179
|
+
],
|
|
1180
|
+
"routes": [
|
|
1181
|
+
"voice.topolo.app"
|
|
1182
|
+
],
|
|
1183
|
+
"serviceId": "voice"
|
|
1184
|
+
}
|
|
1185
|
+
]
|
|
1186
|
+
},
|
|
914
1187
|
"web": {
|
|
915
1188
|
"id": "web",
|
|
916
1189
|
"appDir": "TopoloWeb",
|
|
@@ -956,7 +1229,7 @@ var APPLICATIONS = {
|
|
|
956
1229
|
};
|
|
957
1230
|
|
|
958
1231
|
// src/application-requirements.ts
|
|
959
|
-
var APPLICATION_REQUIREMENTS_VERSION = "2026-04-
|
|
1232
|
+
var APPLICATION_REQUIREMENTS_VERSION = "2026-04-25.1";
|
|
960
1233
|
var APPLICATION_REQUIREMENTS = [
|
|
961
1234
|
{
|
|
962
1235
|
id: "platform-metadata",
|
|
@@ -1088,6 +1361,22 @@ var APPLICATION_REQUIREMENTS = [
|
|
|
1088
1361
|
"Keep command output JSON-stable for agents and human-readable with --no-json"
|
|
1089
1362
|
]
|
|
1090
1363
|
},
|
|
1364
|
+
{
|
|
1365
|
+
id: "native-dashboard-widget",
|
|
1366
|
+
title: "Expose a native dashboard widget contract",
|
|
1367
|
+
summary: "Launchable first-party applications must populate TopoloOne live workspace through an app-owned /api/widget endpoint using the SDK widget response contract.",
|
|
1368
|
+
appliesTo: ["api"],
|
|
1369
|
+
evidence: [
|
|
1370
|
+
"The app-owned API exposes GET /api/widget",
|
|
1371
|
+
"The endpoint returns TopoloWidgetApiResponse from @topolo/sdk",
|
|
1372
|
+
"The endpoint derives organization/user context from the app auth boundary"
|
|
1373
|
+
],
|
|
1374
|
+
implementation: [
|
|
1375
|
+
"Import createTopoloWidgetResponse from @topolo/sdk in the app backend",
|
|
1376
|
+
"Return native app metrics or action widgets instead of generic launch-card fallbacks",
|
|
1377
|
+
"Add a route-level test that validates the response with validateTopoloWidgetResponse"
|
|
1378
|
+
]
|
|
1379
|
+
},
|
|
1091
1380
|
{
|
|
1092
1381
|
id: "observability-and-audit",
|
|
1093
1382
|
title: "Emit platform audit and debugging signals",
|
|
@@ -1123,9 +1412,8 @@ var APPLICATION_REQUIREMENTS = [
|
|
|
1123
1412
|
];
|
|
1124
1413
|
function applicationRequirementScopes(application) {
|
|
1125
1414
|
const scopes = /* @__PURE__ */ new Set(["all"]);
|
|
1126
|
-
const
|
|
1127
|
-
const
|
|
1128
|
-
const hasApiSurface = application.services.length > 0 || deployTargets.some((target) => Boolean(target.apiUrl));
|
|
1415
|
+
const hasBrowserSurface = Boolean(application.productionUrl) || application.deployTargets.some((target) => target.kind === "pages");
|
|
1416
|
+
const hasApiSurface = application.services.length > 0 || application.deployTargets.some((target) => Boolean(target.apiUrl));
|
|
1129
1417
|
if (hasBrowserSurface) scopes.add("browser");
|
|
1130
1418
|
if (hasApiSurface) scopes.add("api");
|
|
1131
1419
|
if (application.id === "cli" || application.id === "mcp" || application.id === "cloudcontrol") {
|
|
@@ -1260,6 +1548,13 @@ function evaluateRequirement(application, requirement) {
|
|
|
1260
1548
|
}
|
|
1261
1549
|
return finding(requirement, "missing", "No SDK service or tooling surface is registered.", evidence);
|
|
1262
1550
|
}
|
|
1551
|
+
case "native-dashboard-widget":
|
|
1552
|
+
return finding(
|
|
1553
|
+
requirement,
|
|
1554
|
+
"needs_review",
|
|
1555
|
+
"Catalog metadata cannot verify app-owned /api/widget implementation details.",
|
|
1556
|
+
evidence
|
|
1557
|
+
);
|
|
1263
1558
|
case "observability-and-audit":
|
|
1264
1559
|
return finding(
|
|
1265
1560
|
requirement,
|
|
@@ -1313,11 +1608,10 @@ function statusRank(status) {
|
|
|
1313
1608
|
// src/services.ts
|
|
1314
1609
|
var DEFAULT_SERVICE_URLS = SERVICES;
|
|
1315
1610
|
function resolveServiceUrl(service, overrides) {
|
|
1316
|
-
|
|
1317
|
-
const override = overrides == null ? void 0 : overrides[service];
|
|
1611
|
+
const override = overrides?.[service];
|
|
1318
1612
|
if (override) return override;
|
|
1319
1613
|
const envKey = `TOPOLO_SERVICE_URL_${service.replace(/\./g, "_").toUpperCase()}`;
|
|
1320
|
-
const envValue = typeof process !== "undefined" ?
|
|
1614
|
+
const envValue = typeof process !== "undefined" ? process.env?.[envKey] : void 0;
|
|
1321
1615
|
if (envValue) return envValue;
|
|
1322
1616
|
return DEFAULT_SERVICE_URLS[service];
|
|
1323
1617
|
}
|
|
@@ -1333,9 +1627,8 @@ var TopoloClient = class {
|
|
|
1333
1627
|
fetchImpl;
|
|
1334
1628
|
debug;
|
|
1335
1629
|
constructor(options) {
|
|
1336
|
-
var _a;
|
|
1337
1630
|
if (!options.credential) throw new TopoloAuthError("credential is required");
|
|
1338
|
-
if (!
|
|
1631
|
+
if (!options.agent?.clientName) throw new TopoloAuthError("agent.clientName is required");
|
|
1339
1632
|
this.credential = options.credential;
|
|
1340
1633
|
this.agent = options.agent;
|
|
1341
1634
|
this.serviceUrls = options.serviceUrls;
|
|
@@ -1525,7 +1818,6 @@ var CrmModule = class {
|
|
|
1525
1818
|
}
|
|
1526
1819
|
client;
|
|
1527
1820
|
async listContacts(options = {}) {
|
|
1528
|
-
var _a, _b, _c;
|
|
1529
1821
|
const res = await this.client.request({
|
|
1530
1822
|
service: "crm",
|
|
1531
1823
|
path: "/api/contacts",
|
|
@@ -1535,12 +1827,12 @@ var CrmModule = class {
|
|
|
1535
1827
|
pageSize: options.pageSize
|
|
1536
1828
|
}
|
|
1537
1829
|
});
|
|
1538
|
-
const rows = Array.isArray(res
|
|
1830
|
+
const rows = Array.isArray(res?.contacts) ? res.contacts : Array.isArray(res?.data) ? res.data : [];
|
|
1539
1831
|
return {
|
|
1540
1832
|
contacts: rows.map(toSummary),
|
|
1541
|
-
total:
|
|
1542
|
-
page:
|
|
1543
|
-
pageSize:
|
|
1833
|
+
total: res?.total ?? res?.pagination?.total ?? rows.length,
|
|
1834
|
+
page: res?.page ?? res?.pagination?.page ?? options.page ?? 1,
|
|
1835
|
+
pageSize: res?.pageSize ?? res?.pagination?.pageSize ?? options.pageSize ?? rows.length
|
|
1544
1836
|
};
|
|
1545
1837
|
}
|
|
1546
1838
|
async getContact(contactId) {
|
|
@@ -1661,6 +1953,126 @@ var TopoloOAuth = class {
|
|
|
1661
1953
|
}
|
|
1662
1954
|
};
|
|
1663
1955
|
|
|
1956
|
+
// src/widgets.ts
|
|
1957
|
+
var TOPOLO_WIDGET_ENDPOINT = "/api/widget";
|
|
1958
|
+
var TOPOLO_WIDGET_REFRESH_INTERVAL_MS = 6e4;
|
|
1959
|
+
function defineTopoloStatsWidget(widget) {
|
|
1960
|
+
return { ...widget, type: "stats" };
|
|
1961
|
+
}
|
|
1962
|
+
function defineTopoloRecentActivityWidget(widget) {
|
|
1963
|
+
return { ...widget, type: "recent-activity" };
|
|
1964
|
+
}
|
|
1965
|
+
function defineTopoloQuickActionsWidget(widget) {
|
|
1966
|
+
return { ...widget, type: "quick-actions" };
|
|
1967
|
+
}
|
|
1968
|
+
function defineTopoloNotificationsWidget(widget) {
|
|
1969
|
+
return { ...widget, type: "notifications" };
|
|
1970
|
+
}
|
|
1971
|
+
function defineTopoloChartWidget(widget) {
|
|
1972
|
+
return { ...widget, type: "chart" };
|
|
1973
|
+
}
|
|
1974
|
+
function createTopoloWidgetResponse({
|
|
1975
|
+
serviceId,
|
|
1976
|
+
serviceName,
|
|
1977
|
+
widgets,
|
|
1978
|
+
now
|
|
1979
|
+
}) {
|
|
1980
|
+
const lastUpdated = toIsoTimestamp(now);
|
|
1981
|
+
return {
|
|
1982
|
+
success: true,
|
|
1983
|
+
widgets: widgets.map((widget) => ({
|
|
1984
|
+
...widget,
|
|
1985
|
+
serviceId: widget.serviceId?.trim() || serviceId,
|
|
1986
|
+
serviceName: widget.serviceName?.trim() || serviceName,
|
|
1987
|
+
lastUpdated: widget.lastUpdated?.trim() || lastUpdated
|
|
1988
|
+
}))
|
|
1989
|
+
};
|
|
1990
|
+
}
|
|
1991
|
+
function createTopoloWidgetError(error) {
|
|
1992
|
+
return {
|
|
1993
|
+
success: false,
|
|
1994
|
+
widgets: [],
|
|
1995
|
+
error
|
|
1996
|
+
};
|
|
1997
|
+
}
|
|
1998
|
+
function validateTopoloWidgetResponse(response) {
|
|
1999
|
+
const errors = [];
|
|
2000
|
+
if (!isRecord(response)) {
|
|
2001
|
+
return { ok: false, errors: ["response must be an object"] };
|
|
2002
|
+
}
|
|
2003
|
+
if (typeof response.success !== "boolean") {
|
|
2004
|
+
errors.push("success must be a boolean");
|
|
2005
|
+
}
|
|
2006
|
+
if (!Array.isArray(response.widgets)) {
|
|
2007
|
+
errors.push("widgets must be an array");
|
|
2008
|
+
return { ok: errors.length === 0, errors };
|
|
2009
|
+
}
|
|
2010
|
+
response.widgets.forEach((widget, index) => {
|
|
2011
|
+
validateWidget(widget, `widgets[${index}]`, errors);
|
|
2012
|
+
});
|
|
2013
|
+
if (response.success === false && response.error !== void 0 && typeof response.error !== "string") {
|
|
2014
|
+
errors.push("error must be a string when provided");
|
|
2015
|
+
}
|
|
2016
|
+
return { ok: errors.length === 0, errors };
|
|
2017
|
+
}
|
|
2018
|
+
function validateWidget(widget, path, errors) {
|
|
2019
|
+
if (!isRecord(widget)) {
|
|
2020
|
+
errors.push(`${path} must be an object`);
|
|
2021
|
+
return;
|
|
2022
|
+
}
|
|
2023
|
+
validateNonEmptyString(widget.serviceId, `${path}.serviceId`, errors);
|
|
2024
|
+
validateNonEmptyString(widget.serviceName, `${path}.serviceName`, errors);
|
|
2025
|
+
validateNonEmptyString(widget.lastUpdated, `${path}.lastUpdated`, errors);
|
|
2026
|
+
switch (widget.type) {
|
|
2027
|
+
case "stats":
|
|
2028
|
+
validateArray(widget.stats, `${path}.stats`, errors);
|
|
2029
|
+
break;
|
|
2030
|
+
case "recent-activity":
|
|
2031
|
+
validateArray(widget.activities, `${path}.activities`, errors);
|
|
2032
|
+
break;
|
|
2033
|
+
case "quick-actions":
|
|
2034
|
+
validateArray(widget.actions, `${path}.actions`, errors);
|
|
2035
|
+
break;
|
|
2036
|
+
case "notifications":
|
|
2037
|
+
validateArray(widget.notifications, `${path}.notifications`, errors);
|
|
2038
|
+
if (typeof widget.unreadCount !== "number") {
|
|
2039
|
+
errors.push(`${path}.unreadCount must be a number`);
|
|
2040
|
+
}
|
|
2041
|
+
break;
|
|
2042
|
+
case "chart":
|
|
2043
|
+
validateNonEmptyString(widget.chartType, `${path}.chartType`, errors);
|
|
2044
|
+
validateNonEmptyString(widget.title, `${path}.title`, errors);
|
|
2045
|
+
if (!isRecord(widget.data)) {
|
|
2046
|
+
errors.push(`${path}.data must be an object`);
|
|
2047
|
+
} else {
|
|
2048
|
+
validateArray(widget.data.labels, `${path}.data.labels`, errors);
|
|
2049
|
+
validateArray(widget.data.values, `${path}.data.values`, errors);
|
|
2050
|
+
}
|
|
2051
|
+
break;
|
|
2052
|
+
default:
|
|
2053
|
+
errors.push(`${path}.type must be a supported Topolo widget type`);
|
|
2054
|
+
}
|
|
2055
|
+
}
|
|
2056
|
+
function validateNonEmptyString(value, path, errors) {
|
|
2057
|
+
if (typeof value !== "string" || value.trim().length === 0) {
|
|
2058
|
+
errors.push(`${path} must be a non-empty string`);
|
|
2059
|
+
}
|
|
2060
|
+
}
|
|
2061
|
+
function validateArray(value, path, errors) {
|
|
2062
|
+
if (!Array.isArray(value)) {
|
|
2063
|
+
errors.push(`${path} must be an array`);
|
|
2064
|
+
}
|
|
2065
|
+
}
|
|
2066
|
+
function isRecord(value) {
|
|
2067
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
2068
|
+
}
|
|
2069
|
+
function toIsoTimestamp(input) {
|
|
2070
|
+
if (input instanceof Date) {
|
|
2071
|
+
return input.toISOString();
|
|
2072
|
+
}
|
|
2073
|
+
return input ?? (/* @__PURE__ */ new Date()).toISOString();
|
|
2074
|
+
}
|
|
2075
|
+
|
|
1664
2076
|
// src/index.ts
|
|
1665
2077
|
function createTopolo(options) {
|
|
1666
2078
|
const client = new TopoloClient(options);
|
|
@@ -1679,6 +2091,8 @@ function createTopolo(options) {
|
|
|
1679
2091
|
DEFAULT_SERVICE_URLS,
|
|
1680
2092
|
IdentityModule,
|
|
1681
2093
|
PLATFORM_SERVICE_IDS,
|
|
2094
|
+
TOPOLO_WIDGET_ENDPOINT,
|
|
2095
|
+
TOPOLO_WIDGET_REFRESH_INTERVAL_MS,
|
|
1682
2096
|
TopoloAuthError,
|
|
1683
2097
|
TopoloClient,
|
|
1684
2098
|
TopoloHttpError,
|
|
@@ -1689,6 +2103,14 @@ function createTopolo(options) {
|
|
|
1689
2103
|
auditAllApplicationRequirements,
|
|
1690
2104
|
auditApplicationRequirements,
|
|
1691
2105
|
createTopolo,
|
|
2106
|
+
createTopoloWidgetError,
|
|
2107
|
+
createTopoloWidgetResponse,
|
|
2108
|
+
defineTopoloChartWidget,
|
|
2109
|
+
defineTopoloNotificationsWidget,
|
|
2110
|
+
defineTopoloQuickActionsWidget,
|
|
2111
|
+
defineTopoloRecentActivityWidget,
|
|
2112
|
+
defineTopoloStatsWidget,
|
|
1692
2113
|
requirementsForApplication,
|
|
1693
|
-
resolveServiceUrl
|
|
2114
|
+
resolveServiceUrl,
|
|
2115
|
+
validateTopoloWidgetResponse
|
|
1694
2116
|
});
|