@hasna/microservices 0.0.18 → 0.0.20

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 CHANGED
@@ -33,7 +33,7 @@ var __toESM = (mod, isNodeMode, target) => {
33
33
  var __commonJS = (cb, mod) => () => (mod || cb((mod = { exports: {} }).exports, mod), mod.exports);
34
34
  var __require = import.meta.require;
35
35
 
36
- // node_modules/commander/lib/error.js
36
+ // node_modules/.bun/commander@12.1.0/node_modules/commander/lib/error.js
37
37
  var require_error = __commonJS((exports) => {
38
38
  class CommanderError extends Error {
39
39
  constructor(exitCode, code, message) {
@@ -57,7 +57,7 @@ var require_error = __commonJS((exports) => {
57
57
  exports.InvalidArgumentError = InvalidArgumentError;
58
58
  });
59
59
 
60
- // node_modules/commander/lib/argument.js
60
+ // node_modules/.bun/commander@12.1.0/node_modules/commander/lib/argument.js
61
61
  var require_argument = __commonJS((exports) => {
62
62
  var { InvalidArgumentError } = require_error();
63
63
 
@@ -136,7 +136,7 @@ var require_argument = __commonJS((exports) => {
136
136
  exports.humanReadableArgName = humanReadableArgName;
137
137
  });
138
138
 
139
- // node_modules/commander/lib/help.js
139
+ // node_modules/.bun/commander@12.1.0/node_modules/commander/lib/help.js
140
140
  var require_help = __commonJS((exports) => {
141
141
  var { humanReadableArgName } = require_argument();
142
142
 
@@ -385,7 +385,7 @@ var require_help = __commonJS((exports) => {
385
385
  exports.Help = Help;
386
386
  });
387
387
 
388
- // node_modules/commander/lib/option.js
388
+ // node_modules/.bun/commander@12.1.0/node_modules/commander/lib/option.js
389
389
  var require_option = __commonJS((exports) => {
390
390
  var { InvalidArgumentError } = require_error();
391
391
 
@@ -536,7 +536,7 @@ var require_option = __commonJS((exports) => {
536
536
  exports.DualOptions = DualOptions;
537
537
  });
538
538
 
539
- // node_modules/commander/lib/suggestSimilar.js
539
+ // node_modules/.bun/commander@12.1.0/node_modules/commander/lib/suggestSimilar.js
540
540
  var require_suggestSimilar = __commonJS((exports) => {
541
541
  var maxDistance = 3;
542
542
  function editDistance(a, b) {
@@ -609,13 +609,13 @@ var require_suggestSimilar = __commonJS((exports) => {
609
609
  exports.suggestSimilar = suggestSimilar;
610
610
  });
611
611
 
612
- // node_modules/commander/lib/command.js
612
+ // node_modules/.bun/commander@12.1.0/node_modules/commander/lib/command.js
613
613
  var require_command = __commonJS((exports) => {
614
614
  var EventEmitter = __require("events").EventEmitter;
615
615
  var childProcess = __require("child_process");
616
616
  var path = __require("path");
617
617
  var fs = __require("fs");
618
- var process2 = __require("process");
618
+ var process3 = __require("process");
619
619
  var { Argument, humanReadableArgName } = require_argument();
620
620
  var { CommanderError } = require_error();
621
621
  var { Help } = require_help();
@@ -657,10 +657,10 @@ var require_command = __commonJS((exports) => {
657
657
  this._showHelpAfterError = false;
658
658
  this._showSuggestionAfterError = true;
659
659
  this._outputConfiguration = {
660
- writeOut: (str) => process2.stdout.write(str),
661
- writeErr: (str) => process2.stderr.write(str),
662
- getOutHelpWidth: () => process2.stdout.isTTY ? process2.stdout.columns : undefined,
663
- getErrHelpWidth: () => process2.stderr.isTTY ? process2.stderr.columns : undefined,
660
+ writeOut: (str) => process3.stdout.write(str),
661
+ writeErr: (str) => process3.stderr.write(str),
662
+ getOutHelpWidth: () => process3.stdout.isTTY ? process3.stdout.columns : undefined,
663
+ getErrHelpWidth: () => process3.stderr.isTTY ? process3.stderr.columns : undefined,
664
664
  outputError: (str, write) => write(str)
665
665
  };
666
666
  this._hidden = false;
@@ -856,7 +856,7 @@ Expecting one of '${allowedValues.join("', '")}'`);
856
856
  if (this._exitCallback) {
857
857
  this._exitCallback(new CommanderError(exitCode, code, message));
858
858
  }
859
- process2.exit(exitCode);
859
+ process3.exit(exitCode);
860
860
  }
861
861
  action(fn) {
862
862
  const listener = (args) => {
@@ -1051,16 +1051,16 @@ Expecting one of '${allowedValues.join("', '")}'`);
1051
1051
  }
1052
1052
  parseOptions = parseOptions || {};
1053
1053
  if (argv === undefined && parseOptions.from === undefined) {
1054
- if (process2.versions?.electron) {
1054
+ if (process3.versions?.electron) {
1055
1055
  parseOptions.from = "electron";
1056
1056
  }
1057
- const execArgv = process2.execArgv ?? [];
1057
+ const execArgv = process3.execArgv ?? [];
1058
1058
  if (execArgv.includes("-e") || execArgv.includes("--eval") || execArgv.includes("-p") || execArgv.includes("--print")) {
1059
1059
  parseOptions.from = "eval";
1060
1060
  }
1061
1061
  }
1062
1062
  if (argv === undefined) {
1063
- argv = process2.argv;
1063
+ argv = process3.argv;
1064
1064
  }
1065
1065
  this.rawArgs = argv.slice();
1066
1066
  let userArgs;
@@ -1071,7 +1071,7 @@ Expecting one of '${allowedValues.join("', '")}'`);
1071
1071
  userArgs = argv.slice(2);
1072
1072
  break;
1073
1073
  case "electron":
1074
- if (process2.defaultApp) {
1074
+ if (process3.defaultApp) {
1075
1075
  this._scriptPath = argv[1];
1076
1076
  userArgs = argv.slice(2);
1077
1077
  } else {
@@ -1142,23 +1142,23 @@ Expecting one of '${allowedValues.join("', '")}'`);
1142
1142
  }
1143
1143
  launchWithNode = sourceExt.includes(path.extname(executableFile));
1144
1144
  let proc;
1145
- if (process2.platform !== "win32") {
1145
+ if (process3.platform !== "win32") {
1146
1146
  if (launchWithNode) {
1147
1147
  args.unshift(executableFile);
1148
- args = incrementNodeInspectorPort(process2.execArgv).concat(args);
1149
- proc = childProcess.spawn(process2.argv[0], args, { stdio: "inherit" });
1148
+ args = incrementNodeInspectorPort(process3.execArgv).concat(args);
1149
+ proc = childProcess.spawn(process3.argv[0], args, { stdio: "inherit" });
1150
1150
  } else {
1151
1151
  proc = childProcess.spawn(executableFile, args, { stdio: "inherit" });
1152
1152
  }
1153
1153
  } else {
1154
1154
  args.unshift(executableFile);
1155
- args = incrementNodeInspectorPort(process2.execArgv).concat(args);
1156
- proc = childProcess.spawn(process2.execPath, args, { stdio: "inherit" });
1155
+ args = incrementNodeInspectorPort(process3.execArgv).concat(args);
1156
+ proc = childProcess.spawn(process3.execPath, args, { stdio: "inherit" });
1157
1157
  }
1158
1158
  if (!proc.killed) {
1159
1159
  const signals = ["SIGUSR1", "SIGUSR2", "SIGTERM", "SIGINT", "SIGHUP"];
1160
1160
  signals.forEach((signal) => {
1161
- process2.on(signal, () => {
1161
+ process3.on(signal, () => {
1162
1162
  if (proc.killed === false && proc.exitCode === null) {
1163
1163
  proc.kill(signal);
1164
1164
  }
@@ -1169,7 +1169,7 @@ Expecting one of '${allowedValues.join("', '")}'`);
1169
1169
  proc.on("close", (code) => {
1170
1170
  code = code ?? 1;
1171
1171
  if (!exitCallback) {
1172
- process2.exit(code);
1172
+ process3.exit(code);
1173
1173
  } else {
1174
1174
  exitCallback(new CommanderError(code, "commander.executeSubCommandAsync", "(close)"));
1175
1175
  }
@@ -1186,7 +1186,7 @@ Expecting one of '${allowedValues.join("', '")}'`);
1186
1186
  throw new Error(`'${executableFile}' not executable`);
1187
1187
  }
1188
1188
  if (!exitCallback) {
1189
- process2.exit(1);
1189
+ process3.exit(1);
1190
1190
  } else {
1191
1191
  const wrappedError = new CommanderError(1, "commander.executeSubCommandAsync", "(error)");
1192
1192
  wrappedError.nestedError = err;
@@ -1534,11 +1534,11 @@ Expecting one of '${allowedValues.join("', '")}'`);
1534
1534
  }
1535
1535
  _parseOptionsEnv() {
1536
1536
  this.options.forEach((option) => {
1537
- if (option.envVar && option.envVar in process2.env) {
1537
+ if (option.envVar && option.envVar in process3.env) {
1538
1538
  const optionKey = option.attributeName();
1539
1539
  if (this.getOptionValue(optionKey) === undefined || ["default", "config", "env"].includes(this.getOptionValueSource(optionKey))) {
1540
1540
  if (option.required || option.optional) {
1541
- this.emit(`optionEnv:${option.name()}`, process2.env[option.envVar]);
1541
+ this.emit(`optionEnv:${option.name()}`, process3.env[option.envVar]);
1542
1542
  } else {
1543
1543
  this.emit(`optionEnv:${option.name()}`);
1544
1544
  }
@@ -1784,7 +1784,7 @@ Expecting one of '${allowedValues.join("', '")}'`);
1784
1784
  }
1785
1785
  help(contextOptions) {
1786
1786
  this.outputHelp(contextOptions);
1787
- let exitCode = process2.exitCode || 0;
1787
+ let exitCode = process3.exitCode || 0;
1788
1788
  if (exitCode === 0 && contextOptions && typeof contextOptions !== "function" && contextOptions.error) {
1789
1789
  exitCode = 1;
1790
1790
  }
@@ -1852,7 +1852,7 @@ Expecting one of '${allowedValues.join("', '")}'`);
1852
1852
  exports.Command = Command;
1853
1853
  });
1854
1854
 
1855
- // node_modules/commander/index.js
1855
+ // node_modules/.bun/commander@12.1.0/node_modules/commander/index.js
1856
1856
  var require_commander = __commonJS((exports) => {
1857
1857
  var { Argument } = require_argument();
1858
1858
  var { Command } = require_command();
@@ -1872,23 +1872,11 @@ var require_commander = __commonJS((exports) => {
1872
1872
  exports.InvalidOptionArgumentError = InvalidArgumentError;
1873
1873
  });
1874
1874
 
1875
- // node_modules/commander/esm.mjs
1876
- var import__ = __toESM(require_commander(), 1);
1877
- var {
1878
- program,
1879
- createCommand,
1880
- createArgument,
1881
- createOption,
1882
- CommanderError,
1883
- InvalidArgumentError,
1884
- InvalidOptionArgumentError,
1885
- Command,
1886
- Argument,
1887
- Option,
1888
- Help
1889
- } = import__.default;
1875
+ // src/cli/index.tsx
1876
+ import fs from "fs";
1877
+ import path from "path";
1890
1878
 
1891
- // node_modules/chalk/source/vendor/ansi-styles/index.js
1879
+ // node_modules/.bun/chalk@5.6.2/node_modules/chalk/source/vendor/ansi-styles/index.js
1892
1880
  var ANSI_BACKGROUND_OFFSET = 10;
1893
1881
  var wrapAnsi16 = (offset = 0) => (code) => `\x1B[${code + offset}m`;
1894
1882
  var wrapAnsi256 = (offset = 0) => (code) => `\x1B[${38 + offset};5;${code}m`;
@@ -2065,7 +2053,7 @@ function assembleStyles() {
2065
2053
  var ansiStyles = assembleStyles();
2066
2054
  var ansi_styles_default = ansiStyles;
2067
2055
 
2068
- // node_modules/chalk/source/vendor/supports-color/index.js
2056
+ // node_modules/.bun/chalk@5.6.2/node_modules/chalk/source/vendor/supports-color/index.js
2069
2057
  import process2 from "process";
2070
2058
  import os from "os";
2071
2059
  import tty from "tty";
@@ -2197,7 +2185,7 @@ var supportsColor = {
2197
2185
  };
2198
2186
  var supports_color_default = supportsColor;
2199
2187
 
2200
- // node_modules/chalk/source/utilities.js
2188
+ // node_modules/.bun/chalk@5.6.2/node_modules/chalk/source/utilities.js
2201
2189
  function stringReplaceAll(string, substring, replacer) {
2202
2190
  let index = string.indexOf(substring);
2203
2191
  if (index === -1) {
@@ -2230,7 +2218,7 @@ function stringEncaseCRLFWithFirstIndex(string, prefix, postfix, index) {
2230
2218
  return returnValue;
2231
2219
  }
2232
2220
 
2233
- // node_modules/chalk/source/index.js
2221
+ // node_modules/.bun/chalk@5.6.2/node_modules/chalk/source/index.js
2234
2222
  var { stdout: stdoutColor, stderr: stderrColor } = supports_color_default;
2235
2223
  var GENERATOR = Symbol("GENERATOR");
2236
2224
  var STYLER = Symbol("STYLER");
@@ -2377,6 +2365,25 @@ var chalk = createChalk();
2377
2365
  var chalkStderr = createChalk({ level: stderrColor ? stderrColor.level : 0 });
2378
2366
  var source_default = chalk;
2379
2367
 
2368
+ // node_modules/.bun/commander@12.1.0/node_modules/commander/esm.mjs
2369
+ var import__ = __toESM(require_commander(), 1);
2370
+ var {
2371
+ program,
2372
+ createCommand,
2373
+ createArgument,
2374
+ createOption,
2375
+ CommanderError,
2376
+ InvalidArgumentError,
2377
+ InvalidOptionArgumentError,
2378
+ Command,
2379
+ Argument,
2380
+ Option,
2381
+ Help
2382
+ } = import__.default;
2383
+
2384
+ // src/lib/installer.ts
2385
+ import { execFileSync, execSync } from "child_process";
2386
+
2380
2387
  // src/lib/registry.ts
2381
2388
  var MICROSERVICES = [
2382
2389
  {
@@ -2387,9 +2394,24 @@ var MICROSERVICES = [
2387
2394
  package: "@hasna/microservice-auth",
2388
2395
  binary: "microservice-auth",
2389
2396
  schemaPrefix: "auth",
2390
- tags: ["auth", "users", "sessions", "jwt", "oauth", "2fa", "api-keys", "magic-links"],
2397
+ tags: [
2398
+ "auth",
2399
+ "users",
2400
+ "sessions",
2401
+ "jwt",
2402
+ "oauth",
2403
+ "2fa",
2404
+ "api-keys",
2405
+ "magic-links"
2406
+ ],
2391
2407
  requiredEnv: ["DATABASE_URL", "JWT_SECRET"],
2392
- optionalEnv: ["GITHUB_CLIENT_ID", "GITHUB_CLIENT_SECRET", "GOOGLE_CLIENT_ID", "GOOGLE_CLIENT_SECRET", "AUTH_PORT"]
2408
+ optionalEnv: [
2409
+ "GITHUB_CLIENT_ID",
2410
+ "GITHUB_CLIENT_SECRET",
2411
+ "GOOGLE_CLIENT_ID",
2412
+ "GOOGLE_CLIENT_SECRET",
2413
+ "AUTH_PORT"
2414
+ ]
2393
2415
  },
2394
2416
  {
2395
2417
  name: "teams",
@@ -2399,7 +2421,14 @@ var MICROSERVICES = [
2399
2421
  package: "@hasna/microservice-teams",
2400
2422
  binary: "microservice-teams",
2401
2423
  schemaPrefix: "teams",
2402
- tags: ["teams", "workspaces", "rbac", "invites", "permissions", "multi-tenancy"],
2424
+ tags: [
2425
+ "teams",
2426
+ "workspaces",
2427
+ "rbac",
2428
+ "invites",
2429
+ "permissions",
2430
+ "multi-tenancy"
2431
+ ],
2403
2432
  requiredEnv: ["DATABASE_URL"],
2404
2433
  optionalEnv: ["TEAMS_PORT"]
2405
2434
  },
@@ -2411,7 +2440,15 @@ var MICROSERVICES = [
2411
2440
  package: "@hasna/microservice-billing",
2412
2441
  binary: "microservice-billing",
2413
2442
  schemaPrefix: "billing",
2414
- tags: ["billing", "stripe", "subscriptions", "plans", "invoices", "usage", "webhooks"],
2443
+ tags: [
2444
+ "billing",
2445
+ "stripe",
2446
+ "subscriptions",
2447
+ "plans",
2448
+ "invoices",
2449
+ "usage",
2450
+ "webhooks"
2451
+ ],
2415
2452
  requiredEnv: ["DATABASE_URL", "STRIPE_SECRET_KEY", "STRIPE_WEBHOOK_SECRET"],
2416
2453
  optionalEnv: ["BILLING_PORT"]
2417
2454
  },
@@ -2423,9 +2460,26 @@ var MICROSERVICES = [
2423
2460
  package: "@hasna/microservice-notify",
2424
2461
  binary: "microservice-notify",
2425
2462
  schemaPrefix: "notify",
2426
- tags: ["notifications", "email", "sms", "in-app", "webhooks", "templates", "sse"],
2463
+ tags: [
2464
+ "notifications",
2465
+ "email",
2466
+ "sms",
2467
+ "in-app",
2468
+ "webhooks",
2469
+ "templates",
2470
+ "sse"
2471
+ ],
2427
2472
  requiredEnv: ["DATABASE_URL"],
2428
- optionalEnv: ["RESEND_API_KEY", "SMTP_HOST", "SMTP_PORT", "SMTP_USER", "SMTP_PASS", "TWILIO_ACCOUNT_SID", "TWILIO_AUTH_TOKEN", "NOTIFY_PORT"]
2473
+ optionalEnv: [
2474
+ "RESEND_API_KEY",
2475
+ "SMTP_HOST",
2476
+ "SMTP_PORT",
2477
+ "SMTP_USER",
2478
+ "SMTP_PASS",
2479
+ "TWILIO_ACCOUNT_SID",
2480
+ "TWILIO_AUTH_TOKEN",
2481
+ "NOTIFY_PORT"
2482
+ ]
2429
2483
  },
2430
2484
  {
2431
2485
  name: "files",
@@ -2435,9 +2489,24 @@ var MICROSERVICES = [
2435
2489
  package: "@hasna/microservice-files",
2436
2490
  binary: "microservice-files",
2437
2491
  schemaPrefix: "files",
2438
- tags: ["files", "uploads", "s3", "storage", "images", "presigned-urls", "cdn"],
2492
+ tags: [
2493
+ "files",
2494
+ "uploads",
2495
+ "s3",
2496
+ "storage",
2497
+ "images",
2498
+ "presigned-urls",
2499
+ "cdn"
2500
+ ],
2439
2501
  requiredEnv: ["DATABASE_URL"],
2440
- optionalEnv: ["S3_BUCKET", "S3_REGION", "AWS_ACCESS_KEY_ID", "AWS_SECRET_ACCESS_KEY", "FILES_STORAGE", "FILES_PORT"]
2502
+ optionalEnv: [
2503
+ "S3_BUCKET",
2504
+ "S3_REGION",
2505
+ "AWS_ACCESS_KEY_ID",
2506
+ "AWS_SECRET_ACCESS_KEY",
2507
+ "FILES_STORAGE",
2508
+ "FILES_PORT"
2509
+ ]
2441
2510
  },
2442
2511
  {
2443
2512
  name: "audit",
@@ -2459,7 +2528,13 @@ var MICROSERVICES = [
2459
2528
  package: "@hasna/microservice-flags",
2460
2529
  binary: "microservice-flags",
2461
2530
  schemaPrefix: "flags",
2462
- tags: ["feature-flags", "experiments", "rollouts", "ab-testing", "targeting"],
2531
+ tags: [
2532
+ "feature-flags",
2533
+ "experiments",
2534
+ "rollouts",
2535
+ "ab-testing",
2536
+ "targeting"
2537
+ ],
2463
2538
  requiredEnv: ["DATABASE_URL"],
2464
2539
  optionalEnv: ["FLAGS_PORT"]
2465
2540
  },
@@ -2471,7 +2546,15 @@ var MICROSERVICES = [
2471
2546
  package: "@hasna/microservice-jobs",
2472
2547
  binary: "microservice-jobs",
2473
2548
  schemaPrefix: "jobs",
2474
- tags: ["jobs", "queues", "background", "cron", "scheduling", "workers", "retry"],
2549
+ tags: [
2550
+ "jobs",
2551
+ "queues",
2552
+ "background",
2553
+ "cron",
2554
+ "scheduling",
2555
+ "workers",
2556
+ "retry"
2557
+ ],
2475
2558
  requiredEnv: ["DATABASE_URL"],
2476
2559
  optionalEnv: ["JOBS_PORT", "JOBS_WORKER_CONCURRENCY"]
2477
2560
  },
@@ -2483,9 +2566,23 @@ var MICROSERVICES = [
2483
2566
  package: "@hasna/microservice-llm",
2484
2567
  binary: "microservice-llm",
2485
2568
  schemaPrefix: "llm",
2486
- tags: ["llm", "openai", "anthropic", "groq", "ai", "gateway", "cost-tracking", "rate-limiting"],
2569
+ tags: [
2570
+ "llm",
2571
+ "openai",
2572
+ "anthropic",
2573
+ "groq",
2574
+ "ai",
2575
+ "gateway",
2576
+ "cost-tracking",
2577
+ "rate-limiting"
2578
+ ],
2487
2579
  requiredEnv: ["DATABASE_URL"],
2488
- optionalEnv: ["OPENAI_API_KEY", "ANTHROPIC_API_KEY", "GROQ_API_KEY", "LLM_PORT"]
2580
+ optionalEnv: [
2581
+ "OPENAI_API_KEY",
2582
+ "ANTHROPIC_API_KEY",
2583
+ "GROQ_API_KEY",
2584
+ "LLM_PORT"
2585
+ ]
2489
2586
  },
2490
2587
  {
2491
2588
  name: "memory",
@@ -2495,7 +2592,15 @@ var MICROSERVICES = [
2495
2592
  package: "@hasna/microservice-memory",
2496
2593
  binary: "microservice-memory",
2497
2594
  schemaPrefix: "memory",
2498
- tags: ["memory", "embeddings", "pgvector", "semantic-search", "rag", "ai-agents", "recall"],
2595
+ tags: [
2596
+ "memory",
2597
+ "embeddings",
2598
+ "pgvector",
2599
+ "semantic-search",
2600
+ "rag",
2601
+ "ai-agents",
2602
+ "recall"
2603
+ ],
2499
2604
  requiredEnv: ["DATABASE_URL"],
2500
2605
  optionalEnv: ["OPENAI_API_KEY", "MEMORY_PORT"]
2501
2606
  },
@@ -2507,10 +2612,38 @@ var MICROSERVICES = [
2507
2612
  package: "@hasna/microservice-search",
2508
2613
  binary: "microservice-search",
2509
2614
  schemaPrefix: "search",
2510
- tags: ["search", "full-text", "semantic", "vector", "pgvector", "hybrid", "rag"],
2615
+ tags: [
2616
+ "search",
2617
+ "full-text",
2618
+ "semantic",
2619
+ "vector",
2620
+ "pgvector",
2621
+ "hybrid",
2622
+ "rag"
2623
+ ],
2511
2624
  requiredEnv: ["DATABASE_URL"],
2512
2625
  optionalEnv: ["OPENAI_API_KEY", "SEARCH_PORT"]
2513
2626
  },
2627
+ {
2628
+ name: "knowledge",
2629
+ displayName: "Knowledge",
2630
+ description: "RAG knowledge base: document ingestion, chunking (fixed/paragraph/sentence/recursive), embedding, and semantic/text/hybrid retrieval with source attribution.",
2631
+ category: "AI",
2632
+ package: "@hasna/microservice-knowledge",
2633
+ binary: "microservice-knowledge",
2634
+ schemaPrefix: "knowledge",
2635
+ tags: [
2636
+ "knowledge",
2637
+ "rag",
2638
+ "chunking",
2639
+ "embeddings",
2640
+ "retrieval",
2641
+ "pgvector",
2642
+ "documents"
2643
+ ],
2644
+ requiredEnv: ["DATABASE_URL"],
2645
+ optionalEnv: ["OPENAI_API_KEY", "KNOWLEDGE_PORT"]
2646
+ },
2514
2647
  {
2515
2648
  name: "usage",
2516
2649
  displayName: "Usage",
@@ -2531,7 +2664,14 @@ var MICROSERVICES = [
2531
2664
  package: "@hasna/microservice-webhooks",
2532
2665
  binary: "microservice-webhooks",
2533
2666
  schemaPrefix: "webhooks",
2534
- tags: ["webhooks", "outbound", "delivery", "retry", "signing", "integrations"],
2667
+ tags: [
2668
+ "webhooks",
2669
+ "outbound",
2670
+ "delivery",
2671
+ "retry",
2672
+ "signing",
2673
+ "integrations"
2674
+ ],
2535
2675
  requiredEnv: ["DATABASE_URL"],
2536
2676
  optionalEnv: ["WEBHOOKS_PORT"]
2537
2677
  },
@@ -2558,6 +2698,104 @@ var MICROSERVICES = [
2558
2698
  tags: ["waitlist", "referral", "invites", "launch", "growth"],
2559
2699
  requiredEnv: ["DATABASE_URL"],
2560
2700
  optionalEnv: ["WAITLIST_PORT"]
2701
+ },
2702
+ {
2703
+ name: "sessions",
2704
+ displayName: "Sessions",
2705
+ description: "AI conversation history: message threads, context window management, multi-turn state, fork/pin, full-text search across messages, export as markdown/JSON.",
2706
+ category: "AI",
2707
+ package: "@hasna/microservice-sessions",
2708
+ binary: "microservice-sessions",
2709
+ schemaPrefix: "sessions",
2710
+ tags: [
2711
+ "sessions",
2712
+ "conversations",
2713
+ "chat",
2714
+ "messages",
2715
+ "context-window",
2716
+ "history"
2717
+ ],
2718
+ requiredEnv: ["DATABASE_URL"],
2719
+ optionalEnv: ["SESSIONS_PORT"]
2720
+ },
2721
+ {
2722
+ name: "guardrails",
2723
+ displayName: "Guardrails",
2724
+ description: "AI safety layer: prompt injection detection, PII scanning (email/phone/SSN/CC), toxicity check, configurable per-workspace policies, violation logging.",
2725
+ category: "AI",
2726
+ package: "@hasna/microservice-guardrails",
2727
+ binary: "microservice-guardrails",
2728
+ schemaPrefix: "guardrails",
2729
+ tags: [
2730
+ "guardrails",
2731
+ "safety",
2732
+ "pii",
2733
+ "injection",
2734
+ "toxicity",
2735
+ "moderation",
2736
+ "policy"
2737
+ ],
2738
+ requiredEnv: ["DATABASE_URL"],
2739
+ optionalEnv: ["GUARDRAILS_PORT"]
2740
+ },
2741
+ {
2742
+ name: "traces",
2743
+ displayName: "Traces",
2744
+ description: "Agent observability: span-based distributed tracing for LLM calls, tool calls, and decisions. Duration, token, and cost tracking per span. Stats with percentiles.",
2745
+ category: "Observability",
2746
+ package: "@hasna/microservice-traces",
2747
+ binary: "microservice-traces",
2748
+ schemaPrefix: "traces",
2749
+ tags: [
2750
+ "traces",
2751
+ "tracing",
2752
+ "spans",
2753
+ "observability",
2754
+ "latency",
2755
+ "debugging",
2756
+ "agent-ops"
2757
+ ],
2758
+ requiredEnv: ["DATABASE_URL"],
2759
+ optionalEnv: ["TRACES_PORT"]
2760
+ },
2761
+ {
2762
+ name: "agents",
2763
+ displayName: "Agents",
2764
+ description: "Agent registry and orchestration: register agents with capabilities, health tracking via heartbeat, capability-based task routing, agent-to-agent messaging.",
2765
+ category: "AI",
2766
+ package: "@hasna/microservice-agents",
2767
+ binary: "microservice-agents",
2768
+ schemaPrefix: "agents",
2769
+ tags: [
2770
+ "agents",
2771
+ "registry",
2772
+ "orchestration",
2773
+ "routing",
2774
+ "multi-agent",
2775
+ "capabilities",
2776
+ "heartbeat"
2777
+ ],
2778
+ requiredEnv: ["DATABASE_URL"],
2779
+ optionalEnv: ["AGENTS_PORT"]
2780
+ },
2781
+ {
2782
+ name: "prompts",
2783
+ displayName: "Prompts",
2784
+ description: "Versioned prompt management: auto-incrementing versions, per-workspace/user/agent overrides, A/B experiment variants, rollback, variable interpolation, diff.",
2785
+ category: "AI",
2786
+ package: "@hasna/microservice-prompts",
2787
+ binary: "microservice-prompts",
2788
+ schemaPrefix: "prompts",
2789
+ tags: [
2790
+ "prompts",
2791
+ "templates",
2792
+ "versioning",
2793
+ "ab-testing",
2794
+ "overrides",
2795
+ "rollback"
2796
+ ],
2797
+ requiredEnv: ["DATABASE_URL"],
2798
+ optionalEnv: ["PROMPTS_PORT"]
2561
2799
  }
2562
2800
  ];
2563
2801
  function getMicroservice(name) {
@@ -2570,7 +2808,6 @@ function searchMicroservices(query) {
2570
2808
  }
2571
2809
 
2572
2810
  // src/lib/installer.ts
2573
- import { execSync, execFileSync } from "child_process";
2574
2811
  function microserviceExists(name) {
2575
2812
  const meta = getMicroservice(name);
2576
2813
  if (!meta)
@@ -2587,7 +2824,9 @@ function getMicroserviceVersion(name) {
2587
2824
  if (!meta)
2588
2825
  return null;
2589
2826
  try {
2590
- const out = execFileSync(meta.binary, ["--version"], { encoding: "utf8" }).trim();
2827
+ const out = execFileSync(meta.binary, ["--version"], {
2828
+ encoding: "utf8"
2829
+ }).trim();
2591
2830
  return out || null;
2592
2831
  } catch {
2593
2832
  return null;
@@ -2596,7 +2835,11 @@ function getMicroserviceVersion(name) {
2596
2835
  function installMicroservice(name, options = {}) {
2597
2836
  const meta = getMicroservice(name);
2598
2837
  if (!meta) {
2599
- return { microservice: name, success: false, error: `Unknown microservice '${name}'` };
2838
+ return {
2839
+ microservice: name,
2840
+ success: false,
2841
+ error: `Unknown microservice '${name}'`
2842
+ };
2600
2843
  }
2601
2844
  if (microserviceExists(name) && !options.force) {
2602
2845
  const version = getMicroserviceVersion(name);
@@ -2617,9 +2860,6 @@ function installMicroservice(name, options = {}) {
2617
2860
  function installMicroservices(names, options = {}) {
2618
2861
  return names.map((name) => installMicroservice(name, options));
2619
2862
  }
2620
- function getInstalledMicroservices() {
2621
- return MICROSERVICES.filter((m) => microserviceExists(m.name)).map((m) => m.name);
2622
- }
2623
2863
  function removeMicroservice(name) {
2624
2864
  const meta = getMicroservice(name);
2625
2865
  if (!meta)
@@ -2640,38 +2880,6 @@ function getMicroserviceStatus(name) {
2640
2880
  };
2641
2881
  }
2642
2882
 
2643
- // src/lib/runner.ts
2644
- import { execFile } from "child_process";
2645
- async function runMicroserviceCommand(name, args, timeout = 30000) {
2646
- const meta = getMicroservice(name);
2647
- if (!meta) {
2648
- return { success: false, stdout: "", stderr: `Unknown microservice '${name}'`, exitCode: 1 };
2649
- }
2650
- if (!microserviceExists(name)) {
2651
- return {
2652
- success: false,
2653
- stdout: "",
2654
- stderr: `microservice-${name} is not installed. Run: bun install -g ${meta.package}`,
2655
- exitCode: 1
2656
- };
2657
- }
2658
- return new Promise((resolve) => {
2659
- execFile(meta.binary, args, { timeout, maxBuffer: 10 * 1024 * 1024 }, (error, stdout, stderr) => {
2660
- if (error && "killed" in error && error.killed) {
2661
- resolve({ success: false, stdout: "", stderr: "Command timed out", exitCode: 1 });
2662
- return;
2663
- }
2664
- const exitCode = error?.code ? typeof error.code === "number" ? error.code : 1 : 0;
2665
- resolve({
2666
- success: exitCode === 0,
2667
- stdout: (stdout || "").trim(),
2668
- stderr: (stderr || "").trim(),
2669
- exitCode
2670
- });
2671
- });
2672
- });
2673
- }
2674
-
2675
2883
  // src/lib/package-info.ts
2676
2884
  import { existsSync, readFileSync } from "fs";
2677
2885
  import { dirname, join, resolve } from "path";
@@ -2704,6 +2912,48 @@ function getPackageVersion(startDir) {
2704
2912
  return readPackageVersion(packageJsonPath);
2705
2913
  }
2706
2914
 
2915
+ // src/lib/runner.ts
2916
+ import { execFile } from "child_process";
2917
+ async function runMicroserviceCommand(name, args, timeout = 30000) {
2918
+ const meta = getMicroservice(name);
2919
+ if (!meta) {
2920
+ return {
2921
+ success: false,
2922
+ stdout: "",
2923
+ stderr: `Unknown microservice '${name}'`,
2924
+ exitCode: 1
2925
+ };
2926
+ }
2927
+ if (!microserviceExists(name)) {
2928
+ return {
2929
+ success: false,
2930
+ stdout: "",
2931
+ stderr: `microservice-${name} is not installed. Run: bun install -g ${meta.package}`,
2932
+ exitCode: 1
2933
+ };
2934
+ }
2935
+ return new Promise((resolve2) => {
2936
+ execFile(meta.binary, args, { timeout, maxBuffer: 10 * 1024 * 1024 }, (error, stdout, stderr) => {
2937
+ if (error && "killed" in error && error.killed) {
2938
+ resolve2({
2939
+ success: false,
2940
+ stdout: "",
2941
+ stderr: "Command timed out",
2942
+ exitCode: 1
2943
+ });
2944
+ return;
2945
+ }
2946
+ const exitCode = error?.code ? typeof error.code === "number" ? error.code : 1 : 0;
2947
+ resolve2({
2948
+ success: exitCode === 0,
2949
+ stdout: (stdout || "").trim(),
2950
+ stderr: (stderr || "").trim(),
2951
+ exitCode
2952
+ });
2953
+ });
2954
+ });
2955
+ }
2956
+
2707
2957
  // src/cli/index.tsx
2708
2958
  var program2 = new Command;
2709
2959
  program2.name("microservices").description("Production-grade microservice building blocks for SaaS apps").version(getPackageVersion());
@@ -2762,10 +3012,10 @@ Microservice status:
2762
3012
  program2.command("run <name> [args...]").description("Run a command on an installed microservice").action(async (name, args) => {
2763
3013
  const result = await runMicroserviceCommand(name, args);
2764
3014
  if (result.stdout)
2765
- process.stdout.write(result.stdout + `
3015
+ process.stdout.write(`${result.stdout}
2766
3016
  `);
2767
3017
  if (result.stderr)
2768
- process.stderr.write(result.stderr + `
3018
+ process.stderr.write(`${result.stderr}
2769
3019
  `);
2770
3020
  process.exit(result.exitCode);
2771
3021
  });
@@ -2779,25 +3029,130 @@ program2.command("search <query>").description("Search microservices by name or
2779
3029
  console.log(` ${source_default.cyan(m.name.padEnd(20))} ${m.description}`);
2780
3030
  }
2781
3031
  });
2782
- program2.command("migrate-all").description("Run migrations on all installed microservices").option("--db <url>", "PostgreSQL connection URL (overrides DATABASE_URL)").action(async (opts) => {
3032
+ program2.command("migrate-all").description("Run database migrations for all installed microservices").option("--db <url>", "PostgreSQL connection URL (overrides DATABASE_URL)").action(async (opts) => {
2783
3033
  if (opts.db)
2784
- process.env["DATABASE_URL"] = opts.db;
2785
- const installed = getInstalledMicroservices();
3034
+ process.env.DATABASE_URL = opts.db;
3035
+ const installed = MICROSERVICES.filter((m) => microserviceExists(m.name));
2786
3036
  if (installed.length === 0) {
2787
- console.log(source_default.yellow("No microservices installed."));
3037
+ console.log(source_default.yellow("No microservices installed to migrate."));
2788
3038
  return;
2789
3039
  }
2790
3040
  console.log(source_default.bold(`
2791
- Migrating ${installed.length} microservice(s)...
3041
+ Migrating ${installed.length} installed microservices...
2792
3042
  `));
2793
- for (const name of installed) {
2794
- const result = await runMicroserviceCommand(name, ["migrate"]);
2795
- if (result.success)
2796
- console.log(` ${source_default.green("\u2713")} ${name}`);
2797
- else
2798
- console.log(` ${source_default.red("\u2717")} ${name}: ${result.stderr || result.stdout}`);
3043
+ let hasErrors = false;
3044
+ for (const m of installed) {
3045
+ console.log(source_default.blue(`Migrating ${m.name}...`));
3046
+ const result = await runMicroserviceCommand(m.name, ["migrate"]);
3047
+ if (result.success) {
3048
+ console.log(` ${source_default.green("\u2713")} ${result.stdout.trim() || "Success"}`);
3049
+ } else {
3050
+ console.log(` ${source_default.red("\u2717")} ${result.stderr.trim() || result.stdout.trim() || "Failed"}`);
3051
+ hasErrors = true;
3052
+ }
2799
3053
  }
2800
3054
  console.log();
3055
+ if (hasErrors) {
3056
+ console.error(source_default.red("Some migrations failed. Please check the logs above."));
3057
+ process.exit(1);
3058
+ } else {
3059
+ console.log(source_default.green("\u2713 All migrations completed successfully."));
3060
+ }
3061
+ });
3062
+ program2.command("serve-all").description("Start HTTP servers for all installed microservices concurrently").option("--db <url>", "PostgreSQL connection URL (overrides DATABASE_URL)").action(async (opts) => {
3063
+ if (opts.db)
3064
+ process.env.DATABASE_URL = opts.db;
3065
+ const installed = MICROSERVICES.filter((m) => microserviceExists(m.name));
3066
+ if (installed.length === 0) {
3067
+ console.log(source_default.yellow("No microservices installed to serve."));
3068
+ return;
3069
+ }
3070
+ console.log(source_default.bold(`
3071
+ Starting ${installed.length} installed microservices...
3072
+ `));
3073
+ const { spawn } = await import("child_process");
3074
+ const procs = [];
3075
+ const colors = [
3076
+ source_default.cyan,
3077
+ source_default.magenta,
3078
+ source_default.green,
3079
+ source_default.yellow,
3080
+ source_default.blue
3081
+ ];
3082
+ for (let i = 0;i < installed.length; i++) {
3083
+ const m = installed[i];
3084
+ const color = colors[i % colors.length];
3085
+ const prefix = color(`[${m.name.padEnd(10)}] `);
3086
+ const proc = spawn(m.binary, ["serve"], {
3087
+ env: process.env,
3088
+ stdio: ["ignore", "pipe", "pipe"]
3089
+ });
3090
+ proc.stdout.on("data", (data) => {
3091
+ const lines = data.toString().trim().split(`
3092
+ `);
3093
+ for (const line of lines)
3094
+ if (line)
3095
+ console.log(`${prefix}${line}`);
3096
+ });
3097
+ proc.stderr.on("data", (data) => {
3098
+ const lines = data.toString().trim().split(`
3099
+ `);
3100
+ for (const line of lines)
3101
+ if (line)
3102
+ console.error(`${prefix}${source_default.red(line)}`);
3103
+ });
3104
+ proc.on("error", (err) => {
3105
+ console.error(`${prefix}${source_default.red("Failed to start:")} ${err.message}`);
3106
+ });
3107
+ procs.push(proc);
3108
+ }
3109
+ process.on("SIGINT", () => {
3110
+ console.log(source_default.yellow(`
3111
+ Stopping all microservices...`));
3112
+ for (const p of procs)
3113
+ p.kill("SIGINT");
3114
+ process.exit(0);
3115
+ });
3116
+ });
3117
+ program2.command("init-all").description("Run init (migrations) for all installed microservices").option("--db <url>", "PostgreSQL connection URL").action(async (opts) => {
3118
+ const installed = MICROSERVICES.filter((m) => microserviceExists(m.name));
3119
+ if (installed.length === 0) {
3120
+ console.log(source_default.yellow("No microservices installed to init."));
3121
+ return;
3122
+ }
3123
+ if (!opts.db) {
3124
+ console.error(source_default.red("--db <url> is required. Example: microservices init-all --db postgres://localhost/myapp"));
3125
+ process.exit(1);
3126
+ }
3127
+ process.env.DATABASE_URL = opts.db;
3128
+ console.log(source_default.bold(`
3129
+ Initializing ${installed.length} installed microservices...
3130
+ `));
3131
+ let hasErrors = false;
3132
+ for (const m of installed) {
3133
+ console.log(source_default.blue(`Initializing ${m.name}...`));
3134
+ const result = await runMicroserviceCommand(m.name, [
3135
+ "init",
3136
+ "--db",
3137
+ opts.db
3138
+ ]);
3139
+ if (result.success) {
3140
+ console.log(` ${source_default.green("\u2713")} ${result.stdout.trim().split(`
3141
+ `).join(`
3142
+ `) || "Success"}`);
3143
+ } else {
3144
+ console.log(` ${source_default.red("\u2717")} ${result.stderr.trim() || result.stdout.trim() || "Failed"}`);
3145
+ hasErrors = true;
3146
+ }
3147
+ }
3148
+ console.log();
3149
+ if (hasErrors) {
3150
+ console.error(source_default.red("Some inits failed. Please check the logs above."));
3151
+ process.exit(1);
3152
+ } else {
3153
+ console.log(source_default.green("\u2713 All services initialized successfully."));
3154
+ console.log(source_default.gray(" You can now run 'microservices serve-all' to start them."));
3155
+ }
2801
3156
  });
2802
3157
  program2.command("info <name>").description("Show detailed info about a microservice").action((name) => {
2803
3158
  const m = getMicroservice(name);
@@ -2820,4 +3175,89 @@ ${m.displayName}`));
2820
3175
  console.log(` Tags: ${m.tags.join(", ")}`);
2821
3176
  console.log();
2822
3177
  });
3178
+ program2.command("check-env").description("Verify environment variables for all installed microservices").action(() => {
3179
+ const installed = MICROSERVICES.filter((m) => microserviceExists(m.name));
3180
+ if (installed.length === 0) {
3181
+ console.log(source_default.yellow("No microservices installed to check."));
3182
+ return;
3183
+ }
3184
+ console.log(source_default.bold(`
3185
+ Checking environment for ${installed.length} microservices...
3186
+ `));
3187
+ let totalMissing = 0;
3188
+ for (const m of installed) {
3189
+ const missingRequired = m.requiredEnv.filter((env2) => !process.env[env2]);
3190
+ const missingOptional = (m.optionalEnv ?? []).filter((env2) => !process.env[env2]);
3191
+ const status = missingRequired.length > 0 ? source_default.red("\u2717 Critical Missing") : missingOptional.length > 0 ? source_default.yellow("\u26A0 Warning") : source_default.green("\u2713 OK");
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;
3196
+ }
3197
+ if (missingOptional.length > 0) {
3198
+ console.log(source_default.gray(` Optional missing: ${missingOptional.join(", ")}`));
3199
+ }
3200
+ if (missingRequired.length === 0 && missingOptional.length === 0) {
3201
+ console.log(source_default.gray(" All variables set."));
3202
+ }
3203
+ console.log();
3204
+ }
3205
+ if (totalMissing > 0) {
3206
+ console.log(source_default.red(`Found ${totalMissing} missing required environment variables.`));
3207
+ console.log(source_default.gray(`Refer to .env.example for guidance.
3208
+ `));
3209
+ process.exit(1);
3210
+ } else {
3211
+ console.log(source_default.green(`\u2713 All required environment variables are set across all installed services.
3212
+ `));
3213
+ }
3214
+ });
3215
+ program2.command("scaffold <name>").description("Scaffold a new microservice from the _template directory").action((name) => {
3216
+ if (!/^[a-z0-9-]+$/.test(name)) {
3217
+ console.error(source_default.red("Error: Name can only contain lowercase letters, numbers, and dashes."));
3218
+ process.exit(1);
3219
+ }
3220
+ const cwd = process.cwd();
3221
+ const templateDir = path.join(cwd, "microservices", "_template");
3222
+ const targetDir = path.join(cwd, "microservices", `microservice-${name}`);
3223
+ if (!fs.existsSync(templateDir)) {
3224
+ console.error(source_default.red(`Template directory not found at ${templateDir}. Make sure you are running this from the monorepo root.`));
3225
+ process.exit(1);
3226
+ }
3227
+ if (fs.existsSync(targetDir)) {
3228
+ console.error(source_default.red(`Target directory already exists at ${targetDir}`));
3229
+ process.exit(1);
3230
+ }
3231
+ console.log(source_default.bold(`
3232
+ Scaffolding microservice-${name}...
3233
+ `));
3234
+ fs.cpSync(templateDir, targetDir, { recursive: true });
3235
+ const replaceInFile = (filePath) => {
3236
+ const content = fs.readFileSync(filePath, "utf-8");
3237
+ let updated = content.replace(/__NAME__/g, name.toUpperCase().replace(/-/g, "_"));
3238
+ updated = updated.replace(/__Name__/g, name.charAt(0).toUpperCase() + name.slice(1));
3239
+ updated = updated.replace(/__name__/g, name);
3240
+ fs.writeFileSync(filePath, updated, "utf-8");
3241
+ };
3242
+ const walkAndReplace = (dir) => {
3243
+ const files = fs.readdirSync(dir);
3244
+ for (const file of files) {
3245
+ const filePath = path.join(dir, file);
3246
+ if (fs.statSync(filePath).isDirectory()) {
3247
+ walkAndReplace(filePath);
3248
+ } else {
3249
+ replaceInFile(filePath);
3250
+ }
3251
+ }
3252
+ };
3253
+ walkAndReplace(targetDir);
3254
+ console.log(` ${source_default.green("\u2713")} Created microservices/microservice-${name}`);
3255
+ console.log(source_default.gray(`
3256
+ Next steps:
3257
+ 1. Add entry to src/lib/registry.ts
3258
+ 2. Implement schema, core logic, HTTP API, MCP, and CLI
3259
+ 3. Run 'bun install' to link the workspace
3260
+ 4. Run 'bun run build'
3261
+ `));
3262
+ });
2823
3263
  program2.parse();