@topolo/sdk 0.11.8 → 0.11.10
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.cjs +14 -1
- package/dist/index.js +14 -1
- package/dist/node/credential-store.cjs +51 -45
- package/dist/node/credential-store.js +51 -45
- package/package.json +2 -2
package/dist/index.cjs
CHANGED
|
@@ -1818,7 +1818,7 @@ var TopoloClient = class _TopoloClient {
|
|
|
1818
1818
|
}
|
|
1819
1819
|
const mapped = mapActionInput(entry, input);
|
|
1820
1820
|
const service = entry.appSlug || entry.appId;
|
|
1821
|
-
|
|
1821
|
+
const result = await this.request({
|
|
1822
1822
|
service,
|
|
1823
1823
|
...entry.apiBaseUrl ? { baseUrl: entry.apiBaseUrl } : {},
|
|
1824
1824
|
method: entry.method,
|
|
@@ -1832,6 +1832,7 @@ var TopoloClient = class _TopoloClient {
|
|
|
1832
1832
|
},
|
|
1833
1833
|
confirm: options.confirm === true || entry.readOnly && !entry.destructive && !entry.requiresConfirmation
|
|
1834
1834
|
});
|
|
1835
|
+
return redactActionResult(result);
|
|
1835
1836
|
}
|
|
1836
1837
|
/**
|
|
1837
1838
|
* Introspect the current credential. Returns the caller's resolved identity,
|
|
@@ -1955,6 +1956,18 @@ function readOptionalString(value) {
|
|
|
1955
1956
|
function isRecord3(value) {
|
|
1956
1957
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
1957
1958
|
}
|
|
1959
|
+
function redactActionResult(value) {
|
|
1960
|
+
if (Array.isArray(value)) return value.map(redactActionResult);
|
|
1961
|
+
if (!isRecord3(value)) return value;
|
|
1962
|
+
return Object.fromEntries(Object.entries(value).map(([key, item]) => [
|
|
1963
|
+
key,
|
|
1964
|
+
isSensitiveActionResultKey(key) ? "[REDACTED]" : redactActionResult(item)
|
|
1965
|
+
]));
|
|
1966
|
+
}
|
|
1967
|
+
function isSensitiveActionResultKey(key) {
|
|
1968
|
+
const normalized = key.toLowerCase().replace(/[^a-z0-9]/g, "");
|
|
1969
|
+
return ["authorization", "cookie", "setcookie", "proxyauthorization", "capability"].includes(normalized) || /(token|secret|password|privatekey|apikey)$/.test(normalized);
|
|
1970
|
+
}
|
|
1958
1971
|
function resolveConfiguredServiceUrl(slug, serviceUrls) {
|
|
1959
1972
|
for (const serviceKey of serviceKeyCandidates2(slug)) {
|
|
1960
1973
|
const configured = serviceUrls?.[serviceKey];
|
package/dist/index.js
CHANGED
|
@@ -1735,7 +1735,7 @@ var TopoloClient = class _TopoloClient {
|
|
|
1735
1735
|
}
|
|
1736
1736
|
const mapped = mapActionInput(entry, input);
|
|
1737
1737
|
const service = entry.appSlug || entry.appId;
|
|
1738
|
-
|
|
1738
|
+
const result = await this.request({
|
|
1739
1739
|
service,
|
|
1740
1740
|
...entry.apiBaseUrl ? { baseUrl: entry.apiBaseUrl } : {},
|
|
1741
1741
|
method: entry.method,
|
|
@@ -1749,6 +1749,7 @@ var TopoloClient = class _TopoloClient {
|
|
|
1749
1749
|
},
|
|
1750
1750
|
confirm: options.confirm === true || entry.readOnly && !entry.destructive && !entry.requiresConfirmation
|
|
1751
1751
|
});
|
|
1752
|
+
return redactActionResult(result);
|
|
1752
1753
|
}
|
|
1753
1754
|
/**
|
|
1754
1755
|
* Introspect the current credential. Returns the caller's resolved identity,
|
|
@@ -1872,6 +1873,18 @@ function readOptionalString(value) {
|
|
|
1872
1873
|
function isRecord3(value) {
|
|
1873
1874
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
1874
1875
|
}
|
|
1876
|
+
function redactActionResult(value) {
|
|
1877
|
+
if (Array.isArray(value)) return value.map(redactActionResult);
|
|
1878
|
+
if (!isRecord3(value)) return value;
|
|
1879
|
+
return Object.fromEntries(Object.entries(value).map(([key, item]) => [
|
|
1880
|
+
key,
|
|
1881
|
+
isSensitiveActionResultKey(key) ? "[REDACTED]" : redactActionResult(item)
|
|
1882
|
+
]));
|
|
1883
|
+
}
|
|
1884
|
+
function isSensitiveActionResultKey(key) {
|
|
1885
|
+
const normalized = key.toLowerCase().replace(/[^a-z0-9]/g, "");
|
|
1886
|
+
return ["authorization", "cookie", "setcookie", "proxyauthorization", "capability"].includes(normalized) || /(token|secret|password|privatekey|apikey)$/.test(normalized);
|
|
1887
|
+
}
|
|
1875
1888
|
function resolveConfiguredServiceUrl(slug, serviceUrls) {
|
|
1876
1889
|
for (const serviceKey of serviceKeyCandidates2(slug)) {
|
|
1877
1890
|
const configured = serviceUrls?.[serviceKey];
|
|
@@ -612,52 +612,58 @@ async function refreshCredentialIfNeeded(environment = selectedEnvironment(), op
|
|
|
612
612
|
if (process.env[`${prefix}_API_KEY`] || process.env[`${prefix}_ACCESS_TOKEN`] || environment === "production" && process.env.TOPOLO_API_KEY || environment === "production" && process.env.TOPOLO_ACCESS_TOKEN) {
|
|
613
613
|
return resolveCredential(environment);
|
|
614
614
|
}
|
|
615
|
-
const
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
);
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
615
|
+
const observed = profileForEnvironment(await readConfig(), environment).credential;
|
|
616
|
+
return withConfigWriteLock(async () => {
|
|
617
|
+
const config = await readConfig();
|
|
618
|
+
const profile = profileForEnvironment(config, environment);
|
|
619
|
+
const cred = profile.credential;
|
|
620
|
+
if (!cred || cred.kind !== "access_token") return cred ?? null;
|
|
621
|
+
if (!cred.refreshToken || !profile.oauthClientId) return cred;
|
|
622
|
+
if (options.force && observed?.kind === "access_token" && observed.accessToken !== cred.accessToken) {
|
|
623
|
+
return cred;
|
|
624
|
+
}
|
|
625
|
+
const now = Math.floor(Date.now() / 1e3);
|
|
626
|
+
if (!options.force && cred.expiresAt && cred.expiresAt - REFRESH_SKEW_SECONDS > now) return cred;
|
|
627
|
+
const serviceUrls = resolveServiceUrls(profile.serviceUrls, environment);
|
|
628
|
+
if (environment === "local" && !serviceUrls?.auth) {
|
|
629
|
+
throw new TopoloSdkError(
|
|
630
|
+
"environment_service_url_required",
|
|
631
|
+
"Local Topolo credential refresh requires an explicit local Auth service origin."
|
|
632
|
+
);
|
|
633
|
+
}
|
|
634
|
+
try {
|
|
635
|
+
const oauth = new TopoloOAuth({
|
|
636
|
+
serviceUrls
|
|
637
|
+
});
|
|
638
|
+
const tokens = await oauth.refreshToken({
|
|
639
|
+
clientId: profile.oauthClientId,
|
|
640
|
+
refreshToken: cred.refreshToken
|
|
641
|
+
});
|
|
642
|
+
const refreshed = {
|
|
643
|
+
kind: "access_token",
|
|
644
|
+
accessToken: tokens.access_token,
|
|
645
|
+
...tokens.refresh_token ? { refreshToken: tokens.refresh_token } : { refreshToken: cred.refreshToken },
|
|
646
|
+
expiresAt: Math.floor(Date.now() / 1e3) + tokens.expires_in
|
|
647
|
+
};
|
|
648
|
+
const activeContext = profile.activeContext;
|
|
649
|
+
const activeEntry = activeContext ? profile.contexts?.[activeContext] : void 0;
|
|
650
|
+
const updated = activeContext && activeEntry ? writeProfileConfig(config, environment, {
|
|
651
|
+
credential: refreshed,
|
|
652
|
+
contexts: {
|
|
653
|
+
...profile.contexts ?? {},
|
|
654
|
+
[activeContext]: {
|
|
655
|
+
...activeEntry,
|
|
656
|
+
credential: refreshed,
|
|
657
|
+
oauthClientId: activeEntry.oauthClientId ?? profile.oauthClientId
|
|
658
|
+
}
|
|
653
659
|
}
|
|
654
|
-
}
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
}
|
|
660
|
+
}) : environment === "production" && !config.profiles?.production ? { ...config, credential: refreshed } : writeProfileConfig(config, environment, { credential: refreshed });
|
|
661
|
+
await writeConfig(updated);
|
|
662
|
+
return refreshed;
|
|
663
|
+
} catch {
|
|
664
|
+
return cred;
|
|
665
|
+
}
|
|
666
|
+
});
|
|
661
667
|
}
|
|
662
668
|
async function refreshContextCredentialIfNeeded(environment, key, options = {}) {
|
|
663
669
|
return withConfigWriteLock(async () => {
|
|
@@ -565,52 +565,58 @@ async function refreshCredentialIfNeeded(environment = selectedEnvironment(), op
|
|
|
565
565
|
if (process.env[`${prefix}_API_KEY`] || process.env[`${prefix}_ACCESS_TOKEN`] || environment === "production" && process.env.TOPOLO_API_KEY || environment === "production" && process.env.TOPOLO_ACCESS_TOKEN) {
|
|
566
566
|
return resolveCredential(environment);
|
|
567
567
|
}
|
|
568
|
-
const
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
);
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
568
|
+
const observed = profileForEnvironment(await readConfig(), environment).credential;
|
|
569
|
+
return withConfigWriteLock(async () => {
|
|
570
|
+
const config = await readConfig();
|
|
571
|
+
const profile = profileForEnvironment(config, environment);
|
|
572
|
+
const cred = profile.credential;
|
|
573
|
+
if (!cred || cred.kind !== "access_token") return cred ?? null;
|
|
574
|
+
if (!cred.refreshToken || !profile.oauthClientId) return cred;
|
|
575
|
+
if (options.force && observed?.kind === "access_token" && observed.accessToken !== cred.accessToken) {
|
|
576
|
+
return cred;
|
|
577
|
+
}
|
|
578
|
+
const now = Math.floor(Date.now() / 1e3);
|
|
579
|
+
if (!options.force && cred.expiresAt && cred.expiresAt - REFRESH_SKEW_SECONDS > now) return cred;
|
|
580
|
+
const serviceUrls = resolveServiceUrls(profile.serviceUrls, environment);
|
|
581
|
+
if (environment === "local" && !serviceUrls?.auth) {
|
|
582
|
+
throw new TopoloSdkError(
|
|
583
|
+
"environment_service_url_required",
|
|
584
|
+
"Local Topolo credential refresh requires an explicit local Auth service origin."
|
|
585
|
+
);
|
|
586
|
+
}
|
|
587
|
+
try {
|
|
588
|
+
const oauth = new TopoloOAuth({
|
|
589
|
+
serviceUrls
|
|
590
|
+
});
|
|
591
|
+
const tokens = await oauth.refreshToken({
|
|
592
|
+
clientId: profile.oauthClientId,
|
|
593
|
+
refreshToken: cred.refreshToken
|
|
594
|
+
});
|
|
595
|
+
const refreshed = {
|
|
596
|
+
kind: "access_token",
|
|
597
|
+
accessToken: tokens.access_token,
|
|
598
|
+
...tokens.refresh_token ? { refreshToken: tokens.refresh_token } : { refreshToken: cred.refreshToken },
|
|
599
|
+
expiresAt: Math.floor(Date.now() / 1e3) + tokens.expires_in
|
|
600
|
+
};
|
|
601
|
+
const activeContext = profile.activeContext;
|
|
602
|
+
const activeEntry = activeContext ? profile.contexts?.[activeContext] : void 0;
|
|
603
|
+
const updated = activeContext && activeEntry ? writeProfileConfig(config, environment, {
|
|
604
|
+
credential: refreshed,
|
|
605
|
+
contexts: {
|
|
606
|
+
...profile.contexts ?? {},
|
|
607
|
+
[activeContext]: {
|
|
608
|
+
...activeEntry,
|
|
609
|
+
credential: refreshed,
|
|
610
|
+
oauthClientId: activeEntry.oauthClientId ?? profile.oauthClientId
|
|
611
|
+
}
|
|
606
612
|
}
|
|
607
|
-
}
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
}
|
|
613
|
+
}) : environment === "production" && !config.profiles?.production ? { ...config, credential: refreshed } : writeProfileConfig(config, environment, { credential: refreshed });
|
|
614
|
+
await writeConfig(updated);
|
|
615
|
+
return refreshed;
|
|
616
|
+
} catch {
|
|
617
|
+
return cred;
|
|
618
|
+
}
|
|
619
|
+
});
|
|
614
620
|
}
|
|
615
621
|
async function refreshContextCredentialIfNeeded(environment, key, options = {}) {
|
|
616
622
|
return withConfigWriteLock(async () => {
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@topolo/sdk",
|
|
3
|
-
"version": "0.11.
|
|
4
|
-
"topoloPublishedVersion": "0.11.
|
|
3
|
+
"version": "0.11.10",
|
|
4
|
+
"topoloPublishedVersion": "0.11.10",
|
|
5
5
|
"description": "Typed client SDK for the Topolo platform. Used by TopoloCli, TopoloMCP, and third-party agents.",
|
|
6
6
|
"license": "UNLICENSED",
|
|
7
7
|
"author": "Topolo",
|