@topolo/cli 0.2.2 → 0.2.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.js +111 -18
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -2582,6 +2582,7 @@ var TopoloClient = class _TopoloClient {
|
|
|
2582
2582
|
const kind = payload.credentialType === "api_key" ? "api_key" : "access_token";
|
|
2583
2583
|
return {
|
|
2584
2584
|
kind,
|
|
2585
|
+
authorizationMode: normalizeCredentialAuthorizationMode(payload.authorizationMode, kind),
|
|
2585
2586
|
user: {
|
|
2586
2587
|
id: user.id,
|
|
2587
2588
|
email: user.email,
|
|
@@ -2844,6 +2845,11 @@ function objectToQuery(value) {
|
|
|
2844
2845
|
}
|
|
2845
2846
|
return Object.keys(query).length > 0 ? query : void 0;
|
|
2846
2847
|
}
|
|
2848
|
+
function normalizeCredentialAuthorizationMode(value, kind) {
|
|
2849
|
+
if (kind === "api_key") return "api_key";
|
|
2850
|
+
if (value === "context_rbac" || value === "oauth_scopes" || value === "session_rbac") return value;
|
|
2851
|
+
return "unknown";
|
|
2852
|
+
}
|
|
2847
2853
|
function describeError(body, fallback) {
|
|
2848
2854
|
if (body && typeof body === "object") {
|
|
2849
2855
|
const maybe = body;
|
|
@@ -3446,7 +3452,7 @@ function resolveOAuthClientId(config, environment = selectedEnvironment()) {
|
|
|
3446
3452
|
const envSpecific = process.env[`${envVarPrefix(environment)}_CLI_CLIENT_ID`];
|
|
3447
3453
|
if (envSpecific) return envSpecific;
|
|
3448
3454
|
if (process.env.TOPOLO_CLI_CLIENT_ID) return process.env.TOPOLO_CLI_CLIENT_ID;
|
|
3449
|
-
return profileForEnvironment(config, environment).oauthClientId
|
|
3455
|
+
return DEFAULT_CLI_CLIENT_IDS[environment] ?? profileForEnvironment(config, environment).oauthClientId;
|
|
3450
3456
|
}
|
|
3451
3457
|
var NON_PROD_URL_MARKERS = {
|
|
3452
3458
|
staging: [".stg.topolo.us", "topolo-staging"],
|
|
@@ -3832,7 +3838,7 @@ function stderrDebugLogger(event) {
|
|
|
3832
3838
|
|
|
3833
3839
|
// src/commands/whoami.ts
|
|
3834
3840
|
function registerWhoamiCommand(program2) {
|
|
3835
|
-
program2.command("whoami").description("Show the user, organization, and
|
|
3841
|
+
program2.command("whoami").description("Show the current user, organization, and authorization mode").option("--json", "Output JSON").option("--no-json", "Output human-readable text").action(async (opts) => {
|
|
3836
3842
|
const mode = resolveOutputMode(opts.json);
|
|
3837
3843
|
try {
|
|
3838
3844
|
const environment = selectedEnvironment();
|
|
@@ -3857,7 +3863,10 @@ function formatPretty(info) {
|
|
|
3857
3863
|
`Organization: ${info.organization ? `${info.organization.name} (${info.organization.slug})` : "(none)"}`
|
|
3858
3864
|
);
|
|
3859
3865
|
lines.push(`Credential: ${info.kind}`);
|
|
3860
|
-
|
|
3866
|
+
const dynamicRbac = info.authorizationMode === "context_rbac";
|
|
3867
|
+
const authorization = dynamicRbac ? "Dynamic RBAC (checked per application action)" : info.authorizationMode === "oauth_scopes" ? "Delegated OAuth scopes" : info.authorizationMode === "api_key" ? "API key scopes" : info.authorizationMode === "session_rbac" ? "Session RBAC" : "Credential scopes";
|
|
3868
|
+
lines.push(`Authorization: ${authorization}`);
|
|
3869
|
+
lines.push(`${dynamicRbac ? "Identity scopes" : "Scopes"}: ${info.user.permissions.length === 0 ? "(none)" : ""}`);
|
|
3861
3870
|
for (const p of info.user.permissions) lines.push(` - ${p}`);
|
|
3862
3871
|
return lines.join("\n");
|
|
3863
3872
|
}
|
|
@@ -5169,7 +5178,6 @@ function isFile(filePath) {
|
|
|
5169
5178
|
}
|
|
5170
5179
|
|
|
5171
5180
|
// src/commands/app-scaffold.ts
|
|
5172
|
-
import { randomBytes } from "crypto";
|
|
5173
5181
|
import { mkdir as mkdir2, writeFile as writeFile2 } from "fs/promises";
|
|
5174
5182
|
import { dirname as dirname3, resolve as resolve2 } from "path";
|
|
5175
5183
|
|
|
@@ -6152,12 +6160,15 @@ function platformAppTsx(application, options) {
|
|
|
6152
6160
|
" }",
|
|
6153
6161
|
"",
|
|
6154
6162
|
" if (!auth) {",
|
|
6163
|
+
" // Pre-AppRoot: appId is still resolving, so auth can't be built yet.",
|
|
6164
|
+
" // Render the SAME scaffold layout AppRoot uses below so this phase and",
|
|
6165
|
+
" // the auth-gate fallback read as one continuous loading state (the",
|
|
6166
|
+
" // scaffold resolves theme + rail width on its own to match the shell).",
|
|
6155
6167
|
" return (",
|
|
6156
6168
|
" <TopoloAppLoadingScaffold",
|
|
6157
6169
|
" appId={appId}",
|
|
6158
6170
|
" appName={APP_NAME}",
|
|
6159
6171
|
" layout={{ shell: 'topbar', content: 'workspace' }}",
|
|
6160
|
-
" subtitle={`Loading ${APP_NAME}...`}",
|
|
6161
6172
|
" />",
|
|
6162
6173
|
" );",
|
|
6163
6174
|
" }",
|
|
@@ -6198,8 +6209,6 @@ function platformAppTsx(application, options) {
|
|
|
6198
6209
|
" appId={appId}",
|
|
6199
6210
|
" appName={APP_NAME}",
|
|
6200
6211
|
" layout={{ shell: loading?.shell || 'topbar', content: loading?.content || 'workspace' }}",
|
|
6201
|
-
" title={loading?.title}",
|
|
6202
|
-
" subtitle={`Loading ${APP_NAME}...`}",
|
|
6203
6212
|
" />",
|
|
6204
6213
|
" )}",
|
|
6205
6214
|
" shell={{",
|
|
@@ -6896,7 +6905,7 @@ function platformWorkerTs(application, options) {
|
|
|
6896
6905
|
"import { createTopoloWorkerRuntime, type TopoloRuntimeContext } from '@topolo-io/worker-runtime';",
|
|
6897
6906
|
"import { withSecurityHeaders } from '@topolo-io/security-headers';",
|
|
6898
6907
|
"import { withErrorReporting } from '@topolo-io/error-middleware';",
|
|
6899
|
-
"import {
|
|
6908
|
+
"import { SCAFFOLD_APP_NAME, SCAFFOLD_SERVICE_SLUG, resolveRuntimeAppId } from './app-identity';",
|
|
6900
6909
|
...options.resources.workflow ? ["import { WorkflowEntrypoint, type WorkflowEvent, type WorkflowStep } from 'cloudflare:workers';"] : [],
|
|
6901
6910
|
"",
|
|
6902
6911
|
"export interface Env {",
|
|
@@ -6921,12 +6930,10 @@ function platformWorkerTs(application, options) {
|
|
|
6921
6930
|
"const runtime = createTopoloWorkerRuntime<Env>({",
|
|
6922
6931
|
" appName: SCAFFOLD_APP_NAME,",
|
|
6923
6932
|
" serviceSlug: SCAFFOLD_SERVICE_SLUG,",
|
|
6924
|
-
"
|
|
6933
|
+
" // Auth verification base URL is environment-driven (staging/prod/dev),",
|
|
6934
|
+
" // so rt.verifyAuth() targets the correct Auth service per deploy.",
|
|
6925
6935
|
" authBaseUrl: (env) => env.AUTH_BASE_URL,",
|
|
6926
|
-
"
|
|
6927
|
-
" appId: SCAFFOLD_APP_ID,",
|
|
6928
|
-
" nexusGatewayUrl: (env) => env.NEXUS_GATEWAY_URL,",
|
|
6929
|
-
" },",
|
|
6936
|
+
" authGateway: { enabled: false },",
|
|
6930
6937
|
"});",
|
|
6931
6938
|
"",
|
|
6932
6939
|
"async function handleRequest(",
|
|
@@ -7348,6 +7355,7 @@ function topoloAppManifestJson(application, options) {
|
|
|
7348
7355
|
}
|
|
7349
7356
|
} : {}
|
|
7350
7357
|
};
|
|
7358
|
+
const actions = options.api ? baselineApiActions() : [];
|
|
7351
7359
|
return `${json({
|
|
7352
7360
|
$schema: "./../../topolo-platform/tooling/app-manifest-schema.json",
|
|
7353
7361
|
name: `topolo-${slug}`,
|
|
@@ -7367,10 +7375,87 @@ function topoloAppManifestJson(application, options) {
|
|
|
7367
7375
|
domain: "topolo.app"
|
|
7368
7376
|
}
|
|
7369
7377
|
},
|
|
7370
|
-
targets
|
|
7378
|
+
targets,
|
|
7379
|
+
...actions.length ? { actions } : {}
|
|
7371
7380
|
})}
|
|
7372
7381
|
`;
|
|
7373
7382
|
}
|
|
7383
|
+
function topoloActionContractsMjs() {
|
|
7384
|
+
return [
|
|
7385
|
+
"// Canonical action contracts \u2014 the source of truth for the agent/SDK/MCP",
|
|
7386
|
+
"// surface. Each entry maps 1:1 to a worker route (method + path) and validates",
|
|
7387
|
+
"// its input with zod. Add product actions here and mirror them into",
|
|
7388
|
+
"// topolo.app.json actions[]. Mirrors the normalized fleet convention.",
|
|
7389
|
+
"",
|
|
7390
|
+
"import { z } from 'zod';",
|
|
7391
|
+
"",
|
|
7392
|
+
"const emptyInput = z.object({}).strict();",
|
|
7393
|
+
"",
|
|
7394
|
+
"export const topoloActionContracts = {",
|
|
7395
|
+
" 'widget.get': {",
|
|
7396
|
+
" name: 'widget.get',",
|
|
7397
|
+
" method: 'GET',",
|
|
7398
|
+
" path: '/api/widget',",
|
|
7399
|
+
" input: emptyInput,",
|
|
7400
|
+
" },",
|
|
7401
|
+
" 'workspace.bootstrap': {",
|
|
7402
|
+
" name: 'workspace.bootstrap',",
|
|
7403
|
+
" method: 'GET',",
|
|
7404
|
+
" path: '/api/bootstrap',",
|
|
7405
|
+
" input: emptyInput,",
|
|
7406
|
+
" },",
|
|
7407
|
+
"};",
|
|
7408
|
+
"",
|
|
7409
|
+
"export const topoloActionInputSchemas = Object.fromEntries(",
|
|
7410
|
+
" Object.entries(topoloActionContracts).map(([name, contract]) => [",
|
|
7411
|
+
" name,",
|
|
7412
|
+
" z.toJSONSchema(contract.input),",
|
|
7413
|
+
" ]),",
|
|
7414
|
+
");",
|
|
7415
|
+
""
|
|
7416
|
+
].join("\n");
|
|
7417
|
+
}
|
|
7418
|
+
function baselineApiActions() {
|
|
7419
|
+
const emptyInputSchema = {
|
|
7420
|
+
$schema: "https://json-schema.org/draft/2020-12/schema",
|
|
7421
|
+
type: "object",
|
|
7422
|
+
properties: {},
|
|
7423
|
+
additionalProperties: false
|
|
7424
|
+
};
|
|
7425
|
+
const openOutputSchema = { type: "object", additionalProperties: true };
|
|
7426
|
+
return [
|
|
7427
|
+
{
|
|
7428
|
+
name: "widget.get",
|
|
7429
|
+
title: "Get widget summary",
|
|
7430
|
+
description: "Get the TopoloOne widget summary for this service.",
|
|
7431
|
+
method: "GET",
|
|
7432
|
+
path: "/api/widget",
|
|
7433
|
+
permission: "workspace:read",
|
|
7434
|
+
readOnly: true,
|
|
7435
|
+
inputSchema: emptyInputSchema,
|
|
7436
|
+
outputSchema: openOutputSchema,
|
|
7437
|
+
target: "api",
|
|
7438
|
+
destructive: false,
|
|
7439
|
+
requiresConfirmation: false,
|
|
7440
|
+
agentAccess: "auto"
|
|
7441
|
+
},
|
|
7442
|
+
{
|
|
7443
|
+
name: "workspace.bootstrap",
|
|
7444
|
+
title: "Get workspace bootstrap",
|
|
7445
|
+
description: "Get the signed workspace bootstrap payload for this service.",
|
|
7446
|
+
method: "GET",
|
|
7447
|
+
path: "/api/bootstrap",
|
|
7448
|
+
permission: "workspace:read",
|
|
7449
|
+
readOnly: true,
|
|
7450
|
+
inputSchema: emptyInputSchema,
|
|
7451
|
+
outputSchema: openOutputSchema,
|
|
7452
|
+
target: "api",
|
|
7453
|
+
destructive: false,
|
|
7454
|
+
requiresConfirmation: false,
|
|
7455
|
+
agentAccess: "auto"
|
|
7456
|
+
}
|
|
7457
|
+
];
|
|
7458
|
+
}
|
|
7374
7459
|
function cloudcontrolJson(application, options) {
|
|
7375
7460
|
const slug = toSlug(application.id);
|
|
7376
7461
|
const appPath = firstPartyAppPath(application.appDir, options.audience);
|
|
@@ -8024,9 +8109,6 @@ function envExample(application) {
|
|
|
8024
8109
|
}
|
|
8025
8110
|
|
|
8026
8111
|
// src/commands/app-scaffold.ts
|
|
8027
|
-
function generateOpaqueAppId() {
|
|
8028
|
-
return `app_${randomBytes(9).toString("base64url")}`;
|
|
8029
|
-
}
|
|
8030
8112
|
function standardScriptStub() {
|
|
8031
8113
|
return `#!/usr/bin/env python3
|
|
8032
8114
|
"""Canonical-fetching stub for .github/scripts/standard_*.py.
|
|
@@ -8122,7 +8204,7 @@ function applicationScaffoldPayload(application, options = {}) {
|
|
|
8122
8204
|
const name = options.name ?? catalogApplication?.name ?? `topolo-${slug}`;
|
|
8123
8205
|
const packageName = options.packageName ?? catalogApplication?.packageName ?? `topolo-${slug}`;
|
|
8124
8206
|
const serviceSlug = api ? target === "platform" ? `topolo-${slug}` : id : null;
|
|
8125
|
-
const defaultAppId = target === "platform" ?
|
|
8207
|
+
const defaultAppId = target === "platform" ? `app_topolo_${id}` : catalogApplication?.services[0] ?? id;
|
|
8126
8208
|
const appId = api ? options.appId ?? defaultAppId : null;
|
|
8127
8209
|
const productionUrl = browser ? options.productionUrl ?? catalogApplication?.productionUrl ?? `https://${slug}.topolo.app` : null;
|
|
8128
8210
|
const scopes = scaffoldScopes({ browser, api });
|
|
@@ -8438,6 +8520,17 @@ function scaffoldFiles(options) {
|
|
|
8438
8520
|
profile: options.payload.profile
|
|
8439
8521
|
})
|
|
8440
8522
|
},
|
|
8523
|
+
...options.api ? [
|
|
8524
|
+
{
|
|
8525
|
+
path: `${base}/topolo.action-contracts.mjs`,
|
|
8526
|
+
purpose: "Zod source of truth for the agent/SDK/MCP action catalog, mirrored into topolo.app.json actions[].",
|
|
8527
|
+
requiredSignals: [
|
|
8528
|
+
"declares topoloActionContracts with name/method/path per action",
|
|
8529
|
+
"each contract has a zod input validator, keeping the manifest actions[] honest"
|
|
8530
|
+
],
|
|
8531
|
+
content: topoloActionContractsMjs()
|
|
8532
|
+
}
|
|
8533
|
+
] : [],
|
|
8441
8534
|
{
|
|
8442
8535
|
path: `${base}/topolo.cloudcontrol.json`,
|
|
8443
8536
|
purpose: "CloudControl source of truth for deploy targets, routes, bindings, and CI metadata.",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@topolo/cli",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.3",
|
|
4
4
|
"description": "Command-line interface for Topolo developers, operators, and agents, with internal first-party scaffolding available under the topolo platform namespace.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|