@topolo/sdk 0.18.0 → 0.20.0
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 +70 -4
- package/dist/index.d.cts +18 -6
- package/dist/index.d.ts +18 -6
- package/dist/index.js +68 -4
- package/dist/node/credential-store.cjs +195 -17
- package/dist/node/credential-store.d.cts +54 -6
- package/dist/node/credential-store.d.ts +54 -6
- package/dist/node/credential-store.js +187 -15
- package/package.json +2 -2
package/dist/index.cjs
CHANGED
|
@@ -46,6 +46,7 @@ __export(index_exports, {
|
|
|
46
46
|
actionContractCompleteness: () => actionContractCompleteness,
|
|
47
47
|
applicationEntryFromCatalog: () => applicationEntryFromCatalog,
|
|
48
48
|
assertTopoloServiceUrlEnvironment: () => assertTopoloServiceUrlEnvironment,
|
|
49
|
+
calculateDpopJkt: () => calculateDpopJkt,
|
|
49
50
|
canonicalJson: () => canonicalJson,
|
|
50
51
|
canonicalTopoloErrorCode: () => canonicalTopoloErrorCode,
|
|
51
52
|
canonicalTopoloRequestId: () => canonicalTopoloRequestId,
|
|
@@ -57,6 +58,7 @@ __export(index_exports, {
|
|
|
57
58
|
compactActionPreparation: () => compactActionPreparation,
|
|
58
59
|
compactActionResult: () => compactActionResult,
|
|
59
60
|
compactActionValidation: () => compactActionValidation,
|
|
61
|
+
createDpopProof: () => createDpopProof,
|
|
60
62
|
createTopolo: () => createTopolo,
|
|
61
63
|
createTopoloAgentExecutionContext: () => createTopoloAgentExecutionContext,
|
|
62
64
|
createTopoloWidgetError: () => createTopoloWidgetError,
|
|
@@ -101,7 +103,7 @@ function applyAuthHeaders(headers, credential) {
|
|
|
101
103
|
headers.set("X-Api-Key", credential.apiKey);
|
|
102
104
|
return;
|
|
103
105
|
}
|
|
104
|
-
headers.set("Authorization",
|
|
106
|
+
headers.set("Authorization", `${credential.kind === "dpop_access_token" ? "DPoP" : "Bearer"} ${credential.accessToken}`);
|
|
105
107
|
}
|
|
106
108
|
function applyAuditHeaders(headers, agent, requestId) {
|
|
107
109
|
headers.set("X-Topolo-Client", `${agent.clientName}/${agent.clientVersion}`);
|
|
@@ -115,6 +117,60 @@ function generateRequestId() {
|
|
|
115
117
|
return `req_${Date.now().toString(36)}_${Math.random().toString(36).slice(2, 10)}`;
|
|
116
118
|
}
|
|
117
119
|
|
|
120
|
+
// src/dpop.ts
|
|
121
|
+
var encoder = new TextEncoder();
|
|
122
|
+
function encodeBase64Url(value) {
|
|
123
|
+
const bytes = value instanceof Uint8Array ? value : new Uint8Array(value);
|
|
124
|
+
let binary = "";
|
|
125
|
+
for (const byte of bytes) binary += String.fromCharCode(byte);
|
|
126
|
+
return btoa(binary).replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/g, "");
|
|
127
|
+
}
|
|
128
|
+
function encodeJson(value) {
|
|
129
|
+
return encodeBase64Url(encoder.encode(JSON.stringify(value)));
|
|
130
|
+
}
|
|
131
|
+
async function sha256Base64Url(value) {
|
|
132
|
+
return encodeBase64Url(await crypto.subtle.digest("SHA-256", encoder.encode(value)));
|
|
133
|
+
}
|
|
134
|
+
function publicJwk(privateJwk) {
|
|
135
|
+
const { crv, kty, x, y } = privateJwk;
|
|
136
|
+
if (kty !== "EC" || crv !== "P-256" || !x || !y || !privateJwk.d) {
|
|
137
|
+
throw new TypeError("A private P-256 JSON Web Key is required for DPoP signing.");
|
|
138
|
+
}
|
|
139
|
+
return { crv, kty, x, y };
|
|
140
|
+
}
|
|
141
|
+
function canonicalTargetUrl(value) {
|
|
142
|
+
const url = new URL(value);
|
|
143
|
+
return `${url.origin}${url.pathname}`;
|
|
144
|
+
}
|
|
145
|
+
async function calculateDpopJkt(privateJwk) {
|
|
146
|
+
const jwk = publicJwk(privateJwk);
|
|
147
|
+
return sha256Base64Url(JSON.stringify({ crv: jwk.crv, kty: jwk.kty, x: jwk.x, y: jwk.y }));
|
|
148
|
+
}
|
|
149
|
+
async function createDpopProof(input) {
|
|
150
|
+
const jwk = publicJwk(input.privateJwk);
|
|
151
|
+
const key = await crypto.subtle.importKey(
|
|
152
|
+
"jwk",
|
|
153
|
+
input.privateJwk,
|
|
154
|
+
{ name: "ECDSA", namedCurve: "P-256" },
|
|
155
|
+
false,
|
|
156
|
+
["sign"]
|
|
157
|
+
);
|
|
158
|
+
const header = encodeJson({ alg: "ES256", typ: "dpop+jwt", jwk });
|
|
159
|
+
const claims = encodeJson({
|
|
160
|
+
jti: crypto.randomUUID(),
|
|
161
|
+
iat: Math.floor(Date.now() / 1e3),
|
|
162
|
+
htm: input.method.toUpperCase(),
|
|
163
|
+
htu: canonicalTargetUrl(input.targetUrl),
|
|
164
|
+
ath: await sha256Base64Url(input.accessToken)
|
|
165
|
+
});
|
|
166
|
+
const signature = await crypto.subtle.sign(
|
|
167
|
+
{ name: "ECDSA", hash: "SHA-256" },
|
|
168
|
+
key,
|
|
169
|
+
encoder.encode(`${header}.${claims}`)
|
|
170
|
+
);
|
|
171
|
+
return `${header}.${claims}.${encodeBase64Url(signature)}`;
|
|
172
|
+
}
|
|
173
|
+
|
|
118
174
|
// src/errors.ts
|
|
119
175
|
var TopoloSdkError = class extends Error {
|
|
120
176
|
code;
|
|
@@ -1471,7 +1527,6 @@ var TopoloClient = class _TopoloClient {
|
|
|
1471
1527
|
if (opts.body !== void 0) headers.set("Content-Type", "application/json");
|
|
1472
1528
|
const platformAppId = resolveConfiguredAppId(resolvedService.serviceKey, this.appIds);
|
|
1473
1529
|
if (platformAppId) headers.set("X-App-ID", platformAppId);
|
|
1474
|
-
applyAuthHeaders(headers, this.credential);
|
|
1475
1530
|
const actorEnvelope = opts.actorEnvelope === void 0 ? void 0 : parseActorEnvelope(opts.actorEnvelope);
|
|
1476
1531
|
const requestId = actorEnvelope?.action.requestId ?? generateRequestId();
|
|
1477
1532
|
applyAuditHeaders(headers, this.agent, requestId);
|
|
@@ -1505,9 +1560,19 @@ var TopoloClient = class _TopoloClient {
|
|
|
1505
1560
|
}, this.timeoutMs);
|
|
1506
1561
|
const signal = opts.signal ? mergeSignals(opts.signal, controller.signal) : controller.signal;
|
|
1507
1562
|
try {
|
|
1563
|
+
const requestHeaders = new Headers(headers);
|
|
1564
|
+
applyAuthHeaders(requestHeaders, this.credential);
|
|
1565
|
+
if (this.credential.kind === "dpop_access_token") {
|
|
1566
|
+
requestHeaders.set("DPoP", await createDpopProof({
|
|
1567
|
+
accessToken: this.credential.accessToken,
|
|
1568
|
+
method,
|
|
1569
|
+
targetUrl: urlStr,
|
|
1570
|
+
privateJwk: this.credential.privateJwk
|
|
1571
|
+
}));
|
|
1572
|
+
}
|
|
1508
1573
|
return await this.fetchImpl(urlStr, {
|
|
1509
1574
|
method,
|
|
1510
|
-
headers:
|
|
1575
|
+
headers: requestHeaders,
|
|
1511
1576
|
body: opts.rawBody ?? (opts.body !== void 0 ? JSON.stringify(opts.body) : null),
|
|
1512
1577
|
signal
|
|
1513
1578
|
});
|
|
@@ -1544,7 +1609,6 @@ var TopoloClient = class _TopoloClient {
|
|
|
1544
1609
|
await res.body?.cancel().catch(() => void 0);
|
|
1545
1610
|
const refreshed = await this.refreshRejectedAccessToken(attemptedCredential.accessToken);
|
|
1546
1611
|
if (refreshed) {
|
|
1547
|
-
applyAuthHeaders(headers, refreshed);
|
|
1548
1612
|
res = await fetchWithReadRetry();
|
|
1549
1613
|
}
|
|
1550
1614
|
}
|
|
@@ -4899,6 +4963,7 @@ function createTopolo(options) {
|
|
|
4899
4963
|
actionContractCompleteness,
|
|
4900
4964
|
applicationEntryFromCatalog,
|
|
4901
4965
|
assertTopoloServiceUrlEnvironment,
|
|
4966
|
+
calculateDpopJkt,
|
|
4902
4967
|
canonicalJson,
|
|
4903
4968
|
canonicalTopoloErrorCode,
|
|
4904
4969
|
canonicalTopoloRequestId,
|
|
@@ -4910,6 +4975,7 @@ function createTopolo(options) {
|
|
|
4910
4975
|
compactActionPreparation,
|
|
4911
4976
|
compactActionResult,
|
|
4912
4977
|
compactActionValidation,
|
|
4978
|
+
createDpopProof,
|
|
4913
4979
|
createTopolo,
|
|
4914
4980
|
createTopoloAgentExecutionContext,
|
|
4915
4981
|
createTopoloWidgetError,
|
package/dist/index.d.cts
CHANGED
|
@@ -1,14 +1,13 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Auth credential types used by the SDK.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
4
|
+
* Supported modes:
|
|
5
5
|
* - `api_key`: a single platform API key (service-scoped at issuance).
|
|
6
|
-
*
|
|
6
|
+
* Used for service integrations that are not installation-bound.
|
|
7
7
|
* - `access_token`: a short-lived JWT from the interactive login flow.
|
|
8
8
|
* Used by TopoloCli after `topolo auth login`.
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
* PKCE flow in TopoloAuth. Those will plug in as a third variant.
|
|
9
|
+
* - `dpop_access_token`: a short-lived delegated token bound to an external
|
|
10
|
+
* agent installation key. Every request proves possession of that key.
|
|
12
11
|
*/
|
|
13
12
|
type TopoloCredential = {
|
|
14
13
|
kind: 'api_key';
|
|
@@ -18,6 +17,11 @@ type TopoloCredential = {
|
|
|
18
17
|
accessToken: string;
|
|
19
18
|
refreshToken?: string;
|
|
20
19
|
expiresAt?: number;
|
|
20
|
+
} | {
|
|
21
|
+
kind: 'dpop_access_token';
|
|
22
|
+
accessToken: string;
|
|
23
|
+
privateJwk: JsonWebKey;
|
|
24
|
+
expiresAt?: number;
|
|
21
25
|
};
|
|
22
26
|
interface AgentIdentity {
|
|
23
27
|
/** Display name of the agent or tool making requests. Included in audit headers. */
|
|
@@ -761,6 +765,14 @@ declare function actionContractCompleteness(
|
|
|
761
765
|
action: ActionContractSource,
|
|
762
766
|
): Record<string, boolean>;
|
|
763
767
|
|
|
768
|
+
declare function calculateDpopJkt(privateJwk: JsonWebKey): Promise<string>;
|
|
769
|
+
declare function createDpopProof(input: {
|
|
770
|
+
accessToken: string;
|
|
771
|
+
method: string;
|
|
772
|
+
targetUrl: string;
|
|
773
|
+
privateJwk: JsonWebKey;
|
|
774
|
+
}): Promise<string>;
|
|
775
|
+
|
|
764
776
|
/**
|
|
765
777
|
* Bootstrap seed URLs — the ONLY static service endpoints in the SDK.
|
|
766
778
|
*
|
|
@@ -1694,4 +1706,4 @@ declare function createTopolo(options: TopoloClientOptions): {
|
|
|
1694
1706
|
};
|
|
1695
1707
|
type Topolo = ReturnType<typeof createTopolo>;
|
|
1696
1708
|
|
|
1697
|
-
export { ACTION_CATALOG_DIGEST_ALGORITHM, ACTOR_AUDIT_PROJECTION_VERSION, ACTOR_ENVELOPE_VERSION, type AccountableSubject, type AccountableSubjectType, type ActionContractManifest, type ActionContractSource, type ActorAssurance, type ActorAuditEventRole, type ActorAuditProjection, type ActorChannel, type ActorDelegationHop, type ActorEnvelope, ActorEnvelopeValidationError, type ActorIdentity, type ActorPrincipalType, type AgentIdentity, type AppApiId, type ApplicationCatalogEntry, type ApplicationDeployTarget, type ApplicationDirectory, type ApplicationDirectoryApplication, type ApplicationDirectoryClient, type ApplicationDirectorySource, type ApplicationId, type CredentialIntrospection, type CrmContactSummary, CrmModule, DEFAULT_APP_URLS, type DeviceAuthorizationResponse, IdentityModule, type ListContactsOptions, type ListContactsResult, type OAuthHelperOptions, type P2PActionDetail, type P2PActionRequestInput, type P2PActionRequestResult, type P2PActionRow, type P2PActionRun, type P2PCapability, type P2PConnection, type P2PHold, type P2PLedgerEntry, P2PModule, type P2PPolicy, type P2PPricingModel, type P2PSettlementBatch, type P2PSettlementGroup, type PublishCapabilityInput, type RequestOptions, type ServiceCatalogUrlEntry, TOPOLO_ACTOR_ENVELOPE_HEADER, TOPOLO_ENVIRONMENT_SERVICE_URLS, TOPOLO_RUNTIME_ENVIRONMENTS, TOPOLO_WIDGET_CONTRACT_VERSION, TOPOLO_WIDGET_ENDPOINT, TOPOLO_WIDGET_OUTPUT_SCHEMA, TOPOLO_WIDGET_REFRESH_INTERVAL_MS, type TokenResponse, type Topolo, type TopoloActionAgentContract, type TopoloActionCatalogEntry, type TopoloActionCatalogSummary, type TopoloActionDigestInput, type TopoloActionPlan, type TopoloActionPreparation, type TopoloActionUploadOptions, type TopoloActionValidationIssue, type TopoloActionValidationResult, type TopoloActionsWidget, type TopoloActivityWidget, type TopoloAgentExecutionContext, type TopoloApiKeyResourceMetadata, TopoloAuthError, type TopoloBinaryResponse, type TopoloBindableResource, type TopoloBindableResourceCatalog, type TopoloChartWidget, TopoloClient, type TopoloClientOptions, TopoloConfirmationRequiredError, type TopoloCredential, type TopoloDebugEvent, TopoloHttpError, type TopoloInlineBase64UploadContract, type TopoloJsonSchema, type TopoloNotificationsWidget, TopoloOAuth, TopoloPermissionError, type TopoloRuntimeEnvironment, TopoloSdkError, type TopoloServiceCatalogEntry, type TopoloStatsWidget, type TopoloWidget, type TopoloWidgetAccessibility, type TopoloWidgetActionBinding, type TopoloWidgetActionRecovery, type TopoloWidgetActivityItem, type TopoloWidgetApiError, type TopoloWidgetApiErrorResponse, type TopoloWidgetApiResponse, type TopoloWidgetApiSuccessResponse, type TopoloWidgetBase, type TopoloWidgetConfig, type TopoloWidgetConfiguration, type TopoloWidgetConfigurationField, type TopoloWidgetConfigurationOption, type TopoloWidgetContext, type TopoloWidgetContribution, type TopoloWidgetDatasetDefinition, type TopoloWidgetDimension, type TopoloWidgetDimensionDefinition, type TopoloWidgetDraft, type TopoloWidgetDrilldown, type TopoloWidgetErrorResponseOptions, type TopoloWidgetEventDefinition, type TopoloWidgetLifecycleStage, type TopoloWidgetLocalization, type TopoloWidgetMetric, type TopoloWidgetMetricAggregation, type TopoloWidgetMetricComparison, type TopoloWidgetMetricDefinition, type TopoloWidgetMetricSemantic, type TopoloWidgetNotificationItem, type TopoloWidgetPeriod, type TopoloWidgetPresentation, type TopoloWidgetRefreshPolicy, type TopoloWidgetResourceBinding, type TopoloWidgetResponseOptions, type TopoloWidgetSeries, type TopoloWidgetSeriesDefinition, type TopoloWidgetSeriesPoint, type TopoloWidgetSize, type TopoloWidgetState, type TopoloWidgetStatus, type TopoloWidgetType, type TopoloWidgetValidationResult, type TopoloWidgetVisualizationFamily, type TopoloWidgetWorkspaceSelector, type TopoloWorkspace, type TopoloWorkspaceListResult, type TopoloWorkspaceMutationResult, type TopoloWorkspacePolicy, WorkspacesModule, actionContractCompleteness, applicationEntryFromCatalog, assertTopoloServiceUrlEnvironment, canonicalJson, canonicalTopoloErrorCode, canonicalTopoloRequestId, canonicalTopoloRequired, canonicalTopoloRetryAfter, canonicalizeActorEnvelope, compactActionCatalogEntry, compactActionPlan, compactActionPreparation, compactActionResult, compactActionValidation, createTopolo, createTopoloAgentExecutionContext, createTopoloWidgetError, createTopoloWidgetResponse, decodeActorEnvelopeHeader, defineTopoloActionsWidget, defineTopoloActivityWidget, defineTopoloChartWidget, defineTopoloNotificationsWidget, defineTopoloStatsWidget, digestTopoloActionCatalog, encodeActorEnvelopeHeader, encodeTopoloActionBase64, enrichActionContract, extractTopoloServiceErrorCode, extractTopoloServiceErrorDetails, formatDirectoryApplicationIds, friendlyAppId, isTopoloWidgetOutputSchema, listApplicationDirectory, parseActorEnvelope, parseTopoloActionUploadContract, preferExactActionMatches, prepareTopoloActionBase64UploadInput, prepareTopoloActionUploadInput, projectActorAuditEvent, publicTopoloErrorMessage, resolveApplicationDirectoryEntry, resolveCatalogServiceUrl, resolveServiceUrl, sha256CanonicalValue, topoloErrorHint, topoloServiceOrigins, validateTopoloActionInput, validateTopoloWidgetResponse };
|
|
1709
|
+
export { ACTION_CATALOG_DIGEST_ALGORITHM, ACTOR_AUDIT_PROJECTION_VERSION, ACTOR_ENVELOPE_VERSION, type AccountableSubject, type AccountableSubjectType, type ActionContractManifest, type ActionContractSource, type ActorAssurance, type ActorAuditEventRole, type ActorAuditProjection, type ActorChannel, type ActorDelegationHop, type ActorEnvelope, ActorEnvelopeValidationError, type ActorIdentity, type ActorPrincipalType, type AgentIdentity, type AppApiId, type ApplicationCatalogEntry, type ApplicationDeployTarget, type ApplicationDirectory, type ApplicationDirectoryApplication, type ApplicationDirectoryClient, type ApplicationDirectorySource, type ApplicationId, type CredentialIntrospection, type CrmContactSummary, CrmModule, DEFAULT_APP_URLS, type DeviceAuthorizationResponse, IdentityModule, type ListContactsOptions, type ListContactsResult, type OAuthHelperOptions, type P2PActionDetail, type P2PActionRequestInput, type P2PActionRequestResult, type P2PActionRow, type P2PActionRun, type P2PCapability, type P2PConnection, type P2PHold, type P2PLedgerEntry, P2PModule, type P2PPolicy, type P2PPricingModel, type P2PSettlementBatch, type P2PSettlementGroup, type PublishCapabilityInput, type RequestOptions, type ServiceCatalogUrlEntry, TOPOLO_ACTOR_ENVELOPE_HEADER, TOPOLO_ENVIRONMENT_SERVICE_URLS, TOPOLO_RUNTIME_ENVIRONMENTS, TOPOLO_WIDGET_CONTRACT_VERSION, TOPOLO_WIDGET_ENDPOINT, TOPOLO_WIDGET_OUTPUT_SCHEMA, TOPOLO_WIDGET_REFRESH_INTERVAL_MS, type TokenResponse, type Topolo, type TopoloActionAgentContract, type TopoloActionCatalogEntry, type TopoloActionCatalogSummary, type TopoloActionDigestInput, type TopoloActionPlan, type TopoloActionPreparation, type TopoloActionUploadOptions, type TopoloActionValidationIssue, type TopoloActionValidationResult, type TopoloActionsWidget, type TopoloActivityWidget, type TopoloAgentExecutionContext, type TopoloApiKeyResourceMetadata, TopoloAuthError, type TopoloBinaryResponse, type TopoloBindableResource, type TopoloBindableResourceCatalog, type TopoloChartWidget, TopoloClient, type TopoloClientOptions, TopoloConfirmationRequiredError, type TopoloCredential, type TopoloDebugEvent, TopoloHttpError, type TopoloInlineBase64UploadContract, type TopoloJsonSchema, type TopoloNotificationsWidget, TopoloOAuth, TopoloPermissionError, type TopoloRuntimeEnvironment, TopoloSdkError, type TopoloServiceCatalogEntry, type TopoloStatsWidget, type TopoloWidget, type TopoloWidgetAccessibility, type TopoloWidgetActionBinding, type TopoloWidgetActionRecovery, type TopoloWidgetActivityItem, type TopoloWidgetApiError, type TopoloWidgetApiErrorResponse, type TopoloWidgetApiResponse, type TopoloWidgetApiSuccessResponse, type TopoloWidgetBase, type TopoloWidgetConfig, type TopoloWidgetConfiguration, type TopoloWidgetConfigurationField, type TopoloWidgetConfigurationOption, type TopoloWidgetContext, type TopoloWidgetContribution, type TopoloWidgetDatasetDefinition, type TopoloWidgetDimension, type TopoloWidgetDimensionDefinition, type TopoloWidgetDraft, type TopoloWidgetDrilldown, type TopoloWidgetErrorResponseOptions, type TopoloWidgetEventDefinition, type TopoloWidgetLifecycleStage, type TopoloWidgetLocalization, type TopoloWidgetMetric, type TopoloWidgetMetricAggregation, type TopoloWidgetMetricComparison, type TopoloWidgetMetricDefinition, type TopoloWidgetMetricSemantic, type TopoloWidgetNotificationItem, type TopoloWidgetPeriod, type TopoloWidgetPresentation, type TopoloWidgetRefreshPolicy, type TopoloWidgetResourceBinding, type TopoloWidgetResponseOptions, type TopoloWidgetSeries, type TopoloWidgetSeriesDefinition, type TopoloWidgetSeriesPoint, type TopoloWidgetSize, type TopoloWidgetState, type TopoloWidgetStatus, type TopoloWidgetType, type TopoloWidgetValidationResult, type TopoloWidgetVisualizationFamily, type TopoloWidgetWorkspaceSelector, type TopoloWorkspace, type TopoloWorkspaceListResult, type TopoloWorkspaceMutationResult, type TopoloWorkspacePolicy, WorkspacesModule, actionContractCompleteness, applicationEntryFromCatalog, assertTopoloServiceUrlEnvironment, calculateDpopJkt, canonicalJson, canonicalTopoloErrorCode, canonicalTopoloRequestId, canonicalTopoloRequired, canonicalTopoloRetryAfter, canonicalizeActorEnvelope, compactActionCatalogEntry, compactActionPlan, compactActionPreparation, compactActionResult, compactActionValidation, createDpopProof, createTopolo, createTopoloAgentExecutionContext, createTopoloWidgetError, createTopoloWidgetResponse, decodeActorEnvelopeHeader, defineTopoloActionsWidget, defineTopoloActivityWidget, defineTopoloChartWidget, defineTopoloNotificationsWidget, defineTopoloStatsWidget, digestTopoloActionCatalog, encodeActorEnvelopeHeader, encodeTopoloActionBase64, enrichActionContract, extractTopoloServiceErrorCode, extractTopoloServiceErrorDetails, formatDirectoryApplicationIds, friendlyAppId, isTopoloWidgetOutputSchema, listApplicationDirectory, parseActorEnvelope, parseTopoloActionUploadContract, preferExactActionMatches, prepareTopoloActionBase64UploadInput, prepareTopoloActionUploadInput, projectActorAuditEvent, publicTopoloErrorMessage, resolveApplicationDirectoryEntry, resolveCatalogServiceUrl, resolveServiceUrl, sha256CanonicalValue, topoloErrorHint, topoloServiceOrigins, validateTopoloActionInput, validateTopoloWidgetResponse };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,14 +1,13 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Auth credential types used by the SDK.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
4
|
+
* Supported modes:
|
|
5
5
|
* - `api_key`: a single platform API key (service-scoped at issuance).
|
|
6
|
-
*
|
|
6
|
+
* Used for service integrations that are not installation-bound.
|
|
7
7
|
* - `access_token`: a short-lived JWT from the interactive login flow.
|
|
8
8
|
* Used by TopoloCli after `topolo auth login`.
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
* PKCE flow in TopoloAuth. Those will plug in as a third variant.
|
|
9
|
+
* - `dpop_access_token`: a short-lived delegated token bound to an external
|
|
10
|
+
* agent installation key. Every request proves possession of that key.
|
|
12
11
|
*/
|
|
13
12
|
type TopoloCredential = {
|
|
14
13
|
kind: 'api_key';
|
|
@@ -18,6 +17,11 @@ type TopoloCredential = {
|
|
|
18
17
|
accessToken: string;
|
|
19
18
|
refreshToken?: string;
|
|
20
19
|
expiresAt?: number;
|
|
20
|
+
} | {
|
|
21
|
+
kind: 'dpop_access_token';
|
|
22
|
+
accessToken: string;
|
|
23
|
+
privateJwk: JsonWebKey;
|
|
24
|
+
expiresAt?: number;
|
|
21
25
|
};
|
|
22
26
|
interface AgentIdentity {
|
|
23
27
|
/** Display name of the agent or tool making requests. Included in audit headers. */
|
|
@@ -761,6 +765,14 @@ declare function actionContractCompleteness(
|
|
|
761
765
|
action: ActionContractSource,
|
|
762
766
|
): Record<string, boolean>;
|
|
763
767
|
|
|
768
|
+
declare function calculateDpopJkt(privateJwk: JsonWebKey): Promise<string>;
|
|
769
|
+
declare function createDpopProof(input: {
|
|
770
|
+
accessToken: string;
|
|
771
|
+
method: string;
|
|
772
|
+
targetUrl: string;
|
|
773
|
+
privateJwk: JsonWebKey;
|
|
774
|
+
}): Promise<string>;
|
|
775
|
+
|
|
764
776
|
/**
|
|
765
777
|
* Bootstrap seed URLs — the ONLY static service endpoints in the SDK.
|
|
766
778
|
*
|
|
@@ -1694,4 +1706,4 @@ declare function createTopolo(options: TopoloClientOptions): {
|
|
|
1694
1706
|
};
|
|
1695
1707
|
type Topolo = ReturnType<typeof createTopolo>;
|
|
1696
1708
|
|
|
1697
|
-
export { ACTION_CATALOG_DIGEST_ALGORITHM, ACTOR_AUDIT_PROJECTION_VERSION, ACTOR_ENVELOPE_VERSION, type AccountableSubject, type AccountableSubjectType, type ActionContractManifest, type ActionContractSource, type ActorAssurance, type ActorAuditEventRole, type ActorAuditProjection, type ActorChannel, type ActorDelegationHop, type ActorEnvelope, ActorEnvelopeValidationError, type ActorIdentity, type ActorPrincipalType, type AgentIdentity, type AppApiId, type ApplicationCatalogEntry, type ApplicationDeployTarget, type ApplicationDirectory, type ApplicationDirectoryApplication, type ApplicationDirectoryClient, type ApplicationDirectorySource, type ApplicationId, type CredentialIntrospection, type CrmContactSummary, CrmModule, DEFAULT_APP_URLS, type DeviceAuthorizationResponse, IdentityModule, type ListContactsOptions, type ListContactsResult, type OAuthHelperOptions, type P2PActionDetail, type P2PActionRequestInput, type P2PActionRequestResult, type P2PActionRow, type P2PActionRun, type P2PCapability, type P2PConnection, type P2PHold, type P2PLedgerEntry, P2PModule, type P2PPolicy, type P2PPricingModel, type P2PSettlementBatch, type P2PSettlementGroup, type PublishCapabilityInput, type RequestOptions, type ServiceCatalogUrlEntry, TOPOLO_ACTOR_ENVELOPE_HEADER, TOPOLO_ENVIRONMENT_SERVICE_URLS, TOPOLO_RUNTIME_ENVIRONMENTS, TOPOLO_WIDGET_CONTRACT_VERSION, TOPOLO_WIDGET_ENDPOINT, TOPOLO_WIDGET_OUTPUT_SCHEMA, TOPOLO_WIDGET_REFRESH_INTERVAL_MS, type TokenResponse, type Topolo, type TopoloActionAgentContract, type TopoloActionCatalogEntry, type TopoloActionCatalogSummary, type TopoloActionDigestInput, type TopoloActionPlan, type TopoloActionPreparation, type TopoloActionUploadOptions, type TopoloActionValidationIssue, type TopoloActionValidationResult, type TopoloActionsWidget, type TopoloActivityWidget, type TopoloAgentExecutionContext, type TopoloApiKeyResourceMetadata, TopoloAuthError, type TopoloBinaryResponse, type TopoloBindableResource, type TopoloBindableResourceCatalog, type TopoloChartWidget, TopoloClient, type TopoloClientOptions, TopoloConfirmationRequiredError, type TopoloCredential, type TopoloDebugEvent, TopoloHttpError, type TopoloInlineBase64UploadContract, type TopoloJsonSchema, type TopoloNotificationsWidget, TopoloOAuth, TopoloPermissionError, type TopoloRuntimeEnvironment, TopoloSdkError, type TopoloServiceCatalogEntry, type TopoloStatsWidget, type TopoloWidget, type TopoloWidgetAccessibility, type TopoloWidgetActionBinding, type TopoloWidgetActionRecovery, type TopoloWidgetActivityItem, type TopoloWidgetApiError, type TopoloWidgetApiErrorResponse, type TopoloWidgetApiResponse, type TopoloWidgetApiSuccessResponse, type TopoloWidgetBase, type TopoloWidgetConfig, type TopoloWidgetConfiguration, type TopoloWidgetConfigurationField, type TopoloWidgetConfigurationOption, type TopoloWidgetContext, type TopoloWidgetContribution, type TopoloWidgetDatasetDefinition, type TopoloWidgetDimension, type TopoloWidgetDimensionDefinition, type TopoloWidgetDraft, type TopoloWidgetDrilldown, type TopoloWidgetErrorResponseOptions, type TopoloWidgetEventDefinition, type TopoloWidgetLifecycleStage, type TopoloWidgetLocalization, type TopoloWidgetMetric, type TopoloWidgetMetricAggregation, type TopoloWidgetMetricComparison, type TopoloWidgetMetricDefinition, type TopoloWidgetMetricSemantic, type TopoloWidgetNotificationItem, type TopoloWidgetPeriod, type TopoloWidgetPresentation, type TopoloWidgetRefreshPolicy, type TopoloWidgetResourceBinding, type TopoloWidgetResponseOptions, type TopoloWidgetSeries, type TopoloWidgetSeriesDefinition, type TopoloWidgetSeriesPoint, type TopoloWidgetSize, type TopoloWidgetState, type TopoloWidgetStatus, type TopoloWidgetType, type TopoloWidgetValidationResult, type TopoloWidgetVisualizationFamily, type TopoloWidgetWorkspaceSelector, type TopoloWorkspace, type TopoloWorkspaceListResult, type TopoloWorkspaceMutationResult, type TopoloWorkspacePolicy, WorkspacesModule, actionContractCompleteness, applicationEntryFromCatalog, assertTopoloServiceUrlEnvironment, canonicalJson, canonicalTopoloErrorCode, canonicalTopoloRequestId, canonicalTopoloRequired, canonicalTopoloRetryAfter, canonicalizeActorEnvelope, compactActionCatalogEntry, compactActionPlan, compactActionPreparation, compactActionResult, compactActionValidation, createTopolo, createTopoloAgentExecutionContext, createTopoloWidgetError, createTopoloWidgetResponse, decodeActorEnvelopeHeader, defineTopoloActionsWidget, defineTopoloActivityWidget, defineTopoloChartWidget, defineTopoloNotificationsWidget, defineTopoloStatsWidget, digestTopoloActionCatalog, encodeActorEnvelopeHeader, encodeTopoloActionBase64, enrichActionContract, extractTopoloServiceErrorCode, extractTopoloServiceErrorDetails, formatDirectoryApplicationIds, friendlyAppId, isTopoloWidgetOutputSchema, listApplicationDirectory, parseActorEnvelope, parseTopoloActionUploadContract, preferExactActionMatches, prepareTopoloActionBase64UploadInput, prepareTopoloActionUploadInput, projectActorAuditEvent, publicTopoloErrorMessage, resolveApplicationDirectoryEntry, resolveCatalogServiceUrl, resolveServiceUrl, sha256CanonicalValue, topoloErrorHint, topoloServiceOrigins, validateTopoloActionInput, validateTopoloWidgetResponse };
|
|
1709
|
+
export { ACTION_CATALOG_DIGEST_ALGORITHM, ACTOR_AUDIT_PROJECTION_VERSION, ACTOR_ENVELOPE_VERSION, type AccountableSubject, type AccountableSubjectType, type ActionContractManifest, type ActionContractSource, type ActorAssurance, type ActorAuditEventRole, type ActorAuditProjection, type ActorChannel, type ActorDelegationHop, type ActorEnvelope, ActorEnvelopeValidationError, type ActorIdentity, type ActorPrincipalType, type AgentIdentity, type AppApiId, type ApplicationCatalogEntry, type ApplicationDeployTarget, type ApplicationDirectory, type ApplicationDirectoryApplication, type ApplicationDirectoryClient, type ApplicationDirectorySource, type ApplicationId, type CredentialIntrospection, type CrmContactSummary, CrmModule, DEFAULT_APP_URLS, type DeviceAuthorizationResponse, IdentityModule, type ListContactsOptions, type ListContactsResult, type OAuthHelperOptions, type P2PActionDetail, type P2PActionRequestInput, type P2PActionRequestResult, type P2PActionRow, type P2PActionRun, type P2PCapability, type P2PConnection, type P2PHold, type P2PLedgerEntry, P2PModule, type P2PPolicy, type P2PPricingModel, type P2PSettlementBatch, type P2PSettlementGroup, type PublishCapabilityInput, type RequestOptions, type ServiceCatalogUrlEntry, TOPOLO_ACTOR_ENVELOPE_HEADER, TOPOLO_ENVIRONMENT_SERVICE_URLS, TOPOLO_RUNTIME_ENVIRONMENTS, TOPOLO_WIDGET_CONTRACT_VERSION, TOPOLO_WIDGET_ENDPOINT, TOPOLO_WIDGET_OUTPUT_SCHEMA, TOPOLO_WIDGET_REFRESH_INTERVAL_MS, type TokenResponse, type Topolo, type TopoloActionAgentContract, type TopoloActionCatalogEntry, type TopoloActionCatalogSummary, type TopoloActionDigestInput, type TopoloActionPlan, type TopoloActionPreparation, type TopoloActionUploadOptions, type TopoloActionValidationIssue, type TopoloActionValidationResult, type TopoloActionsWidget, type TopoloActivityWidget, type TopoloAgentExecutionContext, type TopoloApiKeyResourceMetadata, TopoloAuthError, type TopoloBinaryResponse, type TopoloBindableResource, type TopoloBindableResourceCatalog, type TopoloChartWidget, TopoloClient, type TopoloClientOptions, TopoloConfirmationRequiredError, type TopoloCredential, type TopoloDebugEvent, TopoloHttpError, type TopoloInlineBase64UploadContract, type TopoloJsonSchema, type TopoloNotificationsWidget, TopoloOAuth, TopoloPermissionError, type TopoloRuntimeEnvironment, TopoloSdkError, type TopoloServiceCatalogEntry, type TopoloStatsWidget, type TopoloWidget, type TopoloWidgetAccessibility, type TopoloWidgetActionBinding, type TopoloWidgetActionRecovery, type TopoloWidgetActivityItem, type TopoloWidgetApiError, type TopoloWidgetApiErrorResponse, type TopoloWidgetApiResponse, type TopoloWidgetApiSuccessResponse, type TopoloWidgetBase, type TopoloWidgetConfig, type TopoloWidgetConfiguration, type TopoloWidgetConfigurationField, type TopoloWidgetConfigurationOption, type TopoloWidgetContext, type TopoloWidgetContribution, type TopoloWidgetDatasetDefinition, type TopoloWidgetDimension, type TopoloWidgetDimensionDefinition, type TopoloWidgetDraft, type TopoloWidgetDrilldown, type TopoloWidgetErrorResponseOptions, type TopoloWidgetEventDefinition, type TopoloWidgetLifecycleStage, type TopoloWidgetLocalization, type TopoloWidgetMetric, type TopoloWidgetMetricAggregation, type TopoloWidgetMetricComparison, type TopoloWidgetMetricDefinition, type TopoloWidgetMetricSemantic, type TopoloWidgetNotificationItem, type TopoloWidgetPeriod, type TopoloWidgetPresentation, type TopoloWidgetRefreshPolicy, type TopoloWidgetResourceBinding, type TopoloWidgetResponseOptions, type TopoloWidgetSeries, type TopoloWidgetSeriesDefinition, type TopoloWidgetSeriesPoint, type TopoloWidgetSize, type TopoloWidgetState, type TopoloWidgetStatus, type TopoloWidgetType, type TopoloWidgetValidationResult, type TopoloWidgetVisualizationFamily, type TopoloWidgetWorkspaceSelector, type TopoloWorkspace, type TopoloWorkspaceListResult, type TopoloWorkspaceMutationResult, type TopoloWorkspacePolicy, WorkspacesModule, actionContractCompleteness, applicationEntryFromCatalog, assertTopoloServiceUrlEnvironment, calculateDpopJkt, canonicalJson, canonicalTopoloErrorCode, canonicalTopoloRequestId, canonicalTopoloRequired, canonicalTopoloRetryAfter, canonicalizeActorEnvelope, compactActionCatalogEntry, compactActionPlan, compactActionPreparation, compactActionResult, compactActionValidation, createDpopProof, createTopolo, createTopoloAgentExecutionContext, createTopoloWidgetError, createTopoloWidgetResponse, decodeActorEnvelopeHeader, defineTopoloActionsWidget, defineTopoloActivityWidget, defineTopoloChartWidget, defineTopoloNotificationsWidget, defineTopoloStatsWidget, digestTopoloActionCatalog, encodeActorEnvelopeHeader, encodeTopoloActionBase64, enrichActionContract, extractTopoloServiceErrorCode, extractTopoloServiceErrorDetails, formatDirectoryApplicationIds, friendlyAppId, isTopoloWidgetOutputSchema, listApplicationDirectory, parseActorEnvelope, parseTopoloActionUploadContract, preferExactActionMatches, prepareTopoloActionBase64UploadInput, prepareTopoloActionUploadInput, projectActorAuditEvent, publicTopoloErrorMessage, resolveApplicationDirectoryEntry, resolveCatalogServiceUrl, resolveServiceUrl, sha256CanonicalValue, topoloErrorHint, topoloServiceOrigins, validateTopoloActionInput, validateTopoloWidgetResponse };
|
package/dist/index.js
CHANGED
|
@@ -4,7 +4,7 @@ function applyAuthHeaders(headers, credential) {
|
|
|
4
4
|
headers.set("X-Api-Key", credential.apiKey);
|
|
5
5
|
return;
|
|
6
6
|
}
|
|
7
|
-
headers.set("Authorization",
|
|
7
|
+
headers.set("Authorization", `${credential.kind === "dpop_access_token" ? "DPoP" : "Bearer"} ${credential.accessToken}`);
|
|
8
8
|
}
|
|
9
9
|
function applyAuditHeaders(headers, agent, requestId) {
|
|
10
10
|
headers.set("X-Topolo-Client", `${agent.clientName}/${agent.clientVersion}`);
|
|
@@ -18,6 +18,60 @@ function generateRequestId() {
|
|
|
18
18
|
return `req_${Date.now().toString(36)}_${Math.random().toString(36).slice(2, 10)}`;
|
|
19
19
|
}
|
|
20
20
|
|
|
21
|
+
// src/dpop.ts
|
|
22
|
+
var encoder = new TextEncoder();
|
|
23
|
+
function encodeBase64Url(value) {
|
|
24
|
+
const bytes = value instanceof Uint8Array ? value : new Uint8Array(value);
|
|
25
|
+
let binary = "";
|
|
26
|
+
for (const byte of bytes) binary += String.fromCharCode(byte);
|
|
27
|
+
return btoa(binary).replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/g, "");
|
|
28
|
+
}
|
|
29
|
+
function encodeJson(value) {
|
|
30
|
+
return encodeBase64Url(encoder.encode(JSON.stringify(value)));
|
|
31
|
+
}
|
|
32
|
+
async function sha256Base64Url(value) {
|
|
33
|
+
return encodeBase64Url(await crypto.subtle.digest("SHA-256", encoder.encode(value)));
|
|
34
|
+
}
|
|
35
|
+
function publicJwk(privateJwk) {
|
|
36
|
+
const { crv, kty, x, y } = privateJwk;
|
|
37
|
+
if (kty !== "EC" || crv !== "P-256" || !x || !y || !privateJwk.d) {
|
|
38
|
+
throw new TypeError("A private P-256 JSON Web Key is required for DPoP signing.");
|
|
39
|
+
}
|
|
40
|
+
return { crv, kty, x, y };
|
|
41
|
+
}
|
|
42
|
+
function canonicalTargetUrl(value) {
|
|
43
|
+
const url = new URL(value);
|
|
44
|
+
return `${url.origin}${url.pathname}`;
|
|
45
|
+
}
|
|
46
|
+
async function calculateDpopJkt(privateJwk) {
|
|
47
|
+
const jwk = publicJwk(privateJwk);
|
|
48
|
+
return sha256Base64Url(JSON.stringify({ crv: jwk.crv, kty: jwk.kty, x: jwk.x, y: jwk.y }));
|
|
49
|
+
}
|
|
50
|
+
async function createDpopProof(input) {
|
|
51
|
+
const jwk = publicJwk(input.privateJwk);
|
|
52
|
+
const key = await crypto.subtle.importKey(
|
|
53
|
+
"jwk",
|
|
54
|
+
input.privateJwk,
|
|
55
|
+
{ name: "ECDSA", namedCurve: "P-256" },
|
|
56
|
+
false,
|
|
57
|
+
["sign"]
|
|
58
|
+
);
|
|
59
|
+
const header = encodeJson({ alg: "ES256", typ: "dpop+jwt", jwk });
|
|
60
|
+
const claims = encodeJson({
|
|
61
|
+
jti: crypto.randomUUID(),
|
|
62
|
+
iat: Math.floor(Date.now() / 1e3),
|
|
63
|
+
htm: input.method.toUpperCase(),
|
|
64
|
+
htu: canonicalTargetUrl(input.targetUrl),
|
|
65
|
+
ath: await sha256Base64Url(input.accessToken)
|
|
66
|
+
});
|
|
67
|
+
const signature = await crypto.subtle.sign(
|
|
68
|
+
{ name: "ECDSA", hash: "SHA-256" },
|
|
69
|
+
key,
|
|
70
|
+
encoder.encode(`${header}.${claims}`)
|
|
71
|
+
);
|
|
72
|
+
return `${header}.${claims}.${encodeBase64Url(signature)}`;
|
|
73
|
+
}
|
|
74
|
+
|
|
21
75
|
// src/errors.ts
|
|
22
76
|
var TopoloSdkError = class extends Error {
|
|
23
77
|
code;
|
|
@@ -1374,7 +1428,6 @@ var TopoloClient = class _TopoloClient {
|
|
|
1374
1428
|
if (opts.body !== void 0) headers.set("Content-Type", "application/json");
|
|
1375
1429
|
const platformAppId = resolveConfiguredAppId(resolvedService.serviceKey, this.appIds);
|
|
1376
1430
|
if (platformAppId) headers.set("X-App-ID", platformAppId);
|
|
1377
|
-
applyAuthHeaders(headers, this.credential);
|
|
1378
1431
|
const actorEnvelope = opts.actorEnvelope === void 0 ? void 0 : parseActorEnvelope(opts.actorEnvelope);
|
|
1379
1432
|
const requestId = actorEnvelope?.action.requestId ?? generateRequestId();
|
|
1380
1433
|
applyAuditHeaders(headers, this.agent, requestId);
|
|
@@ -1408,9 +1461,19 @@ var TopoloClient = class _TopoloClient {
|
|
|
1408
1461
|
}, this.timeoutMs);
|
|
1409
1462
|
const signal = opts.signal ? mergeSignals(opts.signal, controller.signal) : controller.signal;
|
|
1410
1463
|
try {
|
|
1464
|
+
const requestHeaders = new Headers(headers);
|
|
1465
|
+
applyAuthHeaders(requestHeaders, this.credential);
|
|
1466
|
+
if (this.credential.kind === "dpop_access_token") {
|
|
1467
|
+
requestHeaders.set("DPoP", await createDpopProof({
|
|
1468
|
+
accessToken: this.credential.accessToken,
|
|
1469
|
+
method,
|
|
1470
|
+
targetUrl: urlStr,
|
|
1471
|
+
privateJwk: this.credential.privateJwk
|
|
1472
|
+
}));
|
|
1473
|
+
}
|
|
1411
1474
|
return await this.fetchImpl(urlStr, {
|
|
1412
1475
|
method,
|
|
1413
|
-
headers:
|
|
1476
|
+
headers: requestHeaders,
|
|
1414
1477
|
body: opts.rawBody ?? (opts.body !== void 0 ? JSON.stringify(opts.body) : null),
|
|
1415
1478
|
signal
|
|
1416
1479
|
});
|
|
@@ -1447,7 +1510,6 @@ var TopoloClient = class _TopoloClient {
|
|
|
1447
1510
|
await res.body?.cancel().catch(() => void 0);
|
|
1448
1511
|
const refreshed = await this.refreshRejectedAccessToken(attemptedCredential.accessToken);
|
|
1449
1512
|
if (refreshed) {
|
|
1450
|
-
applyAuthHeaders(headers, refreshed);
|
|
1451
1513
|
res = await fetchWithReadRetry();
|
|
1452
1514
|
}
|
|
1453
1515
|
}
|
|
@@ -4801,6 +4863,7 @@ export {
|
|
|
4801
4863
|
actionContractCompleteness,
|
|
4802
4864
|
applicationEntryFromCatalog,
|
|
4803
4865
|
assertTopoloServiceUrlEnvironment,
|
|
4866
|
+
calculateDpopJkt,
|
|
4804
4867
|
canonicalJson,
|
|
4805
4868
|
canonicalTopoloErrorCode,
|
|
4806
4869
|
canonicalTopoloRequestId,
|
|
@@ -4812,6 +4875,7 @@ export {
|
|
|
4812
4875
|
compactActionPreparation,
|
|
4813
4876
|
compactActionResult,
|
|
4814
4877
|
compactActionValidation,
|
|
4878
|
+
createDpopProof,
|
|
4815
4879
|
createTopolo,
|
|
4816
4880
|
createTopoloAgentExecutionContext,
|
|
4817
4881
|
createTopoloWidgetError,
|
|
@@ -28,11 +28,16 @@ __export(credential_store_exports, {
|
|
|
28
28
|
clearProfileCredential: () => clearProfileCredential,
|
|
29
29
|
configPath: () => configPath,
|
|
30
30
|
contextKey: () => contextKey,
|
|
31
|
+
createPlatformInstallationSecretBackend: () => createPlatformInstallationSecretBackend,
|
|
31
32
|
credentialSourceFromConfig: () => credentialSourceFromConfig,
|
|
33
|
+
deleteExternalAgentInstallation: () => deleteExternalAgentInstallation,
|
|
32
34
|
envVarPrefix: () => envVarPrefix,
|
|
35
|
+
installationStorePath: () => installationStorePath,
|
|
36
|
+
listExternalAgentInstallations: () => listExternalAgentInstallations,
|
|
33
37
|
normalizeEnvironment: () => normalizeEnvironment,
|
|
34
38
|
profileForEnvironment: () => profileForEnvironment,
|
|
35
39
|
readConfig: () => readConfig,
|
|
40
|
+
readExternalAgentInstallation: () => readExternalAgentInstallation,
|
|
36
41
|
refreshContextCredentialIfNeeded: () => refreshContextCredentialIfNeeded,
|
|
37
42
|
refreshCredentialIfNeeded: () => refreshCredentialIfNeeded,
|
|
38
43
|
resolveAgentName: () => resolveAgentName,
|
|
@@ -43,13 +48,14 @@ __export(credential_store_exports, {
|
|
|
43
48
|
topoloServiceOrigins: () => topoloServiceOrigins,
|
|
44
49
|
writeConfig: () => writeConfig,
|
|
45
50
|
writeContextCredential: () => writeContextCredential,
|
|
51
|
+
writeExternalAgentInstallation: () => writeExternalAgentInstallation,
|
|
46
52
|
writeProfileConfig: () => writeProfileConfig
|
|
47
53
|
});
|
|
48
54
|
module.exports = __toCommonJS(credential_store_exports);
|
|
49
|
-
var
|
|
50
|
-
var
|
|
51
|
-
var
|
|
52
|
-
var
|
|
55
|
+
var import_promises2 = require("fs/promises");
|
|
56
|
+
var import_node_fs2 = require("fs");
|
|
57
|
+
var import_node_os2 = require("os");
|
|
58
|
+
var import_node_path2 = require("path");
|
|
53
59
|
|
|
54
60
|
// src/errors.ts
|
|
55
61
|
var TopoloSdkError = class extends Error {
|
|
@@ -468,6 +474,172 @@ function topoloServiceOrigins(serviceUrls, environment) {
|
|
|
468
474
|
);
|
|
469
475
|
}
|
|
470
476
|
|
|
477
|
+
// src/node/installation-store.ts
|
|
478
|
+
var import_node_child_process = require("child_process");
|
|
479
|
+
var import_promises = require("fs/promises");
|
|
480
|
+
var import_node_fs = require("fs");
|
|
481
|
+
var import_node_os = require("os");
|
|
482
|
+
var import_node_path = require("path");
|
|
483
|
+
var KEYCHAIN_SERVICE = "topolo-external-agent-installation";
|
|
484
|
+
function installationStorePath() {
|
|
485
|
+
const override = process.env.TOPOLO_INSTALLATIONS_PATH?.trim();
|
|
486
|
+
if (override) return override;
|
|
487
|
+
const base = process.env.XDG_CONFIG_HOME || ((0, import_node_os.platform)() === "win32" ? (0, import_node_path.join)((0, import_node_os.homedir)(), "AppData", "Roaming") : (0, import_node_path.join)((0, import_node_os.homedir)(), ".config"));
|
|
488
|
+
return (0, import_node_path.join)(base, "topolo", "installations");
|
|
489
|
+
}
|
|
490
|
+
function installationPath(environment, id) {
|
|
491
|
+
if (!/^[A-Za-z0-9_-]+$/.test(id)) throw new TypeError("Installation id contains unsupported characters.");
|
|
492
|
+
return (0, import_node_path.join)(installationStorePath(), environment, `${id}.json`);
|
|
493
|
+
}
|
|
494
|
+
function accountName(environment, id) {
|
|
495
|
+
return `${environment}:${id}`;
|
|
496
|
+
}
|
|
497
|
+
function runOrThrow(result, operation) {
|
|
498
|
+
if (result.status !== 0) {
|
|
499
|
+
throw new Error(`${operation} failed: ${(result.stderr || result.error?.message || "platform credential store unavailable").trim()}`);
|
|
500
|
+
}
|
|
501
|
+
return result.stdout.trim();
|
|
502
|
+
}
|
|
503
|
+
function createPlatformInstallationSecretBackend(options = {}) {
|
|
504
|
+
const platform2 = options.platform ?? (0, import_node_os.platform)();
|
|
505
|
+
const spawn = options.spawn ?? ((command, args, spawnOptions) => (0, import_node_child_process.spawnSync)(command, args, spawnOptions));
|
|
506
|
+
const root = options.root ?? installationStorePath();
|
|
507
|
+
if (platform2 === "darwin") {
|
|
508
|
+
return {
|
|
509
|
+
async set(account, value) {
|
|
510
|
+
runOrThrow(spawn("security", [
|
|
511
|
+
"add-generic-password",
|
|
512
|
+
"-U",
|
|
513
|
+
"-a",
|
|
514
|
+
account,
|
|
515
|
+
"-s",
|
|
516
|
+
KEYCHAIN_SERVICE,
|
|
517
|
+
"-w"
|
|
518
|
+
], { input: `${value}
|
|
519
|
+
`, encoding: "utf8" }), "macOS Keychain write");
|
|
520
|
+
},
|
|
521
|
+
async get(account) {
|
|
522
|
+
const result = spawn("security", [
|
|
523
|
+
"find-generic-password",
|
|
524
|
+
"-a",
|
|
525
|
+
account,
|
|
526
|
+
"-s",
|
|
527
|
+
KEYCHAIN_SERVICE,
|
|
528
|
+
"-w"
|
|
529
|
+
], { encoding: "utf8" });
|
|
530
|
+
if (result.status === 44) return null;
|
|
531
|
+
return runOrThrow(result, "macOS Keychain read");
|
|
532
|
+
},
|
|
533
|
+
async delete(account) {
|
|
534
|
+
const result = spawn("security", [
|
|
535
|
+
"delete-generic-password",
|
|
536
|
+
"-a",
|
|
537
|
+
account,
|
|
538
|
+
"-s",
|
|
539
|
+
KEYCHAIN_SERVICE
|
|
540
|
+
], { encoding: "utf8" });
|
|
541
|
+
if (result.status !== 44) runOrThrow(result, "macOS Keychain delete");
|
|
542
|
+
}
|
|
543
|
+
};
|
|
544
|
+
}
|
|
545
|
+
if (platform2 === "linux") {
|
|
546
|
+
return {
|
|
547
|
+
async set(account, value) {
|
|
548
|
+
runOrThrow(spawn("secret-tool", [
|
|
549
|
+
"store",
|
|
550
|
+
"--label=Topolo external agent installation",
|
|
551
|
+
"service",
|
|
552
|
+
KEYCHAIN_SERVICE,
|
|
553
|
+
"account",
|
|
554
|
+
account
|
|
555
|
+
], { input: value, encoding: "utf8" }), "Linux Secret Service write");
|
|
556
|
+
},
|
|
557
|
+
async get(account) {
|
|
558
|
+
const result = spawn("secret-tool", [
|
|
559
|
+
"lookup",
|
|
560
|
+
"service",
|
|
561
|
+
KEYCHAIN_SERVICE,
|
|
562
|
+
"account",
|
|
563
|
+
account
|
|
564
|
+
], { encoding: "utf8" });
|
|
565
|
+
if (result.status === 1) return null;
|
|
566
|
+
return runOrThrow(result, "Linux Secret Service read");
|
|
567
|
+
},
|
|
568
|
+
async delete(account) {
|
|
569
|
+
const result = spawn("secret-tool", [
|
|
570
|
+
"clear",
|
|
571
|
+
"service",
|
|
572
|
+
KEYCHAIN_SERVICE,
|
|
573
|
+
"account",
|
|
574
|
+
account
|
|
575
|
+
], { encoding: "utf8" });
|
|
576
|
+
if (result.status !== 1) runOrThrow(result, "Linux Secret Service delete");
|
|
577
|
+
}
|
|
578
|
+
};
|
|
579
|
+
}
|
|
580
|
+
if (platform2 === "win32") {
|
|
581
|
+
const secretPath = (account) => (0, import_node_path.join)(root, ".secrets", `${account.replace(":", "-")}.bin`);
|
|
582
|
+
const powershell = (script, path, input) => spawn(
|
|
583
|
+
"powershell.exe",
|
|
584
|
+
["-NoProfile", "-NonInteractive", "-Command", script],
|
|
585
|
+
{ input, encoding: "utf8", env: { ...process.env, TOPOLO_SECRET_PATH: path } }
|
|
586
|
+
);
|
|
587
|
+
return {
|
|
588
|
+
async set(account, value) {
|
|
589
|
+
const path = secretPath(account);
|
|
590
|
+
await (0, import_promises.mkdir)((0, import_node_path.dirname)(path), { recursive: true });
|
|
591
|
+
const script = "$p=$env:TOPOLO_SECRET_PATH;$v=[Console]::In.ReadToEnd();$b=[Text.Encoding]::UTF8.GetBytes($v);$e=[Security.Cryptography.ProtectedData]::Protect($b,$null,[Security.Cryptography.DataProtectionScope]::CurrentUser);[IO.File]::WriteAllBytes($p,$e)";
|
|
592
|
+
runOrThrow(powershell(script, path, value), "Windows DPAPI write");
|
|
593
|
+
},
|
|
594
|
+
async get(account) {
|
|
595
|
+
const path = secretPath(account);
|
|
596
|
+
if (!(0, import_node_fs.existsSync)(path)) return null;
|
|
597
|
+
const script = "$p=$env:TOPOLO_SECRET_PATH;$b=[IO.File]::ReadAllBytes($p);$d=[Security.Cryptography.ProtectedData]::Unprotect($b,$null,[Security.Cryptography.DataProtectionScope]::CurrentUser);[Console]::Out.Write([Text.Encoding]::UTF8.GetString($d))";
|
|
598
|
+
return runOrThrow(powershell(script, path), "Windows DPAPI read");
|
|
599
|
+
},
|
|
600
|
+
async delete(account) {
|
|
601
|
+
await (0, import_promises.rm)(secretPath(account), { force: true });
|
|
602
|
+
}
|
|
603
|
+
};
|
|
604
|
+
}
|
|
605
|
+
throw new Error(`Secure external-agent installation storage is unsupported on ${platform2}.`);
|
|
606
|
+
}
|
|
607
|
+
async function writeExternalAgentInstallation(installation, secret, backend = createPlatformInstallationSecretBackend()) {
|
|
608
|
+
const path = installationPath(installation.environment, installation.id);
|
|
609
|
+
await backend.set(accountName(installation.environment, installation.id), JSON.stringify(secret));
|
|
610
|
+
const temporary = `${path}.${process.pid}.tmp`;
|
|
611
|
+
try {
|
|
612
|
+
await (0, import_promises.mkdir)((0, import_node_path.dirname)(path), { recursive: true, mode: 448 });
|
|
613
|
+
await (0, import_promises.writeFile)(temporary, `${JSON.stringify(installation, null, 2)}
|
|
614
|
+
`, { encoding: "utf8", mode: 384 });
|
|
615
|
+
await (0, import_promises.rename)(temporary, path);
|
|
616
|
+
if ((0, import_node_os.platform)() !== "win32") await (0, import_promises.chmod)(path, 384);
|
|
617
|
+
} catch (error) {
|
|
618
|
+
await backend.delete(accountName(installation.environment, installation.id)).catch(() => void 0);
|
|
619
|
+
await (0, import_promises.rm)(temporary, { force: true });
|
|
620
|
+
throw error;
|
|
621
|
+
}
|
|
622
|
+
}
|
|
623
|
+
async function readExternalAgentInstallation(environment, id, backend = createPlatformInstallationSecretBackend()) {
|
|
624
|
+
const path = installationPath(environment, id);
|
|
625
|
+
if (!(0, import_node_fs.existsSync)(path)) return null;
|
|
626
|
+
const installation = JSON.parse(await (0, import_promises.readFile)(path, "utf8"));
|
|
627
|
+
const encodedSecret = await backend.get(accountName(environment, id));
|
|
628
|
+
if (!encodedSecret) throw new Error(`Protected secret is missing for installation ${id}.`);
|
|
629
|
+
return { installation, secret: JSON.parse(encodedSecret) };
|
|
630
|
+
}
|
|
631
|
+
async function listExternalAgentInstallations(environment) {
|
|
632
|
+
const directory = (0, import_node_path.join)(installationStorePath(), environment);
|
|
633
|
+
if (!(0, import_node_fs.existsSync)(directory)) return [];
|
|
634
|
+
const entries = await (0, import_promises.readdir)(directory, { withFileTypes: true });
|
|
635
|
+
const installations = await Promise.all(entries.filter((entry) => entry.isFile() && entry.name.endsWith(".json")).map(async (entry) => JSON.parse(await (0, import_promises.readFile)((0, import_node_path.join)(directory, entry.name), "utf8"))));
|
|
636
|
+
return installations.sort((left, right) => left.createdAt.localeCompare(right.createdAt));
|
|
637
|
+
}
|
|
638
|
+
async function deleteExternalAgentInstallation(environment, id, backend = createPlatformInstallationSecretBackend()) {
|
|
639
|
+
await backend.delete(accountName(environment, id));
|
|
640
|
+
await (0, import_promises.rm)(installationPath(environment, id), { force: true });
|
|
641
|
+
}
|
|
642
|
+
|
|
471
643
|
// src/node/credential-store.ts
|
|
472
644
|
var TOPOLO_ENVIRONMENTS = TOPOLO_RUNTIME_ENVIRONMENTS;
|
|
473
645
|
function contextKey(contextType, organizationId) {
|
|
@@ -477,14 +649,14 @@ var ENVIRONMENT_DEFAULT_SERVICE_URLS = TOPOLO_ENVIRONMENT_SERVICE_URLS;
|
|
|
477
649
|
function configPath() {
|
|
478
650
|
const override = process.env.TOPOLO_CONFIG_PATH;
|
|
479
651
|
if (override) return override;
|
|
480
|
-
const base = process.env.XDG_CONFIG_HOME || ((0,
|
|
481
|
-
return (0,
|
|
652
|
+
const base = process.env.XDG_CONFIG_HOME || ((0, import_node_os2.platform)() === "win32" ? (0, import_node_path2.join)((0, import_node_os2.homedir)(), "AppData", "Roaming") : (0, import_node_path2.join)((0, import_node_os2.homedir)(), ".config"));
|
|
653
|
+
return (0, import_node_path2.join)(base, "topolo", "config.json");
|
|
482
654
|
}
|
|
483
655
|
async function readConfig() {
|
|
484
656
|
const path = configPath();
|
|
485
|
-
if (!(0,
|
|
657
|
+
if (!(0, import_node_fs2.existsSync)(path)) return {};
|
|
486
658
|
try {
|
|
487
|
-
const raw = await (0,
|
|
659
|
+
const raw = await (0, import_promises2.readFile)(path, "utf8");
|
|
488
660
|
return JSON.parse(raw);
|
|
489
661
|
} catch {
|
|
490
662
|
return {};
|
|
@@ -492,11 +664,11 @@ async function readConfig() {
|
|
|
492
664
|
}
|
|
493
665
|
async function writeConfig(config) {
|
|
494
666
|
const path = configPath();
|
|
495
|
-
await (0,
|
|
496
|
-
await (0,
|
|
497
|
-
if ((0,
|
|
667
|
+
await (0, import_promises2.mkdir)((0, import_node_path2.dirname)(path), { recursive: true });
|
|
668
|
+
await (0, import_promises2.writeFile)(path, JSON.stringify(config, null, 2) + "\n", "utf8");
|
|
669
|
+
if ((0, import_node_os2.platform)() !== "win32") {
|
|
498
670
|
try {
|
|
499
|
-
await (0,
|
|
671
|
+
await (0, import_promises2.chmod)(path, 384);
|
|
500
672
|
} catch {
|
|
501
673
|
}
|
|
502
674
|
}
|
|
@@ -612,18 +784,18 @@ var CONFIG_LOCK_TIMEOUT_MS = 5e3;
|
|
|
612
784
|
var CONFIG_LOCK_STALE_MS = 12e4;
|
|
613
785
|
async function withConfigWriteLock(operation) {
|
|
614
786
|
const lockPath = `${configPath()}.lock`;
|
|
615
|
-
await (0,
|
|
787
|
+
await (0, import_promises2.mkdir)((0, import_node_path2.dirname)(lockPath), { recursive: true });
|
|
616
788
|
const startedAt = Date.now();
|
|
617
789
|
while (true) {
|
|
618
790
|
try {
|
|
619
|
-
await (0,
|
|
791
|
+
await (0, import_promises2.mkdir)(lockPath);
|
|
620
792
|
break;
|
|
621
793
|
} catch (error) {
|
|
622
794
|
if (error.code !== "EEXIST") throw error;
|
|
623
795
|
try {
|
|
624
|
-
const lock = await (0,
|
|
796
|
+
const lock = await (0, import_promises2.stat)(lockPath);
|
|
625
797
|
if (Date.now() - lock.mtimeMs > CONFIG_LOCK_STALE_MS) {
|
|
626
|
-
await (0,
|
|
798
|
+
await (0, import_promises2.rm)(lockPath, { recursive: true, force: true });
|
|
627
799
|
continue;
|
|
628
800
|
}
|
|
629
801
|
} catch (inspectionError) {
|
|
@@ -639,7 +811,7 @@ async function withConfigWriteLock(operation) {
|
|
|
639
811
|
try {
|
|
640
812
|
return await operation();
|
|
641
813
|
} finally {
|
|
642
|
-
await (0,
|
|
814
|
+
await (0, import_promises2.rm)(lockPath, { recursive: true, force: true });
|
|
643
815
|
}
|
|
644
816
|
}
|
|
645
817
|
async function refreshCredentialIfNeeded(environment = selectedEnvironment(), options = {}) {
|
|
@@ -788,11 +960,16 @@ function resolvedProfileConfig(config, environment = selectedEnvironment()) {
|
|
|
788
960
|
clearProfileCredential,
|
|
789
961
|
configPath,
|
|
790
962
|
contextKey,
|
|
963
|
+
createPlatformInstallationSecretBackend,
|
|
791
964
|
credentialSourceFromConfig,
|
|
965
|
+
deleteExternalAgentInstallation,
|
|
792
966
|
envVarPrefix,
|
|
967
|
+
installationStorePath,
|
|
968
|
+
listExternalAgentInstallations,
|
|
793
969
|
normalizeEnvironment,
|
|
794
970
|
profileForEnvironment,
|
|
795
971
|
readConfig,
|
|
972
|
+
readExternalAgentInstallation,
|
|
796
973
|
refreshContextCredentialIfNeeded,
|
|
797
974
|
refreshCredentialIfNeeded,
|
|
798
975
|
resolveAgentName,
|
|
@@ -803,5 +980,6 @@ function resolvedProfileConfig(config, environment = selectedEnvironment()) {
|
|
|
803
980
|
topoloServiceOrigins,
|
|
804
981
|
writeConfig,
|
|
805
982
|
writeContextCredential,
|
|
983
|
+
writeExternalAgentInstallation,
|
|
806
984
|
writeProfileConfig
|
|
807
985
|
});
|
|
@@ -1,14 +1,15 @@
|
|
|
1
|
+
import { SpawnSyncReturns } from 'node:child_process';
|
|
2
|
+
|
|
1
3
|
/**
|
|
2
4
|
* Auth credential types used by the SDK.
|
|
3
5
|
*
|
|
4
|
-
*
|
|
6
|
+
* Supported modes:
|
|
5
7
|
* - `api_key`: a single platform API key (service-scoped at issuance).
|
|
6
|
-
*
|
|
8
|
+
* Used for service integrations that are not installation-bound.
|
|
7
9
|
* - `access_token`: a short-lived JWT from the interactive login flow.
|
|
8
10
|
* Used by TopoloCli after `topolo auth login`.
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
* PKCE flow in TopoloAuth. Those will plug in as a third variant.
|
|
11
|
+
* - `dpop_access_token`: a short-lived delegated token bound to an external
|
|
12
|
+
* agent installation key. Every request proves possession of that key.
|
|
12
13
|
*/
|
|
13
14
|
type TopoloCredential = {
|
|
14
15
|
kind: 'api_key';
|
|
@@ -18,6 +19,11 @@ type TopoloCredential = {
|
|
|
18
19
|
accessToken: string;
|
|
19
20
|
refreshToken?: string;
|
|
20
21
|
expiresAt?: number;
|
|
22
|
+
} | {
|
|
23
|
+
kind: 'dpop_access_token';
|
|
24
|
+
accessToken: string;
|
|
25
|
+
privateJwk: JsonWebKey;
|
|
26
|
+
expiresAt?: number;
|
|
21
27
|
};
|
|
22
28
|
|
|
23
29
|
declare const TOPOLO_RUNTIME_ENVIRONMENTS: readonly ["production", "staging", "development", "local"];
|
|
@@ -25,6 +31,48 @@ type TopoloRuntimeEnvironment = (typeof TOPOLO_RUNTIME_ENVIRONMENTS)[number];
|
|
|
25
31
|
declare function assertTopoloServiceUrlEnvironment(service: string, value: string, environment: TopoloRuntimeEnvironment): string;
|
|
26
32
|
declare function topoloServiceOrigins(serviceUrls: Record<string, string> | undefined, environment: TopoloRuntimeEnvironment): Record<string, string>;
|
|
27
33
|
|
|
34
|
+
interface ExternalAgentInstallation {
|
|
35
|
+
id: string;
|
|
36
|
+
environment: TopoloRuntimeEnvironment;
|
|
37
|
+
organizationId: string;
|
|
38
|
+
principalId: string;
|
|
39
|
+
credentialId: string;
|
|
40
|
+
clientId: string;
|
|
41
|
+
displayName: string;
|
|
42
|
+
provider: string;
|
|
43
|
+
host: string;
|
|
44
|
+
model?: string;
|
|
45
|
+
dpopJkt: string;
|
|
46
|
+
createdAt: string;
|
|
47
|
+
}
|
|
48
|
+
interface ExternalAgentInstallationSecret {
|
|
49
|
+
clientSecret: string;
|
|
50
|
+
privateJwk: JsonWebKey;
|
|
51
|
+
}
|
|
52
|
+
interface InstallationSecretBackend {
|
|
53
|
+
set(account: string, value: string): Promise<void>;
|
|
54
|
+
get(account: string): Promise<string | null>;
|
|
55
|
+
delete(account: string): Promise<void>;
|
|
56
|
+
}
|
|
57
|
+
type Spawn = (command: string, args: string[], options: {
|
|
58
|
+
input?: string;
|
|
59
|
+
encoding: 'utf8';
|
|
60
|
+
env?: NodeJS.ProcessEnv;
|
|
61
|
+
}) => SpawnSyncReturns<string>;
|
|
62
|
+
declare function installationStorePath(): string;
|
|
63
|
+
declare function createPlatformInstallationSecretBackend(options?: {
|
|
64
|
+
platform?: NodeJS.Platform;
|
|
65
|
+
spawn?: Spawn;
|
|
66
|
+
root?: string;
|
|
67
|
+
}): InstallationSecretBackend;
|
|
68
|
+
declare function writeExternalAgentInstallation(installation: ExternalAgentInstallation, secret: ExternalAgentInstallationSecret, backend?: InstallationSecretBackend): Promise<void>;
|
|
69
|
+
declare function readExternalAgentInstallation(environment: TopoloRuntimeEnvironment, id: string, backend?: InstallationSecretBackend): Promise<{
|
|
70
|
+
installation: ExternalAgentInstallation;
|
|
71
|
+
secret: ExternalAgentInstallationSecret;
|
|
72
|
+
} | null>;
|
|
73
|
+
declare function listExternalAgentInstallations(environment: TopoloRuntimeEnvironment): Promise<ExternalAgentInstallation[]>;
|
|
74
|
+
declare function deleteExternalAgentInstallation(environment: TopoloRuntimeEnvironment, id: string, backend?: InstallationSecretBackend): Promise<void>;
|
|
75
|
+
|
|
28
76
|
/**
|
|
29
77
|
* Node-only credential store shared by the `topolo` CLI and `@topolo/mcp`.
|
|
30
78
|
*
|
|
@@ -118,4 +166,4 @@ declare function resolveServiceUrls(configUrls?: Record<string, string>, environ
|
|
|
118
166
|
declare function assertServiceUrlForEnvironment(service: string, serviceUrl: string | undefined, environment?: TopoloEnvironment): void;
|
|
119
167
|
declare function resolvedProfileConfig(config: TopoloConfig, environment?: TopoloEnvironment): TopoloEnvironmentProfile;
|
|
120
168
|
|
|
121
|
-
export { ENVIRONMENT_DEFAULT_SERVICE_URLS, TOPOLO_ENVIRONMENTS, type TopoloConfig, type TopoloContextCredential, type TopoloEnvironment, type TopoloEnvironmentProfile, activateContext, assertServiceUrlForEnvironment, assertTopoloServiceUrlEnvironment, clearProfileCredential, configPath, contextKey, credentialSourceFromConfig, envVarPrefix, normalizeEnvironment, profileForEnvironment, readConfig, refreshContextCredentialIfNeeded, refreshCredentialIfNeeded, resolveAgentName, resolveCredential, resolveServiceUrls, resolvedProfileConfig, selectedEnvironment, topoloServiceOrigins, writeConfig, writeContextCredential, writeProfileConfig };
|
|
169
|
+
export { ENVIRONMENT_DEFAULT_SERVICE_URLS, type ExternalAgentInstallation, type ExternalAgentInstallationSecret, type InstallationSecretBackend, TOPOLO_ENVIRONMENTS, type TopoloConfig, type TopoloContextCredential, type TopoloEnvironment, type TopoloEnvironmentProfile, activateContext, assertServiceUrlForEnvironment, assertTopoloServiceUrlEnvironment, clearProfileCredential, configPath, contextKey, createPlatformInstallationSecretBackend, credentialSourceFromConfig, deleteExternalAgentInstallation, envVarPrefix, installationStorePath, listExternalAgentInstallations, normalizeEnvironment, profileForEnvironment, readConfig, readExternalAgentInstallation, refreshContextCredentialIfNeeded, refreshCredentialIfNeeded, resolveAgentName, resolveCredential, resolveServiceUrls, resolvedProfileConfig, selectedEnvironment, topoloServiceOrigins, writeConfig, writeContextCredential, writeExternalAgentInstallation, writeProfileConfig };
|
|
@@ -1,14 +1,15 @@
|
|
|
1
|
+
import { SpawnSyncReturns } from 'node:child_process';
|
|
2
|
+
|
|
1
3
|
/**
|
|
2
4
|
* Auth credential types used by the SDK.
|
|
3
5
|
*
|
|
4
|
-
*
|
|
6
|
+
* Supported modes:
|
|
5
7
|
* - `api_key`: a single platform API key (service-scoped at issuance).
|
|
6
|
-
*
|
|
8
|
+
* Used for service integrations that are not installation-bound.
|
|
7
9
|
* - `access_token`: a short-lived JWT from the interactive login flow.
|
|
8
10
|
* Used by TopoloCli after `topolo auth login`.
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
* PKCE flow in TopoloAuth. Those will plug in as a third variant.
|
|
11
|
+
* - `dpop_access_token`: a short-lived delegated token bound to an external
|
|
12
|
+
* agent installation key. Every request proves possession of that key.
|
|
12
13
|
*/
|
|
13
14
|
type TopoloCredential = {
|
|
14
15
|
kind: 'api_key';
|
|
@@ -18,6 +19,11 @@ type TopoloCredential = {
|
|
|
18
19
|
accessToken: string;
|
|
19
20
|
refreshToken?: string;
|
|
20
21
|
expiresAt?: number;
|
|
22
|
+
} | {
|
|
23
|
+
kind: 'dpop_access_token';
|
|
24
|
+
accessToken: string;
|
|
25
|
+
privateJwk: JsonWebKey;
|
|
26
|
+
expiresAt?: number;
|
|
21
27
|
};
|
|
22
28
|
|
|
23
29
|
declare const TOPOLO_RUNTIME_ENVIRONMENTS: readonly ["production", "staging", "development", "local"];
|
|
@@ -25,6 +31,48 @@ type TopoloRuntimeEnvironment = (typeof TOPOLO_RUNTIME_ENVIRONMENTS)[number];
|
|
|
25
31
|
declare function assertTopoloServiceUrlEnvironment(service: string, value: string, environment: TopoloRuntimeEnvironment): string;
|
|
26
32
|
declare function topoloServiceOrigins(serviceUrls: Record<string, string> | undefined, environment: TopoloRuntimeEnvironment): Record<string, string>;
|
|
27
33
|
|
|
34
|
+
interface ExternalAgentInstallation {
|
|
35
|
+
id: string;
|
|
36
|
+
environment: TopoloRuntimeEnvironment;
|
|
37
|
+
organizationId: string;
|
|
38
|
+
principalId: string;
|
|
39
|
+
credentialId: string;
|
|
40
|
+
clientId: string;
|
|
41
|
+
displayName: string;
|
|
42
|
+
provider: string;
|
|
43
|
+
host: string;
|
|
44
|
+
model?: string;
|
|
45
|
+
dpopJkt: string;
|
|
46
|
+
createdAt: string;
|
|
47
|
+
}
|
|
48
|
+
interface ExternalAgentInstallationSecret {
|
|
49
|
+
clientSecret: string;
|
|
50
|
+
privateJwk: JsonWebKey;
|
|
51
|
+
}
|
|
52
|
+
interface InstallationSecretBackend {
|
|
53
|
+
set(account: string, value: string): Promise<void>;
|
|
54
|
+
get(account: string): Promise<string | null>;
|
|
55
|
+
delete(account: string): Promise<void>;
|
|
56
|
+
}
|
|
57
|
+
type Spawn = (command: string, args: string[], options: {
|
|
58
|
+
input?: string;
|
|
59
|
+
encoding: 'utf8';
|
|
60
|
+
env?: NodeJS.ProcessEnv;
|
|
61
|
+
}) => SpawnSyncReturns<string>;
|
|
62
|
+
declare function installationStorePath(): string;
|
|
63
|
+
declare function createPlatformInstallationSecretBackend(options?: {
|
|
64
|
+
platform?: NodeJS.Platform;
|
|
65
|
+
spawn?: Spawn;
|
|
66
|
+
root?: string;
|
|
67
|
+
}): InstallationSecretBackend;
|
|
68
|
+
declare function writeExternalAgentInstallation(installation: ExternalAgentInstallation, secret: ExternalAgentInstallationSecret, backend?: InstallationSecretBackend): Promise<void>;
|
|
69
|
+
declare function readExternalAgentInstallation(environment: TopoloRuntimeEnvironment, id: string, backend?: InstallationSecretBackend): Promise<{
|
|
70
|
+
installation: ExternalAgentInstallation;
|
|
71
|
+
secret: ExternalAgentInstallationSecret;
|
|
72
|
+
} | null>;
|
|
73
|
+
declare function listExternalAgentInstallations(environment: TopoloRuntimeEnvironment): Promise<ExternalAgentInstallation[]>;
|
|
74
|
+
declare function deleteExternalAgentInstallation(environment: TopoloRuntimeEnvironment, id: string, backend?: InstallationSecretBackend): Promise<void>;
|
|
75
|
+
|
|
28
76
|
/**
|
|
29
77
|
* Node-only credential store shared by the `topolo` CLI and `@topolo/mcp`.
|
|
30
78
|
*
|
|
@@ -118,4 +166,4 @@ declare function resolveServiceUrls(configUrls?: Record<string, string>, environ
|
|
|
118
166
|
declare function assertServiceUrlForEnvironment(service: string, serviceUrl: string | undefined, environment?: TopoloEnvironment): void;
|
|
119
167
|
declare function resolvedProfileConfig(config: TopoloConfig, environment?: TopoloEnvironment): TopoloEnvironmentProfile;
|
|
120
168
|
|
|
121
|
-
export { ENVIRONMENT_DEFAULT_SERVICE_URLS, TOPOLO_ENVIRONMENTS, type TopoloConfig, type TopoloContextCredential, type TopoloEnvironment, type TopoloEnvironmentProfile, activateContext, assertServiceUrlForEnvironment, assertTopoloServiceUrlEnvironment, clearProfileCredential, configPath, contextKey, credentialSourceFromConfig, envVarPrefix, normalizeEnvironment, profileForEnvironment, readConfig, refreshContextCredentialIfNeeded, refreshCredentialIfNeeded, resolveAgentName, resolveCredential, resolveServiceUrls, resolvedProfileConfig, selectedEnvironment, topoloServiceOrigins, writeConfig, writeContextCredential, writeProfileConfig };
|
|
169
|
+
export { ENVIRONMENT_DEFAULT_SERVICE_URLS, type ExternalAgentInstallation, type ExternalAgentInstallationSecret, type InstallationSecretBackend, TOPOLO_ENVIRONMENTS, type TopoloConfig, type TopoloContextCredential, type TopoloEnvironment, type TopoloEnvironmentProfile, activateContext, assertServiceUrlForEnvironment, assertTopoloServiceUrlEnvironment, clearProfileCredential, configPath, contextKey, createPlatformInstallationSecretBackend, credentialSourceFromConfig, deleteExternalAgentInstallation, envVarPrefix, installationStorePath, listExternalAgentInstallations, normalizeEnvironment, profileForEnvironment, readConfig, readExternalAgentInstallation, refreshContextCredentialIfNeeded, refreshCredentialIfNeeded, resolveAgentName, resolveCredential, resolveServiceUrls, resolvedProfileConfig, selectedEnvironment, topoloServiceOrigins, writeConfig, writeContextCredential, writeExternalAgentInstallation, writeProfileConfig };
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
// src/node/credential-store.ts
|
|
2
|
-
import { mkdir, readFile, writeFile, chmod, rm, stat } from "fs/promises";
|
|
3
|
-
import { existsSync } from "fs";
|
|
4
|
-
import { homedir, platform } from "os";
|
|
5
|
-
import { dirname, join } from "path";
|
|
2
|
+
import { mkdir as mkdir2, readFile as readFile2, writeFile as writeFile2, chmod as chmod2, rm as rm2, stat } from "fs/promises";
|
|
3
|
+
import { existsSync as existsSync2 } from "fs";
|
|
4
|
+
import { homedir as homedir2, platform } from "os";
|
|
5
|
+
import { dirname as dirname2, join as join2 } from "path";
|
|
6
6
|
|
|
7
7
|
// src/errors.ts
|
|
8
8
|
var TopoloSdkError = class extends Error {
|
|
@@ -421,6 +421,172 @@ function topoloServiceOrigins(serviceUrls, environment) {
|
|
|
421
421
|
);
|
|
422
422
|
}
|
|
423
423
|
|
|
424
|
+
// src/node/installation-store.ts
|
|
425
|
+
import { spawnSync } from "child_process";
|
|
426
|
+
import { mkdir, readFile, readdir, rename, rm, writeFile, chmod } from "fs/promises";
|
|
427
|
+
import { existsSync } from "fs";
|
|
428
|
+
import { homedir, platform as hostPlatform } from "os";
|
|
429
|
+
import { dirname, join } from "path";
|
|
430
|
+
var KEYCHAIN_SERVICE = "topolo-external-agent-installation";
|
|
431
|
+
function installationStorePath() {
|
|
432
|
+
const override = process.env.TOPOLO_INSTALLATIONS_PATH?.trim();
|
|
433
|
+
if (override) return override;
|
|
434
|
+
const base = process.env.XDG_CONFIG_HOME || (hostPlatform() === "win32" ? join(homedir(), "AppData", "Roaming") : join(homedir(), ".config"));
|
|
435
|
+
return join(base, "topolo", "installations");
|
|
436
|
+
}
|
|
437
|
+
function installationPath(environment, id) {
|
|
438
|
+
if (!/^[A-Za-z0-9_-]+$/.test(id)) throw new TypeError("Installation id contains unsupported characters.");
|
|
439
|
+
return join(installationStorePath(), environment, `${id}.json`);
|
|
440
|
+
}
|
|
441
|
+
function accountName(environment, id) {
|
|
442
|
+
return `${environment}:${id}`;
|
|
443
|
+
}
|
|
444
|
+
function runOrThrow(result, operation) {
|
|
445
|
+
if (result.status !== 0) {
|
|
446
|
+
throw new Error(`${operation} failed: ${(result.stderr || result.error?.message || "platform credential store unavailable").trim()}`);
|
|
447
|
+
}
|
|
448
|
+
return result.stdout.trim();
|
|
449
|
+
}
|
|
450
|
+
function createPlatformInstallationSecretBackend(options = {}) {
|
|
451
|
+
const platform2 = options.platform ?? hostPlatform();
|
|
452
|
+
const spawn = options.spawn ?? ((command, args, spawnOptions) => spawnSync(command, args, spawnOptions));
|
|
453
|
+
const root = options.root ?? installationStorePath();
|
|
454
|
+
if (platform2 === "darwin") {
|
|
455
|
+
return {
|
|
456
|
+
async set(account, value) {
|
|
457
|
+
runOrThrow(spawn("security", [
|
|
458
|
+
"add-generic-password",
|
|
459
|
+
"-U",
|
|
460
|
+
"-a",
|
|
461
|
+
account,
|
|
462
|
+
"-s",
|
|
463
|
+
KEYCHAIN_SERVICE,
|
|
464
|
+
"-w"
|
|
465
|
+
], { input: `${value}
|
|
466
|
+
`, encoding: "utf8" }), "macOS Keychain write");
|
|
467
|
+
},
|
|
468
|
+
async get(account) {
|
|
469
|
+
const result = spawn("security", [
|
|
470
|
+
"find-generic-password",
|
|
471
|
+
"-a",
|
|
472
|
+
account,
|
|
473
|
+
"-s",
|
|
474
|
+
KEYCHAIN_SERVICE,
|
|
475
|
+
"-w"
|
|
476
|
+
], { encoding: "utf8" });
|
|
477
|
+
if (result.status === 44) return null;
|
|
478
|
+
return runOrThrow(result, "macOS Keychain read");
|
|
479
|
+
},
|
|
480
|
+
async delete(account) {
|
|
481
|
+
const result = spawn("security", [
|
|
482
|
+
"delete-generic-password",
|
|
483
|
+
"-a",
|
|
484
|
+
account,
|
|
485
|
+
"-s",
|
|
486
|
+
KEYCHAIN_SERVICE
|
|
487
|
+
], { encoding: "utf8" });
|
|
488
|
+
if (result.status !== 44) runOrThrow(result, "macOS Keychain delete");
|
|
489
|
+
}
|
|
490
|
+
};
|
|
491
|
+
}
|
|
492
|
+
if (platform2 === "linux") {
|
|
493
|
+
return {
|
|
494
|
+
async set(account, value) {
|
|
495
|
+
runOrThrow(spawn("secret-tool", [
|
|
496
|
+
"store",
|
|
497
|
+
"--label=Topolo external agent installation",
|
|
498
|
+
"service",
|
|
499
|
+
KEYCHAIN_SERVICE,
|
|
500
|
+
"account",
|
|
501
|
+
account
|
|
502
|
+
], { input: value, encoding: "utf8" }), "Linux Secret Service write");
|
|
503
|
+
},
|
|
504
|
+
async get(account) {
|
|
505
|
+
const result = spawn("secret-tool", [
|
|
506
|
+
"lookup",
|
|
507
|
+
"service",
|
|
508
|
+
KEYCHAIN_SERVICE,
|
|
509
|
+
"account",
|
|
510
|
+
account
|
|
511
|
+
], { encoding: "utf8" });
|
|
512
|
+
if (result.status === 1) return null;
|
|
513
|
+
return runOrThrow(result, "Linux Secret Service read");
|
|
514
|
+
},
|
|
515
|
+
async delete(account) {
|
|
516
|
+
const result = spawn("secret-tool", [
|
|
517
|
+
"clear",
|
|
518
|
+
"service",
|
|
519
|
+
KEYCHAIN_SERVICE,
|
|
520
|
+
"account",
|
|
521
|
+
account
|
|
522
|
+
], { encoding: "utf8" });
|
|
523
|
+
if (result.status !== 1) runOrThrow(result, "Linux Secret Service delete");
|
|
524
|
+
}
|
|
525
|
+
};
|
|
526
|
+
}
|
|
527
|
+
if (platform2 === "win32") {
|
|
528
|
+
const secretPath = (account) => join(root, ".secrets", `${account.replace(":", "-")}.bin`);
|
|
529
|
+
const powershell = (script, path, input) => spawn(
|
|
530
|
+
"powershell.exe",
|
|
531
|
+
["-NoProfile", "-NonInteractive", "-Command", script],
|
|
532
|
+
{ input, encoding: "utf8", env: { ...process.env, TOPOLO_SECRET_PATH: path } }
|
|
533
|
+
);
|
|
534
|
+
return {
|
|
535
|
+
async set(account, value) {
|
|
536
|
+
const path = secretPath(account);
|
|
537
|
+
await mkdir(dirname(path), { recursive: true });
|
|
538
|
+
const script = "$p=$env:TOPOLO_SECRET_PATH;$v=[Console]::In.ReadToEnd();$b=[Text.Encoding]::UTF8.GetBytes($v);$e=[Security.Cryptography.ProtectedData]::Protect($b,$null,[Security.Cryptography.DataProtectionScope]::CurrentUser);[IO.File]::WriteAllBytes($p,$e)";
|
|
539
|
+
runOrThrow(powershell(script, path, value), "Windows DPAPI write");
|
|
540
|
+
},
|
|
541
|
+
async get(account) {
|
|
542
|
+
const path = secretPath(account);
|
|
543
|
+
if (!existsSync(path)) return null;
|
|
544
|
+
const script = "$p=$env:TOPOLO_SECRET_PATH;$b=[IO.File]::ReadAllBytes($p);$d=[Security.Cryptography.ProtectedData]::Unprotect($b,$null,[Security.Cryptography.DataProtectionScope]::CurrentUser);[Console]::Out.Write([Text.Encoding]::UTF8.GetString($d))";
|
|
545
|
+
return runOrThrow(powershell(script, path), "Windows DPAPI read");
|
|
546
|
+
},
|
|
547
|
+
async delete(account) {
|
|
548
|
+
await rm(secretPath(account), { force: true });
|
|
549
|
+
}
|
|
550
|
+
};
|
|
551
|
+
}
|
|
552
|
+
throw new Error(`Secure external-agent installation storage is unsupported on ${platform2}.`);
|
|
553
|
+
}
|
|
554
|
+
async function writeExternalAgentInstallation(installation, secret, backend = createPlatformInstallationSecretBackend()) {
|
|
555
|
+
const path = installationPath(installation.environment, installation.id);
|
|
556
|
+
await backend.set(accountName(installation.environment, installation.id), JSON.stringify(secret));
|
|
557
|
+
const temporary = `${path}.${process.pid}.tmp`;
|
|
558
|
+
try {
|
|
559
|
+
await mkdir(dirname(path), { recursive: true, mode: 448 });
|
|
560
|
+
await writeFile(temporary, `${JSON.stringify(installation, null, 2)}
|
|
561
|
+
`, { encoding: "utf8", mode: 384 });
|
|
562
|
+
await rename(temporary, path);
|
|
563
|
+
if (hostPlatform() !== "win32") await chmod(path, 384);
|
|
564
|
+
} catch (error) {
|
|
565
|
+
await backend.delete(accountName(installation.environment, installation.id)).catch(() => void 0);
|
|
566
|
+
await rm(temporary, { force: true });
|
|
567
|
+
throw error;
|
|
568
|
+
}
|
|
569
|
+
}
|
|
570
|
+
async function readExternalAgentInstallation(environment, id, backend = createPlatformInstallationSecretBackend()) {
|
|
571
|
+
const path = installationPath(environment, id);
|
|
572
|
+
if (!existsSync(path)) return null;
|
|
573
|
+
const installation = JSON.parse(await readFile(path, "utf8"));
|
|
574
|
+
const encodedSecret = await backend.get(accountName(environment, id));
|
|
575
|
+
if (!encodedSecret) throw new Error(`Protected secret is missing for installation ${id}.`);
|
|
576
|
+
return { installation, secret: JSON.parse(encodedSecret) };
|
|
577
|
+
}
|
|
578
|
+
async function listExternalAgentInstallations(environment) {
|
|
579
|
+
const directory = join(installationStorePath(), environment);
|
|
580
|
+
if (!existsSync(directory)) return [];
|
|
581
|
+
const entries = await readdir(directory, { withFileTypes: true });
|
|
582
|
+
const installations = await Promise.all(entries.filter((entry) => entry.isFile() && entry.name.endsWith(".json")).map(async (entry) => JSON.parse(await readFile(join(directory, entry.name), "utf8"))));
|
|
583
|
+
return installations.sort((left, right) => left.createdAt.localeCompare(right.createdAt));
|
|
584
|
+
}
|
|
585
|
+
async function deleteExternalAgentInstallation(environment, id, backend = createPlatformInstallationSecretBackend()) {
|
|
586
|
+
await backend.delete(accountName(environment, id));
|
|
587
|
+
await rm(installationPath(environment, id), { force: true });
|
|
588
|
+
}
|
|
589
|
+
|
|
424
590
|
// src/node/credential-store.ts
|
|
425
591
|
var TOPOLO_ENVIRONMENTS = TOPOLO_RUNTIME_ENVIRONMENTS;
|
|
426
592
|
function contextKey(contextType, organizationId) {
|
|
@@ -430,14 +596,14 @@ var ENVIRONMENT_DEFAULT_SERVICE_URLS = TOPOLO_ENVIRONMENT_SERVICE_URLS;
|
|
|
430
596
|
function configPath() {
|
|
431
597
|
const override = process.env.TOPOLO_CONFIG_PATH;
|
|
432
598
|
if (override) return override;
|
|
433
|
-
const base = process.env.XDG_CONFIG_HOME || (platform() === "win32" ?
|
|
434
|
-
return
|
|
599
|
+
const base = process.env.XDG_CONFIG_HOME || (platform() === "win32" ? join2(homedir2(), "AppData", "Roaming") : join2(homedir2(), ".config"));
|
|
600
|
+
return join2(base, "topolo", "config.json");
|
|
435
601
|
}
|
|
436
602
|
async function readConfig() {
|
|
437
603
|
const path = configPath();
|
|
438
|
-
if (!
|
|
604
|
+
if (!existsSync2(path)) return {};
|
|
439
605
|
try {
|
|
440
|
-
const raw = await
|
|
606
|
+
const raw = await readFile2(path, "utf8");
|
|
441
607
|
return JSON.parse(raw);
|
|
442
608
|
} catch {
|
|
443
609
|
return {};
|
|
@@ -445,11 +611,11 @@ async function readConfig() {
|
|
|
445
611
|
}
|
|
446
612
|
async function writeConfig(config) {
|
|
447
613
|
const path = configPath();
|
|
448
|
-
await
|
|
449
|
-
await
|
|
614
|
+
await mkdir2(dirname2(path), { recursive: true });
|
|
615
|
+
await writeFile2(path, JSON.stringify(config, null, 2) + "\n", "utf8");
|
|
450
616
|
if (platform() !== "win32") {
|
|
451
617
|
try {
|
|
452
|
-
await
|
|
618
|
+
await chmod2(path, 384);
|
|
453
619
|
} catch {
|
|
454
620
|
}
|
|
455
621
|
}
|
|
@@ -565,18 +731,18 @@ var CONFIG_LOCK_TIMEOUT_MS = 5e3;
|
|
|
565
731
|
var CONFIG_LOCK_STALE_MS = 12e4;
|
|
566
732
|
async function withConfigWriteLock(operation) {
|
|
567
733
|
const lockPath = `${configPath()}.lock`;
|
|
568
|
-
await
|
|
734
|
+
await mkdir2(dirname2(lockPath), { recursive: true });
|
|
569
735
|
const startedAt = Date.now();
|
|
570
736
|
while (true) {
|
|
571
737
|
try {
|
|
572
|
-
await
|
|
738
|
+
await mkdir2(lockPath);
|
|
573
739
|
break;
|
|
574
740
|
} catch (error) {
|
|
575
741
|
if (error.code !== "EEXIST") throw error;
|
|
576
742
|
try {
|
|
577
743
|
const lock = await stat(lockPath);
|
|
578
744
|
if (Date.now() - lock.mtimeMs > CONFIG_LOCK_STALE_MS) {
|
|
579
|
-
await
|
|
745
|
+
await rm2(lockPath, { recursive: true, force: true });
|
|
580
746
|
continue;
|
|
581
747
|
}
|
|
582
748
|
} catch (inspectionError) {
|
|
@@ -592,7 +758,7 @@ async function withConfigWriteLock(operation) {
|
|
|
592
758
|
try {
|
|
593
759
|
return await operation();
|
|
594
760
|
} finally {
|
|
595
|
-
await
|
|
761
|
+
await rm2(lockPath, { recursive: true, force: true });
|
|
596
762
|
}
|
|
597
763
|
}
|
|
598
764
|
async function refreshCredentialIfNeeded(environment = selectedEnvironment(), options = {}) {
|
|
@@ -740,11 +906,16 @@ export {
|
|
|
740
906
|
clearProfileCredential,
|
|
741
907
|
configPath,
|
|
742
908
|
contextKey,
|
|
909
|
+
createPlatformInstallationSecretBackend,
|
|
743
910
|
credentialSourceFromConfig,
|
|
911
|
+
deleteExternalAgentInstallation,
|
|
744
912
|
envVarPrefix,
|
|
913
|
+
installationStorePath,
|
|
914
|
+
listExternalAgentInstallations,
|
|
745
915
|
normalizeEnvironment,
|
|
746
916
|
profileForEnvironment,
|
|
747
917
|
readConfig,
|
|
918
|
+
readExternalAgentInstallation,
|
|
748
919
|
refreshContextCredentialIfNeeded,
|
|
749
920
|
refreshCredentialIfNeeded,
|
|
750
921
|
resolveAgentName,
|
|
@@ -755,5 +926,6 @@ export {
|
|
|
755
926
|
topoloServiceOrigins,
|
|
756
927
|
writeConfig,
|
|
757
928
|
writeContextCredential,
|
|
929
|
+
writeExternalAgentInstallation,
|
|
758
930
|
writeProfileConfig
|
|
759
931
|
};
|
package/package.json
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@topolo/sdk",
|
|
3
3
|
"packageManager": "pnpm@10.17.1",
|
|
4
|
-
"version": "0.
|
|
5
|
-
"topoloPublishedVersion": "0.
|
|
4
|
+
"version": "0.20.0",
|
|
5
|
+
"topoloPublishedVersion": "0.20.0",
|
|
6
6
|
"description": "Typed client SDK for the Topolo platform. Used by TopoloCli, TopoloMCP, and third-party agents.",
|
|
7
7
|
"license": "UNLICENSED",
|
|
8
8
|
"author": "Topolo",
|