@hasna/microservices 0.0.21 → 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.
Files changed (2) hide show
  1. package/bin/index.js +130 -28
  2. 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;
@@ -2985,17 +2986,58 @@ async function runMicroserviceCommand(name, args, timeout = 30000) {
2985
2986
 
2986
2987
  // src/cli/index.tsx
2987
2988
  var program2 = new Command;
2989
+ function printJson(value) {
2990
+ process.stdout.write(`${JSON.stringify(value, null, 2)}
2991
+ `);
2992
+ }
2988
2993
  program2.name("microservices").description("Production-grade microservice building blocks for SaaS apps").version(getPackageVersion());
2989
- program2.command("list").description("List all available microservices").option("--installed", "Show only installed microservices").action((opts) => {
2990
- const services = opts.installed ? MICROSERVICES.filter((m) => microserviceExists(m.name)) : MICROSERVICES;
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
+ }
2991
3033
  console.log(source_default.bold(`
2992
3034
  Available microservices:
2993
3035
  `));
2994
- for (const m of services) {
2995
- const installed = microserviceExists(m.name);
2996
- 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");
2997
3038
  console.log(` ${status} ${source_default.cyan(m.binary.padEnd(22))} ${m.description.slice(0, 60)}`);
2998
3039
  }
3040
+ console.log(source_default.gray(`Showing ${payload.length} of ${services.length} result(s) (offset ${offset}${limit === null ? "" : `, limit ${limit}`}).`));
2999
3041
  console.log();
3000
3042
  });
3001
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) => {
@@ -3017,20 +3059,44 @@ Installing ${targets.length} microservice(s)...
3017
3059
  }
3018
3060
  console.log();
3019
3061
  });
3020
- 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
+ }
3021
3080
  const ok = removeMicroservice(name);
3022
- if (ok)
3081
+ if (ok) {
3023
3082
  console.log(source_default.green(`\u2713 Removed ${name}`));
3024
- else
3025
- console.log(source_default.red(`\u2717 Failed to remove ${name} \u2014 is it installed?`));
3083
+ return;
3084
+ }
3085
+ console.error(source_default.red(`\u2717 Failed to remove ${name} \u2014 is it installed?`));
3086
+ process.exit(1);
3026
3087
  });
3027
- 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) => {
3028
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
+ }
3029
3095
  console.log(source_default.bold(`
3030
3096
  Microservice status:
3031
3097
  `));
3032
- for (const n of targets) {
3033
- const s = getMicroserviceStatus(n);
3098
+ for (const [index, n] of targets.entries()) {
3099
+ const s = payload[index];
3034
3100
  const icon = s.installed ? source_default.green("\u2713") : source_default.gray("\u2717");
3035
3101
  const ver = s.version ? source_default.gray(`v${s.version}`) : "";
3036
3102
  const env2 = s.meta?.requiredEnv.join(", ") ?? "";
@@ -3048,8 +3114,12 @@ program2.command("run <name> [args...]").description("Run a command on an instal
3048
3114
  `);
3049
3115
  process.exit(result.exitCode);
3050
3116
  });
3051
- 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) => {
3052
3118
  const results = searchMicroservices(query);
3119
+ if (opts.json) {
3120
+ printJson(results);
3121
+ return;
3122
+ }
3053
3123
  if (results.length === 0) {
3054
3124
  console.log(source_default.gray(`No microservices matching "${query}"`));
3055
3125
  return;
@@ -3183,13 +3253,17 @@ Initializing ${installed.length} installed microservices...
3183
3253
  console.log(source_default.gray(" You can now run 'microservices serve-all' to start them."));
3184
3254
  }
3185
3255
  });
3186
- 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) => {
3187
3257
  const m = getMicroservice(name);
3188
3258
  if (!m) {
3189
3259
  console.error(source_default.red(`Unknown microservice: ${name}`));
3190
3260
  process.exit(1);
3191
3261
  }
3192
3262
  const installed = microserviceExists(name);
3263
+ if (opts.json) {
3264
+ printJson({ ...m, installed });
3265
+ return;
3266
+ }
3193
3267
  console.log(source_default.bold(`
3194
3268
  ${m.displayName}`));
3195
3269
  console.log(` Package: ${source_default.cyan(m.package)}`);
@@ -3204,29 +3278,57 @@ ${m.displayName}`));
3204
3278
  console.log(` Tags: ${m.tags.join(", ")}`);
3205
3279
  console.log();
3206
3280
  });
3207
- 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) => {
3208
3282
  const installed = MICROSERVICES.filter((m) => microserviceExists(m.name));
3209
3283
  if (installed.length === 0) {
3210
- console.log(source_default.yellow("No microservices installed to check."));
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
+ }
3211
3317
  return;
3212
3318
  }
3213
3319
  console.log(source_default.bold(`
3214
3320
  Checking environment for ${installed.length} microservices...
3215
3321
  `));
3216
- let totalMissing = 0;
3217
- for (const m of installed) {
3218
- const missingRequired = m.requiredEnv.filter((env2) => !process.env[env2]);
3219
- const missingOptional = (m.optionalEnv ?? []).filter((env2) => !process.env[env2]);
3220
- const status = missingRequired.length > 0 ? source_default.red("\u2717 Critical Missing") : missingOptional.length > 0 ? source_default.yellow("\u26A0 Warning") : source_default.green("\u2713 OK");
3221
- console.log(`${source_default.bold(m.name.padEnd(12))} [${status}]`);
3222
- if (missingRequired.length > 0) {
3223
- console.log(source_default.red(` Required missing: ${missingRequired.join(", ")}`));
3224
- 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(", ")}`));
3225
3327
  }
3226
- if (missingOptional.length > 0) {
3227
- 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(", ")}`));
3228
3330
  }
3229
- if (missingRequired.length === 0 && missingOptional.length === 0) {
3331
+ if (service.missingRequired.length === 0 && service.missingOptional.length === 0) {
3230
3332
  console.log(source_default.gray(" All variables set."));
3231
3333
  }
3232
3334
  console.log();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hasna/microservices",
3
- "version": "0.0.21",
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": {