@topogram/cli 0.3.44 → 0.3.45

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@topogram/cli",
3
- "version": "0.3.44",
3
+ "version": "0.3.45",
4
4
  "description": "Topogram CLI for checking Topogram workspaces and generating app bundles.",
5
5
  "license": "Apache-2.0",
6
6
  "repository": {
package/src/cli.js CHANGED
@@ -595,9 +595,9 @@ function printGeneratorHelp() {
595
595
  console.log("Inspects generator manifests and checks generator pack conformance.");
596
596
  console.log("");
597
597
  console.log("Notes:");
598
- console.log(" - list shows bundled generators plus installed package-backed generators declared in package.json.");
599
- console.log(" - show accepts an installed package name or a bundled fallback generator id.");
600
- console.log(" - check validates a local generator package path or an already installed package.");
598
+ console.log(" - list shows bundled generators plus installed package-backed generators declared in package.json; it reads manifests only.");
599
+ console.log(" - show accepts an installed package name or a bundled fallback generator id; it does not load adapter code.");
600
+ console.log(" - check validates a local generator package path or an already installed package by loading the adapter and running smoke generation.");
601
601
  console.log(" - Topogram does not install generator packages during show or check.");
602
602
  console.log(` - package-backed project generators are governed by ${GENERATOR_POLICY_FILE}; bundled topogram/* generators are allowed.`);
603
603
  console.log("");
@@ -1250,6 +1250,7 @@ function printGeneratorCheck(payload) {
1250
1250
  console.log(`Projection platforms: ${payload.manifest.projectionPlatforms.join(", ")}`);
1251
1251
  console.log(`Source mode: ${payload.manifest.source}`);
1252
1252
  }
1253
+ console.log("Executes package code: yes (loads adapter and runs smoke generate)");
1253
1254
  console.log("");
1254
1255
  console.log("Checks:");
1255
1256
  for (const check of payload.checks || []) {
@@ -1285,6 +1286,8 @@ function generatorManifestSummary(manifest, metadata = {}) {
1285
1286
  stack: manifest.stack || {},
1286
1287
  capabilities: manifest.capabilities || {},
1287
1288
  source: manifest.source,
1289
+ loadsAdapter: false,
1290
+ executesPackageCode: false,
1288
1291
  ...(manifest.profile ? { profile: manifest.profile } : {}),
1289
1292
  ...(manifest.package ? { package: manifest.package } : {}),
1290
1293
  ...(installCommand ? { installCommand } : {}),
@@ -1496,6 +1499,8 @@ function printGeneratorList(payload) {
1496
1499
  const stack = Object.values(generator.stack || {}).join(" + ") || "not declared";
1497
1500
  console.log(`- ${id}${generator.version ? `@${generator.version}` : ""} (${generator.surface || "unknown"}, ${status})`);
1498
1501
  console.log(` Source: ${generator.source}`);
1502
+ console.log(" Adapter loaded: no");
1503
+ console.log(" Executes package code: no");
1499
1504
  if (generator.source === "package") {
1500
1505
  console.log(` Installed: ${generator.installed ? "yes" : "no"}`);
1501
1506
  }
@@ -1529,6 +1534,8 @@ function printGeneratorShow(payload) {
1529
1534
  console.log(`Generator: ${generator.id}@${generator.version}`);
1530
1535
  console.log(`Surface: ${generator.surface}`);
1531
1536
  console.log(`Source: ${generator.source}${generator.planned ? " (planned)" : ""}`);
1537
+ console.log("Adapter loaded: no");
1538
+ console.log("Executes package code: no");
1532
1539
  if (generator.source === "package") {
1533
1540
  console.log(`Installed: ${generator.installed ? "yes" : "no"}`);
1534
1541
  }
@@ -10,6 +10,10 @@ import {
10
10
  resolveGeneratorManifestForBinding,
11
11
  validateGeneratorManifest
12
12
  } from "./registry.js";
13
+ import {
14
+ generatorPolicyDiagnosticsForBindings,
15
+ loadGeneratorPolicy
16
+ } from "../generator-policy.js";
13
17
  import { generateDbContractGraph } from "./surfaces/databases/contract.js";
14
18
  import { generateDbLifecyclePlan } from "./surfaces/databases/lifecycle-shared.js";
15
19
  import {
@@ -252,6 +256,26 @@ function loadPackageGeneratorAdapter(manifest, component, options = {}) {
252
256
  throw new Error(`Component '${component?.id || "unknown"}' generator '${manifest.id}@${manifest.version}' is package-backed but does not declare a package.`);
253
257
  }
254
258
  const rootDir = options.configDir || options.rootDir || process.cwd();
259
+ const diagnostics = generatorPolicyDiagnosticsForBindings(
260
+ loadGeneratorPolicy(rootDir),
261
+ [{
262
+ componentId: String(component?.id || "unknown"),
263
+ componentType: String(component?.type || manifest.surface || "unknown"),
264
+ projection: String(component?.projection?.id || component?.projection || "unknown"),
265
+ generatorId: String(component?.generator?.id || manifest.id),
266
+ version: String(component?.generator?.version || manifest.version),
267
+ packageName
268
+ }],
269
+ "generator-adapter"
270
+ );
271
+ const errors = diagnostics.filter((diagnostic) => diagnostic.severity === "error");
272
+ if (errors.length > 0) {
273
+ throw new Error(errors.map((diagnostic) =>
274
+ diagnostic.suggestedFix
275
+ ? `${diagnostic.message} Suggested fix: ${diagnostic.suggestedFix}`
276
+ : diagnostic.message
277
+ ).join("\n"));
278
+ }
255
279
  let moduleValue;
256
280
  try {
257
281
  moduleValue = requireFromProject(rootDir)(packageName);
@@ -25,6 +25,7 @@ import {
25
25
  * @property {Array<{ name: string, ok: boolean, message: string }>} checks
26
26
  * @property {string[]} errors
27
27
  * @property {{ files: number, artifacts: number, diagnostics: number }|null} smoke
28
+ * @property {boolean} executesPackageCode
28
29
  */
29
30
 
30
31
  /**
@@ -238,7 +239,8 @@ export function checkGeneratorPack(sourceSpec, options = {}) {
238
239
  manifest: null,
239
240
  checks: [],
240
241
  errors: [],
241
- smoke: null
242
+ smoke: null,
243
+ executesPackageCode: true
242
244
  };
243
245
 
244
246
  /** @type {any|null} */
@@ -1,6 +1,7 @@
1
1
  // @ts-check
2
2
 
3
3
  import { getProjection } from "../shared.js";
4
+ import { generateServerContract } from "./server-contract.js";
4
5
 
5
6
  function renderPackageJson(profile) {
6
7
  const dependencies = profile === "express"
@@ -41,10 +42,10 @@ function routePath(path) {
41
42
  return String(path || "/").replace(/:([A-Za-z0-9_]+)/g, ":$1");
42
43
  }
43
44
 
44
- function renderHonoIndex(projection) {
45
- const routes = (projection.http || []).map((route) => {
45
+ function renderHonoIndex(projection, contract) {
46
+ const routes = (contract.routes || []).map((route) => {
46
47
  const method = String(route.method || "GET").toLowerCase();
47
- return `app.${method}("${routePath(route.path)}", (c) => c.json({ ok: true, capability: "${route.capabilityId}", input: { params: c.req.param(), query: c.req.query() } }, ${route.success || 200} as any));`;
48
+ return `app.${method}("${routePath(route.path)}", (c) => c.json({ ok: true, capability: "${route.capabilityId}", input: { params: c.req.param(), query: c.req.query() } }, ${route.successStatus || 200} as any));`;
48
49
  }).join("\n");
49
50
  return `import { serve } from "@hono/node-server";
50
51
  import { Hono } from "hono";
@@ -65,10 +66,10 @@ function expressPath(path) {
65
66
  return routePath(path);
66
67
  }
67
68
 
68
- function renderExpressIndex(projection) {
69
- const routes = (projection.http || []).map((route) => {
69
+ function renderExpressIndex(projection, contract) {
70
+ const routes = (contract.routes || []).map((route) => {
70
71
  const method = String(route.method || "GET").toLowerCase();
71
- return `app.${method}("${expressPath(route.path)}", (req, res) => res.status(${route.success || 200}).json({ ok: true, capability: "${route.capabilityId}", input: { params: req.params, query: req.query } }));`;
72
+ return `app.${method}("${expressPath(route.path)}", (req, res) => res.status(${route.successStatus || 200}).json({ ok: true, capability: "${route.capabilityId}", input: { params: req.params, query: req.query } }));`;
72
73
  }).join("\n");
73
74
  return `import express from "express";
74
75
 
@@ -88,10 +89,11 @@ app.listen(port, () => {
88
89
 
89
90
  export function generateStatelessServer(graph, options = {}) {
90
91
  const projection = getProjection(graph, options.projectionId);
92
+ const contract = generateServerContract(graph, { ...options, projectionId: projection.id });
91
93
  const profile = options.profile === "express" ? "express" : "hono";
92
94
  return {
93
95
  "package.json": renderPackageJson(profile),
94
96
  "tsconfig.json": renderTsconfig(),
95
- "src/index.ts": profile === "express" ? renderExpressIndex(projection) : renderHonoIndex(projection)
97
+ "src/index.ts": profile === "express" ? renderExpressIndex(projection, contract) : renderHonoIndex(projection, contract)
96
98
  };
97
99
  }