@topolo/sdk 0.9.10 → 0.10.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +21 -16
- package/dist/index.cjs +321 -74
- package/dist/index.d.cts +309 -194
- package/dist/index.d.ts +309 -194
- package/dist/index.js +310 -74
- package/dist/node/credential-store.cjs +2 -51
- package/dist/node/credential-store.js +2 -51
- package/package.json +3 -6
package/README.md
CHANGED
|
@@ -97,22 +97,27 @@ traceable to a specific agent invocation.
|
|
|
97
97
|
Agents should use the action catalog for app-specific operations so new
|
|
98
98
|
services and actions become usable without an SDK, CLI, or MCP release.
|
|
99
99
|
|
|
100
|
-
## Application
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
`
|
|
115
|
-
|
|
100
|
+
## Application directory (live registry)
|
|
101
|
+
|
|
102
|
+
The platform scales to millions of constantly-changing applications, so the
|
|
103
|
+
SDK ships NO compiled application map that decides behavior. The live
|
|
104
|
+
credential-scoped registry is the source of truth:
|
|
105
|
+
|
|
106
|
+
- `TopoloClient.searchServices()` / `getService()` enumerate and resolve
|
|
107
|
+
applications for the current credential.
|
|
108
|
+
- `listApplicationDirectory(client)` walks the registry to exhaustion and
|
|
109
|
+
returns friendly ids derived from live slugs (`topolo-notify` → `notify`).
|
|
110
|
+
- `resolveApplicationDirectoryEntry(client, application)` resolves one app by
|
|
111
|
+
id, slug, or name — including apps registered after this package was built.
|
|
112
|
+
- `friendlyAppId(entry)` derives the display id from a live catalog entry.
|
|
113
|
+
|
|
114
|
+
`DEFAULT_APP_URLS` now contains ONLY the `auth` and `developers` bootstrap
|
|
115
|
+
seeds — the endpoints that must be reachable before the registry can be
|
|
116
|
+
consulted. `APPLICATIONS` remains as a frozen static fallback snapshot used
|
|
117
|
+
only when the registry is unreachable (it can enrich repo/deploy metadata for
|
|
118
|
+
registry-confirmed apps, but never gates or rejects a registry-known app).
|
|
119
|
+
`listBundledServices()` reads that snapshot and is deprecated for anything
|
|
120
|
+
behavior-deciding.
|
|
116
121
|
|
|
117
122
|
## Action catalog
|
|
118
123
|
|
package/dist/index.cjs
CHANGED
|
@@ -39,9 +39,15 @@ __export(index_exports, {
|
|
|
39
39
|
TopoloSdkError: () => TopoloSdkError,
|
|
40
40
|
WorkspacesModule: () => WorkspacesModule,
|
|
41
41
|
actionContractCompleteness: () => actionContractCompleteness,
|
|
42
|
+
applicationEntryFromCatalog: () => applicationEntryFromCatalog,
|
|
42
43
|
applicationRequirementScopes: () => applicationRequirementScopes,
|
|
43
44
|
auditAllApplicationRequirements: () => auditAllApplicationRequirements,
|
|
45
|
+
auditApplicationEntries: () => auditApplicationEntries,
|
|
44
46
|
auditApplicationRequirements: () => auditApplicationRequirements,
|
|
47
|
+
compactActionCatalogEntry: () => compactActionCatalogEntry,
|
|
48
|
+
compactActionPlan: () => compactActionPlan,
|
|
49
|
+
compactActionValidation: () => compactActionValidation,
|
|
50
|
+
compactApplicationAudit: () => compactApplicationAudit,
|
|
45
51
|
createTopolo: () => createTopolo,
|
|
46
52
|
createTopoloWidgetError: () => createTopoloWidgetError,
|
|
47
53
|
createTopoloWidgetResponse: () => createTopoloWidgetResponse,
|
|
@@ -52,12 +58,17 @@ __export(index_exports, {
|
|
|
52
58
|
defineTopoloStatsWidget: () => defineTopoloStatsWidget,
|
|
53
59
|
digestTopoloActionCatalog: () => digestTopoloActionCatalog,
|
|
54
60
|
enrichActionContract: () => enrichActionContract,
|
|
61
|
+
formatDirectoryApplicationIds: () => formatDirectoryApplicationIds,
|
|
62
|
+
friendlyAppId: () => friendlyAppId,
|
|
63
|
+
listApplicationDirectory: () => listApplicationDirectory,
|
|
55
64
|
parseTopoloActionUploadContract: () => parseTopoloActionUploadContract,
|
|
56
65
|
prepareTopoloActionBase64UploadInput: () => prepareTopoloActionBase64UploadInput,
|
|
57
66
|
prepareTopoloActionUploadInput: () => prepareTopoloActionUploadInput,
|
|
58
67
|
requirementsForApplication: () => requirementsForApplication,
|
|
68
|
+
resolveApplicationDirectoryEntry: () => resolveApplicationDirectoryEntry,
|
|
59
69
|
resolveCatalogServiceUrl: () => resolveCatalogServiceUrl,
|
|
60
70
|
resolveServiceUrl: () => resolveServiceUrl,
|
|
71
|
+
staticApplicationDirectory: () => staticApplicationDirectory,
|
|
61
72
|
validateTopoloActionInput: () => validateTopoloActionInput,
|
|
62
73
|
validateTopoloWidgetResponse: () => validateTopoloWidgetResponse
|
|
63
74
|
});
|
|
@@ -166,62 +177,13 @@ var TopoloHttpError = class extends TopoloSdkError {
|
|
|
166
177
|
}
|
|
167
178
|
};
|
|
168
179
|
|
|
169
|
-
// src/services.
|
|
180
|
+
// src/bootstrap-services.ts
|
|
170
181
|
var APP_API_URLS = {
|
|
171
|
-
agent: "https://agent.topolo.app",
|
|
172
182
|
auth: "https://auth.topolo.app",
|
|
173
|
-
|
|
174
|
-
blog: "https://blog.topolo.app",
|
|
175
|
-
books: "https://books.topolo.app",
|
|
176
|
-
brand: "https://brand.topolo.app",
|
|
177
|
-
bugfix: "https://bugfix.topolo.app",
|
|
178
|
-
bytes: "https://bytes.topolo.app",
|
|
179
|
-
calendar: "https://calendar.topolo.app",
|
|
180
|
-
campaigns: "https://campaigns.topolo.app",
|
|
181
|
-
capacity: "https://capacity.topolo.app",
|
|
182
|
-
chat: "https://chat.topolo.app",
|
|
183
|
-
commerce: "https://commerce.topolo.app",
|
|
184
|
-
compose: "https://compose.topolo.app",
|
|
185
|
-
consent: "https://consent.topolo.app",
|
|
186
|
-
crm: "https://crm.topolo.app",
|
|
187
|
-
design: "https://design.topolo.app",
|
|
188
|
-
developers: "https://developers.topolo.app",
|
|
189
|
-
director: "https://director.topolo.app",
|
|
190
|
-
feed: "https://feed.topolo.app",
|
|
191
|
-
flow: "https://flow.topolo.app",
|
|
192
|
-
forecast: "https://forecast.topolo.app",
|
|
193
|
-
forms: "https://forms.topolo.app",
|
|
194
|
-
home: "https://home.topolo.app",
|
|
195
|
-
insights: "https://insights.topolo.app",
|
|
196
|
-
inventory: "https://inventory.topolo.app",
|
|
197
|
-
learn: "https://learn.topolo.app",
|
|
198
|
-
localize: "https://localize.topolo.app",
|
|
199
|
-
mail: "https://mail.topolo.app",
|
|
200
|
-
mdm: "https://mdm.topolo.app",
|
|
201
|
-
messages: "https://messages.topolo.app",
|
|
202
|
-
nexus: "https://nexus.topolo.app",
|
|
203
|
-
notify: "https://notify.topolo.app",
|
|
204
|
-
observability_watch: "https://observability-watch.topolo.app",
|
|
205
|
-
one: "https://www.topolo.app",
|
|
206
|
-
p2p: "https://p2p.topolo.app",
|
|
207
|
-
pay: "https://pay.topolo.app",
|
|
208
|
-
people: "https://people.topolo.app",
|
|
209
|
-
"quro.api": "https://api.ol0.me",
|
|
210
|
-
"quro.redirect": "https://ol0.me",
|
|
211
|
-
roadmapper: "https://roadmapper.topolo.app",
|
|
212
|
-
sign: "https://sign.topolo.app",
|
|
213
|
-
social_studio: "https://studio.topolo.app",
|
|
214
|
-
socialize: "https://socialize.topolo.app",
|
|
215
|
-
spaces: "https://spaces.topolo.app",
|
|
216
|
-
status: "https://status.topolo.app",
|
|
217
|
-
success: "https://success.topolo.app",
|
|
218
|
-
support: "https://support.topolo.app",
|
|
219
|
-
survey: "https://survey.topolo.app",
|
|
220
|
-
voice: "https://voice.topolo.app",
|
|
221
|
-
web: "https://web.topolo.app"
|
|
183
|
+
developers: "https://developers.topolo.app"
|
|
222
184
|
};
|
|
223
185
|
|
|
224
|
-
// src/applications.
|
|
186
|
+
// src/applications-fallback.ts
|
|
225
187
|
var APPLICATIONS = {
|
|
226
188
|
"admin": {
|
|
227
189
|
"id": "admin",
|
|
@@ -1947,8 +1909,148 @@ var APPLICATIONS = {
|
|
|
1947
1909
|
}
|
|
1948
1910
|
};
|
|
1949
1911
|
|
|
1912
|
+
// src/application-directory.ts
|
|
1913
|
+
function friendlyAppId(entry) {
|
|
1914
|
+
for (const value of [entry.slug, entry.name, entry.appId]) {
|
|
1915
|
+
if (typeof value !== "string" || !value.trim()) continue;
|
|
1916
|
+
const normalized = value.trim().toLowerCase().replace(/\s+/g, "-");
|
|
1917
|
+
const withoutPrefix = normalized.replace(/^(?:app[_-])?topolo[-_]+/, "");
|
|
1918
|
+
if (withoutPrefix) return withoutPrefix;
|
|
1919
|
+
}
|
|
1920
|
+
return entry.appId;
|
|
1921
|
+
}
|
|
1922
|
+
function idVariants(value) {
|
|
1923
|
+
const normalized = value.trim().toLowerCase().replace(/\s+/g, "-");
|
|
1924
|
+
return [.../* @__PURE__ */ new Set([
|
|
1925
|
+
normalized,
|
|
1926
|
+
normalized.replace(/-/g, "_"),
|
|
1927
|
+
normalized.replace(/_/g, "-")
|
|
1928
|
+
])].filter(Boolean);
|
|
1929
|
+
}
|
|
1930
|
+
var STATIC_APPLICATIONS = APPLICATIONS;
|
|
1931
|
+
function staticApplicationForId(id) {
|
|
1932
|
+
for (const variant of idVariants(id)) {
|
|
1933
|
+
const entry = STATIC_APPLICATIONS[variant];
|
|
1934
|
+
if (entry) return entry;
|
|
1935
|
+
}
|
|
1936
|
+
return null;
|
|
1937
|
+
}
|
|
1938
|
+
function applicationEntryFromCatalog(live) {
|
|
1939
|
+
const id = friendlyAppId(live);
|
|
1940
|
+
return {
|
|
1941
|
+
id,
|
|
1942
|
+
appDir: "-",
|
|
1943
|
+
name: live.name ?? live.slug ?? live.appId,
|
|
1944
|
+
packageName: null,
|
|
1945
|
+
productionUrl: live.launchUrl ?? live.apiBaseUrl ?? null,
|
|
1946
|
+
services: live.apiBaseUrl ? [id] : [],
|
|
1947
|
+
deployTargets: []
|
|
1948
|
+
};
|
|
1949
|
+
}
|
|
1950
|
+
var DIRECTORY_PAGE_LIMIT = 100;
|
|
1951
|
+
var DIRECTORY_MAX_PAGES = 100;
|
|
1952
|
+
function staticApplicationDirectory() {
|
|
1953
|
+
const applications = Object.entries(STATIC_APPLICATIONS).map(([id, application]) => ({
|
|
1954
|
+
id,
|
|
1955
|
+
application,
|
|
1956
|
+
source: "static",
|
|
1957
|
+
live: null
|
|
1958
|
+
})).sort((left, right) => left.id.localeCompare(right.id));
|
|
1959
|
+
return { source: "static_fallback", applications };
|
|
1960
|
+
}
|
|
1961
|
+
function directoryApplicationFromLive(live) {
|
|
1962
|
+
const id = friendlyAppId(live);
|
|
1963
|
+
return {
|
|
1964
|
+
id,
|
|
1965
|
+
// Prefer the static snapshot's richer repo/deploy metadata when the live
|
|
1966
|
+
// registry confirms the app; synthesize from the live entry otherwise.
|
|
1967
|
+
application: staticApplicationForId(id) ?? applicationEntryFromCatalog(live),
|
|
1968
|
+
source: "live",
|
|
1969
|
+
live
|
|
1970
|
+
};
|
|
1971
|
+
}
|
|
1972
|
+
async function listApplicationDirectory(client) {
|
|
1973
|
+
if (!client) return staticApplicationDirectory();
|
|
1974
|
+
let services;
|
|
1975
|
+
try {
|
|
1976
|
+
services = [];
|
|
1977
|
+
let cursor;
|
|
1978
|
+
for (let page = 0; page < DIRECTORY_MAX_PAGES; page += 1) {
|
|
1979
|
+
const result = await client.searchServices({
|
|
1980
|
+
...cursor ? { cursor } : {},
|
|
1981
|
+
limit: DIRECTORY_PAGE_LIMIT
|
|
1982
|
+
});
|
|
1983
|
+
services.push(...result.services);
|
|
1984
|
+
if (!result.page.nextCursor) break;
|
|
1985
|
+
cursor = result.page.nextCursor;
|
|
1986
|
+
}
|
|
1987
|
+
} catch {
|
|
1988
|
+
return staticApplicationDirectory();
|
|
1989
|
+
}
|
|
1990
|
+
const seen = /* @__PURE__ */ new Map();
|
|
1991
|
+
for (const live of services) {
|
|
1992
|
+
const entry = directoryApplicationFromLive(live);
|
|
1993
|
+
if (!seen.has(entry.id)) seen.set(entry.id, entry);
|
|
1994
|
+
}
|
|
1995
|
+
return {
|
|
1996
|
+
source: "live",
|
|
1997
|
+
applications: [...seen.values()].sort((left, right) => left.id.localeCompare(right.id))
|
|
1998
|
+
};
|
|
1999
|
+
}
|
|
2000
|
+
function matchesDirectoryApplication(app, needle) {
|
|
2001
|
+
const candidates = new Set(idVariants(needle));
|
|
2002
|
+
const keys = [
|
|
2003
|
+
app.id,
|
|
2004
|
+
app.application.id,
|
|
2005
|
+
app.application.name,
|
|
2006
|
+
app.live?.appId,
|
|
2007
|
+
app.live?.slug,
|
|
2008
|
+
app.live?.name
|
|
2009
|
+
];
|
|
2010
|
+
for (const key of keys) {
|
|
2011
|
+
if (typeof key !== "string" || !key.trim()) continue;
|
|
2012
|
+
for (const variant of idVariants(key)) {
|
|
2013
|
+
if (candidates.has(variant)) return true;
|
|
2014
|
+
}
|
|
2015
|
+
for (const variant of idVariants(friendlyAppId({ appId: key }))) {
|
|
2016
|
+
if (candidates.has(variant)) return true;
|
|
2017
|
+
}
|
|
2018
|
+
}
|
|
2019
|
+
return false;
|
|
2020
|
+
}
|
|
2021
|
+
function formatDirectoryApplicationIds(directory) {
|
|
2022
|
+
const ids = directory.applications.map((app) => app.id).sort();
|
|
2023
|
+
const preview = ids.slice(0, 50).join(", ");
|
|
2024
|
+
const suffix = ids.length > 50 ? `, ... +${ids.length - 50} more` : "";
|
|
2025
|
+
const label = directory.source === "live" ? "Applications available to this credential" : "Applications in the bundled static snapshot (live registry unreachable)";
|
|
2026
|
+
return `${label}: ${preview}${suffix}`;
|
|
2027
|
+
}
|
|
2028
|
+
async function resolveApplicationDirectoryEntry(client, application) {
|
|
2029
|
+
const needle = typeof application === "string" ? application.trim() : "";
|
|
2030
|
+
if (!needle) {
|
|
2031
|
+
throw new TopoloSdkError("unknown_application", "application is required");
|
|
2032
|
+
}
|
|
2033
|
+
if (client) {
|
|
2034
|
+
let live = null;
|
|
2035
|
+
try {
|
|
2036
|
+
live = await client.getService(needle);
|
|
2037
|
+
} catch {
|
|
2038
|
+
live = null;
|
|
2039
|
+
}
|
|
2040
|
+
if (live) return directoryApplicationFromLive(live);
|
|
2041
|
+
}
|
|
2042
|
+
const directory = await listApplicationDirectory(client);
|
|
2043
|
+
const match = directory.applications.find((app) => matchesDirectoryApplication(app, needle));
|
|
2044
|
+
if (match) return match;
|
|
2045
|
+
throw new TopoloSdkError(
|
|
2046
|
+
"unknown_application",
|
|
2047
|
+
`Unknown application "${application}". ${formatDirectoryApplicationIds(directory)}`
|
|
2048
|
+
);
|
|
2049
|
+
}
|
|
2050
|
+
|
|
1950
2051
|
// src/application-requirements.ts
|
|
1951
|
-
var
|
|
2052
|
+
var STATIC_APPLICATIONS2 = APPLICATIONS;
|
|
2053
|
+
var APPLICATION_REQUIREMENTS_VERSION = "2026-08-11.1";
|
|
1952
2054
|
var APPLICATION_REQUIREMENTS = [
|
|
1953
2055
|
{
|
|
1954
2056
|
id: "platform-metadata",
|
|
@@ -1958,10 +2060,10 @@ var APPLICATION_REQUIREMENTS = [
|
|
|
1958
2060
|
evidence: [
|
|
1959
2061
|
"topolo.cloudcontrol.json exists for every deployed app surface",
|
|
1960
2062
|
"package.json names the package or app when the repo ships code",
|
|
1961
|
-
"The
|
|
2063
|
+
"The live platform registry exposes the app through topolo apps and MCP discovery"
|
|
1962
2064
|
],
|
|
1963
2065
|
implementation: [
|
|
1964
|
-
"
|
|
2066
|
+
"Register the app in the live platform registry (Auth service catalog) before exposing it to agents",
|
|
1965
2067
|
"Keep production URLs, Worker names, Pages projects, routes, domains, and bindings current in CloudControl metadata",
|
|
1966
2068
|
"Do not leave a new Topolo* app directory without an explicit application ID"
|
|
1967
2069
|
]
|
|
@@ -2036,7 +2138,7 @@ var APPLICATION_REQUIREMENTS = [
|
|
|
2036
2138
|
implementation: [
|
|
2037
2139
|
"Add production Worker api_url metadata and sdk_app_id for every agent-callable API target",
|
|
2038
2140
|
"Mark browser, documentation, and runtime-only Worker targets with agent_callable:false",
|
|
2039
|
-
"Expose stable app IDs through
|
|
2141
|
+
"Expose stable app IDs through live catalog discovery",
|
|
2040
2142
|
"Keep typed SDK/CLI/MCP surfaces in sync when an API contract stabilizes"
|
|
2041
2143
|
]
|
|
2042
2144
|
},
|
|
@@ -2156,15 +2258,24 @@ function applicationRequirementScopes(application) {
|
|
|
2156
2258
|
}
|
|
2157
2259
|
return Array.from(scopes);
|
|
2158
2260
|
}
|
|
2261
|
+
function fallbackApplication(id) {
|
|
2262
|
+
const entry = STATIC_APPLICATIONS2[id];
|
|
2263
|
+
if (!entry) {
|
|
2264
|
+
throw new Error(
|
|
2265
|
+
`Unknown application "${id}" in the static fallback snapshot. Resolve applications from the live registry (resolveApplicationDirectoryEntry) and pass the entry directly.`
|
|
2266
|
+
);
|
|
2267
|
+
}
|
|
2268
|
+
return entry;
|
|
2269
|
+
}
|
|
2159
2270
|
function requirementsForApplication(applicationOrId) {
|
|
2160
|
-
const application = typeof applicationOrId === "string" ?
|
|
2271
|
+
const application = typeof applicationOrId === "string" ? fallbackApplication(applicationOrId) : applicationOrId;
|
|
2161
2272
|
const scopes = new Set(applicationRequirementScopes(application));
|
|
2162
2273
|
return APPLICATION_REQUIREMENTS.filter(
|
|
2163
2274
|
(requirement) => requirement.appliesTo.some((scope) => scopes.has(scope))
|
|
2164
2275
|
);
|
|
2165
2276
|
}
|
|
2166
2277
|
function auditApplicationRequirements(applicationOrId) {
|
|
2167
|
-
const application = typeof applicationOrId === "string" ?
|
|
2278
|
+
const application = typeof applicationOrId === "string" ? fallbackApplication(applicationOrId) : applicationOrId;
|
|
2168
2279
|
const scopes = applicationRequirementScopes(application);
|
|
2169
2280
|
const findings = requirementsForApplication(application).map(
|
|
2170
2281
|
(requirement) => evaluateRequirement(application, requirement)
|
|
@@ -2177,10 +2288,17 @@ function auditApplicationRequirements(applicationOrId) {
|
|
|
2177
2288
|
findings
|
|
2178
2289
|
};
|
|
2179
2290
|
}
|
|
2291
|
+
function auditApplicationEntries(applications) {
|
|
2292
|
+
return buildAuditReport(
|
|
2293
|
+
applications.map((application) => auditApplicationRequirements(application))
|
|
2294
|
+
);
|
|
2295
|
+
}
|
|
2180
2296
|
function auditAllApplicationRequirements(applicationIds = Object.keys(APPLICATIONS).sort()) {
|
|
2181
|
-
|
|
2182
|
-
(applicationId) => auditApplicationRequirements(applicationId)
|
|
2297
|
+
return buildAuditReport(
|
|
2298
|
+
applicationIds.map((applicationId) => auditApplicationRequirements(applicationId))
|
|
2183
2299
|
);
|
|
2300
|
+
}
|
|
2301
|
+
function buildAuditReport(applications) {
|
|
2184
2302
|
const migrationQueue = applications.flatMap(
|
|
2185
2303
|
(audit) => audit.findings.filter((finding2) => finding2.status !== "met").map((finding2) => ({
|
|
2186
2304
|
applicationId: audit.application.id,
|
|
@@ -3491,8 +3609,9 @@ var TopoloClient = class _TopoloClient {
|
|
|
3491
3609
|
});
|
|
3492
3610
|
}
|
|
3493
3611
|
/**
|
|
3494
|
-
*
|
|
3495
|
-
*
|
|
3612
|
+
* @deprecated Static fallback snapshot only. Use `searchServices()` (the
|
|
3613
|
+
* live credential-scoped registry) for anything that decides behavior; this
|
|
3614
|
+
* exists for offline packaging audits when the registry is unreachable.
|
|
3496
3615
|
*/
|
|
3497
3616
|
listBundledServices() {
|
|
3498
3617
|
const apps = Object.values(APPLICATIONS);
|
|
@@ -3884,6 +4003,54 @@ function mergeSignals(a, b) {
|
|
|
3884
4003
|
return controller.signal;
|
|
3885
4004
|
}
|
|
3886
4005
|
|
|
4006
|
+
// src/agent-output.ts
|
|
4007
|
+
function compactActionCatalogEntry(action) {
|
|
4008
|
+
const required = Array.isArray(action.inputSchema["required"]) ? action.inputSchema["required"].filter((value) => typeof value === "string") : [];
|
|
4009
|
+
const examples = action.agentContract?.examples ?? [];
|
|
4010
|
+
return {
|
|
4011
|
+
actionId: action.actionId,
|
|
4012
|
+
title: action.title,
|
|
4013
|
+
description: action.description,
|
|
4014
|
+
method: action.method,
|
|
4015
|
+
readOnly: action.readOnly,
|
|
4016
|
+
requiresConfirmation: action.requiresConfirmation,
|
|
4017
|
+
agentAccess: action.agentAccess ?? (action.requiresConfirmation ? "confirm" : action.readOnly ? "auto" : "confirm"),
|
|
4018
|
+
requiredPermission: action.requiredPermission,
|
|
4019
|
+
requiredInput: required,
|
|
4020
|
+
resourceType: action.agentContract?.resource?.kind ?? null,
|
|
4021
|
+
exampleInput: examples[0]?.input ?? null,
|
|
4022
|
+
docsUrl: action.agentContract?.docsUrl ?? null
|
|
4023
|
+
};
|
|
4024
|
+
}
|
|
4025
|
+
function compactActionValidation(actionId, validation) {
|
|
4026
|
+
return { actionId, valid: validation.valid, errors: validation.errors };
|
|
4027
|
+
}
|
|
4028
|
+
function compactActionPlan(plan) {
|
|
4029
|
+
return {
|
|
4030
|
+
actionId: plan.action.actionId,
|
|
4031
|
+
valid: plan.validation.valid,
|
|
4032
|
+
errors: plan.validation.errors,
|
|
4033
|
+
executable: plan.executable,
|
|
4034
|
+
confirmationRequired: plan.confirmationRequired,
|
|
4035
|
+
confirmationProvided: plan.confirmationProvided,
|
|
4036
|
+
request: plan.request,
|
|
4037
|
+
verification: plan.verification,
|
|
4038
|
+
rollbackActionId: plan.rollbackActionId,
|
|
4039
|
+
nextActionIds: plan.nextActionIds
|
|
4040
|
+
};
|
|
4041
|
+
}
|
|
4042
|
+
function compactApplicationAudit(report) {
|
|
4043
|
+
return {
|
|
4044
|
+
version: report.version,
|
|
4045
|
+
applications: report.applications.map((audit) => ({
|
|
4046
|
+
applicationId: audit.application.id,
|
|
4047
|
+
applicationName: audit.application.name,
|
|
4048
|
+
score: audit.score
|
|
4049
|
+
})),
|
|
4050
|
+
migrationQueueCount: report.migrationQueue.length
|
|
4051
|
+
};
|
|
4052
|
+
}
|
|
4053
|
+
|
|
3887
4054
|
// src/action-catalog-digest.ts
|
|
3888
4055
|
var ACTION_CATALOG_DIGEST_ALGORITHM = "sha256-v1";
|
|
3889
4056
|
function canonicalPermission(value, appId) {
|
|
@@ -4097,25 +4264,90 @@ function derivedOutputSchema(action) {
|
|
|
4097
4264
|
...provenance
|
|
4098
4265
|
};
|
|
4099
4266
|
}
|
|
4100
|
-
function
|
|
4101
|
-
|
|
4267
|
+
function patternedString(pattern, hint) {
|
|
4268
|
+
const candidates = [
|
|
4269
|
+
hint.toLowerCase().includes("email") ? "agent@topolo.app" : null,
|
|
4270
|
+
hint.toLowerCase().includes("url") || hint.toLowerCase().includes("uri") ? "https://topolo.app" : null,
|
|
4271
|
+
hint.toLowerCase().includes("app") && hint.toLowerCase().includes("id") ? "app_topolo_example" : null,
|
|
4272
|
+
hint.toLowerCase().includes("file") ? "sample.ply" : null,
|
|
4273
|
+
hint.toLowerCase().includes("slug") ? "/sample" : null,
|
|
4274
|
+
hint.toLowerCase().includes("year") ? "2026" : null,
|
|
4275
|
+
hint.toLowerCase().includes("date") || hint.toLowerCase().endsWith("at") ? "2026-01-15T12:00:00Z" : null,
|
|
4276
|
+
hint.toLowerCase().includes("period") || hint.toLowerCase().includes("month") ? "2026-01" : null,
|
|
4277
|
+
hint.toLowerCase().includes("event") || hint.toLowerCase().includes("type") ? "resource.created" : null,
|
|
4278
|
+
"app_topolo_example",
|
|
4279
|
+
"2026-01-15T12:00:00Z",
|
|
4280
|
+
"sample.ply",
|
|
4281
|
+
"/sample",
|
|
4282
|
+
"2026-01-15",
|
|
4283
|
+
"2026-01",
|
|
4284
|
+
"2026",
|
|
4285
|
+
"resource.created",
|
|
4286
|
+
"sample-value",
|
|
4287
|
+
"sample_value",
|
|
4288
|
+
"sample"
|
|
4289
|
+
].filter(Boolean);
|
|
4290
|
+
try {
|
|
4291
|
+
const expression = new RegExp(pattern);
|
|
4292
|
+
return candidates.find((candidate) => expression.test(candidate)) ?? "sample";
|
|
4293
|
+
} catch {
|
|
4294
|
+
return "sample";
|
|
4295
|
+
}
|
|
4296
|
+
}
|
|
4297
|
+
function sampleString(schema, hint) {
|
|
4298
|
+
if (schema.format === "email") return "agent@topolo.app";
|
|
4299
|
+
if (schema.format === "uri" || schema.format === "url") return "https://topolo.app";
|
|
4300
|
+
if (schema.format === "date-time") return patternedString(schema.pattern || "", hint) || "2026-01-15T12:00:00Z";
|
|
4301
|
+
const words = String(hint || "value").replace(/([a-z0-9])([A-Z])/g, "$1 $2").replace(/[_-]+/g, " ").toLowerCase();
|
|
4302
|
+
let value = typeof schema.pattern === "string" ? patternedString(schema.pattern, hint) : /(^|\s)id$/.test(words) ? `${slugify(words.replace(/\sid$/, "") || "resource")}_01` : words.includes("date") ? "2026-01-15" : words.includes("period") || words.includes("month") ? "2026-01" : words.includes("year") ? "2026" : `Sample ${words}`;
|
|
4303
|
+
const minimum = Number.isInteger(schema.minLength) ? schema.minLength : 0;
|
|
4304
|
+
const maximum = Number.isInteger(schema.maxLength) ? schema.maxLength : null;
|
|
4305
|
+
if (value.length < minimum) value = value.padEnd(minimum, "x");
|
|
4306
|
+
if (maximum !== null && value.length > maximum) value = value.slice(0, maximum);
|
|
4307
|
+
return value;
|
|
4308
|
+
}
|
|
4309
|
+
function localReference(rootSchema, reference) {
|
|
4310
|
+
if (!isRecord4(rootSchema) || typeof reference !== "string" || !reference.startsWith("#/")) return null;
|
|
4311
|
+
return reference.slice(2).split("/").reduce((value, segment) => {
|
|
4312
|
+
const key = segment.replaceAll("~1", "/").replaceAll("~0", "~");
|
|
4313
|
+
return isRecord4(value) ? value[key] : void 0;
|
|
4314
|
+
}, rootSchema);
|
|
4315
|
+
}
|
|
4316
|
+
function sampleForSchema(schema, depth = 0, hint = "value", rootSchema = schema) {
|
|
4317
|
+
if (!isRecord4(schema) || depth > 20) return null;
|
|
4318
|
+
const referenced = localReference(rootSchema, schema.$ref);
|
|
4319
|
+
if (isRecord4(referenced)) return sampleForSchema(referenced, depth + 1, hint, rootSchema);
|
|
4102
4320
|
if (schema.const !== void 0) return schema.const;
|
|
4103
4321
|
if (Array.isArray(schema.enum) && schema.enum.length > 0) return schema.enum[0];
|
|
4104
|
-
if (Array.isArray(schema.oneOf) && schema.oneOf.length > 0) return sampleForSchema(schema.oneOf[0], depth + 1);
|
|
4105
|
-
if (Array.isArray(schema.anyOf) && schema.anyOf.length > 0) return sampleForSchema(schema.anyOf[0], depth + 1);
|
|
4106
|
-
if (schema.type
|
|
4322
|
+
if (Array.isArray(schema.oneOf) && schema.oneOf.length > 0) return sampleForSchema(schema.oneOf[0], depth + 1, hint, rootSchema);
|
|
4323
|
+
if (Array.isArray(schema.anyOf) && schema.anyOf.length > 0) return sampleForSchema(schema.anyOf[0], depth + 1, hint, rootSchema);
|
|
4324
|
+
if (Array.isArray(schema.type)) {
|
|
4325
|
+
return sampleForSchema({ ...schema, type: schema.type.find((type) => type !== "null") ?? schema.type[0] }, depth + 1, hint, rootSchema);
|
|
4326
|
+
}
|
|
4327
|
+
if (schema.type === "array") {
|
|
4328
|
+
const minimum = Number.isInteger(schema.minItems) ? schema.minItems : 0;
|
|
4329
|
+
const maximum = Number.isInteger(schema.maxItems) ? schema.maxItems : null;
|
|
4330
|
+
const count = maximum === 0 ? 0 : minimum > 0 ? minimum : depth >= 4 ? 0 : 1;
|
|
4331
|
+
return Array.from({ length: count }, () => sampleForSchema(schema.items, depth + 1, singularize(hint), rootSchema));
|
|
4332
|
+
}
|
|
4107
4333
|
if (schema.type === "boolean") return false;
|
|
4108
|
-
if (schema.type === "integer" || schema.type === "number")
|
|
4109
|
-
|
|
4110
|
-
if (schema.
|
|
4111
|
-
|
|
4112
|
-
|
|
4334
|
+
if (schema.type === "integer" || schema.type === "number") {
|
|
4335
|
+
let value = typeof schema.minimum === "number" ? schema.minimum : 0;
|
|
4336
|
+
if (typeof schema.exclusiveMinimum === "number" && value <= schema.exclusiveMinimum) {
|
|
4337
|
+
value = schema.type === "integer" ? Math.floor(schema.exclusiveMinimum) + 1 : schema.exclusiveMinimum + 0.1;
|
|
4338
|
+
}
|
|
4339
|
+
if (typeof schema.maximum === "number") value = Math.min(value, schema.maximum);
|
|
4340
|
+
if (typeof schema.exclusiveMaximum === "number" && value >= schema.exclusiveMaximum) {
|
|
4341
|
+
value = schema.type === "integer" ? Math.ceil(schema.exclusiveMaximum) - 1 : schema.exclusiveMaximum - 0.1;
|
|
4342
|
+
}
|
|
4343
|
+
return value;
|
|
4113
4344
|
}
|
|
4345
|
+
if (schema.type === "string") return sampleString(schema, hint);
|
|
4114
4346
|
if (schema.type === "null") return null;
|
|
4115
4347
|
if (schema.type === "object" || isRecord4(schema.properties)) {
|
|
4116
4348
|
const properties = isRecord4(schema.properties) ? schema.properties : {};
|
|
4117
4349
|
const required = new Set(Array.isArray(schema.required) ? schema.required : []);
|
|
4118
|
-
const entries = Object.entries(properties).filter(([key]) => required.has(key)).map(([key, child]) => [key, sampleForSchema(child, depth + 1)]);
|
|
4350
|
+
const entries = Object.entries(properties).filter(([key]) => required.has(key)).map(([key, child]) => [key, sampleForSchema(child, depth + 1, key, rootSchema)]);
|
|
4119
4351
|
return Object.fromEntries(entries);
|
|
4120
4352
|
}
|
|
4121
4353
|
return null;
|
|
@@ -4191,7 +4423,11 @@ function enrichActionContract(manifest, action, allActions = manifest.actions ||
|
|
|
4191
4423
|
const recovery = isRecord4(existing.recovery) ? existing.recovery : recoveryFor(action, allActions, appId);
|
|
4192
4424
|
const rollbackActionId = typeof existing.rollbackActionId === "string" && existing.rollbackActionId.trim() ? existing.rollbackActionId.trim() : recovery.mode === "compensating_action" ? recovery.actionId : void 0;
|
|
4193
4425
|
const inputExample = sampleForSchema(action.inputSchema);
|
|
4194
|
-
const
|
|
4426
|
+
const expectedExample = readOnly ? `A successful response conforming to outputSchema; verify the returned ${resource.replaceAll("_", " ")} belongs to the selected resource context.` : `A successful response conforming to outputSchema; re-read the affected ${resource.replaceAll("_", " ")} to verify the intended change.`;
|
|
4427
|
+
const examples = Array.isArray(existing.examples) && existing.examples.length > 0 ? existing.examples.map((example) => isRecord4(example) && Object.hasOwn(example, "input") ? { ...example, expected: typeof example.expected === "string" && example.expected.trim() ? example.expected : expectedExample } : { input: example, expected: expectedExample }) : [{
|
|
4428
|
+
input: inputExample ?? {},
|
|
4429
|
+
expected: expectedExample
|
|
4430
|
+
}];
|
|
4195
4431
|
const docsUrl = `https://docs.topolo.app/reference/actions?service=${encodeURIComponent(service)}&action=${encodeURIComponent(action.name)}`;
|
|
4196
4432
|
const existingDocsUrl = typeof existing.docsUrl === "string" && existing.docsUrl.trim() ? existing.docsUrl.trim() : void 0;
|
|
4197
4433
|
return {
|
|
@@ -4832,9 +5068,15 @@ function createTopolo(options) {
|
|
|
4832
5068
|
TopoloSdkError,
|
|
4833
5069
|
WorkspacesModule,
|
|
4834
5070
|
actionContractCompleteness,
|
|
5071
|
+
applicationEntryFromCatalog,
|
|
4835
5072
|
applicationRequirementScopes,
|
|
4836
5073
|
auditAllApplicationRequirements,
|
|
5074
|
+
auditApplicationEntries,
|
|
4837
5075
|
auditApplicationRequirements,
|
|
5076
|
+
compactActionCatalogEntry,
|
|
5077
|
+
compactActionPlan,
|
|
5078
|
+
compactActionValidation,
|
|
5079
|
+
compactApplicationAudit,
|
|
4838
5080
|
createTopolo,
|
|
4839
5081
|
createTopoloWidgetError,
|
|
4840
5082
|
createTopoloWidgetResponse,
|
|
@@ -4845,12 +5087,17 @@ function createTopolo(options) {
|
|
|
4845
5087
|
defineTopoloStatsWidget,
|
|
4846
5088
|
digestTopoloActionCatalog,
|
|
4847
5089
|
enrichActionContract,
|
|
5090
|
+
formatDirectoryApplicationIds,
|
|
5091
|
+
friendlyAppId,
|
|
5092
|
+
listApplicationDirectory,
|
|
4848
5093
|
parseTopoloActionUploadContract,
|
|
4849
5094
|
prepareTopoloActionBase64UploadInput,
|
|
4850
5095
|
prepareTopoloActionUploadInput,
|
|
4851
5096
|
requirementsForApplication,
|
|
5097
|
+
resolveApplicationDirectoryEntry,
|
|
4852
5098
|
resolveCatalogServiceUrl,
|
|
4853
5099
|
resolveServiceUrl,
|
|
5100
|
+
staticApplicationDirectory,
|
|
4854
5101
|
validateTopoloActionInput,
|
|
4855
5102
|
validateTopoloWidgetResponse
|
|
4856
5103
|
});
|