@topolo/cli 0.1.18 → 0.1.20
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 +126 -23
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -2699,7 +2699,28 @@ function sleep(ms) {
|
|
|
2699
2699
|
}
|
|
2700
2700
|
|
|
2701
2701
|
// src/version.ts
|
|
2702
|
-
|
|
2702
|
+
import { readFileSync } from "fs";
|
|
2703
|
+
import { dirname as dirname2, join as join2 } from "path";
|
|
2704
|
+
import { fileURLToPath } from "url";
|
|
2705
|
+
function readCliVersion() {
|
|
2706
|
+
try {
|
|
2707
|
+
const here = dirname2(fileURLToPath(import.meta.url));
|
|
2708
|
+
const candidates = [
|
|
2709
|
+
join2(here, "package.json"),
|
|
2710
|
+
join2(here, "..", "package.json")
|
|
2711
|
+
];
|
|
2712
|
+
for (const path4 of candidates) {
|
|
2713
|
+
try {
|
|
2714
|
+
const pkg = JSON.parse(readFileSync(path4, "utf8"));
|
|
2715
|
+
if (typeof pkg.version === "string" && pkg.version) return pkg.version;
|
|
2716
|
+
} catch {
|
|
2717
|
+
}
|
|
2718
|
+
}
|
|
2719
|
+
} catch {
|
|
2720
|
+
}
|
|
2721
|
+
return "0.0.0";
|
|
2722
|
+
}
|
|
2723
|
+
var CLI_VERSION = readCliVersion();
|
|
2703
2724
|
|
|
2704
2725
|
// src/client.ts
|
|
2705
2726
|
async function buildClient(options) {
|
|
@@ -2938,14 +2959,14 @@ function parseQueryPairs(pairs) {
|
|
|
2938
2959
|
|
|
2939
2960
|
// src/commands/apps.ts
|
|
2940
2961
|
import { execSync } from "child_process";
|
|
2941
|
-
import { existsSync as existsSync3, mkdirSync, readFileSync as
|
|
2962
|
+
import { existsSync as existsSync3, mkdirSync, readFileSync as readFileSync3, writeFileSync } from "fs";
|
|
2942
2963
|
import path2 from "path";
|
|
2943
2964
|
|
|
2944
2965
|
// src/commands/app-audit-local.ts
|
|
2945
2966
|
import {
|
|
2946
2967
|
existsSync as existsSync2,
|
|
2947
2968
|
readdirSync,
|
|
2948
|
-
readFileSync,
|
|
2969
|
+
readFileSync as readFileSync2,
|
|
2949
2970
|
statSync
|
|
2950
2971
|
} from "fs";
|
|
2951
2972
|
import path from "path";
|
|
@@ -2954,7 +2975,7 @@ function readEvidenceFile(appRoot) {
|
|
|
2954
2975
|
const candidate = path.join(appRoot, ".topolo", "evidence.json");
|
|
2955
2976
|
if (!isFile(candidate)) return null;
|
|
2956
2977
|
try {
|
|
2957
|
-
const raw = JSON.parse(
|
|
2978
|
+
const raw = JSON.parse(readFileSync2(candidate, "utf8"));
|
|
2958
2979
|
if (raw && typeof raw === "object" && raw.version === 1) {
|
|
2959
2980
|
return raw;
|
|
2960
2981
|
}
|
|
@@ -3737,7 +3758,7 @@ function readSourceIndex(root) {
|
|
|
3737
3758
|
const files = collectSourceFiles(root, 4e3);
|
|
3738
3759
|
const chunks = files.map((file) => {
|
|
3739
3760
|
try {
|
|
3740
|
-
return
|
|
3761
|
+
return readFileSync2(file, "utf8");
|
|
3741
3762
|
} catch {
|
|
3742
3763
|
return "";
|
|
3743
3764
|
}
|
|
@@ -3797,7 +3818,7 @@ function sortedDirEntries(dir) {
|
|
|
3797
3818
|
function readJson(filePath) {
|
|
3798
3819
|
if (!isFile(filePath)) return null;
|
|
3799
3820
|
try {
|
|
3800
|
-
return JSON.parse(
|
|
3821
|
+
return JSON.parse(readFileSync2(filePath, "utf8"));
|
|
3801
3822
|
} catch {
|
|
3802
3823
|
return null;
|
|
3803
3824
|
}
|
|
@@ -3870,7 +3891,7 @@ function isFile(filePath) {
|
|
|
3870
3891
|
// src/commands/app-scaffold.ts
|
|
3871
3892
|
import { constants } from "fs";
|
|
3872
3893
|
import { access, mkdir as mkdir2, writeFile as writeFile2 } from "fs/promises";
|
|
3873
|
-
import { dirname as
|
|
3894
|
+
import { dirname as dirname3, relative, resolve } from "path";
|
|
3874
3895
|
var CLOUDFLARE_ACCOUNT_ID = "49ef1ba682ad8cfd720c86699ae17521";
|
|
3875
3896
|
var STAGING_CLOUDFLARE_ACCOUNT_ID = "4f4e1c69a3830946f9fea7b1eb7531ac";
|
|
3876
3897
|
var CLOUDFLARE_COMPATIBILITY_DATE = "2026-05-05";
|
|
@@ -3977,7 +3998,7 @@ async function writeApplicationScaffold(payload, options = {}) {
|
|
|
3977
3998
|
const files = [];
|
|
3978
3999
|
for (const planned of plannedFiles) {
|
|
3979
4000
|
const existed = await pathExists(planned.absolutePath);
|
|
3980
|
-
await mkdir2(
|
|
4001
|
+
await mkdir2(dirname3(planned.absolutePath), { recursive: true });
|
|
3981
4002
|
await writeFile2(planned.absolutePath, planned.file.content, "utf8");
|
|
3982
4003
|
files.push({
|
|
3983
4004
|
path: planned.file.path,
|
|
@@ -4168,18 +4189,32 @@ function scaffoldFiles(options) {
|
|
|
4168
4189
|
}
|
|
4169
4190
|
);
|
|
4170
4191
|
if (options.api && application.serviceId) {
|
|
4171
|
-
files.push(
|
|
4172
|
-
|
|
4173
|
-
|
|
4174
|
-
|
|
4175
|
-
|
|
4176
|
-
|
|
4177
|
-
|
|
4178
|
-
|
|
4179
|
-
|
|
4180
|
-
|
|
4181
|
-
|
|
4182
|
-
|
|
4192
|
+
files.push(
|
|
4193
|
+
{
|
|
4194
|
+
path: `PlatformApplications/TopoloAuth/catalog/service-manifests/${application.serviceId}.json`,
|
|
4195
|
+
purpose: "Auth service manifest for first-party permissions, role bundles, and API-key scopes.",
|
|
4196
|
+
requiredSignals: [
|
|
4197
|
+
"serviceId matches the generated Worker service id",
|
|
4198
|
+
"permissions, role bundles, and API-key scopes exist before the app is catalog-visible",
|
|
4199
|
+
"systems metadata maps the service back to the generated TopoloDocs entries"
|
|
4200
|
+
],
|
|
4201
|
+
content: serviceManifestJson(application, {
|
|
4202
|
+
tenancy: options.payload.tenancy
|
|
4203
|
+
})
|
|
4204
|
+
},
|
|
4205
|
+
{
|
|
4206
|
+
path: `PlatformApplications/TopoloAuth/scripts/add-topolo-${slug}-service-production.sql`,
|
|
4207
|
+
purpose: "Auth service catalog registration for embedded first-party login, launcher visibility, and callback origins.",
|
|
4208
|
+
requiredSignals: [
|
|
4209
|
+
"services.id matches the generated Worker service id",
|
|
4210
|
+
"settings.launcher.category is first_party so embedded password login is allowed",
|
|
4211
|
+
"base_url and auth_domain define the production callback origin"
|
|
4212
|
+
],
|
|
4213
|
+
content: serviceRegistrationSql(application, {
|
|
4214
|
+
tenancy: options.payload.tenancy
|
|
4215
|
+
})
|
|
4216
|
+
}
|
|
4217
|
+
);
|
|
4183
4218
|
}
|
|
4184
4219
|
} else {
|
|
4185
4220
|
files.push(
|
|
@@ -5574,6 +5609,7 @@ function internalDocs(application, options) {
|
|
|
5574
5609
|
...options.api ? [`- \`PlatformApplications/${application.appDir}/src/worker.ts\``] : [],
|
|
5575
5610
|
`- \`PlatformApplications/${application.appDir}/topolo.cloudcontrol.json\``,
|
|
5576
5611
|
...options.api && application.serviceId ? [`- \`PlatformApplications/TopoloAuth/catalog/service-manifests/${application.serviceId}.json\``] : [],
|
|
5612
|
+
...options.api && application.serviceId ? [`- \`PlatformApplications/TopoloAuth/scripts/add-topolo-${slug}-service-production.sql\``] : [],
|
|
5577
5613
|
"",
|
|
5578
5614
|
"## API Reference",
|
|
5579
5615
|
"",
|
|
@@ -5604,6 +5640,7 @@ function internalDocs(application, options) {
|
|
|
5604
5640
|
"- run `topolo apps audit <app> --local --repo-root /Users/ashes/Projects/topolo --fail-on needs_review --json` after SDK catalog registration",
|
|
5605
5641
|
"- inspect `topolo.cloudcontrol.json` before deployment changes",
|
|
5606
5642
|
...options.api && application.serviceId ? [`- inspect \`PlatformApplications/TopoloAuth/catalog/service-manifests/${application.serviceId}.json\` when permission grants fail`] : [],
|
|
5643
|
+
...options.api && application.serviceId ? [`- inspect \`PlatformApplications/TopoloAuth/scripts/add-topolo-${slug}-service-production.sql\` when embedded app login fails`] : [],
|
|
5607
5644
|
"",
|
|
5608
5645
|
"## Change Log / Verification",
|
|
5609
5646
|
"",
|
|
@@ -5747,6 +5784,62 @@ function serviceManifestJson(application, options) {
|
|
|
5747
5784
|
})}
|
|
5748
5785
|
`;
|
|
5749
5786
|
}
|
|
5787
|
+
function serviceRegistrationSql(application, options) {
|
|
5788
|
+
const slug = toSlug(application.id);
|
|
5789
|
+
const title = toTitle(application.name);
|
|
5790
|
+
const serviceId = application.serviceId ?? application.id;
|
|
5791
|
+
const productionUrl = application.productionUrl ?? `https://${slug}.topolo.app`;
|
|
5792
|
+
const authDomain = hostnameFromUrl(productionUrl);
|
|
5793
|
+
const surface = options.tenancy === "household" ? "personal-workspace" : "workspace";
|
|
5794
|
+
const settings = JSON.stringify({
|
|
5795
|
+
app_slug: `topolo-${slug}`,
|
|
5796
|
+
surface,
|
|
5797
|
+
auth_domain: authDomain,
|
|
5798
|
+
launcher: {
|
|
5799
|
+
category: "first_party",
|
|
5800
|
+
app_id: slug
|
|
5801
|
+
}
|
|
5802
|
+
});
|
|
5803
|
+
return [
|
|
5804
|
+
`-- Register ${title} in the Topolo Auth service catalog.`,
|
|
5805
|
+
"-- Safe to rerun.",
|
|
5806
|
+
"",
|
|
5807
|
+
"INSERT INTO services (",
|
|
5808
|
+
" id,",
|
|
5809
|
+
" name,",
|
|
5810
|
+
" description,",
|
|
5811
|
+
" base_url,",
|
|
5812
|
+
" version,",
|
|
5813
|
+
" status,",
|
|
5814
|
+
" settings,",
|
|
5815
|
+
" created_at,",
|
|
5816
|
+
" updated_at,",
|
|
5817
|
+
" show_in_app_switcher",
|
|
5818
|
+
")",
|
|
5819
|
+
"VALUES (",
|
|
5820
|
+
` '${sqlString(serviceId)}',`,
|
|
5821
|
+
` '${sqlString(title)}',`,
|
|
5822
|
+
` 'First-party ${sqlString(title)} ${sqlString(surface)} application.',`,
|
|
5823
|
+
` '${sqlString(productionUrl)}',`,
|
|
5824
|
+
" '1.0.0',",
|
|
5825
|
+
" 'active',",
|
|
5826
|
+
` '${sqlString(settings)}',`,
|
|
5827
|
+
" strftime('%s', 'now'),",
|
|
5828
|
+
" strftime('%s', 'now'),",
|
|
5829
|
+
" 1",
|
|
5830
|
+
")",
|
|
5831
|
+
"ON CONFLICT(id) DO UPDATE SET",
|
|
5832
|
+
" name = excluded.name,",
|
|
5833
|
+
" description = excluded.description,",
|
|
5834
|
+
" base_url = excluded.base_url,",
|
|
5835
|
+
" version = excluded.version,",
|
|
5836
|
+
" status = excluded.status,",
|
|
5837
|
+
" settings = excluded.settings,",
|
|
5838
|
+
" updated_at = strftime('%s', 'now'),",
|
|
5839
|
+
" show_in_app_switcher = excluded.show_in_app_switcher;",
|
|
5840
|
+
""
|
|
5841
|
+
].join("\n");
|
|
5842
|
+
}
|
|
5750
5843
|
function developerManifest(application, options) {
|
|
5751
5844
|
return `${json({
|
|
5752
5845
|
schema: "https://topolo.app/schemas/topolo-app-manifest.v1.json",
|
|
@@ -5870,6 +5963,13 @@ function toTitle(value) {
|
|
|
5870
5963
|
function json(value) {
|
|
5871
5964
|
return JSON.stringify(value, null, 2);
|
|
5872
5965
|
}
|
|
5966
|
+
function hostnameFromUrl(value) {
|
|
5967
|
+
try {
|
|
5968
|
+
return new URL(value).hostname;
|
|
5969
|
+
} catch {
|
|
5970
|
+
return value.replace(/^https?:\/\//, "").replace(/\/.*$/, "");
|
|
5971
|
+
}
|
|
5972
|
+
}
|
|
5873
5973
|
async function pathExists(path4) {
|
|
5874
5974
|
try {
|
|
5875
5975
|
await access(path4, constants.F_OK);
|
|
@@ -5892,6 +5992,9 @@ function escapeHtml(value) {
|
|
|
5892
5992
|
function escapeSingleQuoted(value) {
|
|
5893
5993
|
return value.replace(/\\/g, "\\\\").replace(/'/g, "\\'");
|
|
5894
5994
|
}
|
|
5995
|
+
function sqlString(value) {
|
|
5996
|
+
return value.replace(/'/g, "''");
|
|
5997
|
+
}
|
|
5895
5998
|
function escapeDoubleQuoted(value) {
|
|
5896
5999
|
return value.replace(/\\/g, "\\\\").replace(/"/g, '\\"');
|
|
5897
6000
|
}
|
|
@@ -6223,7 +6326,7 @@ function recordApplicationEvidence(application, options = {}) {
|
|
|
6223
6326
|
let before = null;
|
|
6224
6327
|
if (existsSync3(evidencePath)) {
|
|
6225
6328
|
try {
|
|
6226
|
-
const raw = JSON.parse(
|
|
6329
|
+
const raw = JSON.parse(readFileSync3(evidencePath, "utf8"));
|
|
6227
6330
|
if (raw && typeof raw === "object" && raw.version === 1) {
|
|
6228
6331
|
before = raw;
|
|
6229
6332
|
}
|
|
@@ -6499,7 +6602,7 @@ function statusesAtOrWorse(threshold) {
|
|
|
6499
6602
|
}
|
|
6500
6603
|
|
|
6501
6604
|
// src/commands/platform.ts
|
|
6502
|
-
import { readdirSync as readdirSync2, readFileSync as
|
|
6605
|
+
import { readdirSync as readdirSync2, readFileSync as readFileSync4, statSync as statSync2 } from "fs";
|
|
6503
6606
|
import path3 from "path";
|
|
6504
6607
|
function registerPlatformCommand(program2) {
|
|
6505
6608
|
const platform3 = program2.command("platform").description("Internal Topolo first-party platform and personal app commands");
|
|
@@ -6625,7 +6728,7 @@ function scanStagingProductionUrls(rootInput, allowPatterns) {
|
|
|
6625
6728
|
function scanFile(filePath) {
|
|
6626
6729
|
if (shouldSkipFile(filePath)) return;
|
|
6627
6730
|
const relativePath = path3.relative(root, filePath);
|
|
6628
|
-
const content =
|
|
6731
|
+
const content = readFileSync4(filePath, "utf8");
|
|
6629
6732
|
const lines = content.split(/\r?\n/);
|
|
6630
6733
|
lines.forEach((line, index) => {
|
|
6631
6734
|
const matches = [...line.matchAll(PRODUCTION_TOPOLO_URL_PATTERN)].map((match) => match[0]);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@topolo/cli",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.20",
|
|
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": {
|