@hasna/microservices 0.0.4 → 0.0.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (38) hide show
  1. package/microservices/microservice-ads/src/cli/index.ts +198 -0
  2. package/microservices/microservice-ads/src/db/campaigns.ts +304 -0
  3. package/microservices/microservice-ads/src/mcp/index.ts +160 -0
  4. package/microservices/microservice-contracts/src/cli/index.ts +410 -23
  5. package/microservices/microservice-contracts/src/db/contracts.ts +430 -1
  6. package/microservices/microservice-contracts/src/db/migrations.ts +83 -0
  7. package/microservices/microservice-contracts/src/mcp/index.ts +312 -3
  8. package/microservices/microservice-domains/src/cli/index.ts +253 -0
  9. package/microservices/microservice-domains/src/db/domains.ts +613 -0
  10. package/microservices/microservice-domains/src/index.ts +21 -0
  11. package/microservices/microservice-domains/src/mcp/index.ts +168 -0
  12. package/microservices/microservice-hiring/src/cli/index.ts +318 -8
  13. package/microservices/microservice-hiring/src/db/hiring.ts +503 -0
  14. package/microservices/microservice-hiring/src/db/migrations.ts +21 -0
  15. package/microservices/microservice-hiring/src/index.ts +29 -0
  16. package/microservices/microservice-hiring/src/lib/scoring.ts +206 -0
  17. package/microservices/microservice-hiring/src/mcp/index.ts +245 -0
  18. package/microservices/microservice-payments/src/cli/index.ts +255 -3
  19. package/microservices/microservice-payments/src/db/migrations.ts +18 -0
  20. package/microservices/microservice-payments/src/db/payments.ts +552 -0
  21. package/microservices/microservice-payments/src/mcp/index.ts +223 -0
  22. package/microservices/microservice-payroll/src/cli/index.ts +269 -0
  23. package/microservices/microservice-payroll/src/db/migrations.ts +26 -0
  24. package/microservices/microservice-payroll/src/db/payroll.ts +636 -0
  25. package/microservices/microservice-payroll/src/mcp/index.ts +246 -0
  26. package/microservices/microservice-shipping/src/cli/index.ts +211 -3
  27. package/microservices/microservice-shipping/src/db/migrations.ts +8 -0
  28. package/microservices/microservice-shipping/src/db/shipping.ts +453 -3
  29. package/microservices/microservice-shipping/src/mcp/index.ts +149 -1
  30. package/microservices/microservice-social/src/cli/index.ts +244 -2
  31. package/microservices/microservice-social/src/db/migrations.ts +33 -0
  32. package/microservices/microservice-social/src/db/social.ts +378 -4
  33. package/microservices/microservice-social/src/mcp/index.ts +221 -1
  34. package/microservices/microservice-subscriptions/src/cli/index.ts +315 -0
  35. package/microservices/microservice-subscriptions/src/db/migrations.ts +68 -0
  36. package/microservices/microservice-subscriptions/src/db/subscriptions.ts +567 -3
  37. package/microservices/microservice-subscriptions/src/mcp/index.ts +267 -1
  38. package/package.json +1 -1
@@ -21,6 +21,19 @@ import {
21
21
  getChurnRate,
22
22
  listExpiring,
23
23
  getSubscriberStats,
24
+ pauseSubscriber,
25
+ resumeSubscriber,
26
+ extendTrial,
27
+ createDunning,
28
+ listDunning,
29
+ updateDunning,
30
+ bulkImportSubscribers,
31
+ exportSubscribers,
32
+ getLtv,
33
+ getNrr,
34
+ getCohortReport,
35
+ comparePlans,
36
+ getExpiringRenewals,
24
37
  } from "../db/subscriptions.js";
25
38
 
26
39
  const server = new McpServer({
@@ -133,7 +146,7 @@ server.registerTool(
133
146
  plan_id: z.string(),
134
147
  customer_name: z.string(),
135
148
  customer_email: z.string(),
136
- status: z.enum(["trialing", "active", "past_due", "canceled", "expired"]).optional(),
149
+ status: z.enum(["trialing", "active", "past_due", "canceled", "expired", "paused"]).optional(),
137
150
  trial_ends_at: z.string().optional(),
138
151
  metadata: z.record(z.unknown()).optional(),
139
152
  },
@@ -352,6 +365,259 @@ server.registerTool(
352
365
  }
353
366
  );
354
367
 
368
+ // --- Pause/Resume ---
369
+
370
+ server.registerTool(
371
+ "pause_subscriber",
372
+ {
373
+ title: "Pause Subscriber",
374
+ description: "Pause a subscription. Paused subscribers are excluded from MRR.",
375
+ inputSchema: {
376
+ id: z.string(),
377
+ resume_date: z.string().optional().describe("Optional scheduled resume date (YYYY-MM-DD HH:MM:SS)"),
378
+ },
379
+ },
380
+ async ({ id, resume_date }) => {
381
+ const subscriber = pauseSubscriber(id, resume_date);
382
+ if (!subscriber) {
383
+ return { content: [{ type: "text", text: `Subscriber '${id}' not found or cannot be paused.` }], isError: true };
384
+ }
385
+ return { content: [{ type: "text", text: JSON.stringify(subscriber, null, 2) }] };
386
+ }
387
+ );
388
+
389
+ server.registerTool(
390
+ "resume_subscriber",
391
+ {
392
+ title: "Resume Subscriber",
393
+ description: "Resume a paused subscription.",
394
+ inputSchema: { id: z.string() },
395
+ },
396
+ async ({ id }) => {
397
+ const subscriber = resumeSubscriber(id);
398
+ if (!subscriber) {
399
+ return { content: [{ type: "text", text: `Subscriber '${id}' not found or not paused.` }], isError: true };
400
+ }
401
+ return { content: [{ type: "text", text: JSON.stringify(subscriber, null, 2) }] };
402
+ }
403
+ );
404
+
405
+ // --- Trial Extension ---
406
+
407
+ server.registerTool(
408
+ "extend_trial",
409
+ {
410
+ title: "Extend Trial",
411
+ description: "Extend a subscriber's trial period by a number of days.",
412
+ inputSchema: {
413
+ id: z.string(),
414
+ days: z.number().describe("Number of days to extend the trial"),
415
+ },
416
+ },
417
+ async ({ id, days }) => {
418
+ const subscriber = extendTrial(id, days);
419
+ if (!subscriber) {
420
+ return { content: [{ type: "text", text: `Subscriber '${id}' not found.` }], isError: true };
421
+ }
422
+ return { content: [{ type: "text", text: JSON.stringify(subscriber, null, 2) }] };
423
+ }
424
+ );
425
+
426
+ // --- Bulk Import/Export ---
427
+
428
+ server.registerTool(
429
+ "bulk_import_subscribers",
430
+ {
431
+ title: "Bulk Import Subscribers",
432
+ description: "Bulk import multiple subscribers at once.",
433
+ inputSchema: {
434
+ subscribers: z.array(z.object({
435
+ plan_id: z.string(),
436
+ customer_name: z.string(),
437
+ customer_email: z.string(),
438
+ status: z.enum(["trialing", "active", "past_due", "canceled", "expired", "paused"]).optional(),
439
+ trial_ends_at: z.string().optional(),
440
+ current_period_end: z.string().optional(),
441
+ })),
442
+ },
443
+ },
444
+ async ({ subscribers }) => {
445
+ const imported = bulkImportSubscribers(subscribers);
446
+ return {
447
+ content: [
448
+ { type: "text", text: JSON.stringify({ imported: imported.length, subscribers: imported }, null, 2) },
449
+ ],
450
+ };
451
+ }
452
+ );
453
+
454
+ server.registerTool(
455
+ "export_subscribers",
456
+ {
457
+ title: "Export Subscribers",
458
+ description: "Export all subscribers in CSV or JSON format.",
459
+ inputSchema: {
460
+ format: z.enum(["csv", "json"]).default("json"),
461
+ },
462
+ },
463
+ async ({ format }) => {
464
+ const output = exportSubscribers(format);
465
+ return { content: [{ type: "text", text: output }] };
466
+ }
467
+ );
468
+
469
+ // --- Dunning ---
470
+
471
+ server.registerTool(
472
+ "create_dunning",
473
+ {
474
+ title: "Create Dunning Attempt",
475
+ description: "Create a new dunning attempt for a subscriber.",
476
+ inputSchema: {
477
+ subscriber_id: z.string(),
478
+ attempt_number: z.number().optional(),
479
+ status: z.enum(["pending", "retrying", "failed", "recovered"]).optional(),
480
+ next_retry_at: z.string().optional(),
481
+ },
482
+ },
483
+ async (params) => {
484
+ const attempt = createDunning(params);
485
+ return { content: [{ type: "text", text: JSON.stringify(attempt, null, 2) }] };
486
+ }
487
+ );
488
+
489
+ server.registerTool(
490
+ "list_dunning",
491
+ {
492
+ title: "List Dunning Attempts",
493
+ description: "List dunning attempts with optional filters.",
494
+ inputSchema: {
495
+ subscriber_id: z.string().optional(),
496
+ status: z.string().optional(),
497
+ limit: z.number().optional(),
498
+ },
499
+ },
500
+ async (params) => {
501
+ const attempts = listDunning(params);
502
+ return {
503
+ content: [
504
+ { type: "text", text: JSON.stringify({ attempts, count: attempts.length }, null, 2) },
505
+ ],
506
+ };
507
+ }
508
+ );
509
+
510
+ server.registerTool(
511
+ "update_dunning",
512
+ {
513
+ title: "Update Dunning Attempt",
514
+ description: "Update a dunning attempt status or next retry date.",
515
+ inputSchema: {
516
+ id: z.string(),
517
+ status: z.enum(["pending", "retrying", "failed", "recovered"]).optional(),
518
+ next_retry_at: z.string().optional(),
519
+ },
520
+ },
521
+ async ({ id, ...input }) => {
522
+ const attempt = updateDunning(id, input);
523
+ if (!attempt) {
524
+ return { content: [{ type: "text", text: `Dunning attempt '${id}' not found.` }], isError: true };
525
+ }
526
+ return { content: [{ type: "text", text: JSON.stringify(attempt, null, 2) }] };
527
+ }
528
+ );
529
+
530
+ // --- LTV ---
531
+
532
+ server.registerTool(
533
+ "get_ltv",
534
+ {
535
+ title: "Get LTV",
536
+ description: "Get lifetime value per subscriber and average LTV.",
537
+ inputSchema: {},
538
+ },
539
+ async () => {
540
+ const result = getLtv();
541
+ return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
542
+ }
543
+ );
544
+
545
+ // --- NRR ---
546
+
547
+ server.registerTool(
548
+ "get_nrr",
549
+ {
550
+ title: "Get NRR",
551
+ description: "Calculate net revenue retention for a given month.",
552
+ inputSchema: {
553
+ month: z.string().describe("Month in YYYY-MM format"),
554
+ },
555
+ },
556
+ async ({ month }) => {
557
+ const result = getNrr(month);
558
+ return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
559
+ }
560
+ );
561
+
562
+ // --- Cohort Analysis ---
563
+
564
+ server.registerTool(
565
+ "cohort_report",
566
+ {
567
+ title: "Cohort Report",
568
+ description: "Generate a cohort retention analysis for the last N months.",
569
+ inputSchema: {
570
+ months: z.number().default(6),
571
+ },
572
+ },
573
+ async ({ months }) => {
574
+ const report = getCohortReport(months);
575
+ return { content: [{ type: "text", text: JSON.stringify(report, null, 2) }] };
576
+ }
577
+ );
578
+
579
+ // --- Plan Comparison ---
580
+
581
+ server.registerTool(
582
+ "compare_plans",
583
+ {
584
+ title: "Compare Plans",
585
+ description: "Compare two plans side by side showing price and feature differences.",
586
+ inputSchema: {
587
+ id1: z.string().describe("First plan ID"),
588
+ id2: z.string().describe("Second plan ID"),
589
+ },
590
+ },
591
+ async ({ id1, id2 }) => {
592
+ const result = comparePlans(id1, id2);
593
+ if (!result) {
594
+ return { content: [{ type: "text", text: "One or both plans not found." }], isError: true };
595
+ }
596
+ return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
597
+ }
598
+ );
599
+
600
+ // --- Expiring Renewals ---
601
+
602
+ server.registerTool(
603
+ "expiring_renewals",
604
+ {
605
+ title: "Expiring Renewals",
606
+ description: "List subscribers whose current period ends within N days.",
607
+ inputSchema: {
608
+ days: z.number().default(7),
609
+ },
610
+ },
611
+ async ({ days }) => {
612
+ const expiring = getExpiringRenewals(days);
613
+ return {
614
+ content: [
615
+ { type: "text", text: JSON.stringify({ expiring, count: expiring.length }, null, 2) },
616
+ ],
617
+ };
618
+ }
619
+ );
620
+
355
621
  // --- Start ---
356
622
  async function main() {
357
623
  const transport = new StdioServerTransport();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hasna/microservices",
3
- "version": "0.0.4",
3
+ "version": "0.0.5",
4
4
  "description": "Mini business apps for AI agents - invoices, contacts, bookkeeping and more, each with its own SQLite database",
5
5
  "type": "module",
6
6
  "bin": {