@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/README.md +23 -0
- package/dist/index.cjs +277 -3
- package/dist/index.d.cts +182 -2
- package/dist/index.d.ts +182 -2
- package/dist/index.js +266 -2
- package/package.json +1 -1
- package/src/application-requirements.ts +25 -1
- package/src/applications.generated.ts +71 -0
- package/src/index.ts +46 -10
- package/src/services.generated.ts +5 -0
- package/src/services.test.ts +7 -0
- package/src/widgets.test.ts +162 -0
- package/src/widgets.ts +359 -0
|
@@ -173,6 +173,29 @@ export const APPLICATIONS = {
|
|
|
173
173
|
}
|
|
174
174
|
]
|
|
175
175
|
},
|
|
176
|
+
"capacity": {
|
|
177
|
+
"id": "capacity",
|
|
178
|
+
"appDir": "TopoloCapacity",
|
|
179
|
+
"name": "topolo-capacity",
|
|
180
|
+
"packageName": "topolo-capacity",
|
|
181
|
+
"productionUrl": "https://capacity.topolo.app",
|
|
182
|
+
"services": [
|
|
183
|
+
"capacity"
|
|
184
|
+
],
|
|
185
|
+
"deployTargets": [
|
|
186
|
+
{
|
|
187
|
+
"name": "topolo-capacity",
|
|
188
|
+
"kind": "worker",
|
|
189
|
+
"apiUrl": "https://topolo-capacity.topolo.workers.dev",
|
|
190
|
+
"domains": [
|
|
191
|
+
"capacity.topolo.app",
|
|
192
|
+
"topolo-capacity.topolo.workers.dev"
|
|
193
|
+
],
|
|
194
|
+
"routes": [],
|
|
195
|
+
"serviceId": "capacity"
|
|
196
|
+
}
|
|
197
|
+
]
|
|
198
|
+
},
|
|
176
199
|
"chat": {
|
|
177
200
|
"id": "chat",
|
|
178
201
|
"appDir": "TopoloChat",
|
|
@@ -270,6 +293,30 @@ export const APPLICATIONS = {
|
|
|
270
293
|
}
|
|
271
294
|
]
|
|
272
295
|
},
|
|
296
|
+
"compose": {
|
|
297
|
+
"id": "compose",
|
|
298
|
+
"appDir": "TopoloCompose",
|
|
299
|
+
"name": "topolo-compose",
|
|
300
|
+
"packageName": "@topolo/compose",
|
|
301
|
+
"productionUrl": "https://compose.topolo.app",
|
|
302
|
+
"services": [
|
|
303
|
+
"compose"
|
|
304
|
+
],
|
|
305
|
+
"deployTargets": [
|
|
306
|
+
{
|
|
307
|
+
"name": "topolo-compose",
|
|
308
|
+
"kind": "worker",
|
|
309
|
+
"apiUrl": "https://compose.topolo.app",
|
|
310
|
+
"domains": [
|
|
311
|
+
"compose.topolo.app"
|
|
312
|
+
],
|
|
313
|
+
"routes": [
|
|
314
|
+
"compose.topolo.app"
|
|
315
|
+
],
|
|
316
|
+
"serviceId": "compose"
|
|
317
|
+
}
|
|
318
|
+
]
|
|
319
|
+
},
|
|
273
320
|
"crm": {
|
|
274
321
|
"id": "crm",
|
|
275
322
|
"appDir": "TopoloCRM",
|
|
@@ -687,6 +734,30 @@ export const APPLICATIONS = {
|
|
|
687
734
|
}
|
|
688
735
|
]
|
|
689
736
|
},
|
|
737
|
+
"notify": {
|
|
738
|
+
"id": "notify",
|
|
739
|
+
"appDir": "TopoloNotify",
|
|
740
|
+
"name": "topolo-notify",
|
|
741
|
+
"packageName": "@topolo/notify",
|
|
742
|
+
"productionUrl": "https://notify.topolo.app",
|
|
743
|
+
"services": [
|
|
744
|
+
"notify"
|
|
745
|
+
],
|
|
746
|
+
"deployTargets": [
|
|
747
|
+
{
|
|
748
|
+
"name": "topolo-notify",
|
|
749
|
+
"kind": "worker",
|
|
750
|
+
"apiUrl": "https://notify.topolo.app",
|
|
751
|
+
"domains": [
|
|
752
|
+
"notify.topolo.app"
|
|
753
|
+
],
|
|
754
|
+
"routes": [
|
|
755
|
+
"notify.topolo.app"
|
|
756
|
+
],
|
|
757
|
+
"serviceId": "notify"
|
|
758
|
+
}
|
|
759
|
+
]
|
|
760
|
+
},
|
|
690
761
|
"one": {
|
|
691
762
|
"id": "one",
|
|
692
763
|
"appDir": "TopoloOne",
|
package/src/index.ts
CHANGED
|
@@ -4,8 +4,8 @@ export {
|
|
|
4
4
|
type RequestOptions,
|
|
5
5
|
type CredentialIntrospection,
|
|
6
6
|
type TopoloDebugEvent,
|
|
7
|
-
} from
|
|
8
|
-
export type { TopoloCredential, AgentIdentity } from
|
|
7
|
+
} from "./client.js";
|
|
8
|
+
export type { TopoloCredential, AgentIdentity } from "./auth.js";
|
|
9
9
|
export {
|
|
10
10
|
DEFAULT_SERVICE_URLS,
|
|
11
11
|
APPLICATIONS,
|
|
@@ -29,25 +29,61 @@ export {
|
|
|
29
29
|
type ApplicationRequirementStatus,
|
|
30
30
|
type ApplicationRequirementsAuditReport,
|
|
31
31
|
type ServiceId,
|
|
32
|
-
} from
|
|
32
|
+
} from "./services.js";
|
|
33
33
|
export {
|
|
34
34
|
TopoloSdkError,
|
|
35
35
|
TopoloAuthError,
|
|
36
36
|
TopoloPermissionError,
|
|
37
37
|
TopoloHttpError,
|
|
38
|
-
} from
|
|
39
|
-
export {
|
|
40
|
-
|
|
38
|
+
} from "./errors.js";
|
|
39
|
+
export {
|
|
40
|
+
CrmModule,
|
|
41
|
+
type CrmContactSummary,
|
|
42
|
+
type ListContactsOptions,
|
|
43
|
+
type ListContactsResult,
|
|
44
|
+
} from "./modules/crm.js";
|
|
45
|
+
export { IdentityModule } from "./modules/identity.js";
|
|
41
46
|
export {
|
|
42
47
|
TopoloOAuth,
|
|
43
48
|
type OAuthHelperOptions,
|
|
44
49
|
type DeviceAuthorizationResponse,
|
|
45
50
|
type TokenResponse,
|
|
46
|
-
} from
|
|
51
|
+
} from "./oauth.js";
|
|
52
|
+
export {
|
|
53
|
+
TOPOLO_WIDGET_ENDPOINT,
|
|
54
|
+
TOPOLO_WIDGET_REFRESH_INTERVAL_MS,
|
|
55
|
+
createTopoloWidgetError,
|
|
56
|
+
createTopoloWidgetResponse,
|
|
57
|
+
defineTopoloChartWidget,
|
|
58
|
+
defineTopoloNotificationsWidget,
|
|
59
|
+
defineTopoloQuickActionsWidget,
|
|
60
|
+
defineTopoloRecentActivityWidget,
|
|
61
|
+
defineTopoloStatsWidget,
|
|
62
|
+
validateTopoloWidgetResponse,
|
|
63
|
+
type TopoloChartWidget,
|
|
64
|
+
type TopoloNotificationsWidget,
|
|
65
|
+
type TopoloQuickActionsWidget,
|
|
66
|
+
type TopoloRecentActivityWidget,
|
|
67
|
+
type TopoloStatsWidget,
|
|
68
|
+
type TopoloWidget,
|
|
69
|
+
type TopoloWidgetActionItem,
|
|
70
|
+
type TopoloWidgetActivityItem,
|
|
71
|
+
type TopoloWidgetApiResponse,
|
|
72
|
+
type TopoloWidgetBase,
|
|
73
|
+
type TopoloWidgetConfig,
|
|
74
|
+
type TopoloWidgetDraft,
|
|
75
|
+
type TopoloWidgetMetric,
|
|
76
|
+
type TopoloWidgetNotificationItem,
|
|
77
|
+
type TopoloWidgetResponseOptions,
|
|
78
|
+
type TopoloWidgetSnapshotMetadata,
|
|
79
|
+
type TopoloWidgetSnapshotMetric,
|
|
80
|
+
type TopoloWidgetType,
|
|
81
|
+
type TopoloWidgetValidationResult,
|
|
82
|
+
} from "./widgets.js";
|
|
47
83
|
|
|
48
|
-
import { TopoloClient, type TopoloClientOptions } from
|
|
49
|
-
import { CrmModule } from
|
|
50
|
-
import { IdentityModule } from
|
|
84
|
+
import { TopoloClient, type TopoloClientOptions } from "./client.js";
|
|
85
|
+
import { CrmModule } from "./modules/crm.js";
|
|
86
|
+
import { IdentityModule } from "./modules/identity.js";
|
|
51
87
|
|
|
52
88
|
/**
|
|
53
89
|
* Convenience factory that returns a ready-to-use typed Topolo client plus
|
|
@@ -9,8 +9,10 @@ export const SERVICES = {
|
|
|
9
9
|
bugfix: "https://bugfix.topolo.app",
|
|
10
10
|
bytes: "https://r2-media-manager-worker.topolo.workers.dev",
|
|
11
11
|
calendar: "https://calendar.topolo.app",
|
|
12
|
+
capacity: "https://topolo-capacity.topolo.workers.dev",
|
|
12
13
|
chat: "https://chat.topolo.app",
|
|
13
14
|
commerce: "https://topolo-commerce-api.topolo.workers.dev",
|
|
15
|
+
compose: "https://compose.topolo.app",
|
|
14
16
|
crm: "https://crm-api.topolo.app",
|
|
15
17
|
customer_success: "https://customer-success.topolo.app",
|
|
16
18
|
feed: "https://topolo-feed-api.topolo.app",
|
|
@@ -24,6 +26,7 @@ export const SERVICES = {
|
|
|
24
26
|
mdm: "https://topolo-mdm-api.topolo.app",
|
|
25
27
|
messaging: "https://messages.topolo.app",
|
|
26
28
|
nexus: "https://topolo-nexus-gateway.topolo.workers.dev",
|
|
29
|
+
notify: "https://notify.topolo.app",
|
|
27
30
|
one: "https://one.topolo.app",
|
|
28
31
|
pay: "https://topolo-pay.topolo.workers.dev",
|
|
29
32
|
people: "https://people.topolo.app",
|
|
@@ -43,12 +46,14 @@ export type ServiceId = keyof typeof SERVICES;
|
|
|
43
46
|
|
|
44
47
|
export const PLATFORM_SERVICE_IDS: Partial<Record<ServiceId, string>> = {
|
|
45
48
|
books: "srv_topolo_books",
|
|
49
|
+
compose: "srv_topolo_compose",
|
|
46
50
|
crm: "srv_iCwM4jGXcwlj",
|
|
47
51
|
customer_success: "srv_topolo_customer_success",
|
|
48
52
|
flow: "srv_topolo_flow",
|
|
49
53
|
forms: "srv_topolo_forms",
|
|
50
54
|
insights: "srv_topolo_insights",
|
|
51
55
|
inventory: "srv_topolo_inventory",
|
|
56
|
+
notify: "svc_topolo_notify",
|
|
52
57
|
people: "srv_topolo_people",
|
|
53
58
|
sign: "srv_topolo_sign",
|
|
54
59
|
survey: "srv_topolo_survey",
|
package/src/services.test.ts
CHANGED
|
@@ -18,10 +18,12 @@ const EXPECTED_APPLICATION_IDS = [
|
|
|
18
18
|
'bugfix',
|
|
19
19
|
'bytes',
|
|
20
20
|
'calendar',
|
|
21
|
+
'capacity',
|
|
21
22
|
'chat',
|
|
22
23
|
'cli',
|
|
23
24
|
'cloudcontrol',
|
|
24
25
|
'commerce',
|
|
26
|
+
'compose',
|
|
25
27
|
'crm',
|
|
26
28
|
'customer_success',
|
|
27
29
|
'developers',
|
|
@@ -38,6 +40,7 @@ const EXPECTED_APPLICATION_IDS = [
|
|
|
38
40
|
'mdm',
|
|
39
41
|
'messaging',
|
|
40
42
|
'nexus',
|
|
43
|
+
'notify',
|
|
41
44
|
'one',
|
|
42
45
|
'pay',
|
|
43
46
|
'people',
|
|
@@ -135,6 +138,9 @@ describe('application requirements', () => {
|
|
|
135
138
|
expect(APPLICATION_REQUIREMENTS.map((requirement) => requirement.id)).toContain(
|
|
136
139
|
'shared-auth-boundary',
|
|
137
140
|
);
|
|
141
|
+
expect(APPLICATION_REQUIREMENTS.map((requirement) => requirement.id)).toContain(
|
|
142
|
+
'native-dashboard-widget',
|
|
143
|
+
);
|
|
138
144
|
});
|
|
139
145
|
|
|
140
146
|
it('derives browser and API scopes from app metadata', () => {
|
|
@@ -158,6 +164,7 @@ describe('application requirements', () => {
|
|
|
158
164
|
expect(adminRequirementIds).not.toContain('organization-scoped-data');
|
|
159
165
|
expect(mailRequirementIds).toContain('organization-scoped-data');
|
|
160
166
|
expect(mailRequirementIds).toContain('service-registration-and-scopes');
|
|
167
|
+
expect(mailRequirementIds).toContain('native-dashboard-widget');
|
|
161
168
|
expect(cliRequirementIds).toContain('agent-and-operator-surfaces');
|
|
162
169
|
expect(cliRequirementIds).not.toContain('service-registration-and-scopes');
|
|
163
170
|
});
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
import { describe, expect, it } from "vitest";
|
|
2
|
+
import {
|
|
3
|
+
createTopoloWidgetError,
|
|
4
|
+
createTopoloWidgetResponse,
|
|
5
|
+
TOPOLO_WIDGET_ENDPOINT,
|
|
6
|
+
TOPOLO_WIDGET_REFRESH_INTERVAL_MS,
|
|
7
|
+
validateTopoloWidgetResponse,
|
|
8
|
+
} from "./widgets.js";
|
|
9
|
+
|
|
10
|
+
describe("Topolo widget contract", () => {
|
|
11
|
+
it("exports the platform widget endpoint defaults", () => {
|
|
12
|
+
expect(TOPOLO_WIDGET_ENDPOINT).toBe("/api/widget");
|
|
13
|
+
expect(TOPOLO_WIDGET_REFRESH_INTERVAL_MS).toBe(60_000);
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
it("stamps service metadata and timestamp onto widget drafts", () => {
|
|
17
|
+
const response = createTopoloWidgetResponse({
|
|
18
|
+
serviceId: "srv_bytes",
|
|
19
|
+
serviceName: "Bytes",
|
|
20
|
+
now: "2026-04-25T00:00:00.000Z",
|
|
21
|
+
widgets: [
|
|
22
|
+
{
|
|
23
|
+
type: "stats",
|
|
24
|
+
stats: [{ label: "Files", value: 12 }],
|
|
25
|
+
},
|
|
26
|
+
],
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
expect(response).toEqual({
|
|
30
|
+
success: true,
|
|
31
|
+
widgets: [
|
|
32
|
+
{
|
|
33
|
+
serviceId: "srv_bytes",
|
|
34
|
+
serviceName: "Bytes",
|
|
35
|
+
lastUpdated: "2026-04-25T00:00:00.000Z",
|
|
36
|
+
type: "stats",
|
|
37
|
+
stats: [{ label: "Files", value: 12 }],
|
|
38
|
+
},
|
|
39
|
+
],
|
|
40
|
+
});
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
it("keeps explicit widget metadata when an app needs multiple service cards", () => {
|
|
44
|
+
const response = createTopoloWidgetResponse({
|
|
45
|
+
serviceId: "srv_platform",
|
|
46
|
+
serviceName: "Platform",
|
|
47
|
+
now: "2026-04-25T00:00:00.000Z",
|
|
48
|
+
widgets: [
|
|
49
|
+
{
|
|
50
|
+
serviceId: "srv_crm",
|
|
51
|
+
serviceName: "CRM",
|
|
52
|
+
lastUpdated: "2026-04-24T23:00:00.000Z",
|
|
53
|
+
type: "stats",
|
|
54
|
+
stats: [{ label: "Contacts", value: 3 }],
|
|
55
|
+
},
|
|
56
|
+
],
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
expect(response.widgets[0]).toMatchObject({
|
|
60
|
+
serviceId: "srv_crm",
|
|
61
|
+
serviceName: "CRM",
|
|
62
|
+
lastUpdated: "2026-04-24T23:00:00.000Z",
|
|
63
|
+
});
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
it("returns a stable error response shape", () => {
|
|
67
|
+
expect(createTopoloWidgetError("not configured")).toEqual({
|
|
68
|
+
success: false,
|
|
69
|
+
widgets: [],
|
|
70
|
+
error: "not configured",
|
|
71
|
+
});
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
it("validates a compliant response", () => {
|
|
75
|
+
const response = createTopoloWidgetResponse({
|
|
76
|
+
serviceId: "srv_crm",
|
|
77
|
+
serviceName: "CRM",
|
|
78
|
+
now: "2026-04-25T00:00:00.000Z",
|
|
79
|
+
widgets: [
|
|
80
|
+
{
|
|
81
|
+
type: "notifications",
|
|
82
|
+
unreadCount: 1,
|
|
83
|
+
notifications: [
|
|
84
|
+
{
|
|
85
|
+
id: "n_1",
|
|
86
|
+
title: "New lead",
|
|
87
|
+
message: "A lead was created.",
|
|
88
|
+
type: "info",
|
|
89
|
+
timestamp: "2026-04-25T00:00:00.000Z",
|
|
90
|
+
read: false,
|
|
91
|
+
},
|
|
92
|
+
],
|
|
93
|
+
},
|
|
94
|
+
],
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
expect(validateTopoloWidgetResponse(response)).toEqual({
|
|
98
|
+
ok: true,
|
|
99
|
+
errors: [],
|
|
100
|
+
});
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
it("keeps optional snapshot metadata for configurable TopoloOne datapoints", () => {
|
|
104
|
+
const response = createTopoloWidgetResponse({
|
|
105
|
+
serviceId: "srv_admin",
|
|
106
|
+
serviceName: "Admin",
|
|
107
|
+
now: "2026-04-28T00:00:00.000Z",
|
|
108
|
+
widgets: [
|
|
109
|
+
{
|
|
110
|
+
type: "stats",
|
|
111
|
+
stats: [{ label: "Team Members", value: 5 }],
|
|
112
|
+
snapshot: {
|
|
113
|
+
presetKey: "admin_morning_snapshot",
|
|
114
|
+
defaultMetricKeys: ["team_members"],
|
|
115
|
+
availableMetrics: [
|
|
116
|
+
{
|
|
117
|
+
key: "team_members",
|
|
118
|
+
label: "Team Members",
|
|
119
|
+
value: 5,
|
|
120
|
+
unit: "count",
|
|
121
|
+
},
|
|
122
|
+
],
|
|
123
|
+
},
|
|
124
|
+
},
|
|
125
|
+
],
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
expect(validateTopoloWidgetResponse(response)).toEqual({
|
|
129
|
+
ok: true,
|
|
130
|
+
errors: [],
|
|
131
|
+
});
|
|
132
|
+
expect(response.widgets[0]).toMatchObject({
|
|
133
|
+
snapshot: {
|
|
134
|
+
defaultMetricKeys: ["team_members"],
|
|
135
|
+
availableMetrics: [
|
|
136
|
+
{ key: "team_members", label: "Team Members", value: 5 },
|
|
137
|
+
],
|
|
138
|
+
},
|
|
139
|
+
});
|
|
140
|
+
});
|
|
141
|
+
|
|
142
|
+
it("reports missing metadata and unsupported widget types", () => {
|
|
143
|
+
const result = validateTopoloWidgetResponse({
|
|
144
|
+
success: true,
|
|
145
|
+
widgets: [
|
|
146
|
+
{
|
|
147
|
+
serviceId: "",
|
|
148
|
+
serviceName: "Bad App",
|
|
149
|
+
lastUpdated: "",
|
|
150
|
+
type: "calendar",
|
|
151
|
+
},
|
|
152
|
+
],
|
|
153
|
+
});
|
|
154
|
+
|
|
155
|
+
expect(result.ok).toBe(false);
|
|
156
|
+
expect(result.errors).toEqual([
|
|
157
|
+
"widgets[0].serviceId must be a non-empty string",
|
|
158
|
+
"widgets[0].lastUpdated must be a non-empty string",
|
|
159
|
+
"widgets[0].type must be a supported Topolo widget type",
|
|
160
|
+
]);
|
|
161
|
+
});
|
|
162
|
+
});
|