@hasna/microservices 0.0.20 → 0.0.22
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/bin/index.js +173 -42
- package/bin/mcp.js +43 -14
- package/dist/index.js +41 -12
- package/package.json +1 -1
package/bin/index.js
CHANGED
|
@@ -1875,6 +1875,7 @@ var require_commander = __commonJS((exports) => {
|
|
|
1875
1875
|
// src/cli/index.tsx
|
|
1876
1876
|
import fs from "fs";
|
|
1877
1877
|
import path from "path";
|
|
1878
|
+
import { createInterface } from "readline/promises";
|
|
1878
1879
|
|
|
1879
1880
|
// node_modules/.bun/chalk@5.6.2/node_modules/chalk/source/vendor/ansi-styles/index.js
|
|
1880
1881
|
var ANSI_BACKGROUND_OFFSET = 10;
|
|
@@ -2383,6 +2384,8 @@ var {
|
|
|
2383
2384
|
|
|
2384
2385
|
// src/lib/installer.ts
|
|
2385
2386
|
import { execFileSync, execSync } from "child_process";
|
|
2387
|
+
import { accessSync, constants } from "fs";
|
|
2388
|
+
import { join } from "path";
|
|
2386
2389
|
|
|
2387
2390
|
// src/lib/registry.ts
|
|
2388
2391
|
var MICROSERVICES = [
|
|
@@ -2808,23 +2811,41 @@ function searchMicroservices(query) {
|
|
|
2808
2811
|
}
|
|
2809
2812
|
|
|
2810
2813
|
// src/lib/installer.ts
|
|
2811
|
-
function
|
|
2814
|
+
function getBunGlobalBinDir(env2 = process.env) {
|
|
2815
|
+
const bunInstall = env2.BUN_INSTALL?.trim();
|
|
2816
|
+
if (bunInstall) {
|
|
2817
|
+
return join(bunInstall, "bin");
|
|
2818
|
+
}
|
|
2819
|
+
const home = env2.HOME?.trim();
|
|
2820
|
+
if (!home) {
|
|
2821
|
+
throw new Error("Unable to determine Bun global bin path: HOME is not set.");
|
|
2822
|
+
}
|
|
2823
|
+
return join(home, ".bun", "bin");
|
|
2824
|
+
}
|
|
2825
|
+
function resolveMicroserviceBinary(name) {
|
|
2812
2826
|
const meta = getMicroservice(name);
|
|
2813
2827
|
if (!meta)
|
|
2814
|
-
return
|
|
2815
|
-
|
|
2816
|
-
|
|
2817
|
-
|
|
2818
|
-
|
|
2819
|
-
|
|
2828
|
+
return null;
|
|
2829
|
+
const binDir = getBunGlobalBinDir();
|
|
2830
|
+
const accessMode = process.platform === "win32" ? constants.F_OK : constants.X_OK;
|
|
2831
|
+
const candidates = process.platform === "win32" ? [join(binDir, `${meta.binary}.cmd`), join(binDir, `${meta.binary}.exe`)] : [join(binDir, meta.binary)];
|
|
2832
|
+
for (const candidate of candidates) {
|
|
2833
|
+
try {
|
|
2834
|
+
accessSync(candidate, accessMode);
|
|
2835
|
+
return candidate;
|
|
2836
|
+
} catch {}
|
|
2820
2837
|
}
|
|
2838
|
+
return null;
|
|
2839
|
+
}
|
|
2840
|
+
function microserviceExists(name) {
|
|
2841
|
+
return resolveMicroserviceBinary(name) !== null;
|
|
2821
2842
|
}
|
|
2822
2843
|
function getMicroserviceVersion(name) {
|
|
2823
|
-
const
|
|
2824
|
-
if (!
|
|
2844
|
+
const binaryPath = resolveMicroserviceBinary(name);
|
|
2845
|
+
if (!binaryPath)
|
|
2825
2846
|
return null;
|
|
2826
2847
|
try {
|
|
2827
|
-
const out = execFileSync(
|
|
2848
|
+
const out = execFileSync(binaryPath, ["--version"], {
|
|
2828
2849
|
encoding: "utf8"
|
|
2829
2850
|
}).trim();
|
|
2830
2851
|
return out || null;
|
|
@@ -2882,13 +2903,13 @@ function getMicroserviceStatus(name) {
|
|
|
2882
2903
|
|
|
2883
2904
|
// src/lib/package-info.ts
|
|
2884
2905
|
import { existsSync, readFileSync } from "fs";
|
|
2885
|
-
import { dirname, join, resolve } from "path";
|
|
2906
|
+
import { dirname, join as join2, resolve } from "path";
|
|
2886
2907
|
import { fileURLToPath } from "url";
|
|
2887
2908
|
var DEFAULT_VERSION = "0.0.1";
|
|
2888
2909
|
function findNearestPackageJson(startDir) {
|
|
2889
2910
|
let dir = resolve(startDir);
|
|
2890
2911
|
while (true) {
|
|
2891
|
-
const candidate =
|
|
2912
|
+
const candidate = join2(dir, "package.json");
|
|
2892
2913
|
if (existsSync(candidate)) {
|
|
2893
2914
|
return candidate;
|
|
2894
2915
|
}
|
|
@@ -2928,12 +2949,21 @@ async function runMicroserviceCommand(name, args, timeout = 30000) {
|
|
|
2928
2949
|
return {
|
|
2929
2950
|
success: false,
|
|
2930
2951
|
stdout: "",
|
|
2931
|
-
stderr:
|
|
2952
|
+
stderr: `${meta.binary} is not installed. Run: bun install -g ${meta.package}`,
|
|
2953
|
+
exitCode: 1
|
|
2954
|
+
};
|
|
2955
|
+
}
|
|
2956
|
+
const binaryPath = resolveMicroserviceBinary(name);
|
|
2957
|
+
if (!binaryPath) {
|
|
2958
|
+
return {
|
|
2959
|
+
success: false,
|
|
2960
|
+
stdout: "",
|
|
2961
|
+
stderr: `Could not resolve global binary for ${meta.binary}.`,
|
|
2932
2962
|
exitCode: 1
|
|
2933
2963
|
};
|
|
2934
2964
|
}
|
|
2935
2965
|
return new Promise((resolve2) => {
|
|
2936
|
-
execFile(
|
|
2966
|
+
execFile(binaryPath, args, { timeout, maxBuffer: 10 * 1024 * 1024 }, (error, stdout, stderr) => {
|
|
2937
2967
|
if (error && "killed" in error && error.killed) {
|
|
2938
2968
|
resolve2({
|
|
2939
2969
|
success: false,
|
|
@@ -2956,17 +2986,58 @@ async function runMicroserviceCommand(name, args, timeout = 30000) {
|
|
|
2956
2986
|
|
|
2957
2987
|
// src/cli/index.tsx
|
|
2958
2988
|
var program2 = new Command;
|
|
2989
|
+
function printJson(value) {
|
|
2990
|
+
process.stdout.write(`${JSON.stringify(value, null, 2)}
|
|
2991
|
+
`);
|
|
2992
|
+
}
|
|
2959
2993
|
program2.name("microservices").description("Production-grade microservice building blocks for SaaS apps").version(getPackageVersion());
|
|
2960
|
-
program2.command("list").description("List all available microservices").option("--installed", "Show only installed microservices").action((opts) => {
|
|
2961
|
-
const
|
|
2994
|
+
program2.command("list").description("List all available microservices").option("--installed", "Show only installed microservices").option("--category <name>", "Filter by category (case-insensitive)").option("--limit <n>", "Limit number of results").option("--offset <n>", "Skip the first N results").option("--json", "Print machine-readable JSON output").action((opts) => {
|
|
2995
|
+
const limit = opts.limit === undefined ? null : Number(opts.limit);
|
|
2996
|
+
const offset = opts.offset === undefined ? 0 : Number(opts.offset);
|
|
2997
|
+
if (limit !== null && (!Number.isInteger(limit) || limit < 0)) {
|
|
2998
|
+
console.error(source_default.red("--limit must be a non-negative integer"));
|
|
2999
|
+
process.exit(1);
|
|
3000
|
+
}
|
|
3001
|
+
if (!Number.isInteger(offset) || offset < 0) {
|
|
3002
|
+
console.error(source_default.red("--offset must be a non-negative integer"));
|
|
3003
|
+
process.exit(1);
|
|
3004
|
+
}
|
|
3005
|
+
const categoryFilter = opts.category?.trim().toLowerCase();
|
|
3006
|
+
let services = opts.installed ? MICROSERVICES.filter((m) => microserviceExists(m.name)) : MICROSERVICES;
|
|
3007
|
+
if (categoryFilter) {
|
|
3008
|
+
services = services.filter((m) => m.category.toLowerCase() === categoryFilter);
|
|
3009
|
+
}
|
|
3010
|
+
const start = offset;
|
|
3011
|
+
const end = limit === null ? undefined : offset + limit;
|
|
3012
|
+
const page = services.slice(start, end);
|
|
3013
|
+
const payload = page.map((m) => ({
|
|
3014
|
+
name: m.name,
|
|
3015
|
+
displayName: m.displayName,
|
|
3016
|
+
binary: m.binary,
|
|
3017
|
+
package: m.package,
|
|
3018
|
+
category: m.category,
|
|
3019
|
+
installed: microserviceExists(m.name),
|
|
3020
|
+
description: m.description
|
|
3021
|
+
}));
|
|
3022
|
+
if (opts.json) {
|
|
3023
|
+
printJson({
|
|
3024
|
+
total: services.length,
|
|
3025
|
+
count: payload.length,
|
|
3026
|
+
offset,
|
|
3027
|
+
limit,
|
|
3028
|
+
category: opts.category ?? null,
|
|
3029
|
+
services: payload
|
|
3030
|
+
});
|
|
3031
|
+
return;
|
|
3032
|
+
}
|
|
2962
3033
|
console.log(source_default.bold(`
|
|
2963
3034
|
Available microservices:
|
|
2964
3035
|
`));
|
|
2965
|
-
for (const m of
|
|
2966
|
-
const
|
|
2967
|
-
const status = installed ? source_default.green("\u2713 installed") : source_default.gray(" available");
|
|
3036
|
+
for (const m of payload) {
|
|
3037
|
+
const status = m.installed ? source_default.green("\u2713 installed") : source_default.gray(" available");
|
|
2968
3038
|
console.log(` ${status} ${source_default.cyan(m.binary.padEnd(22))} ${m.description.slice(0, 60)}`);
|
|
2969
3039
|
}
|
|
3040
|
+
console.log(source_default.gray(`Showing ${payload.length} of ${services.length} result(s) (offset ${offset}${limit === null ? "" : `, limit ${limit}`}).`));
|
|
2970
3041
|
console.log();
|
|
2971
3042
|
});
|
|
2972
3043
|
program2.command("install [names...]").description("Install microservices globally via bun").option("--all", "Install all microservices").option("--force", "Reinstall even if already installed").action(async (names, opts) => {
|
|
@@ -2988,20 +3059,44 @@ Installing ${targets.length} microservice(s)...
|
|
|
2988
3059
|
}
|
|
2989
3060
|
console.log();
|
|
2990
3061
|
});
|
|
2991
|
-
program2.command("remove <name>").description("Remove an installed microservice").action((name) => {
|
|
3062
|
+
program2.command("remove <name>").description("Remove an installed microservice").option("-y, --yes", "Skip confirmation prompt").action(async (name, opts) => {
|
|
3063
|
+
if (!opts.yes) {
|
|
3064
|
+
if (!process.stdin.isTTY || !process.stdout.isTTY) {
|
|
3065
|
+
console.error(source_default.red("Refusing to remove without confirmation in non-interactive mode. Re-run with --yes."));
|
|
3066
|
+
process.exit(1);
|
|
3067
|
+
}
|
|
3068
|
+
const rl = createInterface({ input: process.stdin, output: process.stdout });
|
|
3069
|
+
try {
|
|
3070
|
+
const answer = await rl.question(`Remove ${name} from your global Bun installation? [y/N] `);
|
|
3071
|
+
const confirmed = ["y", "yes"].includes(answer.trim().toLowerCase());
|
|
3072
|
+
if (!confirmed) {
|
|
3073
|
+
console.log(source_default.yellow("Cancelled."));
|
|
3074
|
+
process.exit(1);
|
|
3075
|
+
}
|
|
3076
|
+
} finally {
|
|
3077
|
+
rl.close();
|
|
3078
|
+
}
|
|
3079
|
+
}
|
|
2992
3080
|
const ok = removeMicroservice(name);
|
|
2993
|
-
if (ok)
|
|
3081
|
+
if (ok) {
|
|
2994
3082
|
console.log(source_default.green(`\u2713 Removed ${name}`));
|
|
2995
|
-
|
|
2996
|
-
|
|
3083
|
+
return;
|
|
3084
|
+
}
|
|
3085
|
+
console.error(source_default.red(`\u2717 Failed to remove ${name} \u2014 is it installed?`));
|
|
3086
|
+
process.exit(1);
|
|
2997
3087
|
});
|
|
2998
|
-
program2.command("status [name]").description("Show installation status").action((name) => {
|
|
3088
|
+
program2.command("status [name]").description("Show installation status").option("--json", "Print machine-readable JSON output").action((name, opts) => {
|
|
2999
3089
|
const targets = name ? [name] : MICROSERVICES.map((m) => m.name);
|
|
3090
|
+
const payload = targets.map((n) => getMicroserviceStatus(n));
|
|
3091
|
+
if (opts.json) {
|
|
3092
|
+
printJson(name ? payload[0] ?? null : payload);
|
|
3093
|
+
return;
|
|
3094
|
+
}
|
|
3000
3095
|
console.log(source_default.bold(`
|
|
3001
3096
|
Microservice status:
|
|
3002
3097
|
`));
|
|
3003
|
-
for (const n of targets) {
|
|
3004
|
-
const s =
|
|
3098
|
+
for (const [index, n] of targets.entries()) {
|
|
3099
|
+
const s = payload[index];
|
|
3005
3100
|
const icon = s.installed ? source_default.green("\u2713") : source_default.gray("\u2717");
|
|
3006
3101
|
const ver = s.version ? source_default.gray(`v${s.version}`) : "";
|
|
3007
3102
|
const env2 = s.meta?.requiredEnv.join(", ") ?? "";
|
|
@@ -3019,8 +3114,12 @@ program2.command("run <name> [args...]").description("Run a command on an instal
|
|
|
3019
3114
|
`);
|
|
3020
3115
|
process.exit(result.exitCode);
|
|
3021
3116
|
});
|
|
3022
|
-
program2.command("search <query>").description("Search microservices by name or keyword").action((query) => {
|
|
3117
|
+
program2.command("search <query>").description("Search microservices by name or keyword").option("--json", "Print machine-readable JSON output").action((query, opts) => {
|
|
3023
3118
|
const results = searchMicroservices(query);
|
|
3119
|
+
if (opts.json) {
|
|
3120
|
+
printJson(results);
|
|
3121
|
+
return;
|
|
3122
|
+
}
|
|
3024
3123
|
if (results.length === 0) {
|
|
3025
3124
|
console.log(source_default.gray(`No microservices matching "${query}"`));
|
|
3026
3125
|
return;
|
|
@@ -3154,13 +3253,17 @@ Initializing ${installed.length} installed microservices...
|
|
|
3154
3253
|
console.log(source_default.gray(" You can now run 'microservices serve-all' to start them."));
|
|
3155
3254
|
}
|
|
3156
3255
|
});
|
|
3157
|
-
program2.command("info <name>").description("Show detailed info about a microservice").action((name) => {
|
|
3256
|
+
program2.command("info <name>").description("Show detailed info about a microservice").option("--json", "Print machine-readable JSON output").action((name, opts) => {
|
|
3158
3257
|
const m = getMicroservice(name);
|
|
3159
3258
|
if (!m) {
|
|
3160
3259
|
console.error(source_default.red(`Unknown microservice: ${name}`));
|
|
3161
3260
|
process.exit(1);
|
|
3162
3261
|
}
|
|
3163
3262
|
const installed = microserviceExists(name);
|
|
3263
|
+
if (opts.json) {
|
|
3264
|
+
printJson({ ...m, installed });
|
|
3265
|
+
return;
|
|
3266
|
+
}
|
|
3164
3267
|
console.log(source_default.bold(`
|
|
3165
3268
|
${m.displayName}`));
|
|
3166
3269
|
console.log(` Package: ${source_default.cyan(m.package)}`);
|
|
@@ -3175,29 +3278,57 @@ ${m.displayName}`));
|
|
|
3175
3278
|
console.log(` Tags: ${m.tags.join(", ")}`);
|
|
3176
3279
|
console.log();
|
|
3177
3280
|
});
|
|
3178
|
-
program2.command("check-env").description("Verify environment variables for all installed microservices").action(() => {
|
|
3281
|
+
program2.command("check-env").description("Verify environment variables for all installed microservices").option("--json", "Print machine-readable JSON output").action((opts) => {
|
|
3179
3282
|
const installed = MICROSERVICES.filter((m) => microserviceExists(m.name));
|
|
3180
3283
|
if (installed.length === 0) {
|
|
3181
|
-
|
|
3284
|
+
if (opts.json) {
|
|
3285
|
+
printJson({
|
|
3286
|
+
summary: { installed: 0, totalMissingRequired: 0, allOk: true },
|
|
3287
|
+
services: []
|
|
3288
|
+
});
|
|
3289
|
+
} else {
|
|
3290
|
+
console.log(source_default.yellow("No microservices installed to check."));
|
|
3291
|
+
}
|
|
3292
|
+
return;
|
|
3293
|
+
}
|
|
3294
|
+
const report = installed.map((m) => {
|
|
3295
|
+
const missingRequired = m.requiredEnv.filter((env2) => !process.env[env2]);
|
|
3296
|
+
const missingOptional = (m.optionalEnv ?? []).filter((env2) => !process.env[env2]);
|
|
3297
|
+
return {
|
|
3298
|
+
name: m.name,
|
|
3299
|
+
missingRequired,
|
|
3300
|
+
missingOptional,
|
|
3301
|
+
ok: missingRequired.length === 0
|
|
3302
|
+
};
|
|
3303
|
+
});
|
|
3304
|
+
const totalMissing = report.reduce((sum, service) => sum + service.missingRequired.length, 0);
|
|
3305
|
+
if (opts.json) {
|
|
3306
|
+
printJson({
|
|
3307
|
+
summary: {
|
|
3308
|
+
installed: installed.length,
|
|
3309
|
+
totalMissingRequired: totalMissing,
|
|
3310
|
+
allOk: totalMissing === 0
|
|
3311
|
+
},
|
|
3312
|
+
services: report
|
|
3313
|
+
});
|
|
3314
|
+
if (totalMissing > 0) {
|
|
3315
|
+
process.exit(1);
|
|
3316
|
+
}
|
|
3182
3317
|
return;
|
|
3183
3318
|
}
|
|
3184
3319
|
console.log(source_default.bold(`
|
|
3185
3320
|
Checking environment for ${installed.length} microservices...
|
|
3186
3321
|
`));
|
|
3187
|
-
|
|
3188
|
-
|
|
3189
|
-
|
|
3190
|
-
|
|
3191
|
-
|
|
3192
|
-
console.log(`${source_default.bold(m.name.padEnd(12))} [${status}]`);
|
|
3193
|
-
if (missingRequired.length > 0) {
|
|
3194
|
-
console.log(source_default.red(` Required missing: ${missingRequired.join(", ")}`));
|
|
3195
|
-
totalMissing += missingRequired.length;
|
|
3322
|
+
for (const service of report) {
|
|
3323
|
+
const status = service.missingRequired.length > 0 ? source_default.red("\u2717 Critical Missing") : service.missingOptional.length > 0 ? source_default.yellow("\u26A0 Warning") : source_default.green("\u2713 OK");
|
|
3324
|
+
console.log(`${source_default.bold(service.name.padEnd(12))} [${status}]`);
|
|
3325
|
+
if (service.missingRequired.length > 0) {
|
|
3326
|
+
console.log(source_default.red(` Required missing: ${service.missingRequired.join(", ")}`));
|
|
3196
3327
|
}
|
|
3197
|
-
if (missingOptional.length > 0) {
|
|
3198
|
-
console.log(source_default.gray(` Optional missing: ${missingOptional.join(", ")}`));
|
|
3328
|
+
if (service.missingOptional.length > 0) {
|
|
3329
|
+
console.log(source_default.gray(` Optional missing: ${service.missingOptional.join(", ")}`));
|
|
3199
3330
|
}
|
|
3200
|
-
if (missingRequired.length === 0 && missingOptional.length === 0) {
|
|
3331
|
+
if (service.missingRequired.length === 0 && service.missingOptional.length === 0) {
|
|
3201
3332
|
console.log(source_default.gray(" All variables set."));
|
|
3202
3333
|
}
|
|
3203
3334
|
console.log();
|
package/bin/mcp.js
CHANGED
|
@@ -19476,6 +19476,8 @@ class StdioServerTransport {
|
|
|
19476
19476
|
|
|
19477
19477
|
// src/lib/installer.ts
|
|
19478
19478
|
import { execFileSync, execSync } from "child_process";
|
|
19479
|
+
import { accessSync, constants } from "fs";
|
|
19480
|
+
import { join } from "path";
|
|
19479
19481
|
|
|
19480
19482
|
// src/lib/registry.ts
|
|
19481
19483
|
var MICROSERVICES = [
|
|
@@ -19901,23 +19903,41 @@ function searchMicroservices(query) {
|
|
|
19901
19903
|
}
|
|
19902
19904
|
|
|
19903
19905
|
// src/lib/installer.ts
|
|
19904
|
-
function
|
|
19906
|
+
function getBunGlobalBinDir(env = process.env) {
|
|
19907
|
+
const bunInstall = env.BUN_INSTALL?.trim();
|
|
19908
|
+
if (bunInstall) {
|
|
19909
|
+
return join(bunInstall, "bin");
|
|
19910
|
+
}
|
|
19911
|
+
const home = env.HOME?.trim();
|
|
19912
|
+
if (!home) {
|
|
19913
|
+
throw new Error("Unable to determine Bun global bin path: HOME is not set.");
|
|
19914
|
+
}
|
|
19915
|
+
return join(home, ".bun", "bin");
|
|
19916
|
+
}
|
|
19917
|
+
function resolveMicroserviceBinary(name) {
|
|
19905
19918
|
const meta = getMicroservice(name);
|
|
19906
19919
|
if (!meta)
|
|
19907
|
-
return
|
|
19908
|
-
|
|
19909
|
-
|
|
19910
|
-
|
|
19911
|
-
|
|
19912
|
-
|
|
19920
|
+
return null;
|
|
19921
|
+
const binDir = getBunGlobalBinDir();
|
|
19922
|
+
const accessMode = process.platform === "win32" ? constants.F_OK : constants.X_OK;
|
|
19923
|
+
const candidates = process.platform === "win32" ? [join(binDir, `${meta.binary}.cmd`), join(binDir, `${meta.binary}.exe`)] : [join(binDir, meta.binary)];
|
|
19924
|
+
for (const candidate of candidates) {
|
|
19925
|
+
try {
|
|
19926
|
+
accessSync(candidate, accessMode);
|
|
19927
|
+
return candidate;
|
|
19928
|
+
} catch {}
|
|
19913
19929
|
}
|
|
19930
|
+
return null;
|
|
19931
|
+
}
|
|
19932
|
+
function microserviceExists(name) {
|
|
19933
|
+
return resolveMicroserviceBinary(name) !== null;
|
|
19914
19934
|
}
|
|
19915
19935
|
function getMicroserviceVersion(name) {
|
|
19916
|
-
const
|
|
19917
|
-
if (!
|
|
19936
|
+
const binaryPath = resolveMicroserviceBinary(name);
|
|
19937
|
+
if (!binaryPath)
|
|
19918
19938
|
return null;
|
|
19919
19939
|
try {
|
|
19920
|
-
const out = execFileSync(
|
|
19940
|
+
const out = execFileSync(binaryPath, ["--version"], {
|
|
19921
19941
|
encoding: "utf8"
|
|
19922
19942
|
}).trim();
|
|
19923
19943
|
return out || null;
|
|
@@ -19972,13 +19992,13 @@ function getMicroserviceStatus(name) {
|
|
|
19972
19992
|
|
|
19973
19993
|
// src/lib/package-info.ts
|
|
19974
19994
|
import { existsSync, readFileSync } from "fs";
|
|
19975
|
-
import { dirname, join, resolve } from "path";
|
|
19995
|
+
import { dirname, join as join2, resolve } from "path";
|
|
19976
19996
|
import { fileURLToPath } from "url";
|
|
19977
19997
|
var DEFAULT_VERSION = "0.0.1";
|
|
19978
19998
|
function findNearestPackageJson(startDir) {
|
|
19979
19999
|
let dir = resolve(startDir);
|
|
19980
20000
|
while (true) {
|
|
19981
|
-
const candidate =
|
|
20001
|
+
const candidate = join2(dir, "package.json");
|
|
19982
20002
|
if (existsSync(candidate)) {
|
|
19983
20003
|
return candidate;
|
|
19984
20004
|
}
|
|
@@ -20018,12 +20038,21 @@ async function runMicroserviceCommand(name, args, timeout = 30000) {
|
|
|
20018
20038
|
return {
|
|
20019
20039
|
success: false,
|
|
20020
20040
|
stdout: "",
|
|
20021
|
-
stderr:
|
|
20041
|
+
stderr: `${meta.binary} is not installed. Run: bun install -g ${meta.package}`,
|
|
20042
|
+
exitCode: 1
|
|
20043
|
+
};
|
|
20044
|
+
}
|
|
20045
|
+
const binaryPath = resolveMicroserviceBinary(name);
|
|
20046
|
+
if (!binaryPath) {
|
|
20047
|
+
return {
|
|
20048
|
+
success: false,
|
|
20049
|
+
stdout: "",
|
|
20050
|
+
stderr: `Could not resolve global binary for ${meta.binary}.`,
|
|
20022
20051
|
exitCode: 1
|
|
20023
20052
|
};
|
|
20024
20053
|
}
|
|
20025
20054
|
return new Promise((resolve2) => {
|
|
20026
|
-
execFile(
|
|
20055
|
+
execFile(binaryPath, args, { timeout, maxBuffer: 10 * 1024 * 1024 }, (error2, stdout, stderr) => {
|
|
20027
20056
|
if (error2 && "killed" in error2 && error2.killed) {
|
|
20028
20057
|
resolve2({
|
|
20029
20058
|
success: false,
|
package/dist/index.js
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
// @bun
|
|
2
2
|
// src/lib/installer.ts
|
|
3
3
|
import { execFileSync, execSync } from "child_process";
|
|
4
|
+
import { accessSync, constants } from "fs";
|
|
5
|
+
import { join } from "path";
|
|
4
6
|
|
|
5
7
|
// src/lib/registry.ts
|
|
6
8
|
var CATEGORIES = [
|
|
@@ -440,23 +442,41 @@ function searchMicroservices(query) {
|
|
|
440
442
|
}
|
|
441
443
|
|
|
442
444
|
// src/lib/installer.ts
|
|
443
|
-
function
|
|
445
|
+
function getBunGlobalBinDir(env = process.env) {
|
|
446
|
+
const bunInstall = env.BUN_INSTALL?.trim();
|
|
447
|
+
if (bunInstall) {
|
|
448
|
+
return join(bunInstall, "bin");
|
|
449
|
+
}
|
|
450
|
+
const home = env.HOME?.trim();
|
|
451
|
+
if (!home) {
|
|
452
|
+
throw new Error("Unable to determine Bun global bin path: HOME is not set.");
|
|
453
|
+
}
|
|
454
|
+
return join(home, ".bun", "bin");
|
|
455
|
+
}
|
|
456
|
+
function resolveMicroserviceBinary(name) {
|
|
444
457
|
const meta = getMicroservice(name);
|
|
445
458
|
if (!meta)
|
|
446
|
-
return
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
459
|
+
return null;
|
|
460
|
+
const binDir = getBunGlobalBinDir();
|
|
461
|
+
const accessMode = process.platform === "win32" ? constants.F_OK : constants.X_OK;
|
|
462
|
+
const candidates = process.platform === "win32" ? [join(binDir, `${meta.binary}.cmd`), join(binDir, `${meta.binary}.exe`)] : [join(binDir, meta.binary)];
|
|
463
|
+
for (const candidate of candidates) {
|
|
464
|
+
try {
|
|
465
|
+
accessSync(candidate, accessMode);
|
|
466
|
+
return candidate;
|
|
467
|
+
} catch {}
|
|
452
468
|
}
|
|
469
|
+
return null;
|
|
470
|
+
}
|
|
471
|
+
function microserviceExists(name) {
|
|
472
|
+
return resolveMicroserviceBinary(name) !== null;
|
|
453
473
|
}
|
|
454
474
|
function getMicroserviceVersion(name) {
|
|
455
|
-
const
|
|
456
|
-
if (!
|
|
475
|
+
const binaryPath = resolveMicroserviceBinary(name);
|
|
476
|
+
if (!binaryPath)
|
|
457
477
|
return null;
|
|
458
478
|
try {
|
|
459
|
-
const out = execFileSync(
|
|
479
|
+
const out = execFileSync(binaryPath, ["--version"], {
|
|
460
480
|
encoding: "utf8"
|
|
461
481
|
}).trim();
|
|
462
482
|
return out || null;
|
|
@@ -530,12 +550,21 @@ async function runMicroserviceCommand(name, args, timeout = 30000) {
|
|
|
530
550
|
return {
|
|
531
551
|
success: false,
|
|
532
552
|
stdout: "",
|
|
533
|
-
stderr:
|
|
553
|
+
stderr: `${meta.binary} is not installed. Run: bun install -g ${meta.package}`,
|
|
554
|
+
exitCode: 1
|
|
555
|
+
};
|
|
556
|
+
}
|
|
557
|
+
const binaryPath = resolveMicroserviceBinary(name);
|
|
558
|
+
if (!binaryPath) {
|
|
559
|
+
return {
|
|
560
|
+
success: false,
|
|
561
|
+
stdout: "",
|
|
562
|
+
stderr: `Could not resolve global binary for ${meta.binary}.`,
|
|
534
563
|
exitCode: 1
|
|
535
564
|
};
|
|
536
565
|
}
|
|
537
566
|
return new Promise((resolve) => {
|
|
538
|
-
execFile(
|
|
567
|
+
execFile(binaryPath, args, { timeout, maxBuffer: 10 * 1024 * 1024 }, (error, stdout, stderr) => {
|
|
539
568
|
if (error && "killed" in error && error.killed) {
|
|
540
569
|
resolve({
|
|
541
570
|
success: false,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hasna/microservices",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.22",
|
|
4
4
|
"description": "21 production-grade microservice building blocks for AI-native SaaS — auth, billing, LLM gateway, agent registry, RAG, guardrails, tracing, and more. Each with PostgreSQL, HTTP API, MCP server, and CLI.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|