blockend-cli 1.4.4 → 1.4.5

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.
Files changed (2) hide show
  1. package/dist/index.js +36 -40
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -14,6 +14,15 @@ var REPO_NAME = "blockend";
14
14
  var BRANCH = "master";
15
15
  var RAW_CDN_BASE = `https://raw.githubusercontent.com/${REPO_OWNER}/${REPO_NAME}/${BRANCH}`;
16
16
  var MANIFEST_URL = `${RAW_CDN_BASE}/registry/index.json`;
17
+ function blockSupportsEnv(block, envKey) {
18
+ if (block.frameworks && block.frameworks.length > 0) {
19
+ return block.frameworks.includes("*") || block.frameworks.includes(envKey);
20
+ }
21
+ return block.adapters?.[envKey] !== void 0 || block.environments?.[envKey] !== void 0;
22
+ }
23
+ function resolveAdapterContext(block, envKey) {
24
+ return block.adapters?.[envKey] ?? block.adapters?.["*"] ?? block.environments?.[envKey] ?? block.environments?.["*"] ?? null;
25
+ }
17
26
  function rewriteFileImports(fileContent, writtenFilePath, blocksRoot, aliasBase) {
18
27
  if (!aliasBase || aliasBase.startsWith(".")) {
19
28
  return fileContent;
@@ -23,9 +32,7 @@ function rewriteFileImports(fileContent, writtenFilePath, blocksRoot, aliasBase)
23
32
  return fileContent.replace(importRegex, (match, keyword, openQuote, relativePath, closeQuote) => {
24
33
  const absoluteTarget = path.resolve(fileDir, relativePath);
25
34
  const fromBlocksRoot = path.relative(blocksRoot, absoluteTarget).replace(/\\/g, "/");
26
- if (fromBlocksRoot.startsWith("..")) {
27
- return match;
28
- }
35
+ if (fromBlocksRoot.startsWith("..")) return match;
29
36
  const aliased = `${aliasBase}/${fromBlocksRoot}`.replace(/\/+/g, "/");
30
37
  return `${keyword}${openQuote}${aliased}${closeQuote}`;
31
38
  });
@@ -41,11 +48,7 @@ function outputResult(json, result) {
41
48
  if (json) {
42
49
  process.stdout.write(JSON.stringify(result) + "\n");
43
50
  } else {
44
- if (result.success) {
45
- outro(pc.green(`\u2728 ${result.message}`));
46
- } else {
47
- outro(pc.yellow(`\u2139 ${result.message}`));
48
- }
51
+ outro(result.success ? pc.green(`\u2728 ${result.message}`) : pc.yellow(`\u2139 ${result.message}`));
49
52
  }
50
53
  }
51
54
  function handleCancel(value) {
@@ -92,7 +95,6 @@ async function addCommand(blockName, options = {}) {
92
95
  }
93
96
  if (config.language !== "typescript") {
94
97
  outputError(json, "Blockend currently only supports TypeScript projects.");
95
- if (!json) outro(pc.dim("Exiting."));
96
98
  return;
97
99
  }
98
100
  const physicalBlocksPath = config.paths.blocks;
@@ -111,9 +113,7 @@ async function addCommand(blockName, options = {}) {
111
113
  if (!json) {
112
114
  s.stop("Failed to fetch registry.");
113
115
  log.error(pc.dim(String(err)));
114
- } else {
115
- outputError(json, "Failed to fetch the component registry from GitHub.");
116
- }
116
+ } else outputError(json, "Failed to fetch registry from GitHub.");
117
117
  return;
118
118
  }
119
119
  const blockMap = registry.blocks && typeof registry.blocks === "object" && !Array.isArray(registry.blocks) ? registry.blocks : registry;
@@ -123,13 +123,11 @@ async function addCommand(blockName, options = {}) {
123
123
  }
124
124
  let targetBlock = blockName;
125
125
  if (!targetBlock) {
126
- const available = Object.entries(blockMap).filter(([, block]) => {
127
- if (!block) return false;
128
- return block.adapters?.[envKey] !== void 0 || block.environments?.[envKey] !== void 0;
129
- });
126
+ const available = Object.entries(blockMap).filter(
127
+ ([, block]) => block != null && blockSupportsEnv(block, envKey)
128
+ );
130
129
  if (available.length === 0) {
131
- const msg = `No blocks available for environment: ${envKey}`;
132
- outputError(json, msg);
130
+ outputError(json, `No blocks available for environment: ${envKey}`);
133
131
  if (!json) outro(pc.dim("Exiting."));
134
132
  return;
135
133
  }
@@ -148,17 +146,24 @@ async function addCommand(blockName, options = {}) {
148
146
  }
149
147
  const blockMeta = blockMap[targetBlock];
150
148
  if (!blockMeta) {
151
- outputError(json, `Block "${targetBlock}" does not exist in the registry.`);
149
+ outputError(json, `Block "${targetBlock}" not found in the registry.`);
152
150
  return;
153
151
  }
154
- const adapterContext = blockMeta.adapters?.[envKey] ?? blockMeta.environments?.[envKey];
155
- if (!adapterContext) {
152
+ if (!blockSupportsEnv(blockMeta, envKey)) {
156
153
  outputError(json, `Block "${targetBlock}" does not support environment: ${envKey}`);
157
154
  return;
158
155
  }
156
+ const adapterContext = resolveAdapterContext(blockMeta, envKey);
157
+ if (!adapterContext) {
158
+ outputError(
159
+ json,
160
+ `Block "${targetBlock}" has no adapter or environment entry for: ${envKey}. This is a registry configuration issue \u2014 please open an issue.`
161
+ );
162
+ return;
163
+ }
159
164
  const variantKeys = Object.keys(adapterContext.variants ?? {});
160
165
  if (variantKeys.length === 0) {
161
- outputError(json, `No variants found for block "${targetBlock}" in environment "${envKey}"`);
166
+ outputError(json, `No variants found for "${targetBlock}" / "${envKey}".`);
162
167
  return;
163
168
  }
164
169
  let selectedVariant;
@@ -205,9 +210,7 @@ async function addCommand(blockName, options = {}) {
205
210
  ...variantMeta?.devDependencies ?? []
206
211
  ].filter((d) => !(d in installedDeps));
207
212
  if (missingProd.length > 0 || missingDev.length > 0) {
208
- if (!json) {
209
- log.warn(`Missing dependencies: ${pc.cyan([...missingProd, ...missingDev].join(", "))}`);
210
- }
213
+ if (!json) log.warn(`Missing: ${pc.cyan([...missingProd, ...missingDev].join(", "))}`);
211
214
  const shouldInstall = yes ? true : await confirm({ message: "Install missing dependencies?", initialValue: true });
212
215
  if (!yes) handleCancel(shouldInstall);
213
216
  if (shouldInstall) {
@@ -246,15 +249,13 @@ async function addCommand(blockName, options = {}) {
246
249
  if (!json) {
247
250
  s.stop("Installation failed.");
248
251
  log.error(pc.dim(String(err)));
249
- } else {
250
- outputError(json, "Dependency installation failed.");
251
- }
252
+ } else outputError(json, "Dependency installation failed.");
252
253
  return;
253
254
  }
254
255
  }
255
256
  }
256
257
  const filesToDownload = [];
257
- if (blockMeta.baseFiles && Array.isArray(blockMeta.baseFiles)) {
258
+ if (blockMeta.baseFiles?.length) {
258
259
  filesToDownload.push(...blockMeta.baseFiles);
259
260
  }
260
261
  if (adapterContext.core) {
@@ -265,11 +266,9 @@ async function addCommand(blockName, options = {}) {
265
266
  }
266
267
  if (variantMeta && Array.isArray(variantMeta.files)) {
267
268
  for (const entry of variantMeta.files) {
268
- if (typeof entry === "string") {
269
- filesToDownload.push({ source: entry, target: path.basename(entry) });
270
- } else {
271
- filesToDownload.push(entry);
272
- }
269
+ filesToDownload.push(
270
+ typeof entry === "string" ? { source: entry, target: path.basename(entry) } : entry
271
+ );
273
272
  }
274
273
  }
275
274
  let hasConflict = false;
@@ -296,9 +295,8 @@ async function addCommand(blockName, options = {}) {
296
295
  const filesWritten = [];
297
296
  try {
298
297
  for (const fm of filesToDownload) {
299
- const fileUrl = `${RAW_CDN_BASE}/${fm.source}`;
300
- const res = await fetch(fileUrl);
301
- if (!res.ok) throw new Error(`Failed to download: ${fm.source} (HTTP ${res.status})`);
298
+ const res = await fetch(`${RAW_CDN_BASE}/${fm.source}`);
299
+ if (!res.ok) throw new Error(`Download failed: ${fm.source} (HTTP ${res.status})`);
302
300
  let content = await res.text();
303
301
  const writtenFilePath = path.join(targetFolder, fm.target);
304
302
  content = rewriteFileImports(content, writtenFilePath, blocksRootAbsolute, aliasBase);
@@ -318,9 +316,7 @@ async function addCommand(blockName, options = {}) {
318
316
  if (!json) {
319
317
  s.stop("Failed.");
320
318
  log.error(pc.dim(String(err)));
321
- } else {
322
- outputError(json, "Fatal error while writing block files.");
323
- }
319
+ } else outputError(json, "Fatal error while writing block files.");
324
320
  }
325
321
  }
326
322
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "blockend-cli",
3
- "version": "1.4.4",
3
+ "version": "1.4.5",
4
4
  "description": "CLI for installing production-ready backend blocks into Next.js, Express, Hono, NestJS, and other Node.js applications.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",