@topolo/cli 0.13.25 → 0.13.27

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.
Files changed (2) hide show
  1. package/dist/index.js +795 -183
  2. 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/.pnpm/@topolo+sdk@0.23.26/node_modules/@topolo/sdk/dist/index.js
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
  }
@@ -326,74 +326,6 @@ function validTopoloActionAccessPolicy(value) {
326
326
  }
327
327
  return true;
328
328
  }
329
- function record2(value) {
330
- return !!value && typeof value === "object" && !Array.isArray(value);
331
- }
332
- function text(value, limit = 512) {
333
- return typeof value === "string" && value.trim() ? value.trim().slice(0, limit) : null;
334
- }
335
- function strings2(value) {
336
- return Array.isArray(value) ? value.slice(0, 8).flatMap((item) => {
337
- const result = text(item);
338
- return result ? [result] : [];
339
- }) : [];
340
- }
341
- function pairs(value, first, second) {
342
- return Array.isArray(value) ? value.slice(0, 8).flatMap((item) => {
343
- if (!record2(item)) return [];
344
- const a = text(item[first], 160);
345
- const b = text(item[second]);
346
- return a && b ? [{ [first]: a, [second]: b }] : [];
347
- }) : [];
348
- }
349
- function docs(value) {
350
- const result = text(value, 2048);
351
- if (!result) return null;
352
- try {
353
- const url = new URL(result);
354
- return url.protocol === "https:" && !url.username && !url.password ? url.href : null;
355
- } catch {
356
- return null;
357
- }
358
- }
359
- function normalizeApplicationGuide(value) {
360
- if (!record2(value) || value.schemaVersion !== 1 || value.source !== "published_application_manifest") return null;
361
- const purpose = text(value.purpose, 2048);
362
- const gettingStarted = strings2(value.gettingStarted);
363
- const docsUrl = docs(value.docsUrl);
364
- return {
365
- schemaVersion: 1,
366
- source: "published_application_manifest",
367
- publishedAt: text(value.publishedAt, 160),
368
- purpose,
369
- problemStatement: text(value.problemStatement, 2048),
370
- solutionStatement: text(value.solutionStatement, 2048),
371
- benefits: strings2(value.benefits),
372
- features: pairs(value.features, "title", "description"),
373
- gettingStarted,
374
- worksWellWith: pairs(value.worksWellWith, "appId", "reason"),
375
- docsUrl,
376
- missingFields: [...!purpose ? ["purpose"] : [], ...!docsUrl ? ["docsUrl"] : [], ...!gettingStarted.length ? ["gettingStarted"] : []]
377
- };
378
- }
379
- function applyAuthHeaders(headers, credential) {
380
- if (credential.kind === "api_key") {
381
- headers.set("X-Api-Key", credential.apiKey);
382
- return;
383
- }
384
- headers.set("Authorization", `${credential.kind === "dpop_access_token" ? "DPoP" : "Bearer"} ${credential.accessToken}`);
385
- }
386
- function applyAuditHeaders(headers, agent, requestId) {
387
- headers.set("X-Topolo-Client", `${agent.clientName}/${agent.clientVersion}`);
388
- if (agent.agentName) headers.set("X-Topolo-Agent", agent.agentName);
389
- headers.set("X-Topolo-Request-Id", requestId);
390
- }
391
- function generateRequestId() {
392
- if (typeof crypto !== "undefined" && typeof crypto.randomUUID === "function") {
393
- return crypto.randomUUID();
394
- }
395
- return `req_${Date.now().toString(36)}_${Math.random().toString(36).slice(2, 10)}`;
396
- }
397
329
  var TopoloSdkError = class extends Error {
398
330
  code;
399
331
  constructor(code, message3) {
@@ -823,6 +755,424 @@ var TopoloReauthRequiredError = class extends TopoloAuthError {
823
755
  this.reauthorization = Object.freeze({ ...reauthorization });
824
756
  }
825
757
  };
758
+ var TOPOLO_FIRST_PARTY_ORIGINS = Object.freeze({
759
+ production: Object.freeze([
760
+ "https://admin.topolo.app",
761
+ "https://agent.topolo.app",
762
+ "https://api.ol0.me",
763
+ "https://auth.topolo.app",
764
+ "https://backup.topolo.app",
765
+ "https://blog.topolo.app",
766
+ "https://books.topolo.app",
767
+ "https://brand.topolo.app",
768
+ "https://bugfix.topolo.app",
769
+ "https://bytes.topolo.app",
770
+ "https://calendar.topolo.app",
771
+ "https://campaigns.topolo.app",
772
+ "https://capacity.topolo.app",
773
+ "https://chat.topolo.app",
774
+ "https://commerce.topolo.app",
775
+ "https://compose.topolo.app",
776
+ "https://consent.topolo.app",
777
+ "https://contracts.topolo.app",
778
+ "https://crm.topolo.app",
779
+ "https://design.topolo.app",
780
+ "https://developers.topolo.app",
781
+ "https://director.topolo.app",
782
+ "https://docs.topolo.app",
783
+ "https://engage.topolo.app",
784
+ "https://events.topolo.app",
785
+ "https://feed-analytics-api.topolo.app",
786
+ "https://feed-api.topolo.app",
787
+ "https://flow.topolo.app",
788
+ "https://forecast.topolo.app",
789
+ "https://forms.topolo.app",
790
+ "https://home.topolo.app",
791
+ "https://insights.topolo.app",
792
+ "https://inventory.topolo.app",
793
+ "https://learn.topolo.app",
794
+ "https://localize.topolo.app",
795
+ "https://mail.topolo.app",
796
+ "https://mcp.topolo.app",
797
+ "https://mdm.topolo.app",
798
+ "https://messages.topolo.app",
799
+ "https://nexus.topolo.app",
800
+ "https://notify.topolo.app",
801
+ "https://nurture.topolo.app",
802
+ "https://observability-watch.topolo.app",
803
+ "https://p2p.topolo.app",
804
+ "https://pay.topolo.app",
805
+ "https://people.topolo.app",
806
+ "https://quro.topolo.app",
807
+ "https://recruit.topolo.app",
808
+ "https://render.topolo.app",
809
+ "https://roadmap.topolo.app",
810
+ "https://sign.topolo.app",
811
+ "https://socialize-api.topolo.app",
812
+ "https://spaces.topolo.app",
813
+ "https://speech.topolo.app",
814
+ "https://status.topolo.app",
815
+ "https://studio.topolo.app",
816
+ "https://success.topolo.app",
817
+ "https://support.topolo.app",
818
+ "https://survey.topolo.app",
819
+ "https://voice.topolo.app",
820
+ "https://web.topolo.app",
821
+ "https://www.topolo.app"
822
+ ]),
823
+ staging: Object.freeze([
824
+ "https://admin.stg.topolo.us",
825
+ "https://agent.stg.topolo.us",
826
+ "https://api.one.stg.topolo.us",
827
+ "https://auth.stg.topolo.us",
828
+ "https://backup.stg.topolo.us",
829
+ "https://blog.stg.topolo.us",
830
+ "https://books.stg.topolo.us",
831
+ "https://brand.stg.topolo.us",
832
+ "https://bugfix.stg.topolo.us",
833
+ "https://bytes.stg.topolo.us",
834
+ "https://calendar.stg.topolo.us",
835
+ "https://campaigns.stg.topolo.us",
836
+ "https://capacity.stg.topolo.us",
837
+ "https://chat.stg.topolo.us",
838
+ "https://commerce.stg.topolo.us",
839
+ "https://compose.stg.topolo.us",
840
+ "https://consent.stg.topolo.us",
841
+ "https://contracts.stg.topolo.us",
842
+ "https://crm.stg.topolo.us",
843
+ "https://design.stg.topolo.us",
844
+ "https://developers.stg.topolo.us",
845
+ "https://director.stg.topolo.us",
846
+ "https://docs.stg.topolo.us",
847
+ "https://engage.stg.topolo.us",
848
+ "https://events.stg.topolo.us",
849
+ "https://feed-analytics-api.stg.topolo.us",
850
+ "https://feed-api.stg.topolo.us",
851
+ "https://flow.stg.topolo.us",
852
+ "https://forecast.stg.topolo.us",
853
+ "https://forms.stg.topolo.us",
854
+ "https://home.stg.topolo.us",
855
+ "https://insights.stg.topolo.us",
856
+ "https://inventory.stg.topolo.us",
857
+ "https://learn.stg.topolo.us",
858
+ "https://localize.stg.topolo.us",
859
+ "https://mail.stg.topolo.us",
860
+ "https://mcp.stg.topolo.us",
861
+ "https://mdm.stg.topolo.us",
862
+ "https://messages.stg.topolo.us",
863
+ "https://nexus.stg.topolo.us",
864
+ "https://notify.stg.topolo.us",
865
+ "https://nurture.stg.topolo.us",
866
+ "https://observability-watch.stg.topolo.us",
867
+ "https://p2p.stg.topolo.us",
868
+ "https://pay.stg.topolo.us",
869
+ "https://people.stg.topolo.us",
870
+ "https://pulse.stg.topolo.us",
871
+ "https://recruit.stg.topolo.us",
872
+ "https://render.stg.topolo.us",
873
+ "https://roadmap.stg.topolo.us",
874
+ "https://seed.stg.topolo.us",
875
+ "https://sign.stg.topolo.us",
876
+ "https://socialize-api.stg.topolo.us",
877
+ "https://spaces.stg.topolo.us",
878
+ "https://speech.stg.topolo.us",
879
+ "https://status.stg.topolo.us",
880
+ "https://studio-api.stg.topolo.us",
881
+ "https://studio.stg.topolo.us",
882
+ "https://success.stg.topolo.us",
883
+ "https://support.stg.topolo.us",
884
+ "https://survey.stg.topolo.us",
885
+ "https://voice.stg.topolo.us",
886
+ "https://web.stg.topolo.us"
887
+ ]),
888
+ development: Object.freeze([
889
+ "https://admin.topolo.dev",
890
+ "https://agent.topolo.dev",
891
+ "https://api.one.topolo.dev",
892
+ "https://auth.topolo.dev",
893
+ "https://backup.topolo.dev",
894
+ "https://blog.topolo.dev",
895
+ "https://books.topolo.dev",
896
+ "https://brand.topolo.dev",
897
+ "https://bugfix.topolo.dev",
898
+ "https://bytes.topolo.dev",
899
+ "https://calendar.topolo.dev",
900
+ "https://campaigns.topolo.dev",
901
+ "https://capacity.topolo.dev",
902
+ "https://chat.topolo.dev",
903
+ "https://commerce.topolo.dev",
904
+ "https://compose.topolo.dev",
905
+ "https://consent.topolo.dev",
906
+ "https://contracts.topolo.dev",
907
+ "https://crm.topolo.dev",
908
+ "https://design.topolo.dev",
909
+ "https://developers.topolo.dev",
910
+ "https://director.topolo.dev",
911
+ "https://docs.topolo.dev",
912
+ "https://engage.topolo.dev",
913
+ "https://events.topolo.dev",
914
+ "https://feed-analytics-api.topolo.dev",
915
+ "https://feed-api.topolo.dev",
916
+ "https://flow.topolo.dev",
917
+ "https://forecast.topolo.dev",
918
+ "https://forms.topolo.dev",
919
+ "https://home.topolo.dev",
920
+ "https://insights.topolo.dev",
921
+ "https://inventory.topolo.dev",
922
+ "https://learn.topolo.dev",
923
+ "https://localize.topolo.dev",
924
+ "https://mail.topolo.dev",
925
+ "https://mcp.topolo.dev",
926
+ "https://mdm.topolo.dev",
927
+ "https://messages.topolo.dev",
928
+ "https://nexus.topolo.dev",
929
+ "https://notify.topolo.dev",
930
+ "https://nurture.topolo.dev",
931
+ "https://observability-watch.topolo.dev",
932
+ "https://p2p.topolo.dev",
933
+ "https://pay.topolo.dev",
934
+ "https://people.topolo.dev",
935
+ "https://pulse.topolo.dev",
936
+ "https://recruit.topolo.dev",
937
+ "https://render.topolo.dev",
938
+ "https://roadmap.topolo.dev",
939
+ "https://seed.topolo.dev",
940
+ "https://sign.topolo.dev",
941
+ "https://socialize-api.topolo.dev",
942
+ "https://spaces.topolo.dev",
943
+ "https://speech.topolo.dev",
944
+ "https://status.topolo.dev",
945
+ "https://studio-api.topolo.dev",
946
+ "https://studio.topolo.dev",
947
+ "https://success.topolo.dev",
948
+ "https://support.topolo.dev",
949
+ "https://survey.topolo.dev",
950
+ "https://voice.topolo.dev",
951
+ "https://web.topolo.dev"
952
+ ])
953
+ });
954
+ var TOPOLO_REFUSED_HOST_SUFFIXES = Object.freeze(["sites.stg.topolo.us", "sites.topolo.app", "sites.topolo.dev", "topolo.site", "try.topolo.io", "workers.dev"]);
955
+ var TOPOLO_RUNTIME_ENVIRONMENTS = ["production", "staging", "development", "local"];
956
+ var TOPOLO_ENVIRONMENT_SERVICE_URLS = Object.freeze({
957
+ production: Object.freeze({
958
+ auth: "https://auth.topolo.app",
959
+ developers: "https://developers.topolo.app"
960
+ }),
961
+ staging: Object.freeze({
962
+ auth: "https://auth.stg.topolo.us",
963
+ developers: "https://developers.stg.topolo.us"
964
+ }),
965
+ development: Object.freeze({
966
+ auth: "https://auth.topolo.dev",
967
+ developers: "https://developers.topolo.dev"
968
+ }),
969
+ local: Object.freeze({})
970
+ });
971
+ var FIRST_PARTY_ORIGIN_SETS = Object.freeze({
972
+ production: new Set(TOPOLO_FIRST_PARTY_ORIGINS.production),
973
+ staging: new Set(TOPOLO_FIRST_PARTY_ORIGINS.staging),
974
+ development: new Set(TOPOLO_FIRST_PARTY_ORIGINS.development)
975
+ });
976
+ var LOOPBACK_HOSTNAMES = /* @__PURE__ */ new Set(["localhost", "127.0.0.1", "[::1]"]);
977
+ function isRuntimeEnvironment(value) {
978
+ return typeof value === "string" && TOPOLO_RUNTIME_ENVIRONMENTS.includes(value);
979
+ }
980
+ function originIsFirstParty(url, environment) {
981
+ if (environment === "local") {
982
+ return (url.protocol === "http:" || url.protocol === "https:") && LOOPBACK_HOSTNAMES.has(url.hostname);
983
+ }
984
+ if (url.protocol !== "https:") return false;
985
+ return FIRST_PARTY_ORIGIN_SETS[environment].has(url.origin);
986
+ }
987
+ function requireTopoloRuntimeEnvironment(environment) {
988
+ if (!isRuntimeEnvironment(environment)) {
989
+ throw new TopoloSdkError(
990
+ "environment_required",
991
+ 'Refusing to send a Topolo credential: the runtime environment is not resolved. Pass environment: "production" | "staging" | "development" | "local".'
992
+ );
993
+ }
994
+ return environment;
995
+ }
996
+ function assertTopoloServiceUrlEnvironment(service, value, environment) {
997
+ const resolved = requireTopoloRuntimeEnvironment(environment);
998
+ let url;
999
+ try {
1000
+ url = new URL(value);
1001
+ } catch {
1002
+ throw new TopoloSdkError("invalid_service_url", `Invalid URL configured for Topolo service "${service}".`);
1003
+ }
1004
+ if (url.protocol !== "https:" && url.protocol !== "http:" || url.username || url.password || !originIsFirstParty(url, resolved)) {
1005
+ throw new TopoloSdkError(
1006
+ "environment_mismatch",
1007
+ `Refusing Topolo service "${service}": ${url.origin} is not a first-party ${resolved} service origin.`
1008
+ );
1009
+ }
1010
+ return url.origin;
1011
+ }
1012
+ function topoloServiceOrigins(serviceUrls, environment) {
1013
+ return Object.fromEntries(
1014
+ Object.entries(serviceUrls ?? {}).sort(([left], [right]) => left.localeCompare(right)).map(([service, value]) => [
1015
+ service,
1016
+ assertTopoloServiceUrlEnvironment(service, value, environment)
1017
+ ])
1018
+ );
1019
+ }
1020
+ var REDIRECT_STATUSES = /* @__PURE__ */ new Set([301, 302, 303, 307, 308]);
1021
+ async function fetchWithCredentialBoundary(fetchImpl, environment, service, target, init) {
1022
+ const url = new URL(String(target));
1023
+ const origin = assertTopoloServiceUrlEnvironment(service, url.toString(), environment);
1024
+ const response = await fetchImpl(url.toString(), { ...init, redirect: "manual" });
1025
+ let responseOrigin = origin;
1026
+ try {
1027
+ if (response.url) responseOrigin = new URL(response.url).origin;
1028
+ } catch {
1029
+ responseOrigin = "";
1030
+ }
1031
+ if (response.redirected === true || responseOrigin !== origin) {
1032
+ await response.body?.cancel().catch(() => void 0);
1033
+ throw new TopoloSdkError(
1034
+ "credential_redirect_refused",
1035
+ `Refusing a redirected response from Topolo service "${service}"; credentials are never forwarded.`
1036
+ );
1037
+ }
1038
+ if (REDIRECT_STATUSES.has(response.status)) {
1039
+ const location = response.headers.get("Location");
1040
+ let destination = null;
1041
+ if (location !== null) {
1042
+ try {
1043
+ destination = new URL(location, url).origin;
1044
+ } catch {
1045
+ destination = null;
1046
+ }
1047
+ }
1048
+ if (location !== null && destination !== origin) {
1049
+ await response.body?.cancel().catch(() => void 0);
1050
+ throw new TopoloSdkError(
1051
+ "credential_redirect_refused",
1052
+ `Refusing a redirect from Topolo service "${service}" to another origin; credentials are never forwarded.`
1053
+ );
1054
+ }
1055
+ }
1056
+ return response;
1057
+ }
1058
+ var MARKETING_ORIGINS = Object.freeze({
1059
+ development: "https://topolo.dev",
1060
+ staging: "https://stg.topolo.us",
1061
+ production: "https://topolo.io"
1062
+ });
1063
+ function isOnePublicMarketingAction(entry) {
1064
+ return entry.appId === "app_topolo_one" && entry.target === "marketing" && entry.authorizationMode === "public";
1065
+ }
1066
+ function publicMarketingOrigin(entry, environment) {
1067
+ const selected = requireTopoloRuntimeEnvironment(environment);
1068
+ const origin = selected === "local" ? void 0 : MARKETING_ORIGINS[selected];
1069
+ if (!isOnePublicMarketingAction(entry) || !origin || entry.apiBaseUrl !== origin && entry.apiBaseUrl !== origin + "/") {
1070
+ throw new TopoloSdkError("environment_mismatch", "Public action target does not match the registered application, target and environment.");
1071
+ }
1072
+ return origin;
1073
+ }
1074
+ async function fetchPublicMarketingAction(fetchImpl, entry, environment, target, init) {
1075
+ const origin = publicMarketingOrigin(entry, environment);
1076
+ if (target.origin !== origin || target.protocol !== "https:" || target.username || target.password || target.port) {
1077
+ throw new TopoloSdkError("service_path_origin_mismatch", "Public action path changes the registered target origin.");
1078
+ }
1079
+ init.signal?.throwIfAborted();
1080
+ const headers = new Headers({
1081
+ Accept: "application/json",
1082
+ "X-Topolo-Action-Id": entry.actionId,
1083
+ "X-Topolo-Action-Name": entry.name
1084
+ });
1085
+ const contentType = new Headers(init.headers).get("Content-Type");
1086
+ if (contentType) headers.set("Content-Type", contentType);
1087
+ const response = await fetchImpl(target.toString(), {
1088
+ method: init.method,
1089
+ headers,
1090
+ body: init.body,
1091
+ signal: init.signal,
1092
+ credentials: "omit",
1093
+ redirect: "manual",
1094
+ referrerPolicy: "no-referrer"
1095
+ });
1096
+ let responseOrigin = origin;
1097
+ try {
1098
+ if (response.url) responseOrigin = new URL(response.url).origin;
1099
+ } catch {
1100
+ responseOrigin = "";
1101
+ }
1102
+ if (response.redirected || responseOrigin !== origin || response.status >= 300 && response.status < 400) {
1103
+ await response.body?.cancel().catch(() => void 0);
1104
+ throw new TopoloSdkError("public_action_redirect_refused", "Public action redirects are refused.");
1105
+ }
1106
+ return response;
1107
+ }
1108
+ function record2(value) {
1109
+ return !!value && typeof value === "object" && !Array.isArray(value);
1110
+ }
1111
+ function text(value, limit = 512) {
1112
+ return typeof value === "string" && value.trim() ? value.trim().slice(0, limit) : null;
1113
+ }
1114
+ function strings2(value) {
1115
+ return Array.isArray(value) ? value.slice(0, 8).flatMap((item) => {
1116
+ const result = text(item);
1117
+ return result ? [result] : [];
1118
+ }) : [];
1119
+ }
1120
+ function pairs(value, first, second) {
1121
+ return Array.isArray(value) ? value.slice(0, 8).flatMap((item) => {
1122
+ if (!record2(item)) return [];
1123
+ const a = text(item[first], 160);
1124
+ const b = text(item[second]);
1125
+ return a && b ? [{ [first]: a, [second]: b }] : [];
1126
+ }) : [];
1127
+ }
1128
+ function docs(value) {
1129
+ const result = text(value, 2048);
1130
+ if (!result) return null;
1131
+ try {
1132
+ const url = new URL(result);
1133
+ return url.protocol === "https:" && !url.username && !url.password ? url.href : null;
1134
+ } catch {
1135
+ return null;
1136
+ }
1137
+ }
1138
+ function normalizeApplicationGuide(value) {
1139
+ if (!record2(value) || value.schemaVersion !== 1 || value.source !== "published_application_manifest") return null;
1140
+ const purpose = text(value.purpose, 2048);
1141
+ const gettingStarted = strings2(value.gettingStarted);
1142
+ const docsUrl = docs(value.docsUrl);
1143
+ return {
1144
+ schemaVersion: 1,
1145
+ source: "published_application_manifest",
1146
+ publishedAt: text(value.publishedAt, 160),
1147
+ purpose,
1148
+ problemStatement: text(value.problemStatement, 2048),
1149
+ solutionStatement: text(value.solutionStatement, 2048),
1150
+ benefits: strings2(value.benefits),
1151
+ features: pairs(value.features, "title", "description"),
1152
+ gettingStarted,
1153
+ worksWellWith: pairs(value.worksWellWith, "appId", "reason"),
1154
+ docsUrl,
1155
+ missingFields: [...!purpose ? ["purpose"] : [], ...!docsUrl ? ["docsUrl"] : [], ...!gettingStarted.length ? ["gettingStarted"] : []]
1156
+ };
1157
+ }
1158
+ function applyAuthHeaders(headers, credential) {
1159
+ if (credential.kind === "api_key") {
1160
+ headers.set("X-Api-Key", credential.apiKey);
1161
+ return;
1162
+ }
1163
+ headers.set("Authorization", `${credential.kind === "dpop_access_token" ? "DPoP" : "Bearer"} ${credential.accessToken}`);
1164
+ }
1165
+ function applyAuditHeaders(headers, agent, requestId) {
1166
+ headers.set("X-Topolo-Client", `${agent.clientName}/${agent.clientVersion}`);
1167
+ if (agent.agentName) headers.set("X-Topolo-Agent", agent.agentName);
1168
+ headers.set("X-Topolo-Request-Id", requestId);
1169
+ }
1170
+ function generateRequestId() {
1171
+ if (typeof crypto !== "undefined" && typeof crypto.randomUUID === "function") {
1172
+ return crypto.randomUUID();
1173
+ }
1174
+ return `req_${Date.now().toString(36)}_${Math.random().toString(36).slice(2, 10)}`;
1175
+ }
826
1176
  var ACTION_SECRET_PREFIX = "topolo-secret:";
827
1177
  function isActionSecretReference(value) {
828
1178
  return typeof value === "string" && value.startsWith(ACTION_SECRET_PREFIX);
@@ -969,51 +1319,6 @@ async function createDpopProof(input2) {
969
1319
  );
970
1320
  return `${header}.${claims}.${encodeBase64Url(signature)}`;
971
1321
  }
972
- function hostnameHasSuffix(hostname, suffix) {
973
- return hostname === suffix || hostname.endsWith(`.${suffix}`);
974
- }
975
- function workersDevAccountMatches(hostname, account) {
976
- if (!hostname.endsWith(".workers.dev")) return false;
977
- const labels = hostname.slice(0, -".workers.dev".length).split(".");
978
- return labels.length >= 2 && labels.at(-1) === account;
979
- }
980
- function originMatchesEnvironment(url, environment) {
981
- const hostname = url.hostname.toLowerCase();
982
- if (environment === "local") {
983
- return hostname === "localhost" || hostname.endsWith(".localhost") || hostname === "127.0.0.1" || hostname === "[::1]";
984
- }
985
- if (url.protocol !== "https:") return false;
986
- if (environment === "production") {
987
- return hostnameHasSuffix(hostname, "topolo.app") || hostnameHasSuffix(hostname, "topolo.io") || hostname === "api.ol0.me" || workersDevAccountMatches(hostname, "topolo");
988
- }
989
- if (environment === "staging") {
990
- return hostnameHasSuffix(hostname, "stg.topolo.us") || workersDevAccountMatches(hostname, "topolo-staging");
991
- }
992
- return hostnameHasSuffix(hostname, "topolo.dev") || workersDevAccountMatches(hostname, "topolo-development");
993
- }
994
- function assertTopoloServiceUrlEnvironment(service, value, environment) {
995
- let url;
996
- try {
997
- url = new URL(value);
998
- } catch {
999
- throw new TopoloSdkError("invalid_service_url", `Invalid URL configured for Topolo service "${service}".`);
1000
- }
1001
- if (url.protocol !== "https:" && url.protocol !== "http:" || url.username || url.password || !originMatchesEnvironment(url, environment)) {
1002
- throw new TopoloSdkError(
1003
- "environment_mismatch",
1004
- `Refusing Topolo service "${service}": ${url.origin} does not belong to ${environment}.`
1005
- );
1006
- }
1007
- return url.origin;
1008
- }
1009
- function topoloServiceOrigins(serviceUrls, environment) {
1010
- return Object.fromEntries(
1011
- Object.entries(serviceUrls ?? {}).sort(([left], [right]) => left.localeCompare(right)).map(([service, value]) => [
1012
- service,
1013
- assertTopoloServiceUrlEnvironment(service, value, environment)
1014
- ])
1015
- );
1016
- }
1017
1322
  var APP_API_URLS = {
1018
1323
  auth: "https://auth.topolo.app",
1019
1324
  developers: "https://developers.topolo.app"
@@ -1036,9 +1341,15 @@ function resolveCatalogServiceUrl(entry, options = {}) {
1036
1341
  if (apiBaseUrl) return apiBaseUrl;
1037
1342
  return null;
1038
1343
  }
1039
- function resolveServiceUrl(service, overrides) {
1344
+ function resolveServiceUrl(service, overrides, environment) {
1040
1345
  const override = resolveServiceUrlOverride([service], overrides);
1041
1346
  if (override) return override;
1347
+ if (environment !== void 0) {
1348
+ const selected = requireTopoloRuntimeEnvironment(environment);
1349
+ const origin = TOPOLO_ENVIRONMENT_SERVICE_URLS[selected][service];
1350
+ if (!origin) throw new TopoloSdkError("service_url_required", `Configure an explicit ${service} origin for ${selected}.`);
1351
+ return origin;
1352
+ }
1042
1353
  return DEFAULT_APP_URLS[service];
1043
1354
  }
1044
1355
  function catalogServiceKeyCandidates(entry, preferred) {
@@ -1082,12 +1393,15 @@ function firstString(...values) {
1082
1393
  }
1083
1394
  return null;
1084
1395
  }
1396
+ var DATA_CLASSIFICATIONS = /* @__PURE__ */ new Set(["public", "internal", "confidential", "restricted", "public_link"]);
1397
+ 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
1398
  var SUPPORTED_SCHEMA_KEYWORDS = /* @__PURE__ */ new Set([
1086
1399
  "$schema",
1087
1400
  "$id",
1088
1401
  "$ref",
1089
1402
  "$defs",
1090
1403
  "definitions",
1404
+ "dataClassification",
1091
1405
  "title",
1092
1406
  "description",
1093
1407
  "default",
@@ -1138,7 +1452,10 @@ function inspectSchema(schema, path, root, depth) {
1138
1452
  if (unsupportedKeyword) {
1139
1453
  return { path, code: "unsupported_schema_keyword", message: `Action schema uses unsupported keyword ${unsupportedKeyword}.` };
1140
1454
  }
1141
- if (typeof schema.format === "string" && !["uri", "email", "date-time", "uuid"].includes(schema.format)) {
1455
+ if (Object.hasOwn(schema, "dataClassification") && !DATA_CLASSIFICATIONS.has(schema.dataClassification)) {
1456
+ return { path: `${path}.dataClassification`, code: "invalid_data_classification", message: "Schema dataClassification must be public, internal, confidential, restricted or public_link." };
1457
+ }
1458
+ if (typeof schema.format === "string" && !["uri", "email", "date-time", "uuid", "topolo-reference"].includes(schema.format)) {
1142
1459
  return { path, code: "unsupported_schema_format", message: `Action schema uses unsupported format ${schema.format}.` };
1143
1460
  }
1144
1461
  if (typeof schema.$ref === "string" && !resolveLocalReference(root, schema.$ref)) {
@@ -1300,6 +1617,10 @@ function validateString(schema, value, path, errors) {
1300
1617
  errors.push({ path, code: "invalid_schema_pattern", message: "Action schema contains an invalid pattern." });
1301
1618
  }
1302
1619
  }
1620
+ if (schema.format === "topolo-reference") {
1621
+ const match = TOPOLO_REFERENCE_PATTERN.exec(value);
1622
+ 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." });
1623
+ }
1303
1624
  if (schema.format === "uri" && !isUrl(value)) errors.push({ path, code: "format_uri", message: "Expected an absolute URL." });
1304
1625
  if (schema.format === "email" && !/^[^@\s]+@[^@\s]+\.[^@\s]+$/.test(value)) errors.push({ path, code: "format_email", message: "Expected an email address." });
1305
1626
  if (schema.format === "date-time" && !isDateTime(value)) errors.push({ path, code: "format_date_time", message: "Expected an ISO-8601 date-time." });
@@ -1869,6 +2190,17 @@ var TopoloClient = class _TopoloClient {
1869
2190
  * use and for the generic `topolo api` / MCP passthrough tool.
1870
2191
  */
1871
2192
  async request(opts) {
2193
+ return this.requestWithTarget(opts);
2194
+ }
2195
+ async requestWithTarget(opts, publicAction) {
2196
+ requireTopoloRuntimeEnvironment(this.environment);
2197
+ const publicOrigin = publicAction ? publicMarketingOrigin(publicAction, this.environment) : void 0;
2198
+ if (publicOrigin && (opts.actorEnvelope !== void 0 || opts.resource !== void 0)) {
2199
+ throw new TopoloSdkError("public_action_context_not_supported", "Public marketing actions do not accept actor or resource authority.");
2200
+ }
2201
+ if (publicOrigin && (!opts.path.startsWith("/") || opts.path.startsWith("//") || opts.path.includes("\\"))) {
2202
+ throw new TopoloSdkError("service_path_origin_mismatch", "Public action paths must be origin-relative paths.");
2203
+ }
1872
2204
  const method = opts.method ?? "GET";
1873
2205
  if (this.requireConfirmForWrites && WRITE_METHODS.has(method) && !opts.confirm) {
1874
2206
  throw new TopoloConfirmationRequiredError(
@@ -1877,7 +2209,7 @@ var TopoloClient = class _TopoloClient {
1877
2209
  }
1878
2210
  const actionId = requestActionId(opts.headers);
1879
2211
  const taskId = opts.actorEnvelope?.delegation?.taskId ?? this.actorContext?.taskId;
1880
- let requestCredential = await this.loadCurrentCredential({
2212
+ let requestCredential = publicOrigin ? void 0 : await this.loadCurrentCredential({
1881
2213
  service: normalizeLookupKey(opts.service),
1882
2214
  method,
1883
2215
  path: opts.path,
@@ -1885,7 +2217,7 @@ var TopoloClient = class _TopoloClient {
1885
2217
  ...taskId ? { taskId } : {},
1886
2218
  ...opts.resource ? { resource: opts.resource } : {}
1887
2219
  });
1888
- const resolvedService = opts.baseUrl ? { serviceKey: normalizeLookupKey(opts.service), baseUrl: this.validatedServiceOrigin(opts.service, opts.baseUrl) } : await this.resolveRequestService(opts.service);
2220
+ const resolvedService = publicOrigin ? { serviceKey: normalizeLookupKey(opts.service), baseUrl: publicOrigin } : opts.baseUrl ? { serviceKey: normalizeLookupKey(opts.service), baseUrl: this.validatedServiceOrigin(opts.service, opts.baseUrl) } : await this.resolveRequestService(opts.service);
1889
2221
  const baseUrl = resolvedService.baseUrl;
1890
2222
  const url = new URL(opts.path, baseUrl.endsWith("/") ? baseUrl : `${baseUrl}/`);
1891
2223
  if (url.origin !== new URL(baseUrl).origin) {
@@ -1906,17 +2238,21 @@ var TopoloClient = class _TopoloClient {
1906
2238
  headers.set("Accept", "application/json");
1907
2239
  if (opts.body !== void 0) headers.set("Content-Type", "application/json");
1908
2240
  const platformAppId = resolveConfiguredAppId(resolvedService.serviceKey, this.appIds);
1909
- if (platformAppId) headers.set("X-App-ID", platformAppId);
1910
- const actorEnvelope = opts.actorEnvelope === void 0 ? void 0 : parseActorEnvelope(opts.actorEnvelope);
2241
+ if (platformAppId && !publicOrigin) headers.set("X-App-ID", platformAppId);
2242
+ const actorEnvelope = publicOrigin || opts.actorEnvelope === void 0 ? void 0 : parseActorEnvelope(opts.actorEnvelope);
1911
2243
  const requestId = actorEnvelope?.action.requestId ?? generateRequestId();
1912
- applyAuditHeaders(headers, this.agent, requestId);
1913
- if (opts.headers) {
2244
+ if (!publicOrigin) applyAuditHeaders(headers, this.agent, requestId);
2245
+ if (publicAction) {
2246
+ headers.set(TOPOLO_ACTION_ID_HEADER, publicAction.actionId);
2247
+ headers.set(TOPOLO_ACTION_NAME_HEADER, publicAction.name);
2248
+ }
2249
+ if (opts.headers && !publicOrigin) {
1914
2250
  for (const [k, v] of Object.entries(opts.headers)) headers.set(k, v);
1915
2251
  }
1916
2252
  if (actorEnvelope) {
1917
2253
  headers.set(TOPOLO_ACTOR_ENVELOPE_HEADER, encodeActorEnvelopeHeader(actorEnvelope));
1918
2254
  }
1919
- if (opts.resource) {
2255
+ if (opts.resource && !publicOrigin) {
1920
2256
  const resourceType = opts.resource.resourceType.trim();
1921
2257
  const resourceId = opts.resource.resourceId.trim();
1922
2258
  if (!resourceType || !resourceId) {
@@ -1941,8 +2277,8 @@ var TopoloClient = class _TopoloClient {
1941
2277
  const signal = opts.signal ? mergeSignals(opts.signal, controller.signal) : controller.signal;
1942
2278
  try {
1943
2279
  const requestHeaders = new Headers(headers);
1944
- applyAuthHeaders(requestHeaders, requestCredential);
1945
- if (requestCredential.kind === "dpop_access_token") {
2280
+ if (requestCredential) applyAuthHeaders(requestHeaders, requestCredential);
2281
+ if (requestCredential?.kind === "dpop_access_token") {
1946
2282
  requestHeaders.set("DPoP", await createDpopProof({
1947
2283
  accessToken: requestCredential.accessToken,
1948
2284
  method,
@@ -1950,12 +2286,13 @@ var TopoloClient = class _TopoloClient {
1950
2286
  privateJwk: requestCredential.privateJwk
1951
2287
  }));
1952
2288
  }
1953
- return await this.fetchImpl(urlStr, {
2289
+ const init = {
1954
2290
  method,
1955
2291
  headers: requestHeaders,
1956
2292
  body: opts.rawBody ?? (opts.body !== void 0 ? JSON.stringify(opts.body) : null),
1957
2293
  signal
1958
- });
2294
+ };
2295
+ return publicOrigin ? await fetchPublicMarketingAction((input2, requestInit) => this.fetchImpl(input2, requestInit), publicAction, this.environment, url, init) : await this.credentialedFetch(resolvedService.serviceKey, urlStr, init);
1959
2296
  } catch (error) {
1960
2297
  if (timedOut) {
1961
2298
  throw new TopoloSdkError(
@@ -1963,6 +2300,9 @@ var TopoloClient = class _TopoloClient {
1963
2300
  `Topolo request timed out after ${this.timeoutMs}ms. Verify current state before retrying a mutation.`
1964
2301
  );
1965
2302
  }
2303
+ if (publicOrigin && opts.signal?.aborted) {
2304
+ throw new TopoloSdkError("request_cancelled", "Public action request was cancelled.");
2305
+ }
1966
2306
  throw error;
1967
2307
  } finally {
1968
2308
  clearTimeout(timeoutId);
@@ -1985,7 +2325,7 @@ var TopoloClient = class _TopoloClient {
1985
2325
  try {
1986
2326
  const attemptedCredential = requestCredential;
1987
2327
  res = await fetchWithReadRetry();
1988
- if (res.status === 401 && attemptedCredential.kind === "access_token" && this.refreshCredential) {
2328
+ if (res.status === 401 && attemptedCredential?.kind === "access_token" && this.refreshCredential) {
1989
2329
  await res.body?.cancel().catch(() => void 0);
1990
2330
  const refreshed = await this.refreshRejectedAccessToken(attemptedCredential.accessToken);
1991
2331
  if (refreshed) {
@@ -2132,10 +2472,16 @@ var TopoloClient = class _TopoloClient {
2132
2472
  return this.refreshInFlight;
2133
2473
  }
2134
2474
  validatedServiceOrigin(service, value) {
2135
- const origin = requireHttpOrigin(value);
2136
- return this.environment ? assertTopoloServiceUrlEnvironment(service, origin, this.environment) : origin;
2475
+ return assertTopoloServiceUrlEnvironment(service, requireHttpOrigin(value), this.environment);
2476
+ }
2477
+ /** The only door to the network for anything this client sends; see fetchWithCredentialBoundary. */
2478
+ credentialedFetch(service, target, init) {
2479
+ return fetchWithCredentialBoundary((input2, requestInit) => this.fetchImpl(input2, requestInit), this.environment, service, target, init);
2137
2480
  }
2138
2481
  validatedActionEntry(entry) {
2482
+ if (isOnePublicMarketingAction(entry)) {
2483
+ return { ...entry, apiBaseUrl: publicMarketingOrigin(entry, this.environment) };
2484
+ }
2139
2485
  if (!entry.apiBaseUrl) return entry;
2140
2486
  return {
2141
2487
  ...entry,
@@ -2156,7 +2502,7 @@ var TopoloClient = class _TopoloClient {
2156
2502
  }
2157
2503
  return {
2158
2504
  serviceKey,
2159
- baseUrl: this.validatedServiceOrigin(serviceKey, DEFAULT_APP_URLS[serviceKey])
2505
+ baseUrl: this.validatedServiceOrigin(serviceKey, resolveServiceUrl(serviceKey, this.serviceUrls, this.environment))
2160
2506
  };
2161
2507
  }
2162
2508
  const live = await this.resolveLiveCallableService(serviceKey);
@@ -2199,7 +2545,7 @@ var TopoloClient = class _TopoloClient {
2199
2545
  if (!normalized) return null;
2200
2546
  const configuredAppId = resolveConfiguredAppId(normalized, this.appIds);
2201
2547
  if (configuredAppId) return configuredAppId;
2202
- const authBase = this.validatedServiceOrigin("developers", resolveServiceUrl("developers", this.serviceUrls));
2548
+ const authBase = this.validatedServiceOrigin("developers", resolveServiceUrl("developers", this.serviceUrls, this.environment));
2203
2549
  const cacheKey = `${authBase}|${normalized}`;
2204
2550
  const now = Date.now();
2205
2551
  const cached = _TopoloClient.appIdCache.get(cacheKey);
@@ -2212,7 +2558,7 @@ var TopoloClient = class _TopoloClient {
2212
2558
  ).toString();
2213
2559
  let res;
2214
2560
  try {
2215
- res = await this.fetchImpl(url, {
2561
+ res = await this.credentialedFetch("developers", url, {
2216
2562
  method: "GET",
2217
2563
  headers: { Accept: "application/json" }
2218
2564
  });
@@ -2377,7 +2723,7 @@ var TopoloClient = class _TopoloClient {
2377
2723
  "TopoloAuth did not return an action catalog for the current credential."
2378
2724
  );
2379
2725
  }
2380
- const entries = raw.map((item) => normalizeActionCatalogEntry(item)).filter((entry) => Boolean(entry)).map((entry) => this.validatedActionEntry(entry));
2726
+ const entries = raw.map((item) => normalizeActionCatalogEntry(item)).filter((entry) => Boolean(entry));
2381
2727
  return {
2382
2728
  actions: entries,
2383
2729
  page: normalizeCatalogPage(
@@ -2442,11 +2788,18 @@ var TopoloClient = class _TopoloClient {
2442
2788
  const raw = res.data?.action ?? res.action;
2443
2789
  const match = normalizeActionCatalogEntry(raw);
2444
2790
  if (!match) throw new TopoloSdkError("unknown_action", `Unknown or unavailable Topolo action "${action}".`);
2791
+ if (isOnePublicMarketingAction(match) && match.actionId !== actionId) {
2792
+ throw new TopoloSdkError("action_contract_mismatch", "Public action catalog response does not match the requested action ID.");
2793
+ }
2445
2794
  return this.validatedActionEntry(match);
2446
2795
  }
2447
2796
  async callAction(action, input2 = {}, options = {}) {
2448
- const entry = await this.getAction(action);
2449
- return this.executeResolvedAction(entry, input2, options);
2797
+ const entry = Object.freeze({ ...await this.getAction(action) });
2798
+ const publicAction = isOnePublicMarketingAction(entry);
2799
+ if (publicAction && entry.actionId !== action.trim()) {
2800
+ throw new TopoloSdkError("action_contract_mismatch", "Public action catalog response does not match the requested action ID.");
2801
+ }
2802
+ return this.executeResolvedAction(entry, input2, options, false, publicAction);
2450
2803
  }
2451
2804
  async issueExternalAgentCredential(input2) {
2452
2805
  const actionId = "app_topolo_auth.principal_credentials.issue";
@@ -2496,7 +2849,7 @@ var TopoloClient = class _TopoloClient {
2496
2849
  }
2497
2850
  async putUrlSessionContent(entry, uploadUrl, method, bytes, options) {
2498
2851
  const service = entry.appSlug || entry.appId;
2499
- const resolved = entry.apiBaseUrl ? { serviceKey: normalizeLookupKey(service), baseUrl: requireHttpOrigin(entry.apiBaseUrl) } : await this.resolveRequestService(service);
2852
+ const resolved = entry.apiBaseUrl ? { serviceKey: normalizeLookupKey(service), baseUrl: this.validatedServiceOrigin(service, entry.apiBaseUrl) } : await this.resolveRequestService(service);
2500
2853
  const target = new URL(uploadUrl, resolved.baseUrl.endsWith("/") ? resolved.baseUrl : `${resolved.baseUrl}/`);
2501
2854
  const body = bytes.buffer.slice(bytes.byteOffset, bytes.byteOffset + bytes.byteLength);
2502
2855
  if (target.origin === new URL(resolved.baseUrl).origin) {
@@ -2512,7 +2865,7 @@ var TopoloClient = class _TopoloClient {
2512
2865
  });
2513
2866
  return;
2514
2867
  }
2515
- const response = await this.fetchImpl(target, {
2868
+ const response = await this.credentialedFetch(service, target, {
2516
2869
  method,
2517
2870
  headers: { "Content-Type": options.contentType.trim().toLowerCase() },
2518
2871
  body
@@ -2590,7 +2943,15 @@ var TopoloClient = class _TopoloClient {
2590
2943
  }
2591
2944
  return this.executeResolvedAction(entry, input2, options);
2592
2945
  }
2593
- async executeResolvedAction(entry, input2, options, preserveSensitiveResult = false) {
2946
+ async executeResolvedAction(entry, input2, options, preserveSensitiveResult = false, allowPublicMarketing = false) {
2947
+ if (isOnePublicMarketingAction(entry)) {
2948
+ if (!allowPublicMarketing) {
2949
+ throw new TopoloSdkError("public_action_entrypoint_required", "Public marketing actions require callAction.");
2950
+ }
2951
+ if (options.actorEnvelope !== void 0 || options.resource !== void 0) {
2952
+ throw new TopoloSdkError("public_action_context_not_supported", "Public marketing actions do not accept actor or resource authority.");
2953
+ }
2954
+ }
2594
2955
  const agentAccess = entry.agentAccess ?? (entry.destructive ? "off" : entry.readOnly && !entry.requiresConfirmation ? "auto" : "confirm");
2595
2956
  if (agentAccess === "off") {
2596
2957
  throw new TopoloPermissionError(
@@ -2619,7 +2980,8 @@ var TopoloClient = class _TopoloClient {
2619
2980
  );
2620
2981
  }
2621
2982
  const mapped = mapActionInput(entry, input2);
2622
- const resolvedActorEnvelope = options.actorEnvelope ?? await this.buildVerifiedAgentActorEnvelope(entry.actionId, input2, options.resource);
2983
+ const publicAction = isOnePublicMarketingAction(entry);
2984
+ const resolvedActorEnvelope = publicAction ? void 0 : options.actorEnvelope ?? await this.buildVerifiedAgentActorEnvelope(entry.actionId, input2, options.resource);
2623
2985
  if (resolvedActorEnvelope) {
2624
2986
  const actorEnvelope = parseActorEnvelope(resolvedActorEnvelope);
2625
2987
  if (actorEnvelope.action.actionId !== entry.actionId) {
@@ -2636,8 +2998,9 @@ var TopoloClient = class _TopoloClient {
2636
2998
  const service = entry.appSlug || entry.appId;
2637
2999
  let result;
2638
3000
  try {
2639
- result = await this.request({
3001
+ result = await this.requestWithTarget({
2640
3002
  service,
3003
+ signal: options.signal,
2641
3004
  ...entry.apiBaseUrl ? { baseUrl: entry.apiBaseUrl } : {},
2642
3005
  method: entry.method,
2643
3006
  path: mapped.path,
@@ -2650,7 +3013,7 @@ var TopoloClient = class _TopoloClient {
2650
3013
  [TOPOLO_ACTION_NAME_HEADER]: entry.name
2651
3014
  },
2652
3015
  confirm: options.confirm === true || entry.readOnly && !entry.destructive && !entry.requiresConfirmation
2653
- });
3016
+ }, publicAction ? entry : void 0);
2654
3017
  } catch (error) {
2655
3018
  throw maskActionSecretError(error, this.actionSecrets);
2656
3019
  }
@@ -3448,9 +3811,11 @@ var DEVICE_GRANT = "urn:ietf:params:oauth:grant-type:device_code";
3448
3811
  var TopoloOAuth = class {
3449
3812
  baseUrl;
3450
3813
  fetchImpl;
3814
+ environment;
3451
3815
  constructor(options = {}) {
3452
- this.baseUrl = options.environment ? assertTopoloServiceUrlEnvironment("auth", resolveServiceUrl("auth", options.serviceUrls), options.environment) : resolveServiceUrl("auth", options.serviceUrls);
3816
+ this.baseUrl = resolveServiceUrl("auth", options.serviceUrls, options.environment);
3453
3817
  this.fetchImpl = options.fetch ?? fetch;
3818
+ this.environment = options.environment;
3454
3819
  }
3455
3820
  /**
3456
3821
  * RFC 8628 device authorization grant — starts the flow by asking the server
@@ -3515,7 +3880,7 @@ var TopoloOAuth = class {
3515
3880
  }
3516
3881
  async #postForm(path, body) {
3517
3882
  const url = new URL(path, this.baseUrl.endsWith("/") ? this.baseUrl : `${this.baseUrl}/`);
3518
- const res = await this.fetchImpl(url.toString(), {
3883
+ const res = await fetchWithCredentialBoundary(this.fetchImpl, this.environment, "auth", url, {
3519
3884
  method: "POST",
3520
3885
  headers: {
3521
3886
  "Content-Type": "application/x-www-form-urlencoded",
@@ -4044,7 +4409,7 @@ async function pollUntilApproved(params) {
4044
4409
  // src/commands/auth-lock.ts
4045
4410
  import { createHash as createHash3 } from "crypto";
4046
4411
 
4047
- // node_modules/.pnpm/@topolo+sdk@0.23.26/node_modules/@topolo/sdk/dist/node/credential-store.js
4412
+ // node_modules/@topolo/sdk/dist/node/credential-store.js
4048
4413
  import { mkdir as mkdir2, readFile as readFile2, chmod as chmod2, lstat, readdir as readdir2 } from "fs/promises";
4049
4414
  import { existsSync as existsSync2, mkdirSync, lstatSync, readdirSync, readFileSync as readFileSync2, openSync, writeFileSync, fsyncSync, closeSync, renameSync, unlinkSync, rmdirSync, linkSync } from "fs";
4050
4415
  import { createHash as createHash2, randomUUID as randomUUID2 } from "crypto";
@@ -4386,55 +4751,256 @@ var TopoloReauthRequiredError2 = class extends TopoloAuthError2 {
4386
4751
  this.reauthorization = Object.freeze({ ...reauthorization });
4387
4752
  }
4388
4753
  };
4389
- var TOPOLO_RUNTIME_ENVIRONMENTS = ["production", "staging", "development", "local"];
4390
- var TOPOLO_ENVIRONMENT_SERVICE_URLS = {
4391
- production: {
4754
+ var TOPOLO_FIRST_PARTY_ORIGINS2 = Object.freeze({
4755
+ production: Object.freeze([
4756
+ "https://admin.topolo.app",
4757
+ "https://agent.topolo.app",
4758
+ "https://api.ol0.me",
4759
+ "https://auth.topolo.app",
4760
+ "https://backup.topolo.app",
4761
+ "https://blog.topolo.app",
4762
+ "https://books.topolo.app",
4763
+ "https://brand.topolo.app",
4764
+ "https://bugfix.topolo.app",
4765
+ "https://bytes.topolo.app",
4766
+ "https://calendar.topolo.app",
4767
+ "https://campaigns.topolo.app",
4768
+ "https://capacity.topolo.app",
4769
+ "https://chat.topolo.app",
4770
+ "https://commerce.topolo.app",
4771
+ "https://compose.topolo.app",
4772
+ "https://consent.topolo.app",
4773
+ "https://contracts.topolo.app",
4774
+ "https://crm.topolo.app",
4775
+ "https://design.topolo.app",
4776
+ "https://developers.topolo.app",
4777
+ "https://director.topolo.app",
4778
+ "https://docs.topolo.app",
4779
+ "https://engage.topolo.app",
4780
+ "https://events.topolo.app",
4781
+ "https://feed-analytics-api.topolo.app",
4782
+ "https://feed-api.topolo.app",
4783
+ "https://flow.topolo.app",
4784
+ "https://forecast.topolo.app",
4785
+ "https://forms.topolo.app",
4786
+ "https://home.topolo.app",
4787
+ "https://insights.topolo.app",
4788
+ "https://inventory.topolo.app",
4789
+ "https://learn.topolo.app",
4790
+ "https://localize.topolo.app",
4791
+ "https://mail.topolo.app",
4792
+ "https://mcp.topolo.app",
4793
+ "https://mdm.topolo.app",
4794
+ "https://messages.topolo.app",
4795
+ "https://nexus.topolo.app",
4796
+ "https://notify.topolo.app",
4797
+ "https://nurture.topolo.app",
4798
+ "https://observability-watch.topolo.app",
4799
+ "https://p2p.topolo.app",
4800
+ "https://pay.topolo.app",
4801
+ "https://people.topolo.app",
4802
+ "https://quro.topolo.app",
4803
+ "https://recruit.topolo.app",
4804
+ "https://render.topolo.app",
4805
+ "https://roadmap.topolo.app",
4806
+ "https://sign.topolo.app",
4807
+ "https://socialize-api.topolo.app",
4808
+ "https://spaces.topolo.app",
4809
+ "https://speech.topolo.app",
4810
+ "https://status.topolo.app",
4811
+ "https://studio.topolo.app",
4812
+ "https://success.topolo.app",
4813
+ "https://support.topolo.app",
4814
+ "https://survey.topolo.app",
4815
+ "https://voice.topolo.app",
4816
+ "https://web.topolo.app",
4817
+ "https://www.topolo.app"
4818
+ ]),
4819
+ staging: Object.freeze([
4820
+ "https://admin.stg.topolo.us",
4821
+ "https://agent.stg.topolo.us",
4822
+ "https://api.one.stg.topolo.us",
4823
+ "https://auth.stg.topolo.us",
4824
+ "https://backup.stg.topolo.us",
4825
+ "https://blog.stg.topolo.us",
4826
+ "https://books.stg.topolo.us",
4827
+ "https://brand.stg.topolo.us",
4828
+ "https://bugfix.stg.topolo.us",
4829
+ "https://bytes.stg.topolo.us",
4830
+ "https://calendar.stg.topolo.us",
4831
+ "https://campaigns.stg.topolo.us",
4832
+ "https://capacity.stg.topolo.us",
4833
+ "https://chat.stg.topolo.us",
4834
+ "https://commerce.stg.topolo.us",
4835
+ "https://compose.stg.topolo.us",
4836
+ "https://consent.stg.topolo.us",
4837
+ "https://contracts.stg.topolo.us",
4838
+ "https://crm.stg.topolo.us",
4839
+ "https://design.stg.topolo.us",
4840
+ "https://developers.stg.topolo.us",
4841
+ "https://director.stg.topolo.us",
4842
+ "https://docs.stg.topolo.us",
4843
+ "https://engage.stg.topolo.us",
4844
+ "https://events.stg.topolo.us",
4845
+ "https://feed-analytics-api.stg.topolo.us",
4846
+ "https://feed-api.stg.topolo.us",
4847
+ "https://flow.stg.topolo.us",
4848
+ "https://forecast.stg.topolo.us",
4849
+ "https://forms.stg.topolo.us",
4850
+ "https://home.stg.topolo.us",
4851
+ "https://insights.stg.topolo.us",
4852
+ "https://inventory.stg.topolo.us",
4853
+ "https://learn.stg.topolo.us",
4854
+ "https://localize.stg.topolo.us",
4855
+ "https://mail.stg.topolo.us",
4856
+ "https://mcp.stg.topolo.us",
4857
+ "https://mdm.stg.topolo.us",
4858
+ "https://messages.stg.topolo.us",
4859
+ "https://nexus.stg.topolo.us",
4860
+ "https://notify.stg.topolo.us",
4861
+ "https://nurture.stg.topolo.us",
4862
+ "https://observability-watch.stg.topolo.us",
4863
+ "https://p2p.stg.topolo.us",
4864
+ "https://pay.stg.topolo.us",
4865
+ "https://people.stg.topolo.us",
4866
+ "https://pulse.stg.topolo.us",
4867
+ "https://recruit.stg.topolo.us",
4868
+ "https://render.stg.topolo.us",
4869
+ "https://roadmap.stg.topolo.us",
4870
+ "https://seed.stg.topolo.us",
4871
+ "https://sign.stg.topolo.us",
4872
+ "https://socialize-api.stg.topolo.us",
4873
+ "https://spaces.stg.topolo.us",
4874
+ "https://speech.stg.topolo.us",
4875
+ "https://status.stg.topolo.us",
4876
+ "https://studio-api.stg.topolo.us",
4877
+ "https://studio.stg.topolo.us",
4878
+ "https://success.stg.topolo.us",
4879
+ "https://support.stg.topolo.us",
4880
+ "https://survey.stg.topolo.us",
4881
+ "https://voice.stg.topolo.us",
4882
+ "https://web.stg.topolo.us"
4883
+ ]),
4884
+ development: Object.freeze([
4885
+ "https://admin.topolo.dev",
4886
+ "https://agent.topolo.dev",
4887
+ "https://api.one.topolo.dev",
4888
+ "https://auth.topolo.dev",
4889
+ "https://backup.topolo.dev",
4890
+ "https://blog.topolo.dev",
4891
+ "https://books.topolo.dev",
4892
+ "https://brand.topolo.dev",
4893
+ "https://bugfix.topolo.dev",
4894
+ "https://bytes.topolo.dev",
4895
+ "https://calendar.topolo.dev",
4896
+ "https://campaigns.topolo.dev",
4897
+ "https://capacity.topolo.dev",
4898
+ "https://chat.topolo.dev",
4899
+ "https://commerce.topolo.dev",
4900
+ "https://compose.topolo.dev",
4901
+ "https://consent.topolo.dev",
4902
+ "https://contracts.topolo.dev",
4903
+ "https://crm.topolo.dev",
4904
+ "https://design.topolo.dev",
4905
+ "https://developers.topolo.dev",
4906
+ "https://director.topolo.dev",
4907
+ "https://docs.topolo.dev",
4908
+ "https://engage.topolo.dev",
4909
+ "https://events.topolo.dev",
4910
+ "https://feed-analytics-api.topolo.dev",
4911
+ "https://feed-api.topolo.dev",
4912
+ "https://flow.topolo.dev",
4913
+ "https://forecast.topolo.dev",
4914
+ "https://forms.topolo.dev",
4915
+ "https://home.topolo.dev",
4916
+ "https://insights.topolo.dev",
4917
+ "https://inventory.topolo.dev",
4918
+ "https://learn.topolo.dev",
4919
+ "https://localize.topolo.dev",
4920
+ "https://mail.topolo.dev",
4921
+ "https://mcp.topolo.dev",
4922
+ "https://mdm.topolo.dev",
4923
+ "https://messages.topolo.dev",
4924
+ "https://nexus.topolo.dev",
4925
+ "https://notify.topolo.dev",
4926
+ "https://nurture.topolo.dev",
4927
+ "https://observability-watch.topolo.dev",
4928
+ "https://p2p.topolo.dev",
4929
+ "https://pay.topolo.dev",
4930
+ "https://people.topolo.dev",
4931
+ "https://pulse.topolo.dev",
4932
+ "https://recruit.topolo.dev",
4933
+ "https://render.topolo.dev",
4934
+ "https://roadmap.topolo.dev",
4935
+ "https://seed.topolo.dev",
4936
+ "https://sign.topolo.dev",
4937
+ "https://socialize-api.topolo.dev",
4938
+ "https://spaces.topolo.dev",
4939
+ "https://speech.topolo.dev",
4940
+ "https://status.topolo.dev",
4941
+ "https://studio-api.topolo.dev",
4942
+ "https://studio.topolo.dev",
4943
+ "https://success.topolo.dev",
4944
+ "https://support.topolo.dev",
4945
+ "https://survey.topolo.dev",
4946
+ "https://voice.topolo.dev",
4947
+ "https://web.topolo.dev"
4948
+ ])
4949
+ });
4950
+ var TOPOLO_REFUSED_HOST_SUFFIXES2 = Object.freeze(["sites.stg.topolo.us", "sites.topolo.app", "sites.topolo.dev", "topolo.site", "try.topolo.io", "workers.dev"]);
4951
+ var TOPOLO_RUNTIME_ENVIRONMENTS2 = ["production", "staging", "development", "local"];
4952
+ var TOPOLO_ENVIRONMENT_SERVICE_URLS2 = Object.freeze({
4953
+ production: Object.freeze({
4392
4954
  auth: "https://auth.topolo.app",
4393
4955
  developers: "https://developers.topolo.app"
4394
- },
4395
- staging: {
4956
+ }),
4957
+ staging: Object.freeze({
4396
4958
  auth: "https://auth.stg.topolo.us",
4397
4959
  developers: "https://developers.stg.topolo.us"
4398
- },
4399
- development: {
4960
+ }),
4961
+ development: Object.freeze({
4400
4962
  auth: "https://auth.topolo.dev",
4401
4963
  developers: "https://developers.topolo.dev"
4402
- },
4403
- local: {}
4404
- };
4405
- function hostnameHasSuffix2(hostname, suffix) {
4406
- return hostname === suffix || hostname.endsWith(`.${suffix}`);
4407
- }
4408
- function workersDevAccountMatches2(hostname, account) {
4409
- if (!hostname.endsWith(".workers.dev")) return false;
4410
- const labels = hostname.slice(0, -".workers.dev".length).split(".");
4411
- return labels.length >= 2 && labels.at(-1) === account;
4964
+ }),
4965
+ local: Object.freeze({})
4966
+ });
4967
+ var FIRST_PARTY_ORIGIN_SETS2 = Object.freeze({
4968
+ production: new Set(TOPOLO_FIRST_PARTY_ORIGINS2.production),
4969
+ staging: new Set(TOPOLO_FIRST_PARTY_ORIGINS2.staging),
4970
+ development: new Set(TOPOLO_FIRST_PARTY_ORIGINS2.development)
4971
+ });
4972
+ var LOOPBACK_HOSTNAMES2 = /* @__PURE__ */ new Set(["localhost", "127.0.0.1", "[::1]"]);
4973
+ function isRuntimeEnvironment2(value) {
4974
+ return typeof value === "string" && TOPOLO_RUNTIME_ENVIRONMENTS2.includes(value);
4412
4975
  }
4413
- function originMatchesEnvironment2(url, environment) {
4414
- const hostname = url.hostname.toLowerCase();
4976
+ function originIsFirstParty2(url, environment) {
4415
4977
  if (environment === "local") {
4416
- return hostname === "localhost" || hostname.endsWith(".localhost") || hostname === "127.0.0.1" || hostname === "[::1]";
4978
+ return (url.protocol === "http:" || url.protocol === "https:") && LOOPBACK_HOSTNAMES2.has(url.hostname);
4417
4979
  }
4418
4980
  if (url.protocol !== "https:") return false;
4419
- if (environment === "production") {
4420
- return hostnameHasSuffix2(hostname, "topolo.app") || hostnameHasSuffix2(hostname, "topolo.io") || hostname === "api.ol0.me" || workersDevAccountMatches2(hostname, "topolo");
4421
- }
4422
- if (environment === "staging") {
4423
- return hostnameHasSuffix2(hostname, "stg.topolo.us") || workersDevAccountMatches2(hostname, "topolo-staging");
4981
+ return FIRST_PARTY_ORIGIN_SETS2[environment].has(url.origin);
4982
+ }
4983
+ function requireTopoloRuntimeEnvironment2(environment) {
4984
+ if (!isRuntimeEnvironment2(environment)) {
4985
+ throw new TopoloSdkError2(
4986
+ "environment_required",
4987
+ 'Refusing to send a Topolo credential: the runtime environment is not resolved. Pass environment: "production" | "staging" | "development" | "local".'
4988
+ );
4424
4989
  }
4425
- return hostnameHasSuffix2(hostname, "topolo.dev") || workersDevAccountMatches2(hostname, "topolo-development");
4990
+ return environment;
4426
4991
  }
4427
4992
  function assertTopoloServiceUrlEnvironment2(service, value, environment) {
4993
+ const resolved = requireTopoloRuntimeEnvironment2(environment);
4428
4994
  let url;
4429
4995
  try {
4430
4996
  url = new URL(value);
4431
4997
  } catch {
4432
4998
  throw new TopoloSdkError2("invalid_service_url", `Invalid URL configured for Topolo service "${service}".`);
4433
4999
  }
4434
- if (url.protocol !== "https:" && url.protocol !== "http:" || url.username || url.password || !originMatchesEnvironment2(url, environment)) {
5000
+ if (url.protocol !== "https:" && url.protocol !== "http:" || url.username || url.password || !originIsFirstParty2(url, resolved)) {
4435
5001
  throw new TopoloSdkError2(
4436
5002
  "environment_mismatch",
4437
- `Refusing Topolo service "${service}": ${url.origin} does not belong to ${environment}.`
5003
+ `Refusing Topolo service "${service}": ${url.origin} is not a first-party ${resolved} service origin.`
4438
5004
  );
4439
5005
  }
4440
5006
  return url.origin;
@@ -4447,14 +5013,58 @@ function topoloServiceOrigins2(serviceUrls, environment) {
4447
5013
  ])
4448
5014
  );
4449
5015
  }
5016
+ var REDIRECT_STATUSES2 = /* @__PURE__ */ new Set([301, 302, 303, 307, 308]);
5017
+ async function fetchWithCredentialBoundary2(fetchImpl, environment, service, target, init) {
5018
+ const url = new URL(String(target));
5019
+ const origin = assertTopoloServiceUrlEnvironment2(service, url.toString(), environment);
5020
+ const response = await fetchImpl(url.toString(), { ...init, redirect: "manual" });
5021
+ let responseOrigin = origin;
5022
+ try {
5023
+ if (response.url) responseOrigin = new URL(response.url).origin;
5024
+ } catch {
5025
+ responseOrigin = "";
5026
+ }
5027
+ if (response.redirected === true || responseOrigin !== origin) {
5028
+ await response.body?.cancel().catch(() => void 0);
5029
+ throw new TopoloSdkError2(
5030
+ "credential_redirect_refused",
5031
+ `Refusing a redirected response from Topolo service "${service}"; credentials are never forwarded.`
5032
+ );
5033
+ }
5034
+ if (REDIRECT_STATUSES2.has(response.status)) {
5035
+ const location = response.headers.get("Location");
5036
+ let destination = null;
5037
+ if (location !== null) {
5038
+ try {
5039
+ destination = new URL(location, url).origin;
5040
+ } catch {
5041
+ destination = null;
5042
+ }
5043
+ }
5044
+ if (location !== null && destination !== origin) {
5045
+ await response.body?.cancel().catch(() => void 0);
5046
+ throw new TopoloSdkError2(
5047
+ "credential_redirect_refused",
5048
+ `Refusing a redirect from Topolo service "${service}" to another origin; credentials are never forwarded.`
5049
+ );
5050
+ }
5051
+ }
5052
+ return response;
5053
+ }
4450
5054
  var APP_API_URLS2 = {
4451
5055
  auth: "https://auth.topolo.app",
4452
5056
  developers: "https://developers.topolo.app"
4453
5057
  };
4454
5058
  var DEFAULT_APP_URLS2 = APP_API_URLS2;
4455
- function resolveServiceUrl2(service, overrides) {
5059
+ function resolveServiceUrl2(service, overrides, environment) {
4456
5060
  const override = resolveServiceUrlOverride2([service], overrides);
4457
5061
  if (override) return override;
5062
+ if (environment !== void 0) {
5063
+ const selected = requireTopoloRuntimeEnvironment2(environment);
5064
+ const origin = TOPOLO_ENVIRONMENT_SERVICE_URLS2[selected][service];
5065
+ if (!origin) throw new TopoloSdkError2("service_url_required", `Configure an explicit ${service} origin for ${selected}.`);
5066
+ return origin;
5067
+ }
4458
5068
  return DEFAULT_APP_URLS2[service];
4459
5069
  }
4460
5070
  function resolveServiceUrlOverride2(keys, overrides) {
@@ -4476,9 +5086,11 @@ var DEVICE_GRANT2 = "urn:ietf:params:oauth:grant-type:device_code";
4476
5086
  var TopoloOAuth2 = class {
4477
5087
  baseUrl;
4478
5088
  fetchImpl;
5089
+ environment;
4479
5090
  constructor(options = {}) {
4480
- this.baseUrl = options.environment ? assertTopoloServiceUrlEnvironment2("auth", resolveServiceUrl2("auth", options.serviceUrls), options.environment) : resolveServiceUrl2("auth", options.serviceUrls);
5091
+ this.baseUrl = resolveServiceUrl2("auth", options.serviceUrls, options.environment);
4481
5092
  this.fetchImpl = options.fetch ?? fetch;
5093
+ this.environment = options.environment;
4482
5094
  }
4483
5095
  /**
4484
5096
  * RFC 8628 device authorization grant — starts the flow by asking the server
@@ -4543,7 +5155,7 @@ var TopoloOAuth2 = class {
4543
5155
  }
4544
5156
  async #postForm(path, body) {
4545
5157
  const url = new URL(path, this.baseUrl.endsWith("/") ? this.baseUrl : `${this.baseUrl}/`);
4546
- const res = await this.fetchImpl(url.toString(), {
5158
+ const res = await fetchWithCredentialBoundary2(this.fetchImpl, this.environment, "auth", url, {
4547
5159
  method: "POST",
4548
5160
  headers: {
4549
5161
  "Content-Type": "application/x-www-form-urlencoded",
@@ -4823,11 +5435,11 @@ function createProtectedActionSecretStore(options) {
4823
5435
  }
4824
5436
  };
4825
5437
  }
4826
- var TOPOLO_ENVIRONMENTS = TOPOLO_RUNTIME_ENVIRONMENTS;
5438
+ var TOPOLO_ENVIRONMENTS = TOPOLO_RUNTIME_ENVIRONMENTS2;
4827
5439
  function contextKey(contextType, organizationId) {
4828
5440
  return contextType === "organization" && organizationId ? `org:${organizationId}` : "personal";
4829
5441
  }
4830
- var ENVIRONMENT_DEFAULT_SERVICE_URLS = TOPOLO_ENVIRONMENT_SERVICE_URLS;
5442
+ var ENVIRONMENT_DEFAULT_SERVICE_URLS = TOPOLO_ENVIRONMENT_SERVICE_URLS2;
4831
5443
  function configPath() {
4832
5444
  const override = process.env.TOPOLO_CONFIG_PATH;
4833
5445
  if (override) return override;
@@ -5155,7 +5767,7 @@ async function signOut(environment, options = {}) {
5155
5767
  if (options.revoke === false || !grants.length) return result;
5156
5768
  let oauth;
5157
5769
  try {
5158
- oauth = boundedOAuth(authServiceUrls(profile, environment, "sign-out"));
5770
+ oauth = boundedOAuth(authServiceUrls(profile, environment, "sign-out"), environment);
5159
5771
  } catch {
5160
5772
  result.revocationFailed = grants.length;
5161
5773
  return result;
@@ -5203,14 +5815,14 @@ function configLockTimeoutMs() {
5203
5815
  const value = Number(process.env.TOPOLO_CONFIG_LOCK_TIMEOUT_MS);
5204
5816
  return Number.isFinite(value) && value >= 1e3 && value <= 12e4 ? value : CONFIG_LOCK_DEFAULT_TIMEOUT_MS;
5205
5817
  }
5206
- function boundedOAuth(serviceUrls) {
5818
+ function boundedOAuth(serviceUrls, environment) {
5207
5819
  const fetchImpl = (input2, init) => globalThis.fetch(input2, {
5208
5820
  ...init,
5209
5821
  // Never re-POST a refresh token, device code or revoked token to another origin.
5210
5822
  redirect: "error",
5211
5823
  signal: init?.signal ?? AbortSignal.timeout(AUTH_EXCHANGE_TIMEOUT_MS)
5212
5824
  });
5213
- return new TopoloOAuth2({ serviceUrls, fetch: fetchImpl });
5825
+ return new TopoloOAuth2({ serviceUrls, fetch: fetchImpl, environment });
5214
5826
  }
5215
5827
  var CONFIG_LOCK_DEAD_OWNER_MIN_AGE_MS = 2e3;
5216
5828
  var ConfigOwnershipError = class extends TopoloSdkError2 {
@@ -5827,7 +6439,7 @@ async function renewTarget(environment, target, options) {
5827
6439
  return endGrant(retired.reason === "rotated" ? "rotated_grant_lost" : retired.reason);
5828
6440
  }
5829
6441
  const serviceUrls = authServiceUrls(profile, environment, target.kind === "active" ? "credential refresh" : "context refresh");
5830
- const oauth = boundedOAuth(serviceUrls);
6442
+ const oauth = boundedOAuth(serviceUrls, environment);
5831
6443
  try {
5832
6444
  await persist((current) => {
5833
6445
  const next = clone(current);
@@ -5922,7 +6534,7 @@ async function continueReauthorization(environment, key) {
5922
6534
  const clientId = (key === DEFAULT_SLOT ? void 0 : profile.contexts?.[key]?.oauthClientId) ?? profile.oauthClientId;
5923
6535
  if (!clientId) throw reauthRequired(environment, key, entry, "unavailable");
5924
6536
  const serviceUrls = authServiceUrls(profile, environment, "sign-in renewal");
5925
- const oauth = boundedOAuth(serviceUrls);
6537
+ const oauth = boundedOAuth(serviceUrls, environment);
5926
6538
  const now = nowSeconds();
5927
6539
  let state = clone(entry);
5928
6540
  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.25",
5
- "topoloPublishedVersion": "0.13.25",
4
+ "version": "0.13.27",
5
+ "topoloPublishedVersion": "0.13.27",
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",
37
- "@topolo/sdk": "0.23.26",
36
+ "@topolo/mcp": "0.14.39",
37
+ "@topolo/sdk": "0.24.1",
38
38
  "commander": "^12.1.0",
39
39
  "undici": "6.29.0"
40
40
  },