@topolo/sdk 0.21.1 → 0.21.3
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 +246 -171
- package/dist/index.d.cts +11 -1
- package/dist/index.d.ts +11 -1
- package/dist/index.js +246 -171
- package/dist/node/credential-store.cjs +193 -99
- package/dist/node/credential-store.d.cts +51 -1
- package/dist/node/credential-store.d.ts +51 -1
- package/dist/node/credential-store.js +190 -97
- package/package.json +2 -2
|
@@ -29,6 +29,7 @@ __export(credential_store_exports, {
|
|
|
29
29
|
configPath: () => configPath,
|
|
30
30
|
contextKey: () => contextKey,
|
|
31
31
|
createPlatformInstallationSecretBackend: () => createPlatformInstallationSecretBackend,
|
|
32
|
+
createProtectedActionSecretStore: () => createProtectedActionSecretStore,
|
|
32
33
|
credentialSourceFromConfig: () => credentialSourceFromConfig,
|
|
33
34
|
deleteExternalAgentInstallation: () => deleteExternalAgentInstallation,
|
|
34
35
|
envVarPrefix: () => envVarPrefix,
|
|
@@ -55,7 +56,7 @@ module.exports = __toCommonJS(credential_store_exports);
|
|
|
55
56
|
var import_promises2 = require("fs/promises");
|
|
56
57
|
var import_node_fs2 = require("fs");
|
|
57
58
|
var import_node_os2 = require("os");
|
|
58
|
-
var
|
|
59
|
+
var import_node_path3 = require("path");
|
|
59
60
|
|
|
60
61
|
// src/errors.ts
|
|
61
62
|
var TopoloSdkError = class extends Error {
|
|
@@ -411,68 +412,12 @@ var TopoloOAuth = class {
|
|
|
411
412
|
}
|
|
412
413
|
};
|
|
413
414
|
|
|
414
|
-
// src/
|
|
415
|
-
var
|
|
416
|
-
var
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
},
|
|
421
|
-
staging: {
|
|
422
|
-
auth: "https://auth.stg.topolo.us",
|
|
423
|
-
developers: "https://developers.stg.topolo.us"
|
|
424
|
-
},
|
|
425
|
-
development: {
|
|
426
|
-
auth: "https://auth.topolo.dev",
|
|
427
|
-
developers: "https://developers.topolo.dev"
|
|
428
|
-
},
|
|
429
|
-
local: {}
|
|
430
|
-
};
|
|
431
|
-
function hostnameHasSuffix(hostname, suffix) {
|
|
432
|
-
return hostname === suffix || hostname.endsWith(`.${suffix}`);
|
|
433
|
-
}
|
|
434
|
-
function workersDevAccountMatches(hostname, account) {
|
|
435
|
-
if (!hostname.endsWith(".workers.dev")) return false;
|
|
436
|
-
const labels = hostname.slice(0, -".workers.dev".length).split(".");
|
|
437
|
-
return labels.length >= 2 && labels.at(-1) === account;
|
|
438
|
-
}
|
|
439
|
-
function originMatchesEnvironment(url, environment) {
|
|
440
|
-
const hostname = url.hostname.toLowerCase();
|
|
441
|
-
if (environment === "local") {
|
|
442
|
-
return hostname === "localhost" || hostname.endsWith(".localhost") || hostname === "127.0.0.1" || hostname === "[::1]";
|
|
443
|
-
}
|
|
444
|
-
if (url.protocol !== "https:") return false;
|
|
445
|
-
if (environment === "production") {
|
|
446
|
-
return hostnameHasSuffix(hostname, "topolo.app") || hostnameHasSuffix(hostname, "topolo.io") || hostname === "api.ol0.me" || workersDevAccountMatches(hostname, "topolo");
|
|
447
|
-
}
|
|
448
|
-
if (environment === "staging") {
|
|
449
|
-
return hostnameHasSuffix(hostname, "stg.topolo.us") || workersDevAccountMatches(hostname, "topolo-staging");
|
|
450
|
-
}
|
|
451
|
-
return hostnameHasSuffix(hostname, "topolo.dev") || workersDevAccountMatches(hostname, "topolo-development");
|
|
452
|
-
}
|
|
453
|
-
function assertTopoloServiceUrlEnvironment(service, value, environment) {
|
|
454
|
-
let url;
|
|
455
|
-
try {
|
|
456
|
-
url = new URL(value);
|
|
457
|
-
} catch {
|
|
458
|
-
throw new TopoloSdkError("invalid_service_url", `Invalid URL configured for Topolo service "${service}".`);
|
|
459
|
-
}
|
|
460
|
-
if (url.protocol !== "https:" && url.protocol !== "http:" || url.username || url.password || !originMatchesEnvironment(url, environment)) {
|
|
461
|
-
throw new TopoloSdkError(
|
|
462
|
-
"environment_mismatch",
|
|
463
|
-
`Refusing Topolo service "${service}": ${url.origin} does not belong to ${environment}.`
|
|
464
|
-
);
|
|
465
|
-
}
|
|
466
|
-
return url.origin;
|
|
467
|
-
}
|
|
468
|
-
function topoloServiceOrigins(serviceUrls, environment) {
|
|
469
|
-
return Object.fromEntries(
|
|
470
|
-
Object.entries(serviceUrls ?? {}).sort(([left], [right]) => left.localeCompare(right)).map(([service, value]) => [
|
|
471
|
-
service,
|
|
472
|
-
assertTopoloServiceUrlEnvironment(service, value, environment)
|
|
473
|
-
])
|
|
474
|
-
);
|
|
475
|
-
}
|
|
415
|
+
// src/node/action-secret-store.ts
|
|
416
|
+
var import_node_crypto = require("crypto");
|
|
417
|
+
var import_node_path2 = require("path");
|
|
418
|
+
|
|
419
|
+
// src/action-secrets.ts
|
|
420
|
+
var ACTION_SECRET_PREFIX = "topolo-secret:";
|
|
476
421
|
|
|
477
422
|
// src/node/installation-store.ts
|
|
478
423
|
var import_node_child_process = require("child_process");
|
|
@@ -481,6 +426,8 @@ var import_node_fs = require("fs");
|
|
|
481
426
|
var import_node_os = require("os");
|
|
482
427
|
var import_node_path = require("path");
|
|
483
428
|
var KEYCHAIN_SERVICE = "topolo-external-agent-installation";
|
|
429
|
+
var MACOS_KEYCHAIN_CHUNK_SIZE = 96;
|
|
430
|
+
var MACOS_KEYCHAIN_CHUNK_PREFIX = "topolo-keychain-chunks:v1:";
|
|
484
431
|
var MACOS_KEYCHAIN_WRITE_SCRIPT = [
|
|
485
432
|
"log_user 0",
|
|
486
433
|
"set timeout 10",
|
|
@@ -520,41 +467,75 @@ function createPlatformInstallationSecretBackend(options = {}) {
|
|
|
520
467
|
const platform2 = options.platform ?? (0, import_node_os.platform)();
|
|
521
468
|
const spawn = options.spawn ?? ((command, args, spawnOptions) => (0, import_node_child_process.spawnSync)(command, args, spawnOptions));
|
|
522
469
|
const root = options.root ?? installationStorePath();
|
|
470
|
+
const service = options.service ?? KEYCHAIN_SERVICE;
|
|
523
471
|
if (platform2 === "darwin") {
|
|
472
|
+
const write = (account, value) => runOrThrow(spawn("/usr/bin/expect", ["-c", MACOS_KEYCHAIN_WRITE_SCRIPT], {
|
|
473
|
+
input: `${value}
|
|
474
|
+
`,
|
|
475
|
+
encoding: "utf8",
|
|
476
|
+
env: {
|
|
477
|
+
...process.env,
|
|
478
|
+
TOPOLO_KEYCHAIN_ACCOUNT: account,
|
|
479
|
+
TOPOLO_KEYCHAIN_SERVICE: service
|
|
480
|
+
}
|
|
481
|
+
}), "macOS Keychain write");
|
|
482
|
+
const read = (account) => {
|
|
483
|
+
const result = spawn("security", [
|
|
484
|
+
"find-generic-password",
|
|
485
|
+
"-a",
|
|
486
|
+
account,
|
|
487
|
+
"-s",
|
|
488
|
+
service,
|
|
489
|
+
"-w"
|
|
490
|
+
], { encoding: "utf8" });
|
|
491
|
+
if (result.status === 44) return null;
|
|
492
|
+
return runOrThrow(result, "macOS Keychain read");
|
|
493
|
+
};
|
|
494
|
+
const remove = (account) => {
|
|
495
|
+
const result = spawn("security", [
|
|
496
|
+
"delete-generic-password",
|
|
497
|
+
"-a",
|
|
498
|
+
account,
|
|
499
|
+
"-s",
|
|
500
|
+
service
|
|
501
|
+
], { encoding: "utf8" });
|
|
502
|
+
if (result.status !== 44) runOrThrow(result, "macOS Keychain delete");
|
|
503
|
+
};
|
|
504
|
+
const chunkAccount = (account, index) => `${account}:chunk:${index}`;
|
|
505
|
+
const chunkCount = (value) => {
|
|
506
|
+
if (!value?.startsWith(MACOS_KEYCHAIN_CHUNK_PREFIX)) return 0;
|
|
507
|
+
const count = Number(value.slice(MACOS_KEYCHAIN_CHUNK_PREFIX.length));
|
|
508
|
+
if (!Number.isSafeInteger(count) || count < 1) throw new Error("macOS Keychain chunk manifest is invalid.");
|
|
509
|
+
return count;
|
|
510
|
+
};
|
|
524
511
|
return {
|
|
525
512
|
async set(account, value) {
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
}
|
|
513
|
+
const previousCount = chunkCount(read(account));
|
|
514
|
+
const chunks = Array.from(
|
|
515
|
+
{ length: Math.max(1, Math.ceil(value.length / MACOS_KEYCHAIN_CHUNK_SIZE)) },
|
|
516
|
+
(_, index) => value.slice(index * MACOS_KEYCHAIN_CHUNK_SIZE, (index + 1) * MACOS_KEYCHAIN_CHUNK_SIZE)
|
|
517
|
+
);
|
|
518
|
+
try {
|
|
519
|
+
chunks.forEach((chunk, index) => write(chunkAccount(account, index), chunk));
|
|
520
|
+
write(account, `${MACOS_KEYCHAIN_CHUNK_PREFIX}${chunks.length}`);
|
|
521
|
+
for (let index = chunks.length; index < previousCount; index += 1) remove(chunkAccount(account, index));
|
|
522
|
+
} catch (error) {
|
|
523
|
+
chunks.forEach((_, index) => remove(chunkAccount(account, index)));
|
|
524
|
+
throw error;
|
|
525
|
+
}
|
|
536
526
|
},
|
|
537
527
|
async get(account) {
|
|
538
|
-
const
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
"-w"
|
|
545
|
-
], { encoding: "utf8" });
|
|
546
|
-
if (result.status === 44) return null;
|
|
547
|
-
return runOrThrow(result, "macOS Keychain read");
|
|
528
|
+
const manifest = read(account);
|
|
529
|
+
const count = chunkCount(manifest);
|
|
530
|
+
if (!count) return manifest;
|
|
531
|
+
const chunks = Array.from({ length: count }, (_, index) => read(chunkAccount(account, index)));
|
|
532
|
+
if (chunks.some((chunk) => chunk === null)) throw new Error("macOS Keychain installation secret is incomplete.");
|
|
533
|
+
return chunks.join("");
|
|
548
534
|
},
|
|
549
535
|
async delete(account) {
|
|
550
|
-
const
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
account,
|
|
554
|
-
"-s",
|
|
555
|
-
KEYCHAIN_SERVICE
|
|
556
|
-
], { encoding: "utf8" });
|
|
557
|
-
if (result.status !== 44) runOrThrow(result, "macOS Keychain delete");
|
|
536
|
+
const count = chunkCount(read(account));
|
|
537
|
+
for (let index = 0; index < count; index += 1) remove(chunkAccount(account, index));
|
|
538
|
+
remove(account);
|
|
558
539
|
}
|
|
559
540
|
};
|
|
560
541
|
}
|
|
@@ -563,9 +544,9 @@ function createPlatformInstallationSecretBackend(options = {}) {
|
|
|
563
544
|
async set(account, value) {
|
|
564
545
|
runOrThrow(spawn("secret-tool", [
|
|
565
546
|
"store",
|
|
566
|
-
"--label=Topolo
|
|
547
|
+
"--label=Topolo protected credential",
|
|
567
548
|
"service",
|
|
568
|
-
|
|
549
|
+
service,
|
|
569
550
|
"account",
|
|
570
551
|
account
|
|
571
552
|
], { input: value, encoding: "utf8" }), "Linux Secret Service write");
|
|
@@ -574,7 +555,7 @@ function createPlatformInstallationSecretBackend(options = {}) {
|
|
|
574
555
|
const result = spawn("secret-tool", [
|
|
575
556
|
"lookup",
|
|
576
557
|
"service",
|
|
577
|
-
|
|
558
|
+
service,
|
|
578
559
|
"account",
|
|
579
560
|
account
|
|
580
561
|
], { encoding: "utf8" });
|
|
@@ -585,7 +566,7 @@ function createPlatformInstallationSecretBackend(options = {}) {
|
|
|
585
566
|
const result = spawn("secret-tool", [
|
|
586
567
|
"clear",
|
|
587
568
|
"service",
|
|
588
|
-
|
|
569
|
+
service,
|
|
589
570
|
"account",
|
|
590
571
|
account
|
|
591
572
|
], { encoding: "utf8" });
|
|
@@ -656,6 +637,118 @@ async function deleteExternalAgentInstallation(environment, id, backend = create
|
|
|
656
637
|
await (0, import_promises.rm)(installationPath(environment, id), { force: true });
|
|
657
638
|
}
|
|
658
639
|
|
|
640
|
+
// src/node/action-secret-store.ts
|
|
641
|
+
function createProtectedActionSecretStore(options) {
|
|
642
|
+
const backend = options.backend ?? createPlatformInstallationSecretBackend({
|
|
643
|
+
service: "topolo-action-handoff",
|
|
644
|
+
root: (0, import_node_path2.join)(installationStorePath(), "action-handoff")
|
|
645
|
+
});
|
|
646
|
+
const now = options.now ?? Date.now;
|
|
647
|
+
async function account(reference) {
|
|
648
|
+
if (!/^topolo-secret:[0-9a-f-]{36}$/.test(reference)) throw new TopoloSdkError("invalid_action_secret_reference", "Invalid protected action reference.");
|
|
649
|
+
const identity = await options.identity();
|
|
650
|
+
if (!identity.user.id) throw new TopoloSdkError("action_secret_identity_required", "A verified identity is required for protected action handoff.");
|
|
651
|
+
if (identity.kind === "api_key" && !identity.apiKey?.id) throw new TopoloSdkError("action_secret_identity_required", "A verified API key identity is required for protected action handoff.");
|
|
652
|
+
const scope = (0, import_node_crypto.createHash)("sha256").update(JSON.stringify([
|
|
653
|
+
options.environment,
|
|
654
|
+
identity.user.principalId ?? identity.user.id,
|
|
655
|
+
identity.organization?.id ?? null,
|
|
656
|
+
identity.apiKey?.id ?? null
|
|
657
|
+
])).digest("hex");
|
|
658
|
+
return `${scope}-${reference.slice(ACTION_SECRET_PREFIX.length)}`;
|
|
659
|
+
}
|
|
660
|
+
return {
|
|
661
|
+
async save(value) {
|
|
662
|
+
const reference = `${ACTION_SECRET_PREFIX}${(0, import_node_crypto.randomUUID)()}`;
|
|
663
|
+
await backend.set(await account(reference), JSON.stringify({ value, expiresAt: now() + 30 * 60 * 1e3 }));
|
|
664
|
+
return reference;
|
|
665
|
+
},
|
|
666
|
+
async load(reference) {
|
|
667
|
+
const key = await account(reference);
|
|
668
|
+
const encoded = await backend.get(key);
|
|
669
|
+
if (!encoded) throw new TopoloSdkError("action_secret_unavailable", "Protected action reference is missing or belongs to another identity or environment.");
|
|
670
|
+
let record;
|
|
671
|
+
try {
|
|
672
|
+
record = JSON.parse(encoded);
|
|
673
|
+
} catch {
|
|
674
|
+
throw new TopoloSdkError("action_secret_invalid", "Protected action reference is corrupt.");
|
|
675
|
+
}
|
|
676
|
+
if (!Number.isFinite(record?.expiresAt) || !Object.hasOwn(record, "value")) throw new TopoloSdkError("action_secret_invalid", "Protected action reference is corrupt.");
|
|
677
|
+
if (record.expiresAt <= now()) {
|
|
678
|
+
await backend.delete(key);
|
|
679
|
+
throw new TopoloSdkError("action_secret_expired", "Protected action reference expired. Repeat the originating action if its contract permits.");
|
|
680
|
+
}
|
|
681
|
+
return record.value;
|
|
682
|
+
},
|
|
683
|
+
async delete(reference) {
|
|
684
|
+
await backend.delete(await account(reference));
|
|
685
|
+
}
|
|
686
|
+
};
|
|
687
|
+
}
|
|
688
|
+
|
|
689
|
+
// src/environment.ts
|
|
690
|
+
var TOPOLO_RUNTIME_ENVIRONMENTS = ["production", "staging", "development", "local"];
|
|
691
|
+
var TOPOLO_ENVIRONMENT_SERVICE_URLS = {
|
|
692
|
+
production: {
|
|
693
|
+
auth: "https://auth.topolo.app",
|
|
694
|
+
developers: "https://developers.topolo.app"
|
|
695
|
+
},
|
|
696
|
+
staging: {
|
|
697
|
+
auth: "https://auth.stg.topolo.us",
|
|
698
|
+
developers: "https://developers.stg.topolo.us"
|
|
699
|
+
},
|
|
700
|
+
development: {
|
|
701
|
+
auth: "https://auth.topolo.dev",
|
|
702
|
+
developers: "https://developers.topolo.dev"
|
|
703
|
+
},
|
|
704
|
+
local: {}
|
|
705
|
+
};
|
|
706
|
+
function hostnameHasSuffix(hostname, suffix) {
|
|
707
|
+
return hostname === suffix || hostname.endsWith(`.${suffix}`);
|
|
708
|
+
}
|
|
709
|
+
function workersDevAccountMatches(hostname, account) {
|
|
710
|
+
if (!hostname.endsWith(".workers.dev")) return false;
|
|
711
|
+
const labels = hostname.slice(0, -".workers.dev".length).split(".");
|
|
712
|
+
return labels.length >= 2 && labels.at(-1) === account;
|
|
713
|
+
}
|
|
714
|
+
function originMatchesEnvironment(url, environment) {
|
|
715
|
+
const hostname = url.hostname.toLowerCase();
|
|
716
|
+
if (environment === "local") {
|
|
717
|
+
return hostname === "localhost" || hostname.endsWith(".localhost") || hostname === "127.0.0.1" || hostname === "[::1]";
|
|
718
|
+
}
|
|
719
|
+
if (url.protocol !== "https:") return false;
|
|
720
|
+
if (environment === "production") {
|
|
721
|
+
return hostnameHasSuffix(hostname, "topolo.app") || hostnameHasSuffix(hostname, "topolo.io") || hostname === "api.ol0.me" || workersDevAccountMatches(hostname, "topolo");
|
|
722
|
+
}
|
|
723
|
+
if (environment === "staging") {
|
|
724
|
+
return hostnameHasSuffix(hostname, "stg.topolo.us") || workersDevAccountMatches(hostname, "topolo-staging");
|
|
725
|
+
}
|
|
726
|
+
return hostnameHasSuffix(hostname, "topolo.dev") || workersDevAccountMatches(hostname, "topolo-development");
|
|
727
|
+
}
|
|
728
|
+
function assertTopoloServiceUrlEnvironment(service, value, environment) {
|
|
729
|
+
let url;
|
|
730
|
+
try {
|
|
731
|
+
url = new URL(value);
|
|
732
|
+
} catch {
|
|
733
|
+
throw new TopoloSdkError("invalid_service_url", `Invalid URL configured for Topolo service "${service}".`);
|
|
734
|
+
}
|
|
735
|
+
if (url.protocol !== "https:" && url.protocol !== "http:" || url.username || url.password || !originMatchesEnvironment(url, environment)) {
|
|
736
|
+
throw new TopoloSdkError(
|
|
737
|
+
"environment_mismatch",
|
|
738
|
+
`Refusing Topolo service "${service}": ${url.origin} does not belong to ${environment}.`
|
|
739
|
+
);
|
|
740
|
+
}
|
|
741
|
+
return url.origin;
|
|
742
|
+
}
|
|
743
|
+
function topoloServiceOrigins(serviceUrls, environment) {
|
|
744
|
+
return Object.fromEntries(
|
|
745
|
+
Object.entries(serviceUrls ?? {}).sort(([left], [right]) => left.localeCompare(right)).map(([service, value]) => [
|
|
746
|
+
service,
|
|
747
|
+
assertTopoloServiceUrlEnvironment(service, value, environment)
|
|
748
|
+
])
|
|
749
|
+
);
|
|
750
|
+
}
|
|
751
|
+
|
|
659
752
|
// src/node/credential-store.ts
|
|
660
753
|
var TOPOLO_ENVIRONMENTS = TOPOLO_RUNTIME_ENVIRONMENTS;
|
|
661
754
|
function contextKey(contextType, organizationId) {
|
|
@@ -665,8 +758,8 @@ var ENVIRONMENT_DEFAULT_SERVICE_URLS = TOPOLO_ENVIRONMENT_SERVICE_URLS;
|
|
|
665
758
|
function configPath() {
|
|
666
759
|
const override = process.env.TOPOLO_CONFIG_PATH;
|
|
667
760
|
if (override) return override;
|
|
668
|
-
const base = process.env.XDG_CONFIG_HOME || ((0, import_node_os2.platform)() === "win32" ? (0,
|
|
669
|
-
return (0,
|
|
761
|
+
const base = process.env.XDG_CONFIG_HOME || ((0, import_node_os2.platform)() === "win32" ? (0, import_node_path3.join)((0, import_node_os2.homedir)(), "AppData", "Roaming") : (0, import_node_path3.join)((0, import_node_os2.homedir)(), ".config"));
|
|
762
|
+
return (0, import_node_path3.join)(base, "topolo", "config.json");
|
|
670
763
|
}
|
|
671
764
|
async function readConfig() {
|
|
672
765
|
const path = configPath();
|
|
@@ -680,7 +773,7 @@ async function readConfig() {
|
|
|
680
773
|
}
|
|
681
774
|
async function writeConfig(config) {
|
|
682
775
|
const path = configPath();
|
|
683
|
-
await (0, import_promises2.mkdir)((0,
|
|
776
|
+
await (0, import_promises2.mkdir)((0, import_node_path3.dirname)(path), { recursive: true });
|
|
684
777
|
await (0, import_promises2.writeFile)(path, JSON.stringify(config, null, 2) + "\n", "utf8");
|
|
685
778
|
if ((0, import_node_os2.platform)() !== "win32") {
|
|
686
779
|
try {
|
|
@@ -800,7 +893,7 @@ var CONFIG_LOCK_TIMEOUT_MS = 5e3;
|
|
|
800
893
|
var CONFIG_LOCK_STALE_MS = 12e4;
|
|
801
894
|
async function withConfigWriteLock(operation) {
|
|
802
895
|
const lockPath = `${configPath()}.lock`;
|
|
803
|
-
await (0, import_promises2.mkdir)((0,
|
|
896
|
+
await (0, import_promises2.mkdir)((0, import_node_path3.dirname)(lockPath), { recursive: true });
|
|
804
897
|
const startedAt = Date.now();
|
|
805
898
|
while (true) {
|
|
806
899
|
try {
|
|
@@ -977,6 +1070,7 @@ function resolvedProfileConfig(config, environment = selectedEnvironment()) {
|
|
|
977
1070
|
configPath,
|
|
978
1071
|
contextKey,
|
|
979
1072
|
createPlatformInstallationSecretBackend,
|
|
1073
|
+
createProtectedActionSecretStore,
|
|
980
1074
|
credentialSourceFromConfig,
|
|
981
1075
|
deleteExternalAgentInstallation,
|
|
982
1076
|
envVarPrefix,
|
|
@@ -26,11 +26,53 @@ type TopoloCredential = {
|
|
|
26
26
|
expiresAt?: number;
|
|
27
27
|
};
|
|
28
28
|
|
|
29
|
+
interface TopoloActionSecretStore {
|
|
30
|
+
save(value: unknown): Promise<string>;
|
|
31
|
+
load(reference: string): Promise<unknown>;
|
|
32
|
+
delete(reference: string): Promise<void>;
|
|
33
|
+
}
|
|
34
|
+
|
|
29
35
|
declare const TOPOLO_RUNTIME_ENVIRONMENTS: readonly ["production", "staging", "development", "local"];
|
|
30
36
|
type TopoloRuntimeEnvironment = (typeof TOPOLO_RUNTIME_ENVIRONMENTS)[number];
|
|
31
37
|
declare function assertTopoloServiceUrlEnvironment(service: string, value: string, environment: TopoloRuntimeEnvironment): string;
|
|
32
38
|
declare function topoloServiceOrigins(serviceUrls: Record<string, string> | undefined, environment: TopoloRuntimeEnvironment): Record<string, string>;
|
|
33
39
|
|
|
40
|
+
interface CredentialIntrospection {
|
|
41
|
+
kind: 'api_key' | 'access_token';
|
|
42
|
+
authorizationMode: 'context_rbac' | 'oauth_scopes' | 'session_rbac' | 'api_key' | 'unknown';
|
|
43
|
+
user: {
|
|
44
|
+
id: string;
|
|
45
|
+
email: string;
|
|
46
|
+
name: string | null;
|
|
47
|
+
role: string;
|
|
48
|
+
permissions: string[];
|
|
49
|
+
principalId?: string | null;
|
|
50
|
+
principalType?: 'agent_employee' | 'external_agent' | null;
|
|
51
|
+
accountableUserId?: string | null;
|
|
52
|
+
agentInstanceId?: string | null;
|
|
53
|
+
installationId?: string | null;
|
|
54
|
+
provider?: string | null;
|
|
55
|
+
model?: string | null;
|
|
56
|
+
serviceScopes?: string[];
|
|
57
|
+
policyRef?: string | null;
|
|
58
|
+
};
|
|
59
|
+
organization: {
|
|
60
|
+
id: string;
|
|
61
|
+
slug: string;
|
|
62
|
+
name: string;
|
|
63
|
+
} | null;
|
|
64
|
+
apiKey: {
|
|
65
|
+
id: string | null;
|
|
66
|
+
name: string | null;
|
|
67
|
+
appId: string | null;
|
|
68
|
+
scopes: string[];
|
|
69
|
+
resourceBindings: Array<{
|
|
70
|
+
resourceType: string;
|
|
71
|
+
resourceId: string;
|
|
72
|
+
}>;
|
|
73
|
+
} | null;
|
|
74
|
+
}
|
|
75
|
+
|
|
34
76
|
interface ExternalAgentInstallation {
|
|
35
77
|
id: string;
|
|
36
78
|
environment: TopoloRuntimeEnvironment;
|
|
@@ -64,6 +106,7 @@ declare function createPlatformInstallationSecretBackend(options?: {
|
|
|
64
106
|
platform?: NodeJS.Platform;
|
|
65
107
|
spawn?: Spawn;
|
|
66
108
|
root?: string;
|
|
109
|
+
service?: string;
|
|
67
110
|
}): InstallationSecretBackend;
|
|
68
111
|
declare function writeExternalAgentInstallation(installation: ExternalAgentInstallation, secret: ExternalAgentInstallationSecret, backend?: InstallationSecretBackend): Promise<void>;
|
|
69
112
|
declare function readExternalAgentInstallation(environment: TopoloRuntimeEnvironment, id: string, backend?: InstallationSecretBackend): Promise<{
|
|
@@ -73,6 +116,13 @@ declare function readExternalAgentInstallation(environment: TopoloRuntimeEnviron
|
|
|
73
116
|
declare function listExternalAgentInstallations(environment: TopoloRuntimeEnvironment): Promise<ExternalAgentInstallation[]>;
|
|
74
117
|
declare function deleteExternalAgentInstallation(environment: TopoloRuntimeEnvironment, id: string, backend?: InstallationSecretBackend): Promise<void>;
|
|
75
118
|
|
|
119
|
+
declare function createProtectedActionSecretStore(options: {
|
|
120
|
+
environment: TopoloRuntimeEnvironment;
|
|
121
|
+
identity: () => Promise<CredentialIntrospection>;
|
|
122
|
+
backend?: InstallationSecretBackend;
|
|
123
|
+
now?: () => number;
|
|
124
|
+
}): TopoloActionSecretStore;
|
|
125
|
+
|
|
76
126
|
/**
|
|
77
127
|
* Node-only credential store shared by the `topolo` CLI and `@topolo/mcp`.
|
|
78
128
|
*
|
|
@@ -166,4 +216,4 @@ declare function resolveServiceUrls(configUrls?: Record<string, string>, environ
|
|
|
166
216
|
declare function assertServiceUrlForEnvironment(service: string, serviceUrl: string | undefined, environment?: TopoloEnvironment): void;
|
|
167
217
|
declare function resolvedProfileConfig(config: TopoloConfig, environment?: TopoloEnvironment): TopoloEnvironmentProfile;
|
|
168
218
|
|
|
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 };
|
|
219
|
+
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, createProtectedActionSecretStore, credentialSourceFromConfig, deleteExternalAgentInstallation, envVarPrefix, installationStorePath, listExternalAgentInstallations, normalizeEnvironment, profileForEnvironment, readConfig, readExternalAgentInstallation, refreshContextCredentialIfNeeded, refreshCredentialIfNeeded, resolveAgentName, resolveCredential, resolveServiceUrls, resolvedProfileConfig, selectedEnvironment, topoloServiceOrigins, writeConfig, writeContextCredential, writeExternalAgentInstallation, writeProfileConfig };
|
|
@@ -26,11 +26,53 @@ type TopoloCredential = {
|
|
|
26
26
|
expiresAt?: number;
|
|
27
27
|
};
|
|
28
28
|
|
|
29
|
+
interface TopoloActionSecretStore {
|
|
30
|
+
save(value: unknown): Promise<string>;
|
|
31
|
+
load(reference: string): Promise<unknown>;
|
|
32
|
+
delete(reference: string): Promise<void>;
|
|
33
|
+
}
|
|
34
|
+
|
|
29
35
|
declare const TOPOLO_RUNTIME_ENVIRONMENTS: readonly ["production", "staging", "development", "local"];
|
|
30
36
|
type TopoloRuntimeEnvironment = (typeof TOPOLO_RUNTIME_ENVIRONMENTS)[number];
|
|
31
37
|
declare function assertTopoloServiceUrlEnvironment(service: string, value: string, environment: TopoloRuntimeEnvironment): string;
|
|
32
38
|
declare function topoloServiceOrigins(serviceUrls: Record<string, string> | undefined, environment: TopoloRuntimeEnvironment): Record<string, string>;
|
|
33
39
|
|
|
40
|
+
interface CredentialIntrospection {
|
|
41
|
+
kind: 'api_key' | 'access_token';
|
|
42
|
+
authorizationMode: 'context_rbac' | 'oauth_scopes' | 'session_rbac' | 'api_key' | 'unknown';
|
|
43
|
+
user: {
|
|
44
|
+
id: string;
|
|
45
|
+
email: string;
|
|
46
|
+
name: string | null;
|
|
47
|
+
role: string;
|
|
48
|
+
permissions: string[];
|
|
49
|
+
principalId?: string | null;
|
|
50
|
+
principalType?: 'agent_employee' | 'external_agent' | null;
|
|
51
|
+
accountableUserId?: string | null;
|
|
52
|
+
agentInstanceId?: string | null;
|
|
53
|
+
installationId?: string | null;
|
|
54
|
+
provider?: string | null;
|
|
55
|
+
model?: string | null;
|
|
56
|
+
serviceScopes?: string[];
|
|
57
|
+
policyRef?: string | null;
|
|
58
|
+
};
|
|
59
|
+
organization: {
|
|
60
|
+
id: string;
|
|
61
|
+
slug: string;
|
|
62
|
+
name: string;
|
|
63
|
+
} | null;
|
|
64
|
+
apiKey: {
|
|
65
|
+
id: string | null;
|
|
66
|
+
name: string | null;
|
|
67
|
+
appId: string | null;
|
|
68
|
+
scopes: string[];
|
|
69
|
+
resourceBindings: Array<{
|
|
70
|
+
resourceType: string;
|
|
71
|
+
resourceId: string;
|
|
72
|
+
}>;
|
|
73
|
+
} | null;
|
|
74
|
+
}
|
|
75
|
+
|
|
34
76
|
interface ExternalAgentInstallation {
|
|
35
77
|
id: string;
|
|
36
78
|
environment: TopoloRuntimeEnvironment;
|
|
@@ -64,6 +106,7 @@ declare function createPlatformInstallationSecretBackend(options?: {
|
|
|
64
106
|
platform?: NodeJS.Platform;
|
|
65
107
|
spawn?: Spawn;
|
|
66
108
|
root?: string;
|
|
109
|
+
service?: string;
|
|
67
110
|
}): InstallationSecretBackend;
|
|
68
111
|
declare function writeExternalAgentInstallation(installation: ExternalAgentInstallation, secret: ExternalAgentInstallationSecret, backend?: InstallationSecretBackend): Promise<void>;
|
|
69
112
|
declare function readExternalAgentInstallation(environment: TopoloRuntimeEnvironment, id: string, backend?: InstallationSecretBackend): Promise<{
|
|
@@ -73,6 +116,13 @@ declare function readExternalAgentInstallation(environment: TopoloRuntimeEnviron
|
|
|
73
116
|
declare function listExternalAgentInstallations(environment: TopoloRuntimeEnvironment): Promise<ExternalAgentInstallation[]>;
|
|
74
117
|
declare function deleteExternalAgentInstallation(environment: TopoloRuntimeEnvironment, id: string, backend?: InstallationSecretBackend): Promise<void>;
|
|
75
118
|
|
|
119
|
+
declare function createProtectedActionSecretStore(options: {
|
|
120
|
+
environment: TopoloRuntimeEnvironment;
|
|
121
|
+
identity: () => Promise<CredentialIntrospection>;
|
|
122
|
+
backend?: InstallationSecretBackend;
|
|
123
|
+
now?: () => number;
|
|
124
|
+
}): TopoloActionSecretStore;
|
|
125
|
+
|
|
76
126
|
/**
|
|
77
127
|
* Node-only credential store shared by the `topolo` CLI and `@topolo/mcp`.
|
|
78
128
|
*
|
|
@@ -166,4 +216,4 @@ declare function resolveServiceUrls(configUrls?: Record<string, string>, environ
|
|
|
166
216
|
declare function assertServiceUrlForEnvironment(service: string, serviceUrl: string | undefined, environment?: TopoloEnvironment): void;
|
|
167
217
|
declare function resolvedProfileConfig(config: TopoloConfig, environment?: TopoloEnvironment): TopoloEnvironmentProfile;
|
|
168
218
|
|
|
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 };
|
|
219
|
+
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, createProtectedActionSecretStore, credentialSourceFromConfig, deleteExternalAgentInstallation, envVarPrefix, installationStorePath, listExternalAgentInstallations, normalizeEnvironment, profileForEnvironment, readConfig, readExternalAgentInstallation, refreshContextCredentialIfNeeded, refreshCredentialIfNeeded, resolveAgentName, resolveCredential, resolveServiceUrls, resolvedProfileConfig, selectedEnvironment, topoloServiceOrigins, writeConfig, writeContextCredential, writeExternalAgentInstallation, writeProfileConfig };
|