@topolo/cli 0.1.24 → 0.1.25
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/README.md +13 -13
- package/dist/index.js +160 -101
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -108,26 +108,26 @@ topolo crm contacts:get contact_abc123
|
|
|
108
108
|
|
|
109
109
|
### `topolo services`
|
|
110
110
|
|
|
111
|
-
Lists
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
111
|
+
Lists the services the current credential can use in its organization, with the
|
|
112
|
+
effective URL and granted permissions. This command requires a credential and
|
|
113
|
+
does not expose the global platform catalog. In staging, `environmentSafe:
|
|
114
|
+
false` means that service still resolves to a production URL and will be
|
|
115
|
+
refused by `topolo api` until a staging URL override is configured.
|
|
115
116
|
|
|
116
117
|
```bash
|
|
117
118
|
topolo services --json
|
|
118
119
|
topolo services --env staging --json
|
|
119
120
|
```
|
|
120
121
|
|
|
121
|
-
`topolo api`
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
offline discovery floor, then rely on the SDK's live resolver for newly
|
|
125
|
-
registered services.
|
|
122
|
+
`topolo api` accepts the IDs/slugs returned by this credential-scoped live
|
|
123
|
+
catalog. New services become usable without a CLI release once Auth grants the
|
|
124
|
+
organization and credential the relevant permissions.
|
|
126
125
|
|
|
127
126
|
### `topolo apps`
|
|
128
127
|
|
|
129
|
-
Lists
|
|
130
|
-
|
|
128
|
+
Lists launchable Topolo applications available to the current credential. This
|
|
129
|
+
uses the same live Auth catalog as `topolo services`; it is not the global
|
|
130
|
+
generated application list.
|
|
131
131
|
|
|
132
132
|
```bash
|
|
133
133
|
topolo apps --json
|
|
@@ -209,8 +209,8 @@ topolo api auth GET /api/me
|
|
|
209
209
|
topolo api crm POST /api/contacts --data '{"first":"Jane"}' --confirm
|
|
210
210
|
```
|
|
211
211
|
|
|
212
|
-
Use `topolo services --json` to discover
|
|
213
|
-
service that does not have a typed command yet.
|
|
212
|
+
Use `topolo services --json` to discover service ids permitted for the current
|
|
213
|
+
credential before calling a service that does not have a typed command yet.
|
|
214
214
|
|
|
215
215
|
## Output modes
|
|
216
216
|
|
package/dist/index.js
CHANGED
|
@@ -2203,12 +2203,16 @@ var TopoloClient = class _TopoloClient {
|
|
|
2203
2203
|
if (!serviceKey) {
|
|
2204
2204
|
throw new TopoloSdkError("unknown_service", "service is required");
|
|
2205
2205
|
}
|
|
2206
|
-
|
|
2207
|
-
|
|
2208
|
-
|
|
2209
|
-
|
|
2206
|
+
if (serviceKey === "auth") {
|
|
2207
|
+
const overrideUrl = resolveConfiguredServiceUrl(serviceKey, this.serviceUrls);
|
|
2208
|
+
if (overrideUrl) return { serviceKey, baseUrl: overrideUrl };
|
|
2209
|
+
return { serviceKey, baseUrl: DEFAULT_SERVICE_URLS.auth };
|
|
2210
|
+
}
|
|
2210
2211
|
const live = await this.resolveLiveCallableService(serviceKey);
|
|
2211
|
-
if (live)
|
|
2212
|
+
if (live) {
|
|
2213
|
+
const overrideUrl = resolveConfiguredServiceUrl(serviceKey, this.serviceUrls);
|
|
2214
|
+
return overrideUrl ? { ...live, baseUrl: overrideUrl } : live;
|
|
2215
|
+
}
|
|
2212
2216
|
throw new TopoloSdkError(
|
|
2213
2217
|
"unknown_service",
|
|
2214
2218
|
`Unknown Topolo service "${service}". Run service discovery first and pass a callable service id or slug.`
|
|
@@ -2218,10 +2222,7 @@ var TopoloClient = class _TopoloClient {
|
|
|
2218
2222
|
const catalog = await this.listServices();
|
|
2219
2223
|
const match = catalog.find((entry) => catalogEntryMatches(entry, serviceKey));
|
|
2220
2224
|
if (!match?.baseUrl || !isCallableCatalogEntry(match)) return null;
|
|
2221
|
-
return {
|
|
2222
|
-
serviceKey: normalizeLookupKey(match.slug || match.name || match.serviceId) || serviceKey,
|
|
2223
|
-
baseUrl: match.baseUrl
|
|
2224
|
-
};
|
|
2225
|
+
return { serviceKey, baseUrl: match.baseUrl };
|
|
2225
2226
|
}
|
|
2226
2227
|
/**
|
|
2227
2228
|
* Resolve a service-slug → opaque service-id via caller config or TopoloAuth.
|
|
@@ -2283,53 +2284,55 @@ var TopoloClient = class _TopoloClient {
|
|
|
2283
2284
|
/**
|
|
2284
2285
|
* List the platform service catalog from the live registry
|
|
2285
2286
|
* (`GET /api/services/catalog` on TopoloAuth). Credential-aware: the
|
|
2286
|
-
* caller's credential is attached, so
|
|
2287
|
-
*
|
|
2288
|
-
* permits; an unauthenticated/agent caller receives `active` only.
|
|
2287
|
+
* caller's credential is attached, so the result only includes services the
|
|
2288
|
+
* credential's organization and effective permissions can use.
|
|
2289
2289
|
*
|
|
2290
|
-
*
|
|
2291
|
-
*
|
|
2292
|
-
*
|
|
2293
|
-
* authoritative; the snapshot is a floor, not a cap.
|
|
2290
|
+
* Security boundary: this never falls back to the generated global snapshot.
|
|
2291
|
+
* The live Auth catalog is the authority because it is scoped to the caller's
|
|
2292
|
+
* organization and effective permissions.
|
|
2294
2293
|
*/
|
|
2295
2294
|
async listServices() {
|
|
2296
2295
|
const now = Date.now();
|
|
2297
2296
|
if (this.serviceCatalogCache && this.serviceCatalogCache.expiresAt > now) {
|
|
2298
2297
|
return this.serviceCatalogCache.entries;
|
|
2299
2298
|
}
|
|
2300
|
-
|
|
2301
|
-
|
|
2302
|
-
|
|
2303
|
-
|
|
2304
|
-
|
|
2305
|
-
|
|
2306
|
-
|
|
2307
|
-
|
|
2308
|
-
|
|
2309
|
-
|
|
2310
|
-
|
|
2311
|
-
|
|
2312
|
-
|
|
2313
|
-
|
|
2314
|
-
|
|
2315
|
-
|
|
2316
|
-
|
|
2317
|
-
|
|
2318
|
-
|
|
2319
|
-
|
|
2320
|
-
|
|
2321
|
-
|
|
2322
|
-
|
|
2323
|
-
|
|
2324
|
-
|
|
2325
|
-
return entries;
|
|
2326
|
-
}
|
|
2327
|
-
}
|
|
2328
|
-
} catch {
|
|
2299
|
+
const res = await this.request({ service: "auth", method: "GET", path: "/api/services/catalog" });
|
|
2300
|
+
const raw = res.data?.services ?? res.services;
|
|
2301
|
+
if (!Array.isArray(raw)) {
|
|
2302
|
+
throw new TopoloSdkError(
|
|
2303
|
+
"service_catalog_unavailable",
|
|
2304
|
+
"TopoloAuth did not return a service catalog for the current credential."
|
|
2305
|
+
);
|
|
2306
|
+
}
|
|
2307
|
+
const entries = [];
|
|
2308
|
+
for (const item of raw) {
|
|
2309
|
+
const s = item;
|
|
2310
|
+
const serviceId = typeof s.service_id === "string" ? s.service_id : typeof s.id === "string" ? s.id : null;
|
|
2311
|
+
if (!serviceId) continue;
|
|
2312
|
+
const permissions = Array.isArray(s.granted_permissions) ? s.granted_permissions.filter((permission) => typeof permission === "string" && permission.trim().length > 0) : [];
|
|
2313
|
+
entries.push({
|
|
2314
|
+
serviceId,
|
|
2315
|
+
slug: typeof s.app_slug === "string" ? s.app_slug : null,
|
|
2316
|
+
name: typeof s.name === "string" ? s.name : null,
|
|
2317
|
+
description: typeof s.description === "string" ? s.description : null,
|
|
2318
|
+
baseUrl: typeof s.base_url === "string" ? s.base_url : null,
|
|
2319
|
+
status: typeof s.status === "string" ? s.status : null,
|
|
2320
|
+
surfaceKind: typeof s.surface_kind === "string" ? s.surface_kind : null,
|
|
2321
|
+
launchable: s.launchable === true,
|
|
2322
|
+
permissions
|
|
2323
|
+
});
|
|
2329
2324
|
}
|
|
2330
|
-
|
|
2325
|
+
this.serviceCatalogCache = {
|
|
2326
|
+
entries,
|
|
2327
|
+
expiresAt: now + CATALOG_CACHE_TTL_MS
|
|
2328
|
+
};
|
|
2329
|
+
return entries;
|
|
2331
2330
|
}
|
|
2332
|
-
|
|
2331
|
+
/**
|
|
2332
|
+
* Bundled generated registry for tooling that audits platform packaging, not
|
|
2333
|
+
* for deciding what the current credential may use.
|
|
2334
|
+
*/
|
|
2335
|
+
listBundledServices() {
|
|
2333
2336
|
const apps = Object.values(APPLICATIONS);
|
|
2334
2337
|
return apps.map((app) => ({
|
|
2335
2338
|
serviceId: app.id,
|
|
@@ -2337,9 +2340,10 @@ var TopoloClient = class _TopoloClient {
|
|
|
2337
2340
|
name: app.name ?? app.id,
|
|
2338
2341
|
description: null,
|
|
2339
2342
|
baseUrl: app.productionUrl ?? null,
|
|
2340
|
-
status: "
|
|
2343
|
+
status: "bundled",
|
|
2341
2344
|
surfaceKind: "application",
|
|
2342
|
-
launchable: Boolean(app.productionUrl)
|
|
2345
|
+
launchable: Boolean(app.productionUrl),
|
|
2346
|
+
permissions: []
|
|
2343
2347
|
}));
|
|
2344
2348
|
}
|
|
2345
2349
|
/**
|
|
@@ -2409,7 +2413,7 @@ function serviceKeyCandidates(slug) {
|
|
|
2409
2413
|
])];
|
|
2410
2414
|
}
|
|
2411
2415
|
function normalizeLookupKey(value) {
|
|
2412
|
-
return String(value || "").trim().toLowerCase();
|
|
2416
|
+
return String(value || "").trim().toLowerCase().replace(/\s+/g, "-");
|
|
2413
2417
|
}
|
|
2414
2418
|
function catalogEntryMatches(entry, needle) {
|
|
2415
2419
|
return catalogEntryLookupKeys(entry).includes(needle);
|
|
@@ -2420,12 +2424,8 @@ function catalogEntryLookupKeys(entry) {
|
|
|
2420
2424
|
for (const value of values) {
|
|
2421
2425
|
const normalized = normalizeLookupKey(value);
|
|
2422
2426
|
if (!normalized) continue;
|
|
2423
|
-
|
|
2424
|
-
|
|
2425
|
-
if (normalized.startsWith("topolo-")) {
|
|
2426
|
-
const withoutTopolo = normalized.slice("topolo-".length);
|
|
2427
|
-
keys.add(withoutTopolo);
|
|
2428
|
-
keys.add(withoutTopolo.replace(/-/g, "_"));
|
|
2427
|
+
for (const candidate of serviceKeyCandidates(normalized)) {
|
|
2428
|
+
keys.add(candidate);
|
|
2429
2429
|
}
|
|
2430
2430
|
}
|
|
2431
2431
|
return [...keys];
|
|
@@ -2433,7 +2433,9 @@ function catalogEntryLookupKeys(entry) {
|
|
|
2433
2433
|
function isCallableCatalogEntry(entry) {
|
|
2434
2434
|
const kind = normalizeLookupKey(entry.surfaceKind || "");
|
|
2435
2435
|
if (kind === "api" || kind === "technical_service" || kind === "service") return true;
|
|
2436
|
-
return Boolean(
|
|
2436
|
+
return Boolean(
|
|
2437
|
+
entry.baseUrl && catalogEntryLookupKeys(entry).some((key) => Object.prototype.hasOwnProperty.call(DEFAULT_SERVICE_URLS, key))
|
|
2438
|
+
);
|
|
2437
2439
|
}
|
|
2438
2440
|
function describeError(body, fallback) {
|
|
2439
2441
|
if (body && typeof body === "object") {
|
|
@@ -6797,8 +6799,14 @@ function topoloAppManifestJson(application, options) {
|
|
|
6797
6799
|
AUTH_BASE_URL: {
|
|
6798
6800
|
staging: "https://auth.stg.topolo.us",
|
|
6799
6801
|
production: "https://auth.topolo.app"
|
|
6800
|
-
}
|
|
6802
|
+
},
|
|
6803
|
+
NEXUS_GATEWAY_URL: {
|
|
6804
|
+
staging: "https://nexus-api.stg.topolo.us",
|
|
6805
|
+
production: "https://nexus-api.topolo.app"
|
|
6806
|
+
},
|
|
6807
|
+
NEXUS_APP_ID: slug
|
|
6801
6808
|
},
|
|
6809
|
+
secrets: ["TOPOLO_SERVICE_CLIENT_SECRET"],
|
|
6802
6810
|
...Object.keys(bindings).length ? { bindings } : {}
|
|
6803
6811
|
};
|
|
6804
6812
|
}
|
|
@@ -7862,20 +7870,28 @@ var CLOUDCONTROL_LOCAL_APPLICATION = {
|
|
|
7862
7870
|
deployTargets: []
|
|
7863
7871
|
};
|
|
7864
7872
|
function registerAppsCommand(program2) {
|
|
7865
|
-
const apps = program2.command("apps").description("List
|
|
7873
|
+
const apps = program2.command("apps").description("List Topolo platform applications available to the current credential").option("--json", "Output JSON", true).option("--no-json", "Output human-readable table").action(async (opts) => {
|
|
7866
7874
|
const mode = resolveOutputMode(opts.json);
|
|
7867
7875
|
try {
|
|
7868
|
-
const
|
|
7876
|
+
const topolo = await buildClient();
|
|
7877
|
+
if (!topolo) {
|
|
7878
|
+
throw new Error("No credential configured. Run `topolo auth login` or set TOPOLO_API_KEY.");
|
|
7879
|
+
}
|
|
7880
|
+
const rows = applicationRowsFromCatalog(await topolo.client.listServices());
|
|
7869
7881
|
emit({ applications: rows }, mode, () => formatRows(rows));
|
|
7870
7882
|
} catch (err) {
|
|
7871
7883
|
fail(err, mode);
|
|
7872
7884
|
}
|
|
7873
7885
|
});
|
|
7874
|
-
apps.command("get <application>").description("Show one Topolo application
|
|
7886
|
+
apps.command("get <application>").description("Show one Topolo application available to the current credential.").option("--json", "Output JSON", true).option("--no-json", "Output human-readable details").action(async (application, opts) => {
|
|
7875
7887
|
const mode = resolveOutputMode(opts.json);
|
|
7876
7888
|
try {
|
|
7877
|
-
const
|
|
7878
|
-
|
|
7889
|
+
const topolo = await buildClient();
|
|
7890
|
+
if (!topolo) {
|
|
7891
|
+
throw new Error("No credential configured. Run `topolo auth login` or set TOPOLO_API_KEY.");
|
|
7892
|
+
}
|
|
7893
|
+
const app = resolveCatalogApplication(await topolo.client.listServices(), application);
|
|
7894
|
+
emit({ application: app }, mode, () => formatApplicationRow(app));
|
|
7879
7895
|
} catch (err) {
|
|
7880
7896
|
fail(err, mode);
|
|
7881
7897
|
}
|
|
@@ -7983,19 +7999,27 @@ function registerAppsCommand(program2) {
|
|
|
7983
7999
|
}
|
|
7984
8000
|
});
|
|
7985
8001
|
}
|
|
7986
|
-
function
|
|
7987
|
-
return
|
|
7988
|
-
|
|
7989
|
-
|
|
7990
|
-
|
|
7991
|
-
|
|
7992
|
-
|
|
7993
|
-
|
|
7994
|
-
|
|
7995
|
-
|
|
7996
|
-
|
|
7997
|
-
|
|
7998
|
-
|
|
8002
|
+
function applicationRowsFromCatalog(catalog) {
|
|
8003
|
+
return catalog.filter((entry) => entry.launchable || entry.surfaceKind === "application").map((entry) => ({
|
|
8004
|
+
id: displayCatalogId(entry),
|
|
8005
|
+
name: entry.name ?? entry.slug ?? entry.serviceId,
|
|
8006
|
+
appDir: "-",
|
|
8007
|
+
packageName: null,
|
|
8008
|
+
productionUrl: entry.baseUrl,
|
|
8009
|
+
services: [displayCatalogId(entry)],
|
|
8010
|
+
deployTargets: 0
|
|
8011
|
+
})).sort((left, right) => left.id.localeCompare(right.id));
|
|
8012
|
+
}
|
|
8013
|
+
function resolveCatalogApplication(catalog, application) {
|
|
8014
|
+
const needle = application.trim().toLowerCase();
|
|
8015
|
+
const rows = applicationRowsFromCatalog(catalog);
|
|
8016
|
+
const match = rows.find(
|
|
8017
|
+
(row) => row.id.toLowerCase() === needle || row.name.toLowerCase() === needle || row.services.some((service) => service.toLowerCase() === needle)
|
|
8018
|
+
);
|
|
8019
|
+
if (!match) {
|
|
8020
|
+
throw new Error(`Unknown application "${application}". Run \`topolo apps --json\` to discover applications available to this credential.`);
|
|
8021
|
+
}
|
|
8022
|
+
return match;
|
|
7999
8023
|
}
|
|
8000
8024
|
function resolveApplication(application) {
|
|
8001
8025
|
const id = application.trim().toLowerCase();
|
|
@@ -8150,28 +8174,31 @@ function formatRows(rows) {
|
|
|
8150
8174
|
}
|
|
8151
8175
|
return lines.join("\n");
|
|
8152
8176
|
}
|
|
8153
|
-
function
|
|
8154
|
-
|
|
8155
|
-
const lines = [
|
|
8177
|
+
function formatApplicationRow(application) {
|
|
8178
|
+
return [
|
|
8156
8179
|
`ID: ${application.id}`,
|
|
8157
8180
|
`Name: ${application.name}`,
|
|
8158
|
-
`Directory: ${application.appDir}`,
|
|
8159
|
-
`Package: ${application.packageName ?? "-"}`,
|
|
8160
8181
|
`URL: ${application.productionUrl ?? "-"}`,
|
|
8161
|
-
`Services: ${application.services.length ? application.services.join(", ") : "-"}
|
|
8162
|
-
|
|
8163
|
-
|
|
8164
|
-
|
|
8165
|
-
|
|
8166
|
-
|
|
8167
|
-
|
|
8168
|
-
|
|
8169
|
-
|
|
8170
|
-
|
|
8171
|
-
lines.push(` - ${parts.join(" ")}`);
|
|
8172
|
-
}
|
|
8182
|
+
`Services: ${application.services.length ? application.services.join(", ") : "-"}`
|
|
8183
|
+
].join("\n");
|
|
8184
|
+
}
|
|
8185
|
+
function displayCatalogId(entry) {
|
|
8186
|
+
for (const value of [entry.slug, entry.name, entry.serviceId]) {
|
|
8187
|
+
if (typeof value !== "string" || !value.trim()) continue;
|
|
8188
|
+
const candidates = catalogIdCandidates(value);
|
|
8189
|
+
const withoutTopolo = candidates.find((candidate) => !candidate.startsWith("topolo-"));
|
|
8190
|
+
if (withoutTopolo) return withoutTopolo;
|
|
8191
|
+
if (candidates[0]) return candidates[0];
|
|
8173
8192
|
}
|
|
8174
|
-
return
|
|
8193
|
+
return entry.serviceId;
|
|
8194
|
+
}
|
|
8195
|
+
function catalogIdCandidates(value) {
|
|
8196
|
+
const normalized = value.trim().toLowerCase().replace(/\s+/g, "-");
|
|
8197
|
+
const withoutTopolo = normalized.startsWith("topolo-") ? normalized.slice("topolo-".length) : normalized;
|
|
8198
|
+
return [.../* @__PURE__ */ new Set([
|
|
8199
|
+
normalized,
|
|
8200
|
+
withoutTopolo
|
|
8201
|
+
])].filter(Boolean);
|
|
8175
8202
|
}
|
|
8176
8203
|
function formatRequirements(payload) {
|
|
8177
8204
|
const lines = [
|
|
@@ -8550,26 +8577,34 @@ function registerServicesCommand(program2) {
|
|
|
8550
8577
|
try {
|
|
8551
8578
|
const environment = selectedEnvironment();
|
|
8552
8579
|
const config = await readConfig();
|
|
8553
|
-
const
|
|
8580
|
+
const topolo = await buildClient();
|
|
8581
|
+
if (!topolo) {
|
|
8582
|
+
throw new Error("No credential configured. Run `topolo auth login` or set TOPOLO_API_KEY.");
|
|
8583
|
+
}
|
|
8584
|
+
const rows = buildRows(await topolo.client.listServices(), config.serviceUrls, environment);
|
|
8554
8585
|
emit({ environment, services: rows }, mode, () => formatRows2(rows, environment));
|
|
8555
8586
|
} catch (err) {
|
|
8556
8587
|
fail(err, mode);
|
|
8557
8588
|
}
|
|
8558
8589
|
});
|
|
8559
8590
|
}
|
|
8560
|
-
function buildRows(overrides, environment = selectedEnvironment()) {
|
|
8591
|
+
function buildRows(catalog, overrides, environment = selectedEnvironment()) {
|
|
8561
8592
|
const resolvedOverrides = resolveServiceUrls(overrides, environment);
|
|
8562
|
-
return
|
|
8563
|
-
const
|
|
8564
|
-
const
|
|
8593
|
+
return catalog.map((entry) => {
|
|
8594
|
+
const id = displayServiceId(entry);
|
|
8595
|
+
const defaultUrl = defaultServiceUrl(id, entry.baseUrl);
|
|
8596
|
+
const effectiveUrl = resolveServiceUrl(id, resolvedOverrides) || defaultUrl;
|
|
8565
8597
|
return {
|
|
8566
8598
|
id,
|
|
8599
|
+
serviceId: entry.serviceId,
|
|
8600
|
+
slug: entry.slug,
|
|
8567
8601
|
defaultUrl,
|
|
8568
8602
|
effectiveUrl,
|
|
8569
8603
|
overridden: defaultUrl !== effectiveUrl,
|
|
8570
|
-
environmentSafe: environment !== "staging" || isStagingUrl(effectiveUrl)
|
|
8604
|
+
environmentSafe: environment !== "staging" || isStagingUrl(effectiveUrl),
|
|
8605
|
+
permissions: [...entry.permissions]
|
|
8571
8606
|
};
|
|
8572
|
-
});
|
|
8607
|
+
}).sort((left, right) => left.id.localeCompare(right.id));
|
|
8573
8608
|
}
|
|
8574
8609
|
function formatRows2(rows, environment = selectedEnvironment()) {
|
|
8575
8610
|
const idWidth = Math.max(3, ...rows.map((r) => r.id.length));
|
|
@@ -8590,6 +8625,30 @@ function isStagingUrl(value) {
|
|
|
8590
8625
|
const url = value.toLowerCase();
|
|
8591
8626
|
return url.includes(".stg.topolo.us") || url.includes("localhost") || url.includes("127.0.0.1") || url.includes("topolo-staging");
|
|
8592
8627
|
}
|
|
8628
|
+
function displayServiceId(entry) {
|
|
8629
|
+
for (const value of [entry.slug, entry.name, entry.serviceId]) {
|
|
8630
|
+
if (typeof value !== "string" || !value.trim()) continue;
|
|
8631
|
+
for (const candidate of serviceIdCandidates(value)) {
|
|
8632
|
+
if (Object.prototype.hasOwnProperty.call(DEFAULT_SERVICE_URLS, candidate)) {
|
|
8633
|
+
return candidate;
|
|
8634
|
+
}
|
|
8635
|
+
}
|
|
8636
|
+
}
|
|
8637
|
+
return serviceIdCandidates(entry.slug || entry.serviceId)[0] || entry.serviceId;
|
|
8638
|
+
}
|
|
8639
|
+
function defaultServiceUrl(id, fallback) {
|
|
8640
|
+
return DEFAULT_SERVICE_URLS[id] ?? fallback ?? "";
|
|
8641
|
+
}
|
|
8642
|
+
function serviceIdCandidates(value) {
|
|
8643
|
+
const normalized = value.trim().toLowerCase().replace(/\s+/g, "-");
|
|
8644
|
+
const withoutTopolo = normalized.startsWith("topolo-") ? normalized.slice("topolo-".length) : normalized;
|
|
8645
|
+
return [.../* @__PURE__ */ new Set([
|
|
8646
|
+
normalized,
|
|
8647
|
+
normalized.replace(/-/g, "_"),
|
|
8648
|
+
withoutTopolo,
|
|
8649
|
+
withoutTopolo.replace(/-/g, "_")
|
|
8650
|
+
])].filter(Boolean);
|
|
8651
|
+
}
|
|
8593
8652
|
|
|
8594
8653
|
// src/commands/seed.ts
|
|
8595
8654
|
var DEFAULT_SEED_BASE_URL = "https://seed.stg.topolo.us";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@topolo/cli",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.25",
|
|
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": {
|