blockend-cli 2.0.2 → 2.1.0
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/commands/add.d.ts +2 -0
- package/dist/commands/init.d.ts +1 -0
- package/dist/index.js +51 -10
- package/package.json +2 -2
package/dist/commands/add.d.ts
CHANGED
|
@@ -29,6 +29,8 @@ export interface RegistryManifest {
|
|
|
29
29
|
blocks?: Record<string, BlockManifest>;
|
|
30
30
|
[blockKey: string]: unknown;
|
|
31
31
|
}
|
|
32
|
+
export declare function selectVariant(variantKeys: string[], preferredVariant?: string): string;
|
|
33
|
+
export declare function resolvePreferredVariant(variantKeys: string[], recordedVariant: string | undefined, targetFolder: string): Promise<string | undefined>;
|
|
32
34
|
export declare function parseDepSpec(dep: string): {
|
|
33
35
|
name: string;
|
|
34
36
|
versionRange: string | null;
|
package/dist/commands/init.d.ts
CHANGED
package/dist/index.js
CHANGED
|
@@ -20,6 +20,34 @@ function blockSupportsEnv(block, envKey) {
|
|
|
20
20
|
}
|
|
21
21
|
return block.adapters?.[envKey] !== void 0 || block.environments?.[envKey] !== void 0;
|
|
22
22
|
}
|
|
23
|
+
function selectVariant(variantKeys, preferredVariant) {
|
|
24
|
+
if (preferredVariant && variantKeys.includes(preferredVariant)) {
|
|
25
|
+
return preferredVariant;
|
|
26
|
+
}
|
|
27
|
+
if (variantKeys.includes("memory")) return "memory";
|
|
28
|
+
if (variantKeys.includes("default")) return "default";
|
|
29
|
+
return variantKeys[0];
|
|
30
|
+
}
|
|
31
|
+
async function resolvePreferredVariant(variantKeys, recordedVariant, targetFolder) {
|
|
32
|
+
if (recordedVariant && variantKeys.includes(recordedVariant)) {
|
|
33
|
+
return recordedVariant;
|
|
34
|
+
}
|
|
35
|
+
if (variantKeys.includes("redis")) {
|
|
36
|
+
const markers = [
|
|
37
|
+
join(targetFolder, "variants", "redis-store.ts"),
|
|
38
|
+
join(targetFolder, "variants", "redis-store.test.ts"),
|
|
39
|
+
join(targetFolder, "variants", "redis.test.ts")
|
|
40
|
+
];
|
|
41
|
+
for (const marker of markers) {
|
|
42
|
+
try {
|
|
43
|
+
await fs.access(marker);
|
|
44
|
+
return "redis";
|
|
45
|
+
} catch {
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
return void 0;
|
|
50
|
+
}
|
|
23
51
|
function parseDepSpec(dep) {
|
|
24
52
|
const atIndex = dep.lastIndexOf("@");
|
|
25
53
|
if (atIndex > 0) {
|
|
@@ -355,7 +383,8 @@ async function addSingleBlock(targetBlock, blockMap, config, rootDir, physicalBl
|
|
|
355
383
|
version: blockVersion,
|
|
356
384
|
installedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
357
385
|
files: filesWritten.map((f) => path.relative(targetFolder, f).replace(/\\/g, "/")),
|
|
358
|
-
contentHash: contentHash.toString(16)
|
|
386
|
+
contentHash: contentHash.toString(16),
|
|
387
|
+
variant: selectedVariant
|
|
359
388
|
};
|
|
360
389
|
try {
|
|
361
390
|
const blockendPath = join(rootDir, "blockend.json");
|
|
@@ -1451,9 +1480,15 @@ async function diffCommand(blockName, options = {}) {
|
|
|
1451
1480
|
}
|
|
1452
1481
|
return { block: blockName, files: [], error };
|
|
1453
1482
|
}
|
|
1454
|
-
const selectedVariant = variantKeys[0];
|
|
1455
|
-
const variantMeta = adapterContext.variants[selectedVariant];
|
|
1456
1483
|
const targetFolder = path4.resolve(blocksRootAbsolute, blockName);
|
|
1484
|
+
const installedRecord = config.installed?.find((b) => b.name === blockName);
|
|
1485
|
+
const preferred = await resolvePreferredVariant(
|
|
1486
|
+
variantKeys,
|
|
1487
|
+
installedRecord?.variant,
|
|
1488
|
+
targetFolder
|
|
1489
|
+
);
|
|
1490
|
+
const selectedVariant = selectVariant(variantKeys, preferred);
|
|
1491
|
+
const variantMeta = adapterContext.variants[selectedVariant];
|
|
1457
1492
|
const filesToDownload = [];
|
|
1458
1493
|
if (blockMeta.baseFiles?.length) {
|
|
1459
1494
|
filesToDownload.push(...blockMeta.baseFiles);
|
|
@@ -1909,12 +1944,16 @@ function outputUpdateResult(json, result) {
|
|
|
1909
1944
|
outro8(pc9.green("All tracked blocks are up to date."));
|
|
1910
1945
|
}
|
|
1911
1946
|
}
|
|
1912
|
-
function resolveBlockFiles(blockMeta, envKey) {
|
|
1947
|
+
async function resolveBlockFiles(blockMeta, envKey, preferredVariant, targetFolder) {
|
|
1913
1948
|
const adapterContext = resolveAdapterContext3(blockMeta, envKey);
|
|
1914
1949
|
if (!adapterContext) return null;
|
|
1915
1950
|
const variantKeys = Object.keys(adapterContext.variants ?? {});
|
|
1916
1951
|
if (variantKeys.length === 0) return null;
|
|
1917
|
-
|
|
1952
|
+
let preferred = preferredVariant;
|
|
1953
|
+
if (targetFolder && (!preferred || !variantKeys.includes(preferred))) {
|
|
1954
|
+
preferred = await resolvePreferredVariant(variantKeys, preferred, targetFolder) ?? preferred;
|
|
1955
|
+
}
|
|
1956
|
+
const selectedVariant = selectVariant(variantKeys, preferred);
|
|
1918
1957
|
const variantMeta = adapterContext.variants[selectedVariant];
|
|
1919
1958
|
const expectedFiles = [];
|
|
1920
1959
|
if (blockMeta.baseFiles?.length) expectedFiles.push(...blockMeta.baseFiles);
|
|
@@ -2000,9 +2039,9 @@ async function updateCommand(options = {}) {
|
|
|
2000
2039
|
status: hasUpdate ? "update-available" : "up-to-date"
|
|
2001
2040
|
});
|
|
2002
2041
|
if (hasUpdate && diff2) {
|
|
2003
|
-
const resolved = resolveBlockFiles(blockMeta, envKey);
|
|
2004
|
-
if (!resolved) continue;
|
|
2005
2042
|
const targetFolder = path6.resolve(blocksRootAbsolute, record.name);
|
|
2043
|
+
const resolved = await resolveBlockFiles(blockMeta, envKey, record.variant, targetFolder);
|
|
2044
|
+
if (!resolved) continue;
|
|
2006
2045
|
const fileDiffs = [];
|
|
2007
2046
|
for (const fm of resolved.files) {
|
|
2008
2047
|
const localPath = join12(targetFolder, fm.target);
|
|
@@ -2087,9 +2126,10 @@ async function updateCommand(options = {}) {
|
|
|
2087
2126
|
for (const blockName of selectedNames) {
|
|
2088
2127
|
const blockMeta = blockMap[blockName];
|
|
2089
2128
|
if (!blockMeta) continue;
|
|
2090
|
-
const
|
|
2091
|
-
if (!resolved) continue;
|
|
2129
|
+
const record = installedRecords.find((r) => r.name === blockName);
|
|
2092
2130
|
const targetFolder = path6.resolve(blocksRootAbsolute, blockName);
|
|
2131
|
+
const resolved = await resolveBlockFiles(blockMeta, envKey, record?.variant, targetFolder);
|
|
2132
|
+
if (!resolved) continue;
|
|
2093
2133
|
const downloadedTargets = /* @__PURE__ */ new Set();
|
|
2094
2134
|
try {
|
|
2095
2135
|
const fileBatches = [];
|
|
@@ -2122,7 +2162,8 @@ async function updateCommand(options = {}) {
|
|
|
2122
2162
|
version: blockVersion,
|
|
2123
2163
|
installedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
2124
2164
|
files: resolved.files.map((f) => f.target),
|
|
2125
|
-
contentHash: contentHash.toString(16)
|
|
2165
|
+
contentHash: contentHash.toString(16),
|
|
2166
|
+
variant: resolved.variant
|
|
2126
2167
|
};
|
|
2127
2168
|
try {
|
|
2128
2169
|
const cfgRaw = await fs7.readFile(configPath, "utf-8");
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "blockend-cli",
|
|
3
|
-
"version": "2.0
|
|
3
|
+
"version": "2.1.0",
|
|
4
4
|
"description": "Blockend CLI — shadcn/ui-style backend blocks for TypeScript. Generate production-ready rate limiting, validation, logging, and error handling as source code into Express, Fastify, Hono, or Next.js projects. You own the code. Ships an MCP server for AI coding assistants.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -82,6 +82,6 @@
|
|
|
82
82
|
"devDependencies": {
|
|
83
83
|
"@types/node": "^25.9.3",
|
|
84
84
|
"tsup": "^8.5.1",
|
|
85
|
-
"vitest": "^1.
|
|
85
|
+
"vitest": "^4.1.11"
|
|
86
86
|
}
|
|
87
87
|
}
|