@topolo/cli 0.6.0 → 0.6.2
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/generate-wrangler.mjs +6 -1
- package/dist/index.js +83 -33
- package/package.json +4 -4
|
@@ -845,7 +845,12 @@ function emitCloudcontrol() {
|
|
|
845
845
|
}
|
|
846
846
|
}
|
|
847
847
|
cc.tags = existing.tags || ['application', 'cloudflare', 'github-actions', 'javascript'];
|
|
848
|
-
|
|
848
|
+
const primaryEnvironment = [...ENVS]
|
|
849
|
+
.reverse()
|
|
850
|
+
.find((environment) => deployableEnvironments.has(environment));
|
|
851
|
+
if (primaryEnvironment) {
|
|
852
|
+
cc.cloudflare_account_id = manifest.environments[primaryEnvironment].accountId;
|
|
853
|
+
}
|
|
849
854
|
|
|
850
855
|
return JSON.stringify(cc, null, 2) + '\n';
|
|
851
856
|
}
|
package/dist/index.js
CHANGED
|
@@ -4724,14 +4724,26 @@ function isEvidenceStampFresh(stamp) {
|
|
|
4724
4724
|
return Date.now() - recordedAt <= EVIDENCE_FRESHNESS_MS;
|
|
4725
4725
|
}
|
|
4726
4726
|
var SKIPPED_DIRS = /* @__PURE__ */ new Set([
|
|
4727
|
+
".action-normalize",
|
|
4728
|
+
".claude",
|
|
4729
|
+
".codex-worktrees",
|
|
4730
|
+
".deploy",
|
|
4727
4731
|
".git",
|
|
4728
4732
|
".next",
|
|
4733
|
+
".playwright",
|
|
4734
|
+
".topolo-tmp",
|
|
4729
4735
|
".turbo",
|
|
4736
|
+
".worktrees",
|
|
4730
4737
|
".wrangler",
|
|
4738
|
+
"_tmp",
|
|
4739
|
+
"_worktrees",
|
|
4740
|
+
"artifacts",
|
|
4731
4741
|
"build",
|
|
4732
4742
|
"coverage",
|
|
4733
4743
|
"dist",
|
|
4734
|
-
"node_modules"
|
|
4744
|
+
"node_modules",
|
|
4745
|
+
"output",
|
|
4746
|
+
"tmp"
|
|
4735
4747
|
]);
|
|
4736
4748
|
var SOURCE_EXTENSIONS = /* @__PURE__ */ new Set([
|
|
4737
4749
|
".cjs",
|
|
@@ -5416,8 +5428,11 @@ function sharedAuthEvidence(evidence) {
|
|
|
5416
5428
|
if (text.includes("TopoloAuthMiddleware")) items.push("source=TopoloAuthMiddleware");
|
|
5417
5429
|
if (text.includes("TopoloClient")) items.push("source=TopoloClient");
|
|
5418
5430
|
if (text.includes("TopoloOAuth")) items.push("source=TopoloOAuth");
|
|
5419
|
-
|
|
5420
|
-
|
|
5431
|
+
const browserRecords = productionBrowserSourceRecords(evidence);
|
|
5432
|
+
const blockingBoot = browserRecords.find(({ text: source }) => /\b(?:auth|authClient|topoloAuth)\.initialize(?:Session)?\(\s*\)/i.test(source));
|
|
5433
|
+
const backgroundBoot = browserRecords.find(({ text: source }) => /cookieRefresh:\s*['"]background['"]/.test(source));
|
|
5434
|
+
if (blockingBoot) items.push("auth-boot=blocking-cookie-refresh", `auth-boot-file=${blockingBoot.path}`);
|
|
5435
|
+
if (backgroundBoot) items.push("auth-boot=background-cookie-refresh", `auth-background-file=${backgroundBoot.path}`);
|
|
5421
5436
|
if (/Authorization.*Bearer/i.test(text) && (text.includes("/validate") || text.includes("TOPOLO_AUTH_URL") || text.includes("AUTH_BASE_URL") || text.includes("auth.topolo.app"))) {
|
|
5422
5437
|
items.push("source=auth-validate-fetch");
|
|
5423
5438
|
}
|
|
@@ -5436,7 +5451,8 @@ function documentedOperatorLocalAuthBoundaryEvidence(evidence) {
|
|
|
5436
5451
|
}
|
|
5437
5452
|
function sharedShellEvidence(evidence) {
|
|
5438
5453
|
const deps = dependencyNames(evidence);
|
|
5439
|
-
const
|
|
5454
|
+
const browserRecords = productionBrowserSourceRecords(evidence);
|
|
5455
|
+
const text = browserRecords.map((record4) => record4.text).join("\n");
|
|
5440
5456
|
const items = [];
|
|
5441
5457
|
if (deps.has("@topolo-io/app-shell")) items.push("dependency=@topolo-io/app-shell");
|
|
5442
5458
|
if (deps.has("@topolo-io/ui-kit")) items.push("dependency=@topolo-io/ui-kit");
|
|
@@ -5456,11 +5472,9 @@ function sharedShellEvidence(evidence) {
|
|
|
5456
5472
|
const hasVisualQaFixtures = hasVisualQaMode && /fixture|visualQaResponse|visualQaApi|mock[A-Z]\w*|devpreview/i.test(text) && /fetch|useQuery|api/i.test(text);
|
|
5457
5473
|
if (hasVisualQaFixtures) items.push("source=visual-qa-fixtures");
|
|
5458
5474
|
if (/from\s+['"]lucide-react['"]/.test(text)) items.push("local=direct-lucide-react");
|
|
5459
|
-
|
|
5460
|
-
|
|
5461
|
-
|
|
5462
|
-
if (/(?:<span[^>]*>|<div[^>]*>)[^<]{0,16}[◈◇⬡⬢▣◉✉▷✦○◆✕⚙🔑💡⚠✓♫]/.test(text)) {
|
|
5463
|
-
items.push("local=raw-symbol-icons");
|
|
5475
|
+
const rawSymbolRecord = browserRecords.find(({ text: source }) => /(?:icon|Icon)\s*:\s*['"][◈◇⬡⬢▣◉✉▷✦○◆✕⚙🔑💡⚠✓♫]/.test(source) || /(?:<span[^>]*>|<div[^>]*>)[^<]{0,16}[◈◇⬡⬢▣◉✉▷✦○◆✕⚙🔑💡⚠✓♫]/.test(source));
|
|
5476
|
+
if (rawSymbolRecord) {
|
|
5477
|
+
items.push("local=raw-symbol-icons", `raw-symbol-file=${rawSymbolRecord.path}`);
|
|
5464
5478
|
}
|
|
5465
5479
|
if (text.includes(["Topolo", "Workspace", "Shell"].join(""))) items.push("forbidden=workspace-shell");
|
|
5466
5480
|
if (/\bTopoloShell\b/.test(text)) items.push("legacy=TopoloShellFrame");
|
|
@@ -5490,6 +5504,16 @@ function hasLocalBrowserSurface(evidence) {
|
|
|
5490
5504
|
(file) => file.endsWith(".tsx") || file.endsWith(".jsx") || file.includes("/src/client/") || file.includes("/client/")
|
|
5491
5505
|
);
|
|
5492
5506
|
}
|
|
5507
|
+
function productionBrowserSourceRecords(evidence) {
|
|
5508
|
+
return evidence.source.records.filter((record4) => {
|
|
5509
|
+
const sourcePath = record4.path.toLowerCase();
|
|
5510
|
+
if (/(^|\/)(?:__tests__|test|tests|scripts|fixtures|migrations)(\/|$)/.test(sourcePath)) return false;
|
|
5511
|
+
if (/\.(?:test|spec)\.[^.]+$/.test(sourcePath)) return false;
|
|
5512
|
+
if (/\/apps\/(?:api|analytics|gateway|jobs|queue|runtime|worker)\//.test(sourcePath)) return false;
|
|
5513
|
+
if (/\.(?:tsx|jsx)$/.test(sourcePath)) return true;
|
|
5514
|
+
return /\/(?:web|marketing|desktop)\/src\//.test(sourcePath) && /\.(?:ts|js)$/.test(sourcePath);
|
|
5515
|
+
});
|
|
5516
|
+
}
|
|
5493
5517
|
function organizationScopeEvidence(evidence) {
|
|
5494
5518
|
const text = evidence.source.text;
|
|
5495
5519
|
const items = [];
|
|
@@ -5657,18 +5681,21 @@ function findWranglerFiles(appRoot) {
|
|
|
5657
5681
|
return ["wrangler.json", "wrangler.jsonc", "wrangler.toml"].filter((file) => isFile(path.join(appRoot, file))).map((file) => relativeTopoloPath(path.join(appRoot, file)));
|
|
5658
5682
|
}
|
|
5659
5683
|
function readSourceIndex(root) {
|
|
5660
|
-
if (!isDirectory(root)) return { files: [], text: "" };
|
|
5684
|
+
if (!isDirectory(root)) return { files: [], text: "", records: [] };
|
|
5661
5685
|
const files = collectSourceFiles(root, 4e3);
|
|
5662
|
-
const
|
|
5686
|
+
const records = files.map((file) => {
|
|
5687
|
+
let text = "";
|
|
5663
5688
|
try {
|
|
5664
|
-
|
|
5689
|
+
text = readFileSync3(file, "utf8");
|
|
5665
5690
|
} catch {
|
|
5666
|
-
|
|
5691
|
+
text = "";
|
|
5667
5692
|
}
|
|
5693
|
+
return { path: relativeTopoloPath(file), text };
|
|
5668
5694
|
});
|
|
5669
5695
|
return {
|
|
5670
|
-
files:
|
|
5671
|
-
text:
|
|
5696
|
+
files: records.map((record4) => record4.path),
|
|
5697
|
+
text: records.map((record4) => record4.text).join("\n"),
|
|
5698
|
+
records
|
|
5672
5699
|
};
|
|
5673
5700
|
}
|
|
5674
5701
|
function collectSourceFiles(root, limit) {
|
|
@@ -6192,7 +6219,7 @@ var APPLICATION_CAPABILITY_REGISTRY = {
|
|
|
6192
6219
|
platform: ["@topolo-io/notifications"],
|
|
6193
6220
|
developer: []
|
|
6194
6221
|
}, [], [], [], ["notification-consumer"], ["notification-inbox-smoke"]),
|
|
6195
|
-
notification_producer: capability("notification_producer", "TopoloNotify + TopoloDevelopers", platformTarget, ["
|
|
6222
|
+
notification_producer: capability("notification_producer", "TopoloNotify + TopoloDevelopers", platformTarget, ["api"], ["api"], {
|
|
6196
6223
|
platform: ["@topolo-io/notifications", "@topolo-io/auth-middleware"],
|
|
6197
6224
|
developer: []
|
|
6198
6225
|
}, [], ["events:write"], [], ["notification-producer-adapter", "notification-contracts"], ["notification-delivery-smoke"]),
|
|
@@ -9396,20 +9423,13 @@ function scaffoldFiles(options) {
|
|
|
9396
9423
|
`CREATE TABLE IF NOT EXISTS ${tablePrefix}_workspaces (`,
|
|
9397
9424
|
" id TEXT PRIMARY KEY,",
|
|
9398
9425
|
` ${tenantColumn} TEXT NOT NULL,`,
|
|
9399
|
-
"
|
|
9400
|
-
" slug TEXT NOT NULL,",
|
|
9401
|
-
" created_by_user_id TEXT,",
|
|
9402
|
-
" created_by_email TEXT,",
|
|
9426
|
+
" status TEXT NOT NULL DEFAULT 'active' CHECK (status IN ('active', 'archived')),",
|
|
9403
9427
|
" created_at TEXT NOT NULL,",
|
|
9404
|
-
" updated_at TEXT NOT NULL
|
|
9405
|
-
` UNIQUE(${tenantColumn}, slug)`,
|
|
9428
|
+
" updated_at TEXT NOT NULL",
|
|
9406
9429
|
");",
|
|
9407
9430
|
"",
|
|
9408
9431
|
`CREATE INDEX IF NOT EXISTS idx_${tablePrefix}_workspaces_${tenantColumn}`,
|
|
9409
9432
|
` ON ${tablePrefix}_workspaces(${tenantColumn});`,
|
|
9410
|
-
"",
|
|
9411
|
-
`CREATE INDEX IF NOT EXISTS idx_${tablePrefix}_workspaces_slug`,
|
|
9412
|
-
` ON ${tablePrefix}_workspaces(${tenantColumn}, slug);`,
|
|
9413
9433
|
""
|
|
9414
9434
|
].join("\n");
|
|
9415
9435
|
const base = target === "platform" ? firstPartyAppPath(application.appDir, options.payload.audience) : application.appDir;
|
|
@@ -9972,10 +9992,10 @@ export default defineConfig({
|
|
|
9972
9992
|
if (options.payload.resources.d1) {
|
|
9973
9993
|
files.push({
|
|
9974
9994
|
path: `${apiBase}/migrations/0001_initial.sql`,
|
|
9975
|
-
purpose: "Canonical multi-tenant baseline: the
|
|
9995
|
+
purpose: "Canonical multi-tenant baseline: the identity-only workspace mirror (platform owns the record).",
|
|
9976
9996
|
requiredSignals: [
|
|
9977
|
-
`${tablePrefix}_workspaces
|
|
9978
|
-
|
|
9997
|
+
`${tablePrefix}_workspaces is an identity-only mirror (id, ${tenantColumn}, status) \u2014 no name/slug/is_default; the workspace record lives in TopoloAuth`,
|
|
9998
|
+
`every domain table added later carries ${tenantColumn} and a workspace_id scope column`
|
|
9979
9999
|
],
|
|
9980
10000
|
content: workspacesMigrationSql
|
|
9981
10001
|
});
|
|
@@ -10267,6 +10287,22 @@ async function reconcileApplicationCapabilitySource(options) {
|
|
|
10267
10287
|
distributionModel: registration.distributionModel === "marketplace" ? "marketplace" : "organization_internal",
|
|
10268
10288
|
requested: [...existing, ...options.additions ?? []]
|
|
10269
10289
|
});
|
|
10290
|
+
const marketplace = record(registration.marketplace);
|
|
10291
|
+
const unlistedNativeArtifact = options.ownerType === "topolo_first_party" && registration.surfaceModel === "mobile_container" && registration.distributionModel === "organization_internal" && marketplace?.intent === "unlisted";
|
|
10292
|
+
if (unlistedNativeArtifact) {
|
|
10293
|
+
return {
|
|
10294
|
+
mode: options.mode,
|
|
10295
|
+
applied: false,
|
|
10296
|
+
status: "in_sync",
|
|
10297
|
+
manifestPath,
|
|
10298
|
+
packagePath,
|
|
10299
|
+
contractPath,
|
|
10300
|
+
capabilities,
|
|
10301
|
+
changes: [],
|
|
10302
|
+
missingResources: [],
|
|
10303
|
+
verticalConfiguration: []
|
|
10304
|
+
};
|
|
10305
|
+
}
|
|
10270
10306
|
const expectedComposition = capabilityCompositionProjection(capabilities);
|
|
10271
10307
|
const expectedNotifications = capabilities.selected.includes("notification_producer") ? { role: "producer", contracts: "topolo.notification-contracts.json" } : capabilities.selected.includes("notifications") ? { role: "consumer_only" } : { role: "internal_non_producer" };
|
|
10272
10308
|
const changes = [];
|
|
@@ -10421,7 +10457,10 @@ function manifestProvidesResource(manifest, resource) {
|
|
|
10421
10457
|
return false;
|
|
10422
10458
|
}
|
|
10423
10459
|
function packageVersion(packageName, target) {
|
|
10424
|
-
if (target === "platform")
|
|
10460
|
+
if (target === "platform") {
|
|
10461
|
+
if (packageName === "@topolo-io/notifications") return "^0.6.8";
|
|
10462
|
+
return "latest";
|
|
10463
|
+
}
|
|
10425
10464
|
if (packageName === "@topolo/login") return "^0.1.0";
|
|
10426
10465
|
if (packageName === "@topolo/sdk") return "^0.8.1";
|
|
10427
10466
|
throw new Error(`Capability registry exposed private package ${packageName} to a third-party application.`);
|
|
@@ -10530,10 +10569,19 @@ function resolveManifestApplicationUrl(manifest, environment) {
|
|
|
10530
10569
|
if (hostOverride) return `https://${hostOverride.replace(/^https?:\/\//, "").replace(/\/+$/, "")}`;
|
|
10531
10570
|
const domain = manifest.environments?.[environment]?.domain;
|
|
10532
10571
|
if (!target.subdomain || !domain) {
|
|
10572
|
+
if (manifest.registration?.productionUrl) {
|
|
10573
|
+
return manifest.registration.productionUrl.replace(/\/+$/, "");
|
|
10574
|
+
}
|
|
10533
10575
|
throw new Error(`Cannot derive the ${environment} application URL from target ${targetName}.`);
|
|
10534
10576
|
}
|
|
10535
10577
|
return `https://${target.subdomain}.${domain}`;
|
|
10536
10578
|
}
|
|
10579
|
+
function resolveManifestHealthcheckPath(manifest) {
|
|
10580
|
+
const targets = manifest.targets || {};
|
|
10581
|
+
const targetName = manifest.primaryTarget || (targets.web ? "web" : Object.keys(targets)[0]);
|
|
10582
|
+
const healthcheckPath = targetName ? targets[targetName]?.healthcheckPath?.trim() : "";
|
|
10583
|
+
return healthcheckPath && healthcheckPath.startsWith("/") && !healthcheckPath.startsWith("//") ? healthcheckPath : "/health";
|
|
10584
|
+
}
|
|
10537
10585
|
function assertRegistration(value) {
|
|
10538
10586
|
const registration = record2(value);
|
|
10539
10587
|
const required = [
|
|
@@ -10549,10 +10597,11 @@ function assertRegistration(value) {
|
|
|
10549
10597
|
"version",
|
|
10550
10598
|
"pricing",
|
|
10551
10599
|
"supportEmail",
|
|
10552
|
-
"auth",
|
|
10553
10600
|
"capabilities",
|
|
10554
10601
|
"marketplace"
|
|
10555
10602
|
];
|
|
10603
|
+
const marketplace = record2(registration?.marketplace);
|
|
10604
|
+
if (marketplace?.intent !== "unlisted") required.push("auth");
|
|
10556
10605
|
const missing = required.filter((field) => registration?.[field] == null || registration[field] === "");
|
|
10557
10606
|
if (missing.length) {
|
|
10558
10607
|
throw new Error(
|
|
@@ -10656,7 +10705,7 @@ async function loadApplicationReconcileRequest(options) {
|
|
|
10656
10705
|
}
|
|
10657
10706
|
const environment = options.environment || selectedEnvironment();
|
|
10658
10707
|
const productionUrl = resolveManifestApplicationUrl(manifest, environment);
|
|
10659
|
-
const callbackPath = registration.auth.callbackPath.startsWith("/") ? registration.auth.callbackPath : `/${registration.auth.callbackPath}
|
|
10708
|
+
const callbackPath = registration.auth ? registration.auth.callbackPath.startsWith("/") ? registration.auth.callbackPath : `/${registration.auth.callbackPath}` : null;
|
|
10660
10709
|
const appId = String(manifest.appId || manifest.app_id || "").trim();
|
|
10661
10710
|
if (!appId) throw new Error("topolo.app.json must declare the immutable appId.");
|
|
10662
10711
|
return {
|
|
@@ -10680,13 +10729,14 @@ async function loadApplicationReconcileRequest(options) {
|
|
|
10680
10729
|
pricingType: registration.pricing.type,
|
|
10681
10730
|
monthlyPrice: registration.pricing.monthlyPrice ?? null,
|
|
10682
10731
|
productionUrl,
|
|
10732
|
+
healthcheckPath: resolveManifestHealthcheckPath(manifest),
|
|
10683
10733
|
demoUrl: registration.ownerType === "topolo_first_party" ? productionUrl : registration.demoUrl ?? productionUrl,
|
|
10684
10734
|
repoUrl: registration.repoUrl ?? null,
|
|
10685
10735
|
supportEmail: registration.supportEmail,
|
|
10686
10736
|
tags: registration.tags ?? [],
|
|
10687
10737
|
screenshots: registration.screenshots ?? [],
|
|
10688
|
-
callbackUrls: [`${productionUrl}${callbackPath}`],
|
|
10689
|
-
requestedScopes: registration.auth
|
|
10738
|
+
callbackUrls: callbackPath ? [`${productionUrl}${callbackPath}`] : [],
|
|
10739
|
+
requestedScopes: registration.auth?.requestedScopes ?? [],
|
|
10690
10740
|
capabilities: registration.capabilities,
|
|
10691
10741
|
marketplace: { ...registration.marketplace, appUrl: productionUrl },
|
|
10692
10742
|
notifications: manifest.notifications ?? null
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@topolo/cli",
|
|
3
|
-
"version": "0.6.
|
|
4
|
-
"topoloPublishedVersion": "0.6.
|
|
3
|
+
"version": "0.6.2",
|
|
4
|
+
"topoloPublishedVersion": "0.6.2",
|
|
5
5
|
"description": "Command-line interface for Topolo developers, operators, and agents, with internal first-party scaffolding available under the topolo platform namespace.",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"bin": {
|
|
@@ -31,10 +31,10 @@
|
|
|
31
31
|
"devDependencies": {
|
|
32
32
|
"@topolo/sdk": "latest",
|
|
33
33
|
"@types/node": "^20.12.0",
|
|
34
|
-
"@vitest/coverage-v8": "
|
|
34
|
+
"@vitest/coverage-v8": "3.2.6",
|
|
35
35
|
"tsup": "^8.0.0",
|
|
36
36
|
"typescript": "^5.4.0",
|
|
37
|
-
"vitest": "
|
|
37
|
+
"vitest": "3.2.6"
|
|
38
38
|
},
|
|
39
39
|
"engines": {
|
|
40
40
|
"node": ">=20"
|