@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/dist/index.js CHANGED
@@ -1,4 +1,9 @@
1
1
  // @bun
2
+ // src/lib/installer.ts
3
+ import { execFileSync, execSync } from "child_process";
4
+ import { accessSync, constants } from "fs";
5
+ import { join } from "path";
6
+
2
7
  // src/lib/registry.ts
3
8
  var CATEGORIES = [
4
9
  "Identity",
@@ -20,9 +25,24 @@ var MICROSERVICES = [
20
25
  package: "@hasna/microservice-auth",
21
26
  binary: "microservice-auth",
22
27
  schemaPrefix: "auth",
23
- tags: ["auth", "users", "sessions", "jwt", "oauth", "2fa", "api-keys", "magic-links"],
28
+ tags: [
29
+ "auth",
30
+ "users",
31
+ "sessions",
32
+ "jwt",
33
+ "oauth",
34
+ "2fa",
35
+ "api-keys",
36
+ "magic-links"
37
+ ],
24
38
  requiredEnv: ["DATABASE_URL", "JWT_SECRET"],
25
- optionalEnv: ["GITHUB_CLIENT_ID", "GITHUB_CLIENT_SECRET", "GOOGLE_CLIENT_ID", "GOOGLE_CLIENT_SECRET", "AUTH_PORT"]
39
+ optionalEnv: [
40
+ "GITHUB_CLIENT_ID",
41
+ "GITHUB_CLIENT_SECRET",
42
+ "GOOGLE_CLIENT_ID",
43
+ "GOOGLE_CLIENT_SECRET",
44
+ "AUTH_PORT"
45
+ ]
26
46
  },
27
47
  {
28
48
  name: "teams",
@@ -32,7 +52,14 @@ var MICROSERVICES = [
32
52
  package: "@hasna/microservice-teams",
33
53
  binary: "microservice-teams",
34
54
  schemaPrefix: "teams",
35
- tags: ["teams", "workspaces", "rbac", "invites", "permissions", "multi-tenancy"],
55
+ tags: [
56
+ "teams",
57
+ "workspaces",
58
+ "rbac",
59
+ "invites",
60
+ "permissions",
61
+ "multi-tenancy"
62
+ ],
36
63
  requiredEnv: ["DATABASE_URL"],
37
64
  optionalEnv: ["TEAMS_PORT"]
38
65
  },
@@ -44,7 +71,15 @@ var MICROSERVICES = [
44
71
  package: "@hasna/microservice-billing",
45
72
  binary: "microservice-billing",
46
73
  schemaPrefix: "billing",
47
- tags: ["billing", "stripe", "subscriptions", "plans", "invoices", "usage", "webhooks"],
74
+ tags: [
75
+ "billing",
76
+ "stripe",
77
+ "subscriptions",
78
+ "plans",
79
+ "invoices",
80
+ "usage",
81
+ "webhooks"
82
+ ],
48
83
  requiredEnv: ["DATABASE_URL", "STRIPE_SECRET_KEY", "STRIPE_WEBHOOK_SECRET"],
49
84
  optionalEnv: ["BILLING_PORT"]
50
85
  },
@@ -56,9 +91,26 @@ var MICROSERVICES = [
56
91
  package: "@hasna/microservice-notify",
57
92
  binary: "microservice-notify",
58
93
  schemaPrefix: "notify",
59
- tags: ["notifications", "email", "sms", "in-app", "webhooks", "templates", "sse"],
94
+ tags: [
95
+ "notifications",
96
+ "email",
97
+ "sms",
98
+ "in-app",
99
+ "webhooks",
100
+ "templates",
101
+ "sse"
102
+ ],
60
103
  requiredEnv: ["DATABASE_URL"],
61
- optionalEnv: ["RESEND_API_KEY", "SMTP_HOST", "SMTP_PORT", "SMTP_USER", "SMTP_PASS", "TWILIO_ACCOUNT_SID", "TWILIO_AUTH_TOKEN", "NOTIFY_PORT"]
104
+ optionalEnv: [
105
+ "RESEND_API_KEY",
106
+ "SMTP_HOST",
107
+ "SMTP_PORT",
108
+ "SMTP_USER",
109
+ "SMTP_PASS",
110
+ "TWILIO_ACCOUNT_SID",
111
+ "TWILIO_AUTH_TOKEN",
112
+ "NOTIFY_PORT"
113
+ ]
62
114
  },
63
115
  {
64
116
  name: "files",
@@ -68,9 +120,24 @@ var MICROSERVICES = [
68
120
  package: "@hasna/microservice-files",
69
121
  binary: "microservice-files",
70
122
  schemaPrefix: "files",
71
- tags: ["files", "uploads", "s3", "storage", "images", "presigned-urls", "cdn"],
123
+ tags: [
124
+ "files",
125
+ "uploads",
126
+ "s3",
127
+ "storage",
128
+ "images",
129
+ "presigned-urls",
130
+ "cdn"
131
+ ],
72
132
  requiredEnv: ["DATABASE_URL"],
73
- optionalEnv: ["S3_BUCKET", "S3_REGION", "AWS_ACCESS_KEY_ID", "AWS_SECRET_ACCESS_KEY", "FILES_STORAGE", "FILES_PORT"]
133
+ optionalEnv: [
134
+ "S3_BUCKET",
135
+ "S3_REGION",
136
+ "AWS_ACCESS_KEY_ID",
137
+ "AWS_SECRET_ACCESS_KEY",
138
+ "FILES_STORAGE",
139
+ "FILES_PORT"
140
+ ]
74
141
  },
75
142
  {
76
143
  name: "audit",
@@ -92,7 +159,13 @@ var MICROSERVICES = [
92
159
  package: "@hasna/microservice-flags",
93
160
  binary: "microservice-flags",
94
161
  schemaPrefix: "flags",
95
- tags: ["feature-flags", "experiments", "rollouts", "ab-testing", "targeting"],
162
+ tags: [
163
+ "feature-flags",
164
+ "experiments",
165
+ "rollouts",
166
+ "ab-testing",
167
+ "targeting"
168
+ ],
96
169
  requiredEnv: ["DATABASE_URL"],
97
170
  optionalEnv: ["FLAGS_PORT"]
98
171
  },
@@ -104,7 +177,15 @@ var MICROSERVICES = [
104
177
  package: "@hasna/microservice-jobs",
105
178
  binary: "microservice-jobs",
106
179
  schemaPrefix: "jobs",
107
- tags: ["jobs", "queues", "background", "cron", "scheduling", "workers", "retry"],
180
+ tags: [
181
+ "jobs",
182
+ "queues",
183
+ "background",
184
+ "cron",
185
+ "scheduling",
186
+ "workers",
187
+ "retry"
188
+ ],
108
189
  requiredEnv: ["DATABASE_URL"],
109
190
  optionalEnv: ["JOBS_PORT", "JOBS_WORKER_CONCURRENCY"]
110
191
  },
@@ -116,9 +197,23 @@ var MICROSERVICES = [
116
197
  package: "@hasna/microservice-llm",
117
198
  binary: "microservice-llm",
118
199
  schemaPrefix: "llm",
119
- tags: ["llm", "openai", "anthropic", "groq", "ai", "gateway", "cost-tracking", "rate-limiting"],
200
+ tags: [
201
+ "llm",
202
+ "openai",
203
+ "anthropic",
204
+ "groq",
205
+ "ai",
206
+ "gateway",
207
+ "cost-tracking",
208
+ "rate-limiting"
209
+ ],
120
210
  requiredEnv: ["DATABASE_URL"],
121
- optionalEnv: ["OPENAI_API_KEY", "ANTHROPIC_API_KEY", "GROQ_API_KEY", "LLM_PORT"]
211
+ optionalEnv: [
212
+ "OPENAI_API_KEY",
213
+ "ANTHROPIC_API_KEY",
214
+ "GROQ_API_KEY",
215
+ "LLM_PORT"
216
+ ]
122
217
  },
123
218
  {
124
219
  name: "memory",
@@ -128,7 +223,15 @@ var MICROSERVICES = [
128
223
  package: "@hasna/microservice-memory",
129
224
  binary: "microservice-memory",
130
225
  schemaPrefix: "memory",
131
- tags: ["memory", "embeddings", "pgvector", "semantic-search", "rag", "ai-agents", "recall"],
226
+ tags: [
227
+ "memory",
228
+ "embeddings",
229
+ "pgvector",
230
+ "semantic-search",
231
+ "rag",
232
+ "ai-agents",
233
+ "recall"
234
+ ],
132
235
  requiredEnv: ["DATABASE_URL"],
133
236
  optionalEnv: ["OPENAI_API_KEY", "MEMORY_PORT"]
134
237
  },
@@ -140,7 +243,15 @@ var MICROSERVICES = [
140
243
  package: "@hasna/microservice-search",
141
244
  binary: "microservice-search",
142
245
  schemaPrefix: "search",
143
- tags: ["search", "full-text", "semantic", "vector", "pgvector", "hybrid", "rag"],
246
+ tags: [
247
+ "search",
248
+ "full-text",
249
+ "semantic",
250
+ "vector",
251
+ "pgvector",
252
+ "hybrid",
253
+ "rag"
254
+ ],
144
255
  requiredEnv: ["DATABASE_URL"],
145
256
  optionalEnv: ["OPENAI_API_KEY", "SEARCH_PORT"]
146
257
  },
@@ -152,7 +263,15 @@ var MICROSERVICES = [
152
263
  package: "@hasna/microservice-knowledge",
153
264
  binary: "microservice-knowledge",
154
265
  schemaPrefix: "knowledge",
155
- tags: ["knowledge", "rag", "chunking", "embeddings", "retrieval", "pgvector", "documents"],
266
+ tags: [
267
+ "knowledge",
268
+ "rag",
269
+ "chunking",
270
+ "embeddings",
271
+ "retrieval",
272
+ "pgvector",
273
+ "documents"
274
+ ],
156
275
  requiredEnv: ["DATABASE_URL"],
157
276
  optionalEnv: ["OPENAI_API_KEY", "KNOWLEDGE_PORT"]
158
277
  },
@@ -176,7 +295,14 @@ var MICROSERVICES = [
176
295
  package: "@hasna/microservice-webhooks",
177
296
  binary: "microservice-webhooks",
178
297
  schemaPrefix: "webhooks",
179
- tags: ["webhooks", "outbound", "delivery", "retry", "signing", "integrations"],
298
+ tags: [
299
+ "webhooks",
300
+ "outbound",
301
+ "delivery",
302
+ "retry",
303
+ "signing",
304
+ "integrations"
305
+ ],
180
306
  requiredEnv: ["DATABASE_URL"],
181
307
  optionalEnv: ["WEBHOOKS_PORT"]
182
308
  },
@@ -212,7 +338,14 @@ var MICROSERVICES = [
212
338
  package: "@hasna/microservice-sessions",
213
339
  binary: "microservice-sessions",
214
340
  schemaPrefix: "sessions",
215
- tags: ["sessions", "conversations", "chat", "messages", "context-window", "history"],
341
+ tags: [
342
+ "sessions",
343
+ "conversations",
344
+ "chat",
345
+ "messages",
346
+ "context-window",
347
+ "history"
348
+ ],
216
349
  requiredEnv: ["DATABASE_URL"],
217
350
  optionalEnv: ["SESSIONS_PORT"]
218
351
  },
@@ -224,22 +357,18 @@ var MICROSERVICES = [
224
357
  package: "@hasna/microservice-guardrails",
225
358
  binary: "microservice-guardrails",
226
359
  schemaPrefix: "guardrails",
227
- tags: ["guardrails", "safety", "pii", "injection", "toxicity", "moderation", "policy"],
360
+ tags: [
361
+ "guardrails",
362
+ "safety",
363
+ "pii",
364
+ "injection",
365
+ "toxicity",
366
+ "moderation",
367
+ "policy"
368
+ ],
228
369
  requiredEnv: ["DATABASE_URL"],
229
370
  optionalEnv: ["GUARDRAILS_PORT"]
230
371
  },
231
- {
232
- name: "knowledge",
233
- displayName: "Knowledge",
234
- description: "RAG pipeline: document ingestion, chunking (fixed/paragraph/sentence/recursive), embedding via pgvector, retrieval with source attribution and scoring.",
235
- category: "AI",
236
- package: "@hasna/microservice-knowledge",
237
- binary: "microservice-knowledge",
238
- schemaPrefix: "knowledge",
239
- tags: ["knowledge", "rag", "chunking", "ingestion", "retrieval", "documents", "pgvector"],
240
- requiredEnv: ["DATABASE_URL"],
241
- optionalEnv: ["OPENAI_API_KEY", "KNOWLEDGE_PORT"]
242
- },
243
372
  {
244
373
  name: "traces",
245
374
  displayName: "Traces",
@@ -248,7 +377,15 @@ var MICROSERVICES = [
248
377
  package: "@hasna/microservice-traces",
249
378
  binary: "microservice-traces",
250
379
  schemaPrefix: "traces",
251
- tags: ["traces", "tracing", "spans", "observability", "latency", "debugging", "agent-ops"],
380
+ tags: [
381
+ "traces",
382
+ "tracing",
383
+ "spans",
384
+ "observability",
385
+ "latency",
386
+ "debugging",
387
+ "agent-ops"
388
+ ],
252
389
  requiredEnv: ["DATABASE_URL"],
253
390
  optionalEnv: ["TRACES_PORT"]
254
391
  },
@@ -260,7 +397,15 @@ var MICROSERVICES = [
260
397
  package: "@hasna/microservice-agents",
261
398
  binary: "microservice-agents",
262
399
  schemaPrefix: "agents",
263
- tags: ["agents", "registry", "orchestration", "routing", "multi-agent", "capabilities", "heartbeat"],
400
+ tags: [
401
+ "agents",
402
+ "registry",
403
+ "orchestration",
404
+ "routing",
405
+ "multi-agent",
406
+ "capabilities",
407
+ "heartbeat"
408
+ ],
264
409
  requiredEnv: ["DATABASE_URL"],
265
410
  optionalEnv: ["AGENTS_PORT"]
266
411
  },
@@ -272,7 +417,14 @@ var MICROSERVICES = [
272
417
  package: "@hasna/microservice-prompts",
273
418
  binary: "microservice-prompts",
274
419
  schemaPrefix: "prompts",
275
- tags: ["prompts", "templates", "versioning", "ab-testing", "overrides", "rollback"],
420
+ tags: [
421
+ "prompts",
422
+ "templates",
423
+ "versioning",
424
+ "ab-testing",
425
+ "overrides",
426
+ "rollback"
427
+ ],
276
428
  requiredEnv: ["DATABASE_URL"],
277
429
  optionalEnv: ["PROMPTS_PORT"]
278
430
  }
@@ -288,25 +440,45 @@ function searchMicroservices(query) {
288
440
  const q = query.toLowerCase();
289
441
  return MICROSERVICES.filter((m) => m.name.includes(q) || m.displayName.toLowerCase().includes(q) || m.description.toLowerCase().includes(q) || m.category.toLowerCase().includes(q) || m.tags.some((t) => t.includes(q)));
290
442
  }
443
+
291
444
  // src/lib/installer.ts
292
- import { execSync, execFileSync } from "child_process";
293
- function microserviceExists(name) {
445
+ function getBunGlobalBinDir(env = process.env) {
446
+ const bunInstall = env.BUN_INSTALL?.trim();
447
+ if (bunInstall) {
448
+ return join(bunInstall, "bin");
449
+ }
450
+ const home = env.HOME?.trim();
451
+ if (!home) {
452
+ throw new Error("Unable to determine Bun global bin path: HOME is not set.");
453
+ }
454
+ return join(home, ".bun", "bin");
455
+ }
456
+ function resolveMicroserviceBinary(name) {
294
457
  const meta = getMicroservice(name);
295
458
  if (!meta)
296
- return false;
297
- try {
298
- execSync(`which ${meta.binary}`, { stdio: "ignore" });
299
- return true;
300
- } catch {
301
- return false;
459
+ return null;
460
+ const binDir = getBunGlobalBinDir();
461
+ const accessMode = process.platform === "win32" ? constants.F_OK : constants.X_OK;
462
+ const candidates = process.platform === "win32" ? [join(binDir, `${meta.binary}.cmd`), join(binDir, `${meta.binary}.exe`)] : [join(binDir, meta.binary)];
463
+ for (const candidate of candidates) {
464
+ try {
465
+ accessSync(candidate, accessMode);
466
+ return candidate;
467
+ } catch {}
302
468
  }
469
+ return null;
470
+ }
471
+ function microserviceExists(name) {
472
+ return resolveMicroserviceBinary(name) !== null;
303
473
  }
304
474
  function getMicroserviceVersion(name) {
305
- const meta = getMicroservice(name);
306
- if (!meta)
475
+ const binaryPath = resolveMicroserviceBinary(name);
476
+ if (!binaryPath)
307
477
  return null;
308
478
  try {
309
- const out = execFileSync(meta.binary, ["--version"], { encoding: "utf8" }).trim();
479
+ const out = execFileSync(binaryPath, ["--version"], {
480
+ encoding: "utf8"
481
+ }).trim();
310
482
  return out || null;
311
483
  } catch {
312
484
  return null;
@@ -315,7 +487,11 @@ function getMicroserviceVersion(name) {
315
487
  function installMicroservice(name, options = {}) {
316
488
  const meta = getMicroservice(name);
317
489
  if (!meta) {
318
- return { microservice: name, success: false, error: `Unknown microservice '${name}'` };
490
+ return {
491
+ microservice: name,
492
+ success: false,
493
+ error: `Unknown microservice '${name}'`
494
+ };
319
495
  }
320
496
  if (microserviceExists(name) && !options.force) {
321
497
  const version = getMicroserviceVersion(name);
@@ -363,20 +539,39 @@ import { execFile } from "child_process";
363
539
  async function runMicroserviceCommand(name, args, timeout = 30000) {
364
540
  const meta = getMicroservice(name);
365
541
  if (!meta) {
366
- return { success: false, stdout: "", stderr: `Unknown microservice '${name}'`, exitCode: 1 };
542
+ return {
543
+ success: false,
544
+ stdout: "",
545
+ stderr: `Unknown microservice '${name}'`,
546
+ exitCode: 1
547
+ };
367
548
  }
368
549
  if (!microserviceExists(name)) {
369
550
  return {
370
551
  success: false,
371
552
  stdout: "",
372
- stderr: `microservice-${name} is not installed. Run: bun install -g ${meta.package}`,
553
+ stderr: `${meta.binary} is not installed. Run: bun install -g ${meta.package}`,
554
+ exitCode: 1
555
+ };
556
+ }
557
+ const binaryPath = resolveMicroserviceBinary(name);
558
+ if (!binaryPath) {
559
+ return {
560
+ success: false,
561
+ stdout: "",
562
+ stderr: `Could not resolve global binary for ${meta.binary}.`,
373
563
  exitCode: 1
374
564
  };
375
565
  }
376
566
  return new Promise((resolve) => {
377
- execFile(meta.binary, args, { timeout, maxBuffer: 10 * 1024 * 1024 }, (error, stdout, stderr) => {
567
+ execFile(binaryPath, args, { timeout, maxBuffer: 10 * 1024 * 1024 }, (error, stdout, stderr) => {
378
568
  if (error && "killed" in error && error.killed) {
379
- resolve({ success: false, stdout: "", stderr: "Command timed out", exitCode: 1 });
569
+ resolve({
570
+ success: false,
571
+ stdout: "",
572
+ stderr: "Command timed out",
573
+ exitCode: 1
574
+ });
380
575
  return;
381
576
  }
382
577
  const exitCode = error?.code ? typeof error.code === "number" ? error.code : 1 : 0;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hasna/microservices",
3
- "version": "0.0.19",
3
+ "version": "0.0.21",
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": {
@@ -23,10 +23,18 @@
23
23
  "types": "./dist/index.d.ts",
24
24
  "scripts": {
25
25
  "build": "bun build ./src/cli/index.tsx --outfile ./bin/index.js --target bun && bun build ./src/mcp/index.ts --outfile ./bin/mcp.js --target bun && bun build ./src/index.ts --outdir ./dist --target bun",
26
+ "build:all": "bun run build && bun run --filter '*' build",
26
27
  "dev": "bun run ./src/cli/index.tsx",
28
+ "gateway": "bun run gateway.ts",
27
29
  "typecheck": "tsc --noEmit",
30
+ "typecheck:all": "bun run typecheck && bun run --filter '*' typecheck",
28
31
  "test": "bun test",
29
- "prepublishOnly": "bun run build",
32
+ "test:all": "bun test && bun run --filter '*' test",
33
+ "lint": "bunx biome check .",
34
+ "format": "bunx biome format --write .",
35
+ "clean": "rm -rf dist bin microservices/*/dist microservices/*/bin node_modules microservices/*/node_modules",
36
+ "pre-commit": "bun run lint && bun run format",
37
+ "prepublishOnly": "bun run build:all",
30
38
  "postinstall": "true"
31
39
  },
32
40
  "keywords": [
@@ -50,6 +58,7 @@
50
58
  "author": "Hasna",
51
59
  "license": "Apache-2.0",
52
60
  "devDependencies": {
61
+ "@biomejs/biome": "^2.4.10",
53
62
  "@types/bun": "latest",
54
63
  "typescript": "^5"
55
64
  },
@@ -85,6 +94,9 @@
85
94
  "engines": {
86
95
  "bun": ">=1.0.0"
87
96
  },
97
+ "workspaces": [
98
+ "microservices/*"
99
+ ],
88
100
  "publishConfig": {
89
101
  "registry": "https://registry.npmjs.org",
90
102
  "access": "public"