@topolo/cli 0.13.25 → 0.13.26
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 +594 -70
- package/package.json +4 -4
package/dist/index.js
CHANGED
|
@@ -308,7 +308,7 @@ import { Command, Help } from "commander";
|
|
|
308
308
|
import { createInterface } from "readline/promises";
|
|
309
309
|
import { stdin as input } from "process";
|
|
310
310
|
|
|
311
|
-
// node_modules
|
|
311
|
+
// node_modules/@topolo/sdk/dist/index.js
|
|
312
312
|
function record(value) {
|
|
313
313
|
return Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
|
314
314
|
}
|
|
@@ -969,39 +969,256 @@ async function createDpopProof(input2) {
|
|
|
969
969
|
);
|
|
970
970
|
return `${header}.${claims}.${encodeBase64Url(signature)}`;
|
|
971
971
|
}
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
972
|
+
var TOPOLO_FIRST_PARTY_ORIGINS = Object.freeze({
|
|
973
|
+
production: Object.freeze([
|
|
974
|
+
"https://admin.topolo.app",
|
|
975
|
+
"https://agent.topolo.app",
|
|
976
|
+
"https://api.ol0.me",
|
|
977
|
+
"https://auth.topolo.app",
|
|
978
|
+
"https://backup.topolo.app",
|
|
979
|
+
"https://blog.topolo.app",
|
|
980
|
+
"https://books.topolo.app",
|
|
981
|
+
"https://brand.topolo.app",
|
|
982
|
+
"https://bugfix.topolo.app",
|
|
983
|
+
"https://bytes.topolo.app",
|
|
984
|
+
"https://calendar.topolo.app",
|
|
985
|
+
"https://campaigns.topolo.app",
|
|
986
|
+
"https://capacity.topolo.app",
|
|
987
|
+
"https://chat.topolo.app",
|
|
988
|
+
"https://commerce.topolo.app",
|
|
989
|
+
"https://compose.topolo.app",
|
|
990
|
+
"https://consent.topolo.app",
|
|
991
|
+
"https://contracts.topolo.app",
|
|
992
|
+
"https://crm.topolo.app",
|
|
993
|
+
"https://design.topolo.app",
|
|
994
|
+
"https://developers.topolo.app",
|
|
995
|
+
"https://director.topolo.app",
|
|
996
|
+
"https://docs.topolo.app",
|
|
997
|
+
"https://engage.topolo.app",
|
|
998
|
+
"https://events.topolo.app",
|
|
999
|
+
"https://feed-analytics-api.topolo.app",
|
|
1000
|
+
"https://feed-api.topolo.app",
|
|
1001
|
+
"https://flow.topolo.app",
|
|
1002
|
+
"https://forecast.topolo.app",
|
|
1003
|
+
"https://forms.topolo.app",
|
|
1004
|
+
"https://home.topolo.app",
|
|
1005
|
+
"https://insights.topolo.app",
|
|
1006
|
+
"https://inventory.topolo.app",
|
|
1007
|
+
"https://learn.topolo.app",
|
|
1008
|
+
"https://localize.topolo.app",
|
|
1009
|
+
"https://mail.topolo.app",
|
|
1010
|
+
"https://mcp.topolo.app",
|
|
1011
|
+
"https://mdm.topolo.app",
|
|
1012
|
+
"https://messages.topolo.app",
|
|
1013
|
+
"https://nexus.topolo.app",
|
|
1014
|
+
"https://notify.topolo.app",
|
|
1015
|
+
"https://nurture.topolo.app",
|
|
1016
|
+
"https://observability-watch.topolo.app",
|
|
1017
|
+
"https://p2p.topolo.app",
|
|
1018
|
+
"https://pay.topolo.app",
|
|
1019
|
+
"https://people.topolo.app",
|
|
1020
|
+
"https://quro.topolo.app",
|
|
1021
|
+
"https://recruit.topolo.app",
|
|
1022
|
+
"https://render.topolo.app",
|
|
1023
|
+
"https://roadmap.topolo.app",
|
|
1024
|
+
"https://sign.topolo.app",
|
|
1025
|
+
"https://socialize-api.topolo.app",
|
|
1026
|
+
"https://spaces.topolo.app",
|
|
1027
|
+
"https://speech.topolo.app",
|
|
1028
|
+
"https://status.topolo.app",
|
|
1029
|
+
"https://studio.topolo.app",
|
|
1030
|
+
"https://success.topolo.app",
|
|
1031
|
+
"https://support.topolo.app",
|
|
1032
|
+
"https://survey.topolo.app",
|
|
1033
|
+
"https://voice.topolo.app",
|
|
1034
|
+
"https://web.topolo.app",
|
|
1035
|
+
"https://www.topolo.app"
|
|
1036
|
+
]),
|
|
1037
|
+
staging: Object.freeze([
|
|
1038
|
+
"https://admin.stg.topolo.us",
|
|
1039
|
+
"https://agent.stg.topolo.us",
|
|
1040
|
+
"https://api.one.stg.topolo.us",
|
|
1041
|
+
"https://auth.stg.topolo.us",
|
|
1042
|
+
"https://backup.stg.topolo.us",
|
|
1043
|
+
"https://blog.stg.topolo.us",
|
|
1044
|
+
"https://books.stg.topolo.us",
|
|
1045
|
+
"https://brand.stg.topolo.us",
|
|
1046
|
+
"https://bugfix.stg.topolo.us",
|
|
1047
|
+
"https://bytes.stg.topolo.us",
|
|
1048
|
+
"https://calendar.stg.topolo.us",
|
|
1049
|
+
"https://campaigns.stg.topolo.us",
|
|
1050
|
+
"https://capacity.stg.topolo.us",
|
|
1051
|
+
"https://chat.stg.topolo.us",
|
|
1052
|
+
"https://commerce.stg.topolo.us",
|
|
1053
|
+
"https://compose.stg.topolo.us",
|
|
1054
|
+
"https://consent.stg.topolo.us",
|
|
1055
|
+
"https://contracts.stg.topolo.us",
|
|
1056
|
+
"https://crm.stg.topolo.us",
|
|
1057
|
+
"https://design.stg.topolo.us",
|
|
1058
|
+
"https://developers.stg.topolo.us",
|
|
1059
|
+
"https://director.stg.topolo.us",
|
|
1060
|
+
"https://docs.stg.topolo.us",
|
|
1061
|
+
"https://engage.stg.topolo.us",
|
|
1062
|
+
"https://events.stg.topolo.us",
|
|
1063
|
+
"https://feed-analytics-api.stg.topolo.us",
|
|
1064
|
+
"https://feed-api.stg.topolo.us",
|
|
1065
|
+
"https://flow.stg.topolo.us",
|
|
1066
|
+
"https://forecast.stg.topolo.us",
|
|
1067
|
+
"https://forms.stg.topolo.us",
|
|
1068
|
+
"https://home.stg.topolo.us",
|
|
1069
|
+
"https://insights.stg.topolo.us",
|
|
1070
|
+
"https://inventory.stg.topolo.us",
|
|
1071
|
+
"https://learn.stg.topolo.us",
|
|
1072
|
+
"https://localize.stg.topolo.us",
|
|
1073
|
+
"https://mail.stg.topolo.us",
|
|
1074
|
+
"https://mcp.stg.topolo.us",
|
|
1075
|
+
"https://mdm.stg.topolo.us",
|
|
1076
|
+
"https://messages.stg.topolo.us",
|
|
1077
|
+
"https://nexus.stg.topolo.us",
|
|
1078
|
+
"https://notify.stg.topolo.us",
|
|
1079
|
+
"https://nurture.stg.topolo.us",
|
|
1080
|
+
"https://observability-watch.stg.topolo.us",
|
|
1081
|
+
"https://p2p.stg.topolo.us",
|
|
1082
|
+
"https://pay.stg.topolo.us",
|
|
1083
|
+
"https://people.stg.topolo.us",
|
|
1084
|
+
"https://pulse.stg.topolo.us",
|
|
1085
|
+
"https://recruit.stg.topolo.us",
|
|
1086
|
+
"https://render.stg.topolo.us",
|
|
1087
|
+
"https://roadmap.stg.topolo.us",
|
|
1088
|
+
"https://seed.stg.topolo.us",
|
|
1089
|
+
"https://sign.stg.topolo.us",
|
|
1090
|
+
"https://socialize-api.stg.topolo.us",
|
|
1091
|
+
"https://spaces.stg.topolo.us",
|
|
1092
|
+
"https://speech.stg.topolo.us",
|
|
1093
|
+
"https://status.stg.topolo.us",
|
|
1094
|
+
"https://studio-api.stg.topolo.us",
|
|
1095
|
+
"https://studio.stg.topolo.us",
|
|
1096
|
+
"https://success.stg.topolo.us",
|
|
1097
|
+
"https://support.stg.topolo.us",
|
|
1098
|
+
"https://survey.stg.topolo.us",
|
|
1099
|
+
"https://voice.stg.topolo.us",
|
|
1100
|
+
"https://web.stg.topolo.us"
|
|
1101
|
+
]),
|
|
1102
|
+
development: Object.freeze([
|
|
1103
|
+
"https://admin.topolo.dev",
|
|
1104
|
+
"https://agent.topolo.dev",
|
|
1105
|
+
"https://api.one.topolo.dev",
|
|
1106
|
+
"https://auth.topolo.dev",
|
|
1107
|
+
"https://backup.topolo.dev",
|
|
1108
|
+
"https://blog.topolo.dev",
|
|
1109
|
+
"https://books.topolo.dev",
|
|
1110
|
+
"https://brand.topolo.dev",
|
|
1111
|
+
"https://bugfix.topolo.dev",
|
|
1112
|
+
"https://bytes.topolo.dev",
|
|
1113
|
+
"https://calendar.topolo.dev",
|
|
1114
|
+
"https://campaigns.topolo.dev",
|
|
1115
|
+
"https://capacity.topolo.dev",
|
|
1116
|
+
"https://chat.topolo.dev",
|
|
1117
|
+
"https://commerce.topolo.dev",
|
|
1118
|
+
"https://compose.topolo.dev",
|
|
1119
|
+
"https://consent.topolo.dev",
|
|
1120
|
+
"https://contracts.topolo.dev",
|
|
1121
|
+
"https://crm.topolo.dev",
|
|
1122
|
+
"https://design.topolo.dev",
|
|
1123
|
+
"https://developers.topolo.dev",
|
|
1124
|
+
"https://director.topolo.dev",
|
|
1125
|
+
"https://docs.topolo.dev",
|
|
1126
|
+
"https://engage.topolo.dev",
|
|
1127
|
+
"https://events.topolo.dev",
|
|
1128
|
+
"https://feed-analytics-api.topolo.dev",
|
|
1129
|
+
"https://feed-api.topolo.dev",
|
|
1130
|
+
"https://flow.topolo.dev",
|
|
1131
|
+
"https://forecast.topolo.dev",
|
|
1132
|
+
"https://forms.topolo.dev",
|
|
1133
|
+
"https://home.topolo.dev",
|
|
1134
|
+
"https://insights.topolo.dev",
|
|
1135
|
+
"https://inventory.topolo.dev",
|
|
1136
|
+
"https://learn.topolo.dev",
|
|
1137
|
+
"https://localize.topolo.dev",
|
|
1138
|
+
"https://mail.topolo.dev",
|
|
1139
|
+
"https://mcp.topolo.dev",
|
|
1140
|
+
"https://mdm.topolo.dev",
|
|
1141
|
+
"https://messages.topolo.dev",
|
|
1142
|
+
"https://nexus.topolo.dev",
|
|
1143
|
+
"https://notify.topolo.dev",
|
|
1144
|
+
"https://nurture.topolo.dev",
|
|
1145
|
+
"https://observability-watch.topolo.dev",
|
|
1146
|
+
"https://p2p.topolo.dev",
|
|
1147
|
+
"https://pay.topolo.dev",
|
|
1148
|
+
"https://people.topolo.dev",
|
|
1149
|
+
"https://pulse.topolo.dev",
|
|
1150
|
+
"https://recruit.topolo.dev",
|
|
1151
|
+
"https://render.topolo.dev",
|
|
1152
|
+
"https://roadmap.topolo.dev",
|
|
1153
|
+
"https://seed.topolo.dev",
|
|
1154
|
+
"https://sign.topolo.dev",
|
|
1155
|
+
"https://socialize-api.topolo.dev",
|
|
1156
|
+
"https://spaces.topolo.dev",
|
|
1157
|
+
"https://speech.topolo.dev",
|
|
1158
|
+
"https://status.topolo.dev",
|
|
1159
|
+
"https://studio-api.topolo.dev",
|
|
1160
|
+
"https://studio.topolo.dev",
|
|
1161
|
+
"https://success.topolo.dev",
|
|
1162
|
+
"https://support.topolo.dev",
|
|
1163
|
+
"https://survey.topolo.dev",
|
|
1164
|
+
"https://voice.topolo.dev",
|
|
1165
|
+
"https://web.topolo.dev"
|
|
1166
|
+
])
|
|
1167
|
+
});
|
|
1168
|
+
var TOPOLO_REFUSED_HOST_SUFFIXES = Object.freeze(["sites.stg.topolo.us", "sites.topolo.app", "sites.topolo.dev", "topolo.site", "try.topolo.io", "workers.dev"]);
|
|
1169
|
+
var TOPOLO_RUNTIME_ENVIRONMENTS = ["production", "staging", "development", "local"];
|
|
1170
|
+
var TOPOLO_ENVIRONMENT_SERVICE_URLS = Object.freeze({
|
|
1171
|
+
production: Object.freeze({
|
|
1172
|
+
auth: "https://auth.topolo.app",
|
|
1173
|
+
developers: "https://developers.topolo.app"
|
|
1174
|
+
}),
|
|
1175
|
+
staging: Object.freeze({
|
|
1176
|
+
auth: "https://auth.stg.topolo.us",
|
|
1177
|
+
developers: "https://developers.stg.topolo.us"
|
|
1178
|
+
}),
|
|
1179
|
+
development: Object.freeze({
|
|
1180
|
+
auth: "https://auth.topolo.dev",
|
|
1181
|
+
developers: "https://developers.topolo.dev"
|
|
1182
|
+
}),
|
|
1183
|
+
local: Object.freeze({})
|
|
1184
|
+
});
|
|
1185
|
+
var FIRST_PARTY_ORIGIN_SETS = Object.freeze({
|
|
1186
|
+
production: new Set(TOPOLO_FIRST_PARTY_ORIGINS.production),
|
|
1187
|
+
staging: new Set(TOPOLO_FIRST_PARTY_ORIGINS.staging),
|
|
1188
|
+
development: new Set(TOPOLO_FIRST_PARTY_ORIGINS.development)
|
|
1189
|
+
});
|
|
1190
|
+
var LOOPBACK_HOSTNAMES = /* @__PURE__ */ new Set(["localhost", "127.0.0.1", "[::1]"]);
|
|
1191
|
+
function isRuntimeEnvironment(value) {
|
|
1192
|
+
return typeof value === "string" && TOPOLO_RUNTIME_ENVIRONMENTS.includes(value);
|
|
979
1193
|
}
|
|
980
|
-
function
|
|
981
|
-
const hostname = url.hostname.toLowerCase();
|
|
1194
|
+
function originIsFirstParty(url, environment) {
|
|
982
1195
|
if (environment === "local") {
|
|
983
|
-
return
|
|
1196
|
+
return (url.protocol === "http:" || url.protocol === "https:") && LOOPBACK_HOSTNAMES.has(url.hostname);
|
|
984
1197
|
}
|
|
985
1198
|
if (url.protocol !== "https:") return false;
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
if (environment
|
|
990
|
-
|
|
1199
|
+
return FIRST_PARTY_ORIGIN_SETS[environment].has(url.origin);
|
|
1200
|
+
}
|
|
1201
|
+
function requireTopoloRuntimeEnvironment(environment) {
|
|
1202
|
+
if (!isRuntimeEnvironment(environment)) {
|
|
1203
|
+
throw new TopoloSdkError(
|
|
1204
|
+
"environment_required",
|
|
1205
|
+
'Refusing to send a Topolo credential: the runtime environment is not resolved. Pass environment: "production" | "staging" | "development" | "local".'
|
|
1206
|
+
);
|
|
991
1207
|
}
|
|
992
|
-
return
|
|
1208
|
+
return environment;
|
|
993
1209
|
}
|
|
994
1210
|
function assertTopoloServiceUrlEnvironment(service, value, environment) {
|
|
1211
|
+
const resolved = requireTopoloRuntimeEnvironment(environment);
|
|
995
1212
|
let url;
|
|
996
1213
|
try {
|
|
997
1214
|
url = new URL(value);
|
|
998
1215
|
} catch {
|
|
999
1216
|
throw new TopoloSdkError("invalid_service_url", `Invalid URL configured for Topolo service "${service}".`);
|
|
1000
1217
|
}
|
|
1001
|
-
if (url.protocol !== "https:" && url.protocol !== "http:" || url.username || url.password || !
|
|
1218
|
+
if (url.protocol !== "https:" && url.protocol !== "http:" || url.username || url.password || !originIsFirstParty(url, resolved)) {
|
|
1002
1219
|
throw new TopoloSdkError(
|
|
1003
1220
|
"environment_mismatch",
|
|
1004
|
-
`Refusing Topolo service "${service}": ${url.origin}
|
|
1221
|
+
`Refusing Topolo service "${service}": ${url.origin} is not a first-party ${resolved} service origin.`
|
|
1005
1222
|
);
|
|
1006
1223
|
}
|
|
1007
1224
|
return url.origin;
|
|
@@ -1014,6 +1231,44 @@ function topoloServiceOrigins(serviceUrls, environment) {
|
|
|
1014
1231
|
])
|
|
1015
1232
|
);
|
|
1016
1233
|
}
|
|
1234
|
+
var REDIRECT_STATUSES = /* @__PURE__ */ new Set([301, 302, 303, 307, 308]);
|
|
1235
|
+
async function fetchWithCredentialBoundary(fetchImpl, environment, service, target, init) {
|
|
1236
|
+
const url = new URL(String(target));
|
|
1237
|
+
const origin = assertTopoloServiceUrlEnvironment(service, url.toString(), environment);
|
|
1238
|
+
const response = await fetchImpl(url.toString(), { ...init, redirect: "manual" });
|
|
1239
|
+
let responseOrigin = origin;
|
|
1240
|
+
try {
|
|
1241
|
+
if (response.url) responseOrigin = new URL(response.url).origin;
|
|
1242
|
+
} catch {
|
|
1243
|
+
responseOrigin = "";
|
|
1244
|
+
}
|
|
1245
|
+
if (response.redirected === true || responseOrigin !== origin) {
|
|
1246
|
+
await response.body?.cancel().catch(() => void 0);
|
|
1247
|
+
throw new TopoloSdkError(
|
|
1248
|
+
"credential_redirect_refused",
|
|
1249
|
+
`Refusing a redirected response from Topolo service "${service}"; credentials are never forwarded.`
|
|
1250
|
+
);
|
|
1251
|
+
}
|
|
1252
|
+
if (REDIRECT_STATUSES.has(response.status)) {
|
|
1253
|
+
const location = response.headers.get("Location");
|
|
1254
|
+
let destination = null;
|
|
1255
|
+
if (location !== null) {
|
|
1256
|
+
try {
|
|
1257
|
+
destination = new URL(location, url).origin;
|
|
1258
|
+
} catch {
|
|
1259
|
+
destination = null;
|
|
1260
|
+
}
|
|
1261
|
+
}
|
|
1262
|
+
if (location !== null && destination !== origin) {
|
|
1263
|
+
await response.body?.cancel().catch(() => void 0);
|
|
1264
|
+
throw new TopoloSdkError(
|
|
1265
|
+
"credential_redirect_refused",
|
|
1266
|
+
`Refusing a redirect from Topolo service "${service}" to another origin; credentials are never forwarded.`
|
|
1267
|
+
);
|
|
1268
|
+
}
|
|
1269
|
+
}
|
|
1270
|
+
return response;
|
|
1271
|
+
}
|
|
1017
1272
|
var APP_API_URLS = {
|
|
1018
1273
|
auth: "https://auth.topolo.app",
|
|
1019
1274
|
developers: "https://developers.topolo.app"
|
|
@@ -1036,9 +1291,15 @@ function resolveCatalogServiceUrl(entry, options = {}) {
|
|
|
1036
1291
|
if (apiBaseUrl) return apiBaseUrl;
|
|
1037
1292
|
return null;
|
|
1038
1293
|
}
|
|
1039
|
-
function resolveServiceUrl(service, overrides) {
|
|
1294
|
+
function resolveServiceUrl(service, overrides, environment) {
|
|
1040
1295
|
const override = resolveServiceUrlOverride([service], overrides);
|
|
1041
1296
|
if (override) return override;
|
|
1297
|
+
if (environment !== void 0) {
|
|
1298
|
+
const selected = requireTopoloRuntimeEnvironment(environment);
|
|
1299
|
+
const origin = TOPOLO_ENVIRONMENT_SERVICE_URLS[selected][service];
|
|
1300
|
+
if (!origin) throw new TopoloSdkError("service_url_required", `Configure an explicit ${service} origin for ${selected}.`);
|
|
1301
|
+
return origin;
|
|
1302
|
+
}
|
|
1042
1303
|
return DEFAULT_APP_URLS[service];
|
|
1043
1304
|
}
|
|
1044
1305
|
function catalogServiceKeyCandidates(entry, preferred) {
|
|
@@ -1082,12 +1343,15 @@ function firstString(...values) {
|
|
|
1082
1343
|
}
|
|
1083
1344
|
return null;
|
|
1084
1345
|
}
|
|
1346
|
+
var DATA_CLASSIFICATIONS = /* @__PURE__ */ new Set(["public", "internal", "confidential", "restricted", "public_link"]);
|
|
1347
|
+
var TOPOLO_REFERENCE_PATTERN = /^topolo:app_[a-z0-9]+(?:_[a-z0-9]+)+\/[A-Za-z0-9][A-Za-z0-9_-]{0,127}\/[a-z][a-z0-9_]*\.[a-z][a-z0-9_]*\/[A-Za-z0-9][A-Za-z0-9_.:-]{0,255}(?:@([1-9][0-9]*))?(?![\s\S])/;
|
|
1085
1348
|
var SUPPORTED_SCHEMA_KEYWORDS = /* @__PURE__ */ new Set([
|
|
1086
1349
|
"$schema",
|
|
1087
1350
|
"$id",
|
|
1088
1351
|
"$ref",
|
|
1089
1352
|
"$defs",
|
|
1090
1353
|
"definitions",
|
|
1354
|
+
"dataClassification",
|
|
1091
1355
|
"title",
|
|
1092
1356
|
"description",
|
|
1093
1357
|
"default",
|
|
@@ -1138,7 +1402,10 @@ function inspectSchema(schema, path, root, depth) {
|
|
|
1138
1402
|
if (unsupportedKeyword) {
|
|
1139
1403
|
return { path, code: "unsupported_schema_keyword", message: `Action schema uses unsupported keyword ${unsupportedKeyword}.` };
|
|
1140
1404
|
}
|
|
1141
|
-
if (
|
|
1405
|
+
if (Object.hasOwn(schema, "dataClassification") && !DATA_CLASSIFICATIONS.has(schema.dataClassification)) {
|
|
1406
|
+
return { path: `${path}.dataClassification`, code: "invalid_data_classification", message: "Schema dataClassification must be public, internal, confidential, restricted or public_link." };
|
|
1407
|
+
}
|
|
1408
|
+
if (typeof schema.format === "string" && !["uri", "email", "date-time", "uuid", "topolo-reference"].includes(schema.format)) {
|
|
1142
1409
|
return { path, code: "unsupported_schema_format", message: `Action schema uses unsupported format ${schema.format}.` };
|
|
1143
1410
|
}
|
|
1144
1411
|
if (typeof schema.$ref === "string" && !resolveLocalReference(root, schema.$ref)) {
|
|
@@ -1300,6 +1567,10 @@ function validateString(schema, value, path, errors) {
|
|
|
1300
1567
|
errors.push({ path, code: "invalid_schema_pattern", message: "Action schema contains an invalid pattern." });
|
|
1301
1568
|
}
|
|
1302
1569
|
}
|
|
1570
|
+
if (schema.format === "topolo-reference") {
|
|
1571
|
+
const match = TOPOLO_REFERENCE_PATTERN.exec(value);
|
|
1572
|
+
if (!match || match[1] !== void 0 && !Number.isSafeInteger(Number(match[1]))) errors.push({ path, code: "format_topolo_reference", message: "Expected a canonical Topolo resource reference." });
|
|
1573
|
+
}
|
|
1303
1574
|
if (schema.format === "uri" && !isUrl(value)) errors.push({ path, code: "format_uri", message: "Expected an absolute URL." });
|
|
1304
1575
|
if (schema.format === "email" && !/^[^@\s]+@[^@\s]+\.[^@\s]+$/.test(value)) errors.push({ path, code: "format_email", message: "Expected an email address." });
|
|
1305
1576
|
if (schema.format === "date-time" && !isDateTime(value)) errors.push({ path, code: "format_date_time", message: "Expected an ISO-8601 date-time." });
|
|
@@ -1869,6 +2140,7 @@ var TopoloClient = class _TopoloClient {
|
|
|
1869
2140
|
* use and for the generic `topolo api` / MCP passthrough tool.
|
|
1870
2141
|
*/
|
|
1871
2142
|
async request(opts) {
|
|
2143
|
+
requireTopoloRuntimeEnvironment(this.environment);
|
|
1872
2144
|
const method = opts.method ?? "GET";
|
|
1873
2145
|
if (this.requireConfirmForWrites && WRITE_METHODS.has(method) && !opts.confirm) {
|
|
1874
2146
|
throw new TopoloConfirmationRequiredError(
|
|
@@ -1950,7 +2222,7 @@ var TopoloClient = class _TopoloClient {
|
|
|
1950
2222
|
privateJwk: requestCredential.privateJwk
|
|
1951
2223
|
}));
|
|
1952
2224
|
}
|
|
1953
|
-
return await this.
|
|
2225
|
+
return await this.credentialedFetch(resolvedService.serviceKey, urlStr, {
|
|
1954
2226
|
method,
|
|
1955
2227
|
headers: requestHeaders,
|
|
1956
2228
|
body: opts.rawBody ?? (opts.body !== void 0 ? JSON.stringify(opts.body) : null),
|
|
@@ -2132,8 +2404,11 @@ var TopoloClient = class _TopoloClient {
|
|
|
2132
2404
|
return this.refreshInFlight;
|
|
2133
2405
|
}
|
|
2134
2406
|
validatedServiceOrigin(service, value) {
|
|
2135
|
-
|
|
2136
|
-
|
|
2407
|
+
return assertTopoloServiceUrlEnvironment(service, requireHttpOrigin(value), this.environment);
|
|
2408
|
+
}
|
|
2409
|
+
/** The only door to the network for anything this client sends; see fetchWithCredentialBoundary. */
|
|
2410
|
+
credentialedFetch(service, target, init) {
|
|
2411
|
+
return fetchWithCredentialBoundary((input2, requestInit) => this.fetchImpl(input2, requestInit), this.environment, service, target, init);
|
|
2137
2412
|
}
|
|
2138
2413
|
validatedActionEntry(entry) {
|
|
2139
2414
|
if (!entry.apiBaseUrl) return entry;
|
|
@@ -2156,7 +2431,7 @@ var TopoloClient = class _TopoloClient {
|
|
|
2156
2431
|
}
|
|
2157
2432
|
return {
|
|
2158
2433
|
serviceKey,
|
|
2159
|
-
baseUrl: this.validatedServiceOrigin(serviceKey,
|
|
2434
|
+
baseUrl: this.validatedServiceOrigin(serviceKey, resolveServiceUrl(serviceKey, this.serviceUrls, this.environment))
|
|
2160
2435
|
};
|
|
2161
2436
|
}
|
|
2162
2437
|
const live = await this.resolveLiveCallableService(serviceKey);
|
|
@@ -2199,7 +2474,7 @@ var TopoloClient = class _TopoloClient {
|
|
|
2199
2474
|
if (!normalized) return null;
|
|
2200
2475
|
const configuredAppId = resolveConfiguredAppId(normalized, this.appIds);
|
|
2201
2476
|
if (configuredAppId) return configuredAppId;
|
|
2202
|
-
const authBase = this.validatedServiceOrigin("developers", resolveServiceUrl("developers", this.serviceUrls));
|
|
2477
|
+
const authBase = this.validatedServiceOrigin("developers", resolveServiceUrl("developers", this.serviceUrls, this.environment));
|
|
2203
2478
|
const cacheKey = `${authBase}|${normalized}`;
|
|
2204
2479
|
const now = Date.now();
|
|
2205
2480
|
const cached = _TopoloClient.appIdCache.get(cacheKey);
|
|
@@ -2212,7 +2487,7 @@ var TopoloClient = class _TopoloClient {
|
|
|
2212
2487
|
).toString();
|
|
2213
2488
|
let res;
|
|
2214
2489
|
try {
|
|
2215
|
-
res = await this.
|
|
2490
|
+
res = await this.credentialedFetch("developers", url, {
|
|
2216
2491
|
method: "GET",
|
|
2217
2492
|
headers: { Accept: "application/json" }
|
|
2218
2493
|
});
|
|
@@ -2496,7 +2771,7 @@ var TopoloClient = class _TopoloClient {
|
|
|
2496
2771
|
}
|
|
2497
2772
|
async putUrlSessionContent(entry, uploadUrl, method, bytes, options) {
|
|
2498
2773
|
const service = entry.appSlug || entry.appId;
|
|
2499
|
-
const resolved = entry.apiBaseUrl ? { serviceKey: normalizeLookupKey(service), baseUrl:
|
|
2774
|
+
const resolved = entry.apiBaseUrl ? { serviceKey: normalizeLookupKey(service), baseUrl: this.validatedServiceOrigin(service, entry.apiBaseUrl) } : await this.resolveRequestService(service);
|
|
2500
2775
|
const target = new URL(uploadUrl, resolved.baseUrl.endsWith("/") ? resolved.baseUrl : `${resolved.baseUrl}/`);
|
|
2501
2776
|
const body = bytes.buffer.slice(bytes.byteOffset, bytes.byteOffset + bytes.byteLength);
|
|
2502
2777
|
if (target.origin === new URL(resolved.baseUrl).origin) {
|
|
@@ -2512,7 +2787,7 @@ var TopoloClient = class _TopoloClient {
|
|
|
2512
2787
|
});
|
|
2513
2788
|
return;
|
|
2514
2789
|
}
|
|
2515
|
-
const response = await this.
|
|
2790
|
+
const response = await this.credentialedFetch(service, target, {
|
|
2516
2791
|
method,
|
|
2517
2792
|
headers: { "Content-Type": options.contentType.trim().toLowerCase() },
|
|
2518
2793
|
body
|
|
@@ -3448,9 +3723,11 @@ var DEVICE_GRANT = "urn:ietf:params:oauth:grant-type:device_code";
|
|
|
3448
3723
|
var TopoloOAuth = class {
|
|
3449
3724
|
baseUrl;
|
|
3450
3725
|
fetchImpl;
|
|
3726
|
+
environment;
|
|
3451
3727
|
constructor(options = {}) {
|
|
3452
|
-
this.baseUrl =
|
|
3728
|
+
this.baseUrl = resolveServiceUrl("auth", options.serviceUrls, options.environment);
|
|
3453
3729
|
this.fetchImpl = options.fetch ?? fetch;
|
|
3730
|
+
this.environment = options.environment;
|
|
3454
3731
|
}
|
|
3455
3732
|
/**
|
|
3456
3733
|
* RFC 8628 device authorization grant — starts the flow by asking the server
|
|
@@ -3515,7 +3792,7 @@ var TopoloOAuth = class {
|
|
|
3515
3792
|
}
|
|
3516
3793
|
async #postForm(path, body) {
|
|
3517
3794
|
const url = new URL(path, this.baseUrl.endsWith("/") ? this.baseUrl : `${this.baseUrl}/`);
|
|
3518
|
-
const res = await this.fetchImpl
|
|
3795
|
+
const res = await fetchWithCredentialBoundary(this.fetchImpl, this.environment, "auth", url, {
|
|
3519
3796
|
method: "POST",
|
|
3520
3797
|
headers: {
|
|
3521
3798
|
"Content-Type": "application/x-www-form-urlencoded",
|
|
@@ -4044,7 +4321,7 @@ async function pollUntilApproved(params) {
|
|
|
4044
4321
|
// src/commands/auth-lock.ts
|
|
4045
4322
|
import { createHash as createHash3 } from "crypto";
|
|
4046
4323
|
|
|
4047
|
-
// node_modules
|
|
4324
|
+
// node_modules/@topolo/sdk/dist/node/credential-store.js
|
|
4048
4325
|
import { mkdir as mkdir2, readFile as readFile2, chmod as chmod2, lstat, readdir as readdir2 } from "fs/promises";
|
|
4049
4326
|
import { existsSync as existsSync2, mkdirSync, lstatSync, readdirSync, readFileSync as readFileSync2, openSync, writeFileSync, fsyncSync, closeSync, renameSync, unlinkSync, rmdirSync, linkSync } from "fs";
|
|
4050
4327
|
import { createHash as createHash2, randomUUID as randomUUID2 } from "crypto";
|
|
@@ -4386,55 +4663,256 @@ var TopoloReauthRequiredError2 = class extends TopoloAuthError2 {
|
|
|
4386
4663
|
this.reauthorization = Object.freeze({ ...reauthorization });
|
|
4387
4664
|
}
|
|
4388
4665
|
};
|
|
4389
|
-
var
|
|
4390
|
-
|
|
4391
|
-
|
|
4666
|
+
var TOPOLO_FIRST_PARTY_ORIGINS2 = Object.freeze({
|
|
4667
|
+
production: Object.freeze([
|
|
4668
|
+
"https://admin.topolo.app",
|
|
4669
|
+
"https://agent.topolo.app",
|
|
4670
|
+
"https://api.ol0.me",
|
|
4671
|
+
"https://auth.topolo.app",
|
|
4672
|
+
"https://backup.topolo.app",
|
|
4673
|
+
"https://blog.topolo.app",
|
|
4674
|
+
"https://books.topolo.app",
|
|
4675
|
+
"https://brand.topolo.app",
|
|
4676
|
+
"https://bugfix.topolo.app",
|
|
4677
|
+
"https://bytes.topolo.app",
|
|
4678
|
+
"https://calendar.topolo.app",
|
|
4679
|
+
"https://campaigns.topolo.app",
|
|
4680
|
+
"https://capacity.topolo.app",
|
|
4681
|
+
"https://chat.topolo.app",
|
|
4682
|
+
"https://commerce.topolo.app",
|
|
4683
|
+
"https://compose.topolo.app",
|
|
4684
|
+
"https://consent.topolo.app",
|
|
4685
|
+
"https://contracts.topolo.app",
|
|
4686
|
+
"https://crm.topolo.app",
|
|
4687
|
+
"https://design.topolo.app",
|
|
4688
|
+
"https://developers.topolo.app",
|
|
4689
|
+
"https://director.topolo.app",
|
|
4690
|
+
"https://docs.topolo.app",
|
|
4691
|
+
"https://engage.topolo.app",
|
|
4692
|
+
"https://events.topolo.app",
|
|
4693
|
+
"https://feed-analytics-api.topolo.app",
|
|
4694
|
+
"https://feed-api.topolo.app",
|
|
4695
|
+
"https://flow.topolo.app",
|
|
4696
|
+
"https://forecast.topolo.app",
|
|
4697
|
+
"https://forms.topolo.app",
|
|
4698
|
+
"https://home.topolo.app",
|
|
4699
|
+
"https://insights.topolo.app",
|
|
4700
|
+
"https://inventory.topolo.app",
|
|
4701
|
+
"https://learn.topolo.app",
|
|
4702
|
+
"https://localize.topolo.app",
|
|
4703
|
+
"https://mail.topolo.app",
|
|
4704
|
+
"https://mcp.topolo.app",
|
|
4705
|
+
"https://mdm.topolo.app",
|
|
4706
|
+
"https://messages.topolo.app",
|
|
4707
|
+
"https://nexus.topolo.app",
|
|
4708
|
+
"https://notify.topolo.app",
|
|
4709
|
+
"https://nurture.topolo.app",
|
|
4710
|
+
"https://observability-watch.topolo.app",
|
|
4711
|
+
"https://p2p.topolo.app",
|
|
4712
|
+
"https://pay.topolo.app",
|
|
4713
|
+
"https://people.topolo.app",
|
|
4714
|
+
"https://quro.topolo.app",
|
|
4715
|
+
"https://recruit.topolo.app",
|
|
4716
|
+
"https://render.topolo.app",
|
|
4717
|
+
"https://roadmap.topolo.app",
|
|
4718
|
+
"https://sign.topolo.app",
|
|
4719
|
+
"https://socialize-api.topolo.app",
|
|
4720
|
+
"https://spaces.topolo.app",
|
|
4721
|
+
"https://speech.topolo.app",
|
|
4722
|
+
"https://status.topolo.app",
|
|
4723
|
+
"https://studio.topolo.app",
|
|
4724
|
+
"https://success.topolo.app",
|
|
4725
|
+
"https://support.topolo.app",
|
|
4726
|
+
"https://survey.topolo.app",
|
|
4727
|
+
"https://voice.topolo.app",
|
|
4728
|
+
"https://web.topolo.app",
|
|
4729
|
+
"https://www.topolo.app"
|
|
4730
|
+
]),
|
|
4731
|
+
staging: Object.freeze([
|
|
4732
|
+
"https://admin.stg.topolo.us",
|
|
4733
|
+
"https://agent.stg.topolo.us",
|
|
4734
|
+
"https://api.one.stg.topolo.us",
|
|
4735
|
+
"https://auth.stg.topolo.us",
|
|
4736
|
+
"https://backup.stg.topolo.us",
|
|
4737
|
+
"https://blog.stg.topolo.us",
|
|
4738
|
+
"https://books.stg.topolo.us",
|
|
4739
|
+
"https://brand.stg.topolo.us",
|
|
4740
|
+
"https://bugfix.stg.topolo.us",
|
|
4741
|
+
"https://bytes.stg.topolo.us",
|
|
4742
|
+
"https://calendar.stg.topolo.us",
|
|
4743
|
+
"https://campaigns.stg.topolo.us",
|
|
4744
|
+
"https://capacity.stg.topolo.us",
|
|
4745
|
+
"https://chat.stg.topolo.us",
|
|
4746
|
+
"https://commerce.stg.topolo.us",
|
|
4747
|
+
"https://compose.stg.topolo.us",
|
|
4748
|
+
"https://consent.stg.topolo.us",
|
|
4749
|
+
"https://contracts.stg.topolo.us",
|
|
4750
|
+
"https://crm.stg.topolo.us",
|
|
4751
|
+
"https://design.stg.topolo.us",
|
|
4752
|
+
"https://developers.stg.topolo.us",
|
|
4753
|
+
"https://director.stg.topolo.us",
|
|
4754
|
+
"https://docs.stg.topolo.us",
|
|
4755
|
+
"https://engage.stg.topolo.us",
|
|
4756
|
+
"https://events.stg.topolo.us",
|
|
4757
|
+
"https://feed-analytics-api.stg.topolo.us",
|
|
4758
|
+
"https://feed-api.stg.topolo.us",
|
|
4759
|
+
"https://flow.stg.topolo.us",
|
|
4760
|
+
"https://forecast.stg.topolo.us",
|
|
4761
|
+
"https://forms.stg.topolo.us",
|
|
4762
|
+
"https://home.stg.topolo.us",
|
|
4763
|
+
"https://insights.stg.topolo.us",
|
|
4764
|
+
"https://inventory.stg.topolo.us",
|
|
4765
|
+
"https://learn.stg.topolo.us",
|
|
4766
|
+
"https://localize.stg.topolo.us",
|
|
4767
|
+
"https://mail.stg.topolo.us",
|
|
4768
|
+
"https://mcp.stg.topolo.us",
|
|
4769
|
+
"https://mdm.stg.topolo.us",
|
|
4770
|
+
"https://messages.stg.topolo.us",
|
|
4771
|
+
"https://nexus.stg.topolo.us",
|
|
4772
|
+
"https://notify.stg.topolo.us",
|
|
4773
|
+
"https://nurture.stg.topolo.us",
|
|
4774
|
+
"https://observability-watch.stg.topolo.us",
|
|
4775
|
+
"https://p2p.stg.topolo.us",
|
|
4776
|
+
"https://pay.stg.topolo.us",
|
|
4777
|
+
"https://people.stg.topolo.us",
|
|
4778
|
+
"https://pulse.stg.topolo.us",
|
|
4779
|
+
"https://recruit.stg.topolo.us",
|
|
4780
|
+
"https://render.stg.topolo.us",
|
|
4781
|
+
"https://roadmap.stg.topolo.us",
|
|
4782
|
+
"https://seed.stg.topolo.us",
|
|
4783
|
+
"https://sign.stg.topolo.us",
|
|
4784
|
+
"https://socialize-api.stg.topolo.us",
|
|
4785
|
+
"https://spaces.stg.topolo.us",
|
|
4786
|
+
"https://speech.stg.topolo.us",
|
|
4787
|
+
"https://status.stg.topolo.us",
|
|
4788
|
+
"https://studio-api.stg.topolo.us",
|
|
4789
|
+
"https://studio.stg.topolo.us",
|
|
4790
|
+
"https://success.stg.topolo.us",
|
|
4791
|
+
"https://support.stg.topolo.us",
|
|
4792
|
+
"https://survey.stg.topolo.us",
|
|
4793
|
+
"https://voice.stg.topolo.us",
|
|
4794
|
+
"https://web.stg.topolo.us"
|
|
4795
|
+
]),
|
|
4796
|
+
development: Object.freeze([
|
|
4797
|
+
"https://admin.topolo.dev",
|
|
4798
|
+
"https://agent.topolo.dev",
|
|
4799
|
+
"https://api.one.topolo.dev",
|
|
4800
|
+
"https://auth.topolo.dev",
|
|
4801
|
+
"https://backup.topolo.dev",
|
|
4802
|
+
"https://blog.topolo.dev",
|
|
4803
|
+
"https://books.topolo.dev",
|
|
4804
|
+
"https://brand.topolo.dev",
|
|
4805
|
+
"https://bugfix.topolo.dev",
|
|
4806
|
+
"https://bytes.topolo.dev",
|
|
4807
|
+
"https://calendar.topolo.dev",
|
|
4808
|
+
"https://campaigns.topolo.dev",
|
|
4809
|
+
"https://capacity.topolo.dev",
|
|
4810
|
+
"https://chat.topolo.dev",
|
|
4811
|
+
"https://commerce.topolo.dev",
|
|
4812
|
+
"https://compose.topolo.dev",
|
|
4813
|
+
"https://consent.topolo.dev",
|
|
4814
|
+
"https://contracts.topolo.dev",
|
|
4815
|
+
"https://crm.topolo.dev",
|
|
4816
|
+
"https://design.topolo.dev",
|
|
4817
|
+
"https://developers.topolo.dev",
|
|
4818
|
+
"https://director.topolo.dev",
|
|
4819
|
+
"https://docs.topolo.dev",
|
|
4820
|
+
"https://engage.topolo.dev",
|
|
4821
|
+
"https://events.topolo.dev",
|
|
4822
|
+
"https://feed-analytics-api.topolo.dev",
|
|
4823
|
+
"https://feed-api.topolo.dev",
|
|
4824
|
+
"https://flow.topolo.dev",
|
|
4825
|
+
"https://forecast.topolo.dev",
|
|
4826
|
+
"https://forms.topolo.dev",
|
|
4827
|
+
"https://home.topolo.dev",
|
|
4828
|
+
"https://insights.topolo.dev",
|
|
4829
|
+
"https://inventory.topolo.dev",
|
|
4830
|
+
"https://learn.topolo.dev",
|
|
4831
|
+
"https://localize.topolo.dev",
|
|
4832
|
+
"https://mail.topolo.dev",
|
|
4833
|
+
"https://mcp.topolo.dev",
|
|
4834
|
+
"https://mdm.topolo.dev",
|
|
4835
|
+
"https://messages.topolo.dev",
|
|
4836
|
+
"https://nexus.topolo.dev",
|
|
4837
|
+
"https://notify.topolo.dev",
|
|
4838
|
+
"https://nurture.topolo.dev",
|
|
4839
|
+
"https://observability-watch.topolo.dev",
|
|
4840
|
+
"https://p2p.topolo.dev",
|
|
4841
|
+
"https://pay.topolo.dev",
|
|
4842
|
+
"https://people.topolo.dev",
|
|
4843
|
+
"https://pulse.topolo.dev",
|
|
4844
|
+
"https://recruit.topolo.dev",
|
|
4845
|
+
"https://render.topolo.dev",
|
|
4846
|
+
"https://roadmap.topolo.dev",
|
|
4847
|
+
"https://seed.topolo.dev",
|
|
4848
|
+
"https://sign.topolo.dev",
|
|
4849
|
+
"https://socialize-api.topolo.dev",
|
|
4850
|
+
"https://spaces.topolo.dev",
|
|
4851
|
+
"https://speech.topolo.dev",
|
|
4852
|
+
"https://status.topolo.dev",
|
|
4853
|
+
"https://studio-api.topolo.dev",
|
|
4854
|
+
"https://studio.topolo.dev",
|
|
4855
|
+
"https://success.topolo.dev",
|
|
4856
|
+
"https://support.topolo.dev",
|
|
4857
|
+
"https://survey.topolo.dev",
|
|
4858
|
+
"https://voice.topolo.dev",
|
|
4859
|
+
"https://web.topolo.dev"
|
|
4860
|
+
])
|
|
4861
|
+
});
|
|
4862
|
+
var TOPOLO_REFUSED_HOST_SUFFIXES2 = Object.freeze(["sites.stg.topolo.us", "sites.topolo.app", "sites.topolo.dev", "topolo.site", "try.topolo.io", "workers.dev"]);
|
|
4863
|
+
var TOPOLO_RUNTIME_ENVIRONMENTS2 = ["production", "staging", "development", "local"];
|
|
4864
|
+
var TOPOLO_ENVIRONMENT_SERVICE_URLS2 = Object.freeze({
|
|
4865
|
+
production: Object.freeze({
|
|
4392
4866
|
auth: "https://auth.topolo.app",
|
|
4393
4867
|
developers: "https://developers.topolo.app"
|
|
4394
|
-
},
|
|
4395
|
-
staging: {
|
|
4868
|
+
}),
|
|
4869
|
+
staging: Object.freeze({
|
|
4396
4870
|
auth: "https://auth.stg.topolo.us",
|
|
4397
4871
|
developers: "https://developers.stg.topolo.us"
|
|
4398
|
-
},
|
|
4399
|
-
development: {
|
|
4872
|
+
}),
|
|
4873
|
+
development: Object.freeze({
|
|
4400
4874
|
auth: "https://auth.topolo.dev",
|
|
4401
4875
|
developers: "https://developers.topolo.dev"
|
|
4402
|
-
},
|
|
4403
|
-
local: {}
|
|
4404
|
-
};
|
|
4405
|
-
|
|
4406
|
-
|
|
4407
|
-
|
|
4408
|
-
|
|
4409
|
-
|
|
4410
|
-
|
|
4411
|
-
|
|
4876
|
+
}),
|
|
4877
|
+
local: Object.freeze({})
|
|
4878
|
+
});
|
|
4879
|
+
var FIRST_PARTY_ORIGIN_SETS2 = Object.freeze({
|
|
4880
|
+
production: new Set(TOPOLO_FIRST_PARTY_ORIGINS2.production),
|
|
4881
|
+
staging: new Set(TOPOLO_FIRST_PARTY_ORIGINS2.staging),
|
|
4882
|
+
development: new Set(TOPOLO_FIRST_PARTY_ORIGINS2.development)
|
|
4883
|
+
});
|
|
4884
|
+
var LOOPBACK_HOSTNAMES2 = /* @__PURE__ */ new Set(["localhost", "127.0.0.1", "[::1]"]);
|
|
4885
|
+
function isRuntimeEnvironment2(value) {
|
|
4886
|
+
return typeof value === "string" && TOPOLO_RUNTIME_ENVIRONMENTS2.includes(value);
|
|
4412
4887
|
}
|
|
4413
|
-
function
|
|
4414
|
-
const hostname = url.hostname.toLowerCase();
|
|
4888
|
+
function originIsFirstParty2(url, environment) {
|
|
4415
4889
|
if (environment === "local") {
|
|
4416
|
-
return
|
|
4890
|
+
return (url.protocol === "http:" || url.protocol === "https:") && LOOPBACK_HOSTNAMES2.has(url.hostname);
|
|
4417
4891
|
}
|
|
4418
4892
|
if (url.protocol !== "https:") return false;
|
|
4419
|
-
|
|
4420
|
-
|
|
4421
|
-
|
|
4422
|
-
if (environment
|
|
4423
|
-
|
|
4893
|
+
return FIRST_PARTY_ORIGIN_SETS2[environment].has(url.origin);
|
|
4894
|
+
}
|
|
4895
|
+
function requireTopoloRuntimeEnvironment2(environment) {
|
|
4896
|
+
if (!isRuntimeEnvironment2(environment)) {
|
|
4897
|
+
throw new TopoloSdkError2(
|
|
4898
|
+
"environment_required",
|
|
4899
|
+
'Refusing to send a Topolo credential: the runtime environment is not resolved. Pass environment: "production" | "staging" | "development" | "local".'
|
|
4900
|
+
);
|
|
4424
4901
|
}
|
|
4425
|
-
return
|
|
4902
|
+
return environment;
|
|
4426
4903
|
}
|
|
4427
4904
|
function assertTopoloServiceUrlEnvironment2(service, value, environment) {
|
|
4905
|
+
const resolved = requireTopoloRuntimeEnvironment2(environment);
|
|
4428
4906
|
let url;
|
|
4429
4907
|
try {
|
|
4430
4908
|
url = new URL(value);
|
|
4431
4909
|
} catch {
|
|
4432
4910
|
throw new TopoloSdkError2("invalid_service_url", `Invalid URL configured for Topolo service "${service}".`);
|
|
4433
4911
|
}
|
|
4434
|
-
if (url.protocol !== "https:" && url.protocol !== "http:" || url.username || url.password || !
|
|
4912
|
+
if (url.protocol !== "https:" && url.protocol !== "http:" || url.username || url.password || !originIsFirstParty2(url, resolved)) {
|
|
4435
4913
|
throw new TopoloSdkError2(
|
|
4436
4914
|
"environment_mismatch",
|
|
4437
|
-
`Refusing Topolo service "${service}": ${url.origin}
|
|
4915
|
+
`Refusing Topolo service "${service}": ${url.origin} is not a first-party ${resolved} service origin.`
|
|
4438
4916
|
);
|
|
4439
4917
|
}
|
|
4440
4918
|
return url.origin;
|
|
@@ -4447,14 +4925,58 @@ function topoloServiceOrigins2(serviceUrls, environment) {
|
|
|
4447
4925
|
])
|
|
4448
4926
|
);
|
|
4449
4927
|
}
|
|
4928
|
+
var REDIRECT_STATUSES2 = /* @__PURE__ */ new Set([301, 302, 303, 307, 308]);
|
|
4929
|
+
async function fetchWithCredentialBoundary2(fetchImpl, environment, service, target, init) {
|
|
4930
|
+
const url = new URL(String(target));
|
|
4931
|
+
const origin = assertTopoloServiceUrlEnvironment2(service, url.toString(), environment);
|
|
4932
|
+
const response = await fetchImpl(url.toString(), { ...init, redirect: "manual" });
|
|
4933
|
+
let responseOrigin = origin;
|
|
4934
|
+
try {
|
|
4935
|
+
if (response.url) responseOrigin = new URL(response.url).origin;
|
|
4936
|
+
} catch {
|
|
4937
|
+
responseOrigin = "";
|
|
4938
|
+
}
|
|
4939
|
+
if (response.redirected === true || responseOrigin !== origin) {
|
|
4940
|
+
await response.body?.cancel().catch(() => void 0);
|
|
4941
|
+
throw new TopoloSdkError2(
|
|
4942
|
+
"credential_redirect_refused",
|
|
4943
|
+
`Refusing a redirected response from Topolo service "${service}"; credentials are never forwarded.`
|
|
4944
|
+
);
|
|
4945
|
+
}
|
|
4946
|
+
if (REDIRECT_STATUSES2.has(response.status)) {
|
|
4947
|
+
const location = response.headers.get("Location");
|
|
4948
|
+
let destination = null;
|
|
4949
|
+
if (location !== null) {
|
|
4950
|
+
try {
|
|
4951
|
+
destination = new URL(location, url).origin;
|
|
4952
|
+
} catch {
|
|
4953
|
+
destination = null;
|
|
4954
|
+
}
|
|
4955
|
+
}
|
|
4956
|
+
if (location !== null && destination !== origin) {
|
|
4957
|
+
await response.body?.cancel().catch(() => void 0);
|
|
4958
|
+
throw new TopoloSdkError2(
|
|
4959
|
+
"credential_redirect_refused",
|
|
4960
|
+
`Refusing a redirect from Topolo service "${service}" to another origin; credentials are never forwarded.`
|
|
4961
|
+
);
|
|
4962
|
+
}
|
|
4963
|
+
}
|
|
4964
|
+
return response;
|
|
4965
|
+
}
|
|
4450
4966
|
var APP_API_URLS2 = {
|
|
4451
4967
|
auth: "https://auth.topolo.app",
|
|
4452
4968
|
developers: "https://developers.topolo.app"
|
|
4453
4969
|
};
|
|
4454
4970
|
var DEFAULT_APP_URLS2 = APP_API_URLS2;
|
|
4455
|
-
function resolveServiceUrl2(service, overrides) {
|
|
4971
|
+
function resolveServiceUrl2(service, overrides, environment) {
|
|
4456
4972
|
const override = resolveServiceUrlOverride2([service], overrides);
|
|
4457
4973
|
if (override) return override;
|
|
4974
|
+
if (environment !== void 0) {
|
|
4975
|
+
const selected = requireTopoloRuntimeEnvironment2(environment);
|
|
4976
|
+
const origin = TOPOLO_ENVIRONMENT_SERVICE_URLS2[selected][service];
|
|
4977
|
+
if (!origin) throw new TopoloSdkError2("service_url_required", `Configure an explicit ${service} origin for ${selected}.`);
|
|
4978
|
+
return origin;
|
|
4979
|
+
}
|
|
4458
4980
|
return DEFAULT_APP_URLS2[service];
|
|
4459
4981
|
}
|
|
4460
4982
|
function resolveServiceUrlOverride2(keys, overrides) {
|
|
@@ -4476,9 +4998,11 @@ var DEVICE_GRANT2 = "urn:ietf:params:oauth:grant-type:device_code";
|
|
|
4476
4998
|
var TopoloOAuth2 = class {
|
|
4477
4999
|
baseUrl;
|
|
4478
5000
|
fetchImpl;
|
|
5001
|
+
environment;
|
|
4479
5002
|
constructor(options = {}) {
|
|
4480
|
-
this.baseUrl =
|
|
5003
|
+
this.baseUrl = resolveServiceUrl2("auth", options.serviceUrls, options.environment);
|
|
4481
5004
|
this.fetchImpl = options.fetch ?? fetch;
|
|
5005
|
+
this.environment = options.environment;
|
|
4482
5006
|
}
|
|
4483
5007
|
/**
|
|
4484
5008
|
* RFC 8628 device authorization grant — starts the flow by asking the server
|
|
@@ -4543,7 +5067,7 @@ var TopoloOAuth2 = class {
|
|
|
4543
5067
|
}
|
|
4544
5068
|
async #postForm(path, body) {
|
|
4545
5069
|
const url = new URL(path, this.baseUrl.endsWith("/") ? this.baseUrl : `${this.baseUrl}/`);
|
|
4546
|
-
const res = await this.fetchImpl
|
|
5070
|
+
const res = await fetchWithCredentialBoundary2(this.fetchImpl, this.environment, "auth", url, {
|
|
4547
5071
|
method: "POST",
|
|
4548
5072
|
headers: {
|
|
4549
5073
|
"Content-Type": "application/x-www-form-urlencoded",
|
|
@@ -4823,11 +5347,11 @@ function createProtectedActionSecretStore(options) {
|
|
|
4823
5347
|
}
|
|
4824
5348
|
};
|
|
4825
5349
|
}
|
|
4826
|
-
var TOPOLO_ENVIRONMENTS =
|
|
5350
|
+
var TOPOLO_ENVIRONMENTS = TOPOLO_RUNTIME_ENVIRONMENTS2;
|
|
4827
5351
|
function contextKey(contextType, organizationId) {
|
|
4828
5352
|
return contextType === "organization" && organizationId ? `org:${organizationId}` : "personal";
|
|
4829
5353
|
}
|
|
4830
|
-
var ENVIRONMENT_DEFAULT_SERVICE_URLS =
|
|
5354
|
+
var ENVIRONMENT_DEFAULT_SERVICE_URLS = TOPOLO_ENVIRONMENT_SERVICE_URLS2;
|
|
4831
5355
|
function configPath() {
|
|
4832
5356
|
const override = process.env.TOPOLO_CONFIG_PATH;
|
|
4833
5357
|
if (override) return override;
|
|
@@ -5155,7 +5679,7 @@ async function signOut(environment, options = {}) {
|
|
|
5155
5679
|
if (options.revoke === false || !grants.length) return result;
|
|
5156
5680
|
let oauth;
|
|
5157
5681
|
try {
|
|
5158
|
-
oauth = boundedOAuth(authServiceUrls(profile, environment, "sign-out"));
|
|
5682
|
+
oauth = boundedOAuth(authServiceUrls(profile, environment, "sign-out"), environment);
|
|
5159
5683
|
} catch {
|
|
5160
5684
|
result.revocationFailed = grants.length;
|
|
5161
5685
|
return result;
|
|
@@ -5203,14 +5727,14 @@ function configLockTimeoutMs() {
|
|
|
5203
5727
|
const value = Number(process.env.TOPOLO_CONFIG_LOCK_TIMEOUT_MS);
|
|
5204
5728
|
return Number.isFinite(value) && value >= 1e3 && value <= 12e4 ? value : CONFIG_LOCK_DEFAULT_TIMEOUT_MS;
|
|
5205
5729
|
}
|
|
5206
|
-
function boundedOAuth(serviceUrls) {
|
|
5730
|
+
function boundedOAuth(serviceUrls, environment) {
|
|
5207
5731
|
const fetchImpl = (input2, init) => globalThis.fetch(input2, {
|
|
5208
5732
|
...init,
|
|
5209
5733
|
// Never re-POST a refresh token, device code or revoked token to another origin.
|
|
5210
5734
|
redirect: "error",
|
|
5211
5735
|
signal: init?.signal ?? AbortSignal.timeout(AUTH_EXCHANGE_TIMEOUT_MS)
|
|
5212
5736
|
});
|
|
5213
|
-
return new TopoloOAuth2({ serviceUrls, fetch: fetchImpl });
|
|
5737
|
+
return new TopoloOAuth2({ serviceUrls, fetch: fetchImpl, environment });
|
|
5214
5738
|
}
|
|
5215
5739
|
var CONFIG_LOCK_DEAD_OWNER_MIN_AGE_MS = 2e3;
|
|
5216
5740
|
var ConfigOwnershipError = class extends TopoloSdkError2 {
|
|
@@ -5827,7 +6351,7 @@ async function renewTarget(environment, target, options) {
|
|
|
5827
6351
|
return endGrant(retired.reason === "rotated" ? "rotated_grant_lost" : retired.reason);
|
|
5828
6352
|
}
|
|
5829
6353
|
const serviceUrls = authServiceUrls(profile, environment, target.kind === "active" ? "credential refresh" : "context refresh");
|
|
5830
|
-
const oauth = boundedOAuth(serviceUrls);
|
|
6354
|
+
const oauth = boundedOAuth(serviceUrls, environment);
|
|
5831
6355
|
try {
|
|
5832
6356
|
await persist((current) => {
|
|
5833
6357
|
const next = clone(current);
|
|
@@ -5922,7 +6446,7 @@ async function continueReauthorization(environment, key) {
|
|
|
5922
6446
|
const clientId = (key === DEFAULT_SLOT ? void 0 : profile.contexts?.[key]?.oauthClientId) ?? profile.oauthClientId;
|
|
5923
6447
|
if (!clientId) throw reauthRequired(environment, key, entry, "unavailable");
|
|
5924
6448
|
const serviceUrls = authServiceUrls(profile, environment, "sign-in renewal");
|
|
5925
|
-
const oauth = boundedOAuth(serviceUrls);
|
|
6449
|
+
const oauth = boundedOAuth(serviceUrls, environment);
|
|
5926
6450
|
const now = nowSeconds();
|
|
5927
6451
|
let state = clone(entry);
|
|
5928
6452
|
const save = async (update) => {
|
package/package.json
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@topolo/cli",
|
|
3
3
|
"packageManager": "pnpm@10.17.1",
|
|
4
|
-
"version": "0.13.
|
|
5
|
-
"topoloPublishedVersion": "0.13.
|
|
4
|
+
"version": "0.13.26",
|
|
5
|
+
"topoloPublishedVersion": "0.13.26",
|
|
6
6
|
"description": "Public command-line interface for Topolo customer organizations, developers, and agents.",
|
|
7
7
|
"license": "UNLICENSED",
|
|
8
8
|
"author": "Topolo",
|
|
@@ -33,8 +33,8 @@
|
|
|
33
33
|
},
|
|
34
34
|
"dependencies": {
|
|
35
35
|
"@modelcontextprotocol/sdk": "1.31.0",
|
|
36
|
-
"@topolo/mcp": "0.14.
|
|
37
|
-
"@topolo/sdk": "0.
|
|
36
|
+
"@topolo/mcp": "0.14.38",
|
|
37
|
+
"@topolo/sdk": "0.24.0",
|
|
38
38
|
"commander": "^12.1.0",
|
|
39
39
|
"undici": "6.29.0"
|
|
40
40
|
},
|