@hasna/microservices 0.0.19 → 0.0.21
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/README.md +19 -8
- package/bin/index.js +527 -142
- package/bin/mcp.js +750 -276
- package/dist/index.js +244 -49
- package/package.json +14 -2
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
|
|
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) =>
|
|
661
|
-
writeErr: (str) =>
|
|
662
|
-
getOutHelpWidth: () =>
|
|
663
|
-
getErrHelpWidth: () =>
|
|
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
|
-
|
|
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 (
|
|
1054
|
+
if (process3.versions?.electron) {
|
|
1055
1055
|
parseOptions.from = "electron";
|
|
1056
1056
|
}
|
|
1057
|
-
const 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 =
|
|
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 (
|
|
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 (
|
|
1145
|
+
if (process3.platform !== "win32") {
|
|
1146
1146
|
if (launchWithNode) {
|
|
1147
1147
|
args.unshift(executableFile);
|
|
1148
|
-
args = incrementNodeInspectorPort(
|
|
1149
|
-
proc = childProcess.spawn(
|
|
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(
|
|
1156
|
-
proc = childProcess.spawn(
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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()}`,
|
|
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 =
|
|
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
|
-
//
|
|
1876
|
-
|
|
1877
|
-
|
|
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,27 @@ 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
|
+
import { accessSync, constants } from "fs";
|
|
2387
|
+
import { join } from "path";
|
|
2388
|
+
|
|
2380
2389
|
// src/lib/registry.ts
|
|
2381
2390
|
var MICROSERVICES = [
|
|
2382
2391
|
{
|
|
@@ -2387,9 +2396,24 @@ var MICROSERVICES = [
|
|
|
2387
2396
|
package: "@hasna/microservice-auth",
|
|
2388
2397
|
binary: "microservice-auth",
|
|
2389
2398
|
schemaPrefix: "auth",
|
|
2390
|
-
tags: [
|
|
2399
|
+
tags: [
|
|
2400
|
+
"auth",
|
|
2401
|
+
"users",
|
|
2402
|
+
"sessions",
|
|
2403
|
+
"jwt",
|
|
2404
|
+
"oauth",
|
|
2405
|
+
"2fa",
|
|
2406
|
+
"api-keys",
|
|
2407
|
+
"magic-links"
|
|
2408
|
+
],
|
|
2391
2409
|
requiredEnv: ["DATABASE_URL", "JWT_SECRET"],
|
|
2392
|
-
optionalEnv: [
|
|
2410
|
+
optionalEnv: [
|
|
2411
|
+
"GITHUB_CLIENT_ID",
|
|
2412
|
+
"GITHUB_CLIENT_SECRET",
|
|
2413
|
+
"GOOGLE_CLIENT_ID",
|
|
2414
|
+
"GOOGLE_CLIENT_SECRET",
|
|
2415
|
+
"AUTH_PORT"
|
|
2416
|
+
]
|
|
2393
2417
|
},
|
|
2394
2418
|
{
|
|
2395
2419
|
name: "teams",
|
|
@@ -2399,7 +2423,14 @@ var MICROSERVICES = [
|
|
|
2399
2423
|
package: "@hasna/microservice-teams",
|
|
2400
2424
|
binary: "microservice-teams",
|
|
2401
2425
|
schemaPrefix: "teams",
|
|
2402
|
-
tags: [
|
|
2426
|
+
tags: [
|
|
2427
|
+
"teams",
|
|
2428
|
+
"workspaces",
|
|
2429
|
+
"rbac",
|
|
2430
|
+
"invites",
|
|
2431
|
+
"permissions",
|
|
2432
|
+
"multi-tenancy"
|
|
2433
|
+
],
|
|
2403
2434
|
requiredEnv: ["DATABASE_URL"],
|
|
2404
2435
|
optionalEnv: ["TEAMS_PORT"]
|
|
2405
2436
|
},
|
|
@@ -2411,7 +2442,15 @@ var MICROSERVICES = [
|
|
|
2411
2442
|
package: "@hasna/microservice-billing",
|
|
2412
2443
|
binary: "microservice-billing",
|
|
2413
2444
|
schemaPrefix: "billing",
|
|
2414
|
-
tags: [
|
|
2445
|
+
tags: [
|
|
2446
|
+
"billing",
|
|
2447
|
+
"stripe",
|
|
2448
|
+
"subscriptions",
|
|
2449
|
+
"plans",
|
|
2450
|
+
"invoices",
|
|
2451
|
+
"usage",
|
|
2452
|
+
"webhooks"
|
|
2453
|
+
],
|
|
2415
2454
|
requiredEnv: ["DATABASE_URL", "STRIPE_SECRET_KEY", "STRIPE_WEBHOOK_SECRET"],
|
|
2416
2455
|
optionalEnv: ["BILLING_PORT"]
|
|
2417
2456
|
},
|
|
@@ -2423,9 +2462,26 @@ var MICROSERVICES = [
|
|
|
2423
2462
|
package: "@hasna/microservice-notify",
|
|
2424
2463
|
binary: "microservice-notify",
|
|
2425
2464
|
schemaPrefix: "notify",
|
|
2426
|
-
tags: [
|
|
2465
|
+
tags: [
|
|
2466
|
+
"notifications",
|
|
2467
|
+
"email",
|
|
2468
|
+
"sms",
|
|
2469
|
+
"in-app",
|
|
2470
|
+
"webhooks",
|
|
2471
|
+
"templates",
|
|
2472
|
+
"sse"
|
|
2473
|
+
],
|
|
2427
2474
|
requiredEnv: ["DATABASE_URL"],
|
|
2428
|
-
optionalEnv: [
|
|
2475
|
+
optionalEnv: [
|
|
2476
|
+
"RESEND_API_KEY",
|
|
2477
|
+
"SMTP_HOST",
|
|
2478
|
+
"SMTP_PORT",
|
|
2479
|
+
"SMTP_USER",
|
|
2480
|
+
"SMTP_PASS",
|
|
2481
|
+
"TWILIO_ACCOUNT_SID",
|
|
2482
|
+
"TWILIO_AUTH_TOKEN",
|
|
2483
|
+
"NOTIFY_PORT"
|
|
2484
|
+
]
|
|
2429
2485
|
},
|
|
2430
2486
|
{
|
|
2431
2487
|
name: "files",
|
|
@@ -2435,9 +2491,24 @@ var MICROSERVICES = [
|
|
|
2435
2491
|
package: "@hasna/microservice-files",
|
|
2436
2492
|
binary: "microservice-files",
|
|
2437
2493
|
schemaPrefix: "files",
|
|
2438
|
-
tags: [
|
|
2494
|
+
tags: [
|
|
2495
|
+
"files",
|
|
2496
|
+
"uploads",
|
|
2497
|
+
"s3",
|
|
2498
|
+
"storage",
|
|
2499
|
+
"images",
|
|
2500
|
+
"presigned-urls",
|
|
2501
|
+
"cdn"
|
|
2502
|
+
],
|
|
2439
2503
|
requiredEnv: ["DATABASE_URL"],
|
|
2440
|
-
optionalEnv: [
|
|
2504
|
+
optionalEnv: [
|
|
2505
|
+
"S3_BUCKET",
|
|
2506
|
+
"S3_REGION",
|
|
2507
|
+
"AWS_ACCESS_KEY_ID",
|
|
2508
|
+
"AWS_SECRET_ACCESS_KEY",
|
|
2509
|
+
"FILES_STORAGE",
|
|
2510
|
+
"FILES_PORT"
|
|
2511
|
+
]
|
|
2441
2512
|
},
|
|
2442
2513
|
{
|
|
2443
2514
|
name: "audit",
|
|
@@ -2459,7 +2530,13 @@ var MICROSERVICES = [
|
|
|
2459
2530
|
package: "@hasna/microservice-flags",
|
|
2460
2531
|
binary: "microservice-flags",
|
|
2461
2532
|
schemaPrefix: "flags",
|
|
2462
|
-
tags: [
|
|
2533
|
+
tags: [
|
|
2534
|
+
"feature-flags",
|
|
2535
|
+
"experiments",
|
|
2536
|
+
"rollouts",
|
|
2537
|
+
"ab-testing",
|
|
2538
|
+
"targeting"
|
|
2539
|
+
],
|
|
2463
2540
|
requiredEnv: ["DATABASE_URL"],
|
|
2464
2541
|
optionalEnv: ["FLAGS_PORT"]
|
|
2465
2542
|
},
|
|
@@ -2471,7 +2548,15 @@ var MICROSERVICES = [
|
|
|
2471
2548
|
package: "@hasna/microservice-jobs",
|
|
2472
2549
|
binary: "microservice-jobs",
|
|
2473
2550
|
schemaPrefix: "jobs",
|
|
2474
|
-
tags: [
|
|
2551
|
+
tags: [
|
|
2552
|
+
"jobs",
|
|
2553
|
+
"queues",
|
|
2554
|
+
"background",
|
|
2555
|
+
"cron",
|
|
2556
|
+
"scheduling",
|
|
2557
|
+
"workers",
|
|
2558
|
+
"retry"
|
|
2559
|
+
],
|
|
2475
2560
|
requiredEnv: ["DATABASE_URL"],
|
|
2476
2561
|
optionalEnv: ["JOBS_PORT", "JOBS_WORKER_CONCURRENCY"]
|
|
2477
2562
|
},
|
|
@@ -2483,9 +2568,23 @@ var MICROSERVICES = [
|
|
|
2483
2568
|
package: "@hasna/microservice-llm",
|
|
2484
2569
|
binary: "microservice-llm",
|
|
2485
2570
|
schemaPrefix: "llm",
|
|
2486
|
-
tags: [
|
|
2571
|
+
tags: [
|
|
2572
|
+
"llm",
|
|
2573
|
+
"openai",
|
|
2574
|
+
"anthropic",
|
|
2575
|
+
"groq",
|
|
2576
|
+
"ai",
|
|
2577
|
+
"gateway",
|
|
2578
|
+
"cost-tracking",
|
|
2579
|
+
"rate-limiting"
|
|
2580
|
+
],
|
|
2487
2581
|
requiredEnv: ["DATABASE_URL"],
|
|
2488
|
-
optionalEnv: [
|
|
2582
|
+
optionalEnv: [
|
|
2583
|
+
"OPENAI_API_KEY",
|
|
2584
|
+
"ANTHROPIC_API_KEY",
|
|
2585
|
+
"GROQ_API_KEY",
|
|
2586
|
+
"LLM_PORT"
|
|
2587
|
+
]
|
|
2489
2588
|
},
|
|
2490
2589
|
{
|
|
2491
2590
|
name: "memory",
|
|
@@ -2495,7 +2594,15 @@ var MICROSERVICES = [
|
|
|
2495
2594
|
package: "@hasna/microservice-memory",
|
|
2496
2595
|
binary: "microservice-memory",
|
|
2497
2596
|
schemaPrefix: "memory",
|
|
2498
|
-
tags: [
|
|
2597
|
+
tags: [
|
|
2598
|
+
"memory",
|
|
2599
|
+
"embeddings",
|
|
2600
|
+
"pgvector",
|
|
2601
|
+
"semantic-search",
|
|
2602
|
+
"rag",
|
|
2603
|
+
"ai-agents",
|
|
2604
|
+
"recall"
|
|
2605
|
+
],
|
|
2499
2606
|
requiredEnv: ["DATABASE_URL"],
|
|
2500
2607
|
optionalEnv: ["OPENAI_API_KEY", "MEMORY_PORT"]
|
|
2501
2608
|
},
|
|
@@ -2507,7 +2614,15 @@ var MICROSERVICES = [
|
|
|
2507
2614
|
package: "@hasna/microservice-search",
|
|
2508
2615
|
binary: "microservice-search",
|
|
2509
2616
|
schemaPrefix: "search",
|
|
2510
|
-
tags: [
|
|
2617
|
+
tags: [
|
|
2618
|
+
"search",
|
|
2619
|
+
"full-text",
|
|
2620
|
+
"semantic",
|
|
2621
|
+
"vector",
|
|
2622
|
+
"pgvector",
|
|
2623
|
+
"hybrid",
|
|
2624
|
+
"rag"
|
|
2625
|
+
],
|
|
2511
2626
|
requiredEnv: ["DATABASE_URL"],
|
|
2512
2627
|
optionalEnv: ["OPENAI_API_KEY", "SEARCH_PORT"]
|
|
2513
2628
|
},
|
|
@@ -2519,7 +2634,15 @@ var MICROSERVICES = [
|
|
|
2519
2634
|
package: "@hasna/microservice-knowledge",
|
|
2520
2635
|
binary: "microservice-knowledge",
|
|
2521
2636
|
schemaPrefix: "knowledge",
|
|
2522
|
-
tags: [
|
|
2637
|
+
tags: [
|
|
2638
|
+
"knowledge",
|
|
2639
|
+
"rag",
|
|
2640
|
+
"chunking",
|
|
2641
|
+
"embeddings",
|
|
2642
|
+
"retrieval",
|
|
2643
|
+
"pgvector",
|
|
2644
|
+
"documents"
|
|
2645
|
+
],
|
|
2523
2646
|
requiredEnv: ["DATABASE_URL"],
|
|
2524
2647
|
optionalEnv: ["OPENAI_API_KEY", "KNOWLEDGE_PORT"]
|
|
2525
2648
|
},
|
|
@@ -2543,7 +2666,14 @@ var MICROSERVICES = [
|
|
|
2543
2666
|
package: "@hasna/microservice-webhooks",
|
|
2544
2667
|
binary: "microservice-webhooks",
|
|
2545
2668
|
schemaPrefix: "webhooks",
|
|
2546
|
-
tags: [
|
|
2669
|
+
tags: [
|
|
2670
|
+
"webhooks",
|
|
2671
|
+
"outbound",
|
|
2672
|
+
"delivery",
|
|
2673
|
+
"retry",
|
|
2674
|
+
"signing",
|
|
2675
|
+
"integrations"
|
|
2676
|
+
],
|
|
2547
2677
|
requiredEnv: ["DATABASE_URL"],
|
|
2548
2678
|
optionalEnv: ["WEBHOOKS_PORT"]
|
|
2549
2679
|
},
|
|
@@ -2579,7 +2709,14 @@ var MICROSERVICES = [
|
|
|
2579
2709
|
package: "@hasna/microservice-sessions",
|
|
2580
2710
|
binary: "microservice-sessions",
|
|
2581
2711
|
schemaPrefix: "sessions",
|
|
2582
|
-
tags: [
|
|
2712
|
+
tags: [
|
|
2713
|
+
"sessions",
|
|
2714
|
+
"conversations",
|
|
2715
|
+
"chat",
|
|
2716
|
+
"messages",
|
|
2717
|
+
"context-window",
|
|
2718
|
+
"history"
|
|
2719
|
+
],
|
|
2583
2720
|
requiredEnv: ["DATABASE_URL"],
|
|
2584
2721
|
optionalEnv: ["SESSIONS_PORT"]
|
|
2585
2722
|
},
|
|
@@ -2591,22 +2728,18 @@ var MICROSERVICES = [
|
|
|
2591
2728
|
package: "@hasna/microservice-guardrails",
|
|
2592
2729
|
binary: "microservice-guardrails",
|
|
2593
2730
|
schemaPrefix: "guardrails",
|
|
2594
|
-
tags: [
|
|
2731
|
+
tags: [
|
|
2732
|
+
"guardrails",
|
|
2733
|
+
"safety",
|
|
2734
|
+
"pii",
|
|
2735
|
+
"injection",
|
|
2736
|
+
"toxicity",
|
|
2737
|
+
"moderation",
|
|
2738
|
+
"policy"
|
|
2739
|
+
],
|
|
2595
2740
|
requiredEnv: ["DATABASE_URL"],
|
|
2596
2741
|
optionalEnv: ["GUARDRAILS_PORT"]
|
|
2597
2742
|
},
|
|
2598
|
-
{
|
|
2599
|
-
name: "knowledge",
|
|
2600
|
-
displayName: "Knowledge",
|
|
2601
|
-
description: "RAG pipeline: document ingestion, chunking (fixed/paragraph/sentence/recursive), embedding via pgvector, retrieval with source attribution and scoring.",
|
|
2602
|
-
category: "AI",
|
|
2603
|
-
package: "@hasna/microservice-knowledge",
|
|
2604
|
-
binary: "microservice-knowledge",
|
|
2605
|
-
schemaPrefix: "knowledge",
|
|
2606
|
-
tags: ["knowledge", "rag", "chunking", "ingestion", "retrieval", "documents", "pgvector"],
|
|
2607
|
-
requiredEnv: ["DATABASE_URL"],
|
|
2608
|
-
optionalEnv: ["OPENAI_API_KEY", "KNOWLEDGE_PORT"]
|
|
2609
|
-
},
|
|
2610
2743
|
{
|
|
2611
2744
|
name: "traces",
|
|
2612
2745
|
displayName: "Traces",
|
|
@@ -2615,7 +2748,15 @@ var MICROSERVICES = [
|
|
|
2615
2748
|
package: "@hasna/microservice-traces",
|
|
2616
2749
|
binary: "microservice-traces",
|
|
2617
2750
|
schemaPrefix: "traces",
|
|
2618
|
-
tags: [
|
|
2751
|
+
tags: [
|
|
2752
|
+
"traces",
|
|
2753
|
+
"tracing",
|
|
2754
|
+
"spans",
|
|
2755
|
+
"observability",
|
|
2756
|
+
"latency",
|
|
2757
|
+
"debugging",
|
|
2758
|
+
"agent-ops"
|
|
2759
|
+
],
|
|
2619
2760
|
requiredEnv: ["DATABASE_URL"],
|
|
2620
2761
|
optionalEnv: ["TRACES_PORT"]
|
|
2621
2762
|
},
|
|
@@ -2627,7 +2768,15 @@ var MICROSERVICES = [
|
|
|
2627
2768
|
package: "@hasna/microservice-agents",
|
|
2628
2769
|
binary: "microservice-agents",
|
|
2629
2770
|
schemaPrefix: "agents",
|
|
2630
|
-
tags: [
|
|
2771
|
+
tags: [
|
|
2772
|
+
"agents",
|
|
2773
|
+
"registry",
|
|
2774
|
+
"orchestration",
|
|
2775
|
+
"routing",
|
|
2776
|
+
"multi-agent",
|
|
2777
|
+
"capabilities",
|
|
2778
|
+
"heartbeat"
|
|
2779
|
+
],
|
|
2631
2780
|
requiredEnv: ["DATABASE_URL"],
|
|
2632
2781
|
optionalEnv: ["AGENTS_PORT"]
|
|
2633
2782
|
},
|
|
@@ -2639,7 +2788,14 @@ var MICROSERVICES = [
|
|
|
2639
2788
|
package: "@hasna/microservice-prompts",
|
|
2640
2789
|
binary: "microservice-prompts",
|
|
2641
2790
|
schemaPrefix: "prompts",
|
|
2642
|
-
tags: [
|
|
2791
|
+
tags: [
|
|
2792
|
+
"prompts",
|
|
2793
|
+
"templates",
|
|
2794
|
+
"versioning",
|
|
2795
|
+
"ab-testing",
|
|
2796
|
+
"overrides",
|
|
2797
|
+
"rollback"
|
|
2798
|
+
],
|
|
2643
2799
|
requiredEnv: ["DATABASE_URL"],
|
|
2644
2800
|
optionalEnv: ["PROMPTS_PORT"]
|
|
2645
2801
|
}
|
|
@@ -2654,24 +2810,43 @@ function searchMicroservices(query) {
|
|
|
2654
2810
|
}
|
|
2655
2811
|
|
|
2656
2812
|
// src/lib/installer.ts
|
|
2657
|
-
|
|
2658
|
-
|
|
2813
|
+
function getBunGlobalBinDir(env2 = process.env) {
|
|
2814
|
+
const bunInstall = env2.BUN_INSTALL?.trim();
|
|
2815
|
+
if (bunInstall) {
|
|
2816
|
+
return join(bunInstall, "bin");
|
|
2817
|
+
}
|
|
2818
|
+
const home = env2.HOME?.trim();
|
|
2819
|
+
if (!home) {
|
|
2820
|
+
throw new Error("Unable to determine Bun global bin path: HOME is not set.");
|
|
2821
|
+
}
|
|
2822
|
+
return join(home, ".bun", "bin");
|
|
2823
|
+
}
|
|
2824
|
+
function resolveMicroserviceBinary(name) {
|
|
2659
2825
|
const meta = getMicroservice(name);
|
|
2660
2826
|
if (!meta)
|
|
2661
|
-
return
|
|
2662
|
-
|
|
2663
|
-
|
|
2664
|
-
|
|
2665
|
-
|
|
2666
|
-
|
|
2827
|
+
return null;
|
|
2828
|
+
const binDir = getBunGlobalBinDir();
|
|
2829
|
+
const accessMode = process.platform === "win32" ? constants.F_OK : constants.X_OK;
|
|
2830
|
+
const candidates = process.platform === "win32" ? [join(binDir, `${meta.binary}.cmd`), join(binDir, `${meta.binary}.exe`)] : [join(binDir, meta.binary)];
|
|
2831
|
+
for (const candidate of candidates) {
|
|
2832
|
+
try {
|
|
2833
|
+
accessSync(candidate, accessMode);
|
|
2834
|
+
return candidate;
|
|
2835
|
+
} catch {}
|
|
2667
2836
|
}
|
|
2837
|
+
return null;
|
|
2838
|
+
}
|
|
2839
|
+
function microserviceExists(name) {
|
|
2840
|
+
return resolveMicroserviceBinary(name) !== null;
|
|
2668
2841
|
}
|
|
2669
2842
|
function getMicroserviceVersion(name) {
|
|
2670
|
-
const
|
|
2671
|
-
if (!
|
|
2843
|
+
const binaryPath = resolveMicroserviceBinary(name);
|
|
2844
|
+
if (!binaryPath)
|
|
2672
2845
|
return null;
|
|
2673
2846
|
try {
|
|
2674
|
-
const out = execFileSync(
|
|
2847
|
+
const out = execFileSync(binaryPath, ["--version"], {
|
|
2848
|
+
encoding: "utf8"
|
|
2849
|
+
}).trim();
|
|
2675
2850
|
return out || null;
|
|
2676
2851
|
} catch {
|
|
2677
2852
|
return null;
|
|
@@ -2680,7 +2855,11 @@ function getMicroserviceVersion(name) {
|
|
|
2680
2855
|
function installMicroservice(name, options = {}) {
|
|
2681
2856
|
const meta = getMicroservice(name);
|
|
2682
2857
|
if (!meta) {
|
|
2683
|
-
return {
|
|
2858
|
+
return {
|
|
2859
|
+
microservice: name,
|
|
2860
|
+
success: false,
|
|
2861
|
+
error: `Unknown microservice '${name}'`
|
|
2862
|
+
};
|
|
2684
2863
|
}
|
|
2685
2864
|
if (microserviceExists(name) && !options.force) {
|
|
2686
2865
|
const version = getMicroserviceVersion(name);
|
|
@@ -2701,9 +2880,6 @@ function installMicroservice(name, options = {}) {
|
|
|
2701
2880
|
function installMicroservices(names, options = {}) {
|
|
2702
2881
|
return names.map((name) => installMicroservice(name, options));
|
|
2703
2882
|
}
|
|
2704
|
-
function getInstalledMicroservices() {
|
|
2705
|
-
return MICROSERVICES.filter((m) => microserviceExists(m.name)).map((m) => m.name);
|
|
2706
|
-
}
|
|
2707
2883
|
function removeMicroservice(name) {
|
|
2708
2884
|
const meta = getMicroservice(name);
|
|
2709
2885
|
if (!meta)
|
|
@@ -2724,47 +2900,15 @@ function getMicroserviceStatus(name) {
|
|
|
2724
2900
|
};
|
|
2725
2901
|
}
|
|
2726
2902
|
|
|
2727
|
-
// src/lib/runner.ts
|
|
2728
|
-
import { execFile } from "child_process";
|
|
2729
|
-
async function runMicroserviceCommand(name, args, timeout = 30000) {
|
|
2730
|
-
const meta = getMicroservice(name);
|
|
2731
|
-
if (!meta) {
|
|
2732
|
-
return { success: false, stdout: "", stderr: `Unknown microservice '${name}'`, exitCode: 1 };
|
|
2733
|
-
}
|
|
2734
|
-
if (!microserviceExists(name)) {
|
|
2735
|
-
return {
|
|
2736
|
-
success: false,
|
|
2737
|
-
stdout: "",
|
|
2738
|
-
stderr: `microservice-${name} is not installed. Run: bun install -g ${meta.package}`,
|
|
2739
|
-
exitCode: 1
|
|
2740
|
-
};
|
|
2741
|
-
}
|
|
2742
|
-
return new Promise((resolve) => {
|
|
2743
|
-
execFile(meta.binary, args, { timeout, maxBuffer: 10 * 1024 * 1024 }, (error, stdout, stderr) => {
|
|
2744
|
-
if (error && "killed" in error && error.killed) {
|
|
2745
|
-
resolve({ success: false, stdout: "", stderr: "Command timed out", exitCode: 1 });
|
|
2746
|
-
return;
|
|
2747
|
-
}
|
|
2748
|
-
const exitCode = error?.code ? typeof error.code === "number" ? error.code : 1 : 0;
|
|
2749
|
-
resolve({
|
|
2750
|
-
success: exitCode === 0,
|
|
2751
|
-
stdout: (stdout || "").trim(),
|
|
2752
|
-
stderr: (stderr || "").trim(),
|
|
2753
|
-
exitCode
|
|
2754
|
-
});
|
|
2755
|
-
});
|
|
2756
|
-
});
|
|
2757
|
-
}
|
|
2758
|
-
|
|
2759
2903
|
// src/lib/package-info.ts
|
|
2760
2904
|
import { existsSync, readFileSync } from "fs";
|
|
2761
|
-
import { dirname, join, resolve } from "path";
|
|
2905
|
+
import { dirname, join as join2, resolve } from "path";
|
|
2762
2906
|
import { fileURLToPath } from "url";
|
|
2763
2907
|
var DEFAULT_VERSION = "0.0.1";
|
|
2764
2908
|
function findNearestPackageJson(startDir) {
|
|
2765
2909
|
let dir = resolve(startDir);
|
|
2766
2910
|
while (true) {
|
|
2767
|
-
const candidate =
|
|
2911
|
+
const candidate = join2(dir, "package.json");
|
|
2768
2912
|
if (existsSync(candidate)) {
|
|
2769
2913
|
return candidate;
|
|
2770
2914
|
}
|
|
@@ -2788,6 +2932,57 @@ function getPackageVersion(startDir) {
|
|
|
2788
2932
|
return readPackageVersion(packageJsonPath);
|
|
2789
2933
|
}
|
|
2790
2934
|
|
|
2935
|
+
// src/lib/runner.ts
|
|
2936
|
+
import { execFile } from "child_process";
|
|
2937
|
+
async function runMicroserviceCommand(name, args, timeout = 30000) {
|
|
2938
|
+
const meta = getMicroservice(name);
|
|
2939
|
+
if (!meta) {
|
|
2940
|
+
return {
|
|
2941
|
+
success: false,
|
|
2942
|
+
stdout: "",
|
|
2943
|
+
stderr: `Unknown microservice '${name}'`,
|
|
2944
|
+
exitCode: 1
|
|
2945
|
+
};
|
|
2946
|
+
}
|
|
2947
|
+
if (!microserviceExists(name)) {
|
|
2948
|
+
return {
|
|
2949
|
+
success: false,
|
|
2950
|
+
stdout: "",
|
|
2951
|
+
stderr: `${meta.binary} is not installed. Run: bun install -g ${meta.package}`,
|
|
2952
|
+
exitCode: 1
|
|
2953
|
+
};
|
|
2954
|
+
}
|
|
2955
|
+
const binaryPath = resolveMicroserviceBinary(name);
|
|
2956
|
+
if (!binaryPath) {
|
|
2957
|
+
return {
|
|
2958
|
+
success: false,
|
|
2959
|
+
stdout: "",
|
|
2960
|
+
stderr: `Could not resolve global binary for ${meta.binary}.`,
|
|
2961
|
+
exitCode: 1
|
|
2962
|
+
};
|
|
2963
|
+
}
|
|
2964
|
+
return new Promise((resolve2) => {
|
|
2965
|
+
execFile(binaryPath, args, { timeout, maxBuffer: 10 * 1024 * 1024 }, (error, stdout, stderr) => {
|
|
2966
|
+
if (error && "killed" in error && error.killed) {
|
|
2967
|
+
resolve2({
|
|
2968
|
+
success: false,
|
|
2969
|
+
stdout: "",
|
|
2970
|
+
stderr: "Command timed out",
|
|
2971
|
+
exitCode: 1
|
|
2972
|
+
});
|
|
2973
|
+
return;
|
|
2974
|
+
}
|
|
2975
|
+
const exitCode = error?.code ? typeof error.code === "number" ? error.code : 1 : 0;
|
|
2976
|
+
resolve2({
|
|
2977
|
+
success: exitCode === 0,
|
|
2978
|
+
stdout: (stdout || "").trim(),
|
|
2979
|
+
stderr: (stderr || "").trim(),
|
|
2980
|
+
exitCode
|
|
2981
|
+
});
|
|
2982
|
+
});
|
|
2983
|
+
});
|
|
2984
|
+
}
|
|
2985
|
+
|
|
2791
2986
|
// src/cli/index.tsx
|
|
2792
2987
|
var program2 = new Command;
|
|
2793
2988
|
program2.name("microservices").description("Production-grade microservice building blocks for SaaS apps").version(getPackageVersion());
|
|
@@ -2846,10 +3041,10 @@ Microservice status:
|
|
|
2846
3041
|
program2.command("run <name> [args...]").description("Run a command on an installed microservice").action(async (name, args) => {
|
|
2847
3042
|
const result = await runMicroserviceCommand(name, args);
|
|
2848
3043
|
if (result.stdout)
|
|
2849
|
-
process.stdout.write(result.stdout
|
|
3044
|
+
process.stdout.write(`${result.stdout}
|
|
2850
3045
|
`);
|
|
2851
3046
|
if (result.stderr)
|
|
2852
|
-
process.stderr.write(result.stderr
|
|
3047
|
+
process.stderr.write(`${result.stderr}
|
|
2853
3048
|
`);
|
|
2854
3049
|
process.exit(result.exitCode);
|
|
2855
3050
|
});
|
|
@@ -2863,25 +3058,130 @@ program2.command("search <query>").description("Search microservices by name or
|
|
|
2863
3058
|
console.log(` ${source_default.cyan(m.name.padEnd(20))} ${m.description}`);
|
|
2864
3059
|
}
|
|
2865
3060
|
});
|
|
2866
|
-
program2.command("migrate-all").description("Run migrations
|
|
3061
|
+
program2.command("migrate-all").description("Run database migrations for all installed microservices").option("--db <url>", "PostgreSQL connection URL (overrides DATABASE_URL)").action(async (opts) => {
|
|
3062
|
+
if (opts.db)
|
|
3063
|
+
process.env.DATABASE_URL = opts.db;
|
|
3064
|
+
const installed = MICROSERVICES.filter((m) => microserviceExists(m.name));
|
|
3065
|
+
if (installed.length === 0) {
|
|
3066
|
+
console.log(source_default.yellow("No microservices installed to migrate."));
|
|
3067
|
+
return;
|
|
3068
|
+
}
|
|
3069
|
+
console.log(source_default.bold(`
|
|
3070
|
+
Migrating ${installed.length} installed microservices...
|
|
3071
|
+
`));
|
|
3072
|
+
let hasErrors = false;
|
|
3073
|
+
for (const m of installed) {
|
|
3074
|
+
console.log(source_default.blue(`Migrating ${m.name}...`));
|
|
3075
|
+
const result = await runMicroserviceCommand(m.name, ["migrate"]);
|
|
3076
|
+
if (result.success) {
|
|
3077
|
+
console.log(` ${source_default.green("\u2713")} ${result.stdout.trim() || "Success"}`);
|
|
3078
|
+
} else {
|
|
3079
|
+
console.log(` ${source_default.red("\u2717")} ${result.stderr.trim() || result.stdout.trim() || "Failed"}`);
|
|
3080
|
+
hasErrors = true;
|
|
3081
|
+
}
|
|
3082
|
+
}
|
|
3083
|
+
console.log();
|
|
3084
|
+
if (hasErrors) {
|
|
3085
|
+
console.error(source_default.red("Some migrations failed. Please check the logs above."));
|
|
3086
|
+
process.exit(1);
|
|
3087
|
+
} else {
|
|
3088
|
+
console.log(source_default.green("\u2713 All migrations completed successfully."));
|
|
3089
|
+
}
|
|
3090
|
+
});
|
|
3091
|
+
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) => {
|
|
2867
3092
|
if (opts.db)
|
|
2868
|
-
process.env
|
|
2869
|
-
const installed =
|
|
3093
|
+
process.env.DATABASE_URL = opts.db;
|
|
3094
|
+
const installed = MICROSERVICES.filter((m) => microserviceExists(m.name));
|
|
2870
3095
|
if (installed.length === 0) {
|
|
2871
|
-
console.log(source_default.yellow("No microservices installed."));
|
|
3096
|
+
console.log(source_default.yellow("No microservices installed to serve."));
|
|
2872
3097
|
return;
|
|
2873
3098
|
}
|
|
2874
3099
|
console.log(source_default.bold(`
|
|
2875
|
-
|
|
3100
|
+
Starting ${installed.length} installed microservices...
|
|
2876
3101
|
`));
|
|
2877
|
-
|
|
2878
|
-
|
|
2879
|
-
|
|
2880
|
-
|
|
2881
|
-
|
|
2882
|
-
|
|
3102
|
+
const { spawn } = await import("child_process");
|
|
3103
|
+
const procs = [];
|
|
3104
|
+
const colors = [
|
|
3105
|
+
source_default.cyan,
|
|
3106
|
+
source_default.magenta,
|
|
3107
|
+
source_default.green,
|
|
3108
|
+
source_default.yellow,
|
|
3109
|
+
source_default.blue
|
|
3110
|
+
];
|
|
3111
|
+
for (let i = 0;i < installed.length; i++) {
|
|
3112
|
+
const m = installed[i];
|
|
3113
|
+
const color = colors[i % colors.length];
|
|
3114
|
+
const prefix = color(`[${m.name.padEnd(10)}] `);
|
|
3115
|
+
const proc = spawn(m.binary, ["serve"], {
|
|
3116
|
+
env: process.env,
|
|
3117
|
+
stdio: ["ignore", "pipe", "pipe"]
|
|
3118
|
+
});
|
|
3119
|
+
proc.stdout.on("data", (data) => {
|
|
3120
|
+
const lines = data.toString().trim().split(`
|
|
3121
|
+
`);
|
|
3122
|
+
for (const line of lines)
|
|
3123
|
+
if (line)
|
|
3124
|
+
console.log(`${prefix}${line}`);
|
|
3125
|
+
});
|
|
3126
|
+
proc.stderr.on("data", (data) => {
|
|
3127
|
+
const lines = data.toString().trim().split(`
|
|
3128
|
+
`);
|
|
3129
|
+
for (const line of lines)
|
|
3130
|
+
if (line)
|
|
3131
|
+
console.error(`${prefix}${source_default.red(line)}`);
|
|
3132
|
+
});
|
|
3133
|
+
proc.on("error", (err) => {
|
|
3134
|
+
console.error(`${prefix}${source_default.red("Failed to start:")} ${err.message}`);
|
|
3135
|
+
});
|
|
3136
|
+
procs.push(proc);
|
|
3137
|
+
}
|
|
3138
|
+
process.on("SIGINT", () => {
|
|
3139
|
+
console.log(source_default.yellow(`
|
|
3140
|
+
Stopping all microservices...`));
|
|
3141
|
+
for (const p of procs)
|
|
3142
|
+
p.kill("SIGINT");
|
|
3143
|
+
process.exit(0);
|
|
3144
|
+
});
|
|
3145
|
+
});
|
|
3146
|
+
program2.command("init-all").description("Run init (migrations) for all installed microservices").option("--db <url>", "PostgreSQL connection URL").action(async (opts) => {
|
|
3147
|
+
const installed = MICROSERVICES.filter((m) => microserviceExists(m.name));
|
|
3148
|
+
if (installed.length === 0) {
|
|
3149
|
+
console.log(source_default.yellow("No microservices installed to init."));
|
|
3150
|
+
return;
|
|
3151
|
+
}
|
|
3152
|
+
if (!opts.db) {
|
|
3153
|
+
console.error(source_default.red("--db <url> is required. Example: microservices init-all --db postgres://localhost/myapp"));
|
|
3154
|
+
process.exit(1);
|
|
3155
|
+
}
|
|
3156
|
+
process.env.DATABASE_URL = opts.db;
|
|
3157
|
+
console.log(source_default.bold(`
|
|
3158
|
+
Initializing ${installed.length} installed microservices...
|
|
3159
|
+
`));
|
|
3160
|
+
let hasErrors = false;
|
|
3161
|
+
for (const m of installed) {
|
|
3162
|
+
console.log(source_default.blue(`Initializing ${m.name}...`));
|
|
3163
|
+
const result = await runMicroserviceCommand(m.name, [
|
|
3164
|
+
"init",
|
|
3165
|
+
"--db",
|
|
3166
|
+
opts.db
|
|
3167
|
+
]);
|
|
3168
|
+
if (result.success) {
|
|
3169
|
+
console.log(` ${source_default.green("\u2713")} ${result.stdout.trim().split(`
|
|
3170
|
+
`).join(`
|
|
3171
|
+
`) || "Success"}`);
|
|
3172
|
+
} else {
|
|
3173
|
+
console.log(` ${source_default.red("\u2717")} ${result.stderr.trim() || result.stdout.trim() || "Failed"}`);
|
|
3174
|
+
hasErrors = true;
|
|
3175
|
+
}
|
|
2883
3176
|
}
|
|
2884
3177
|
console.log();
|
|
3178
|
+
if (hasErrors) {
|
|
3179
|
+
console.error(source_default.red("Some inits failed. Please check the logs above."));
|
|
3180
|
+
process.exit(1);
|
|
3181
|
+
} else {
|
|
3182
|
+
console.log(source_default.green("\u2713 All services initialized successfully."));
|
|
3183
|
+
console.log(source_default.gray(" You can now run 'microservices serve-all' to start them."));
|
|
3184
|
+
}
|
|
2885
3185
|
});
|
|
2886
3186
|
program2.command("info <name>").description("Show detailed info about a microservice").action((name) => {
|
|
2887
3187
|
const m = getMicroservice(name);
|
|
@@ -2904,4 +3204,89 @@ ${m.displayName}`));
|
|
|
2904
3204
|
console.log(` Tags: ${m.tags.join(", ")}`);
|
|
2905
3205
|
console.log();
|
|
2906
3206
|
});
|
|
3207
|
+
program2.command("check-env").description("Verify environment variables for all installed microservices").action(() => {
|
|
3208
|
+
const installed = MICROSERVICES.filter((m) => microserviceExists(m.name));
|
|
3209
|
+
if (installed.length === 0) {
|
|
3210
|
+
console.log(source_default.yellow("No microservices installed to check."));
|
|
3211
|
+
return;
|
|
3212
|
+
}
|
|
3213
|
+
console.log(source_default.bold(`
|
|
3214
|
+
Checking environment for ${installed.length} microservices...
|
|
3215
|
+
`));
|
|
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;
|
|
3225
|
+
}
|
|
3226
|
+
if (missingOptional.length > 0) {
|
|
3227
|
+
console.log(source_default.gray(` Optional missing: ${missingOptional.join(", ")}`));
|
|
3228
|
+
}
|
|
3229
|
+
if (missingRequired.length === 0 && missingOptional.length === 0) {
|
|
3230
|
+
console.log(source_default.gray(" All variables set."));
|
|
3231
|
+
}
|
|
3232
|
+
console.log();
|
|
3233
|
+
}
|
|
3234
|
+
if (totalMissing > 0) {
|
|
3235
|
+
console.log(source_default.red(`Found ${totalMissing} missing required environment variables.`));
|
|
3236
|
+
console.log(source_default.gray(`Refer to .env.example for guidance.
|
|
3237
|
+
`));
|
|
3238
|
+
process.exit(1);
|
|
3239
|
+
} else {
|
|
3240
|
+
console.log(source_default.green(`\u2713 All required environment variables are set across all installed services.
|
|
3241
|
+
`));
|
|
3242
|
+
}
|
|
3243
|
+
});
|
|
3244
|
+
program2.command("scaffold <name>").description("Scaffold a new microservice from the _template directory").action((name) => {
|
|
3245
|
+
if (!/^[a-z0-9-]+$/.test(name)) {
|
|
3246
|
+
console.error(source_default.red("Error: Name can only contain lowercase letters, numbers, and dashes."));
|
|
3247
|
+
process.exit(1);
|
|
3248
|
+
}
|
|
3249
|
+
const cwd = process.cwd();
|
|
3250
|
+
const templateDir = path.join(cwd, "microservices", "_template");
|
|
3251
|
+
const targetDir = path.join(cwd, "microservices", `microservice-${name}`);
|
|
3252
|
+
if (!fs.existsSync(templateDir)) {
|
|
3253
|
+
console.error(source_default.red(`Template directory not found at ${templateDir}. Make sure you are running this from the monorepo root.`));
|
|
3254
|
+
process.exit(1);
|
|
3255
|
+
}
|
|
3256
|
+
if (fs.existsSync(targetDir)) {
|
|
3257
|
+
console.error(source_default.red(`Target directory already exists at ${targetDir}`));
|
|
3258
|
+
process.exit(1);
|
|
3259
|
+
}
|
|
3260
|
+
console.log(source_default.bold(`
|
|
3261
|
+
Scaffolding microservice-${name}...
|
|
3262
|
+
`));
|
|
3263
|
+
fs.cpSync(templateDir, targetDir, { recursive: true });
|
|
3264
|
+
const replaceInFile = (filePath) => {
|
|
3265
|
+
const content = fs.readFileSync(filePath, "utf-8");
|
|
3266
|
+
let updated = content.replace(/__NAME__/g, name.toUpperCase().replace(/-/g, "_"));
|
|
3267
|
+
updated = updated.replace(/__Name__/g, name.charAt(0).toUpperCase() + name.slice(1));
|
|
3268
|
+
updated = updated.replace(/__name__/g, name);
|
|
3269
|
+
fs.writeFileSync(filePath, updated, "utf-8");
|
|
3270
|
+
};
|
|
3271
|
+
const walkAndReplace = (dir) => {
|
|
3272
|
+
const files = fs.readdirSync(dir);
|
|
3273
|
+
for (const file of files) {
|
|
3274
|
+
const filePath = path.join(dir, file);
|
|
3275
|
+
if (fs.statSync(filePath).isDirectory()) {
|
|
3276
|
+
walkAndReplace(filePath);
|
|
3277
|
+
} else {
|
|
3278
|
+
replaceInFile(filePath);
|
|
3279
|
+
}
|
|
3280
|
+
}
|
|
3281
|
+
};
|
|
3282
|
+
walkAndReplace(targetDir);
|
|
3283
|
+
console.log(` ${source_default.green("\u2713")} Created microservices/microservice-${name}`);
|
|
3284
|
+
console.log(source_default.gray(`
|
|
3285
|
+
Next steps:
|
|
3286
|
+
1. Add entry to src/lib/registry.ts
|
|
3287
|
+
2. Implement schema, core logic, HTTP API, MCP, and CLI
|
|
3288
|
+
3. Run 'bun install' to link the workspace
|
|
3289
|
+
4. Run 'bun run build'
|
|
3290
|
+
`));
|
|
3291
|
+
});
|
|
2907
3292
|
program2.parse();
|