@jaypie/fabric 0.2.0 → 0.2.2

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 (47) hide show
  1. package/dist/cjs/ServiceSuite.d.ts +3 -1
  2. package/dist/cjs/commander/index.cjs +42 -11
  3. package/dist/cjs/commander/index.cjs.map +1 -1
  4. package/dist/cjs/data/index.cjs +40 -11
  5. package/dist/cjs/data/index.cjs.map +1 -1
  6. package/dist/cjs/http/index.cjs +43 -13
  7. package/dist/cjs/http/index.cjs.map +1 -1
  8. package/dist/cjs/index.cjs +50 -21
  9. package/dist/cjs/index.cjs.map +1 -1
  10. package/dist/cjs/index.d.ts +1 -1
  11. package/dist/cjs/lambda/index.cjs +42 -11
  12. package/dist/cjs/lambda/index.cjs.map +1 -1
  13. package/dist/cjs/llm/index.cjs +42 -11
  14. package/dist/cjs/llm/index.cjs.map +1 -1
  15. package/dist/cjs/mcp/FabricMcpServer.d.ts +1 -1
  16. package/dist/cjs/mcp/index.cjs +43 -12
  17. package/dist/cjs/mcp/index.cjs.map +1 -1
  18. package/dist/cjs/models/base.d.ts +6 -6
  19. package/dist/cjs/resolveService.d.ts +7 -4
  20. package/dist/cjs/service.d.ts +6 -4
  21. package/dist/cjs/types.d.ts +9 -3
  22. package/dist/cjs/websocket/fabricWebSocket.d.ts +120 -0
  23. package/dist/cjs/websocket/index.d.ts +2 -0
  24. package/dist/esm/ServiceSuite.d.ts +3 -1
  25. package/dist/esm/commander/index.js +42 -11
  26. package/dist/esm/commander/index.js.map +1 -1
  27. package/dist/esm/data/index.js +40 -11
  28. package/dist/esm/data/index.js.map +1 -1
  29. package/dist/esm/http/index.js +43 -13
  30. package/dist/esm/http/index.js.map +1 -1
  31. package/dist/esm/index.d.ts +1 -1
  32. package/dist/esm/index.js +50 -21
  33. package/dist/esm/index.js.map +1 -1
  34. package/dist/esm/lambda/index.js +42 -11
  35. package/dist/esm/lambda/index.js.map +1 -1
  36. package/dist/esm/llm/index.js +42 -11
  37. package/dist/esm/llm/index.js.map +1 -1
  38. package/dist/esm/mcp/FabricMcpServer.d.ts +1 -1
  39. package/dist/esm/mcp/index.js +43 -12
  40. package/dist/esm/mcp/index.js.map +1 -1
  41. package/dist/esm/models/base.d.ts +6 -6
  42. package/dist/esm/resolveService.d.ts +7 -4
  43. package/dist/esm/service.d.ts +6 -4
  44. package/dist/esm/types.d.ts +9 -3
  45. package/dist/esm/websocket/fabricWebSocket.d.ts +120 -0
  46. package/dist/esm/websocket/index.d.ts +2 -0
  47. package/package.json +6 -1
@@ -34,7 +34,7 @@ const FABRIC_MODEL_FIELDS = {
34
34
  // Identity (required)
35
35
  ID: "id",
36
36
  // Schema
37
- CLASS: "class",
37
+ CATEGORY: "category",
38
38
  MODEL: "model",
39
39
  TYPE: "type",
40
40
  // Storage
@@ -799,8 +799,8 @@ const DEFAULT_INDEXES = [
799
799
  sparse: true,
800
800
  },
801
801
  {
802
- name: "indexClass",
803
- pk: ["scope", "model", "class"],
802
+ name: "indexCategory",
803
+ pk: ["scope", "model", "category"],
804
804
  sk: ["sequence"],
805
805
  sparse: true,
806
806
  },
@@ -1459,42 +1459,68 @@ async function processField(fieldName, value, definition) {
1459
1459
  function isService(value) {
1460
1460
  return typeof value === "function" && "$fabric" in value;
1461
1461
  }
1462
+ /**
1463
+ * Run serializer hook if provided
1464
+ * Returns transformed output or original if serializer returns undefined/null/void
1465
+ */
1466
+ async function runSerializer(data, serializer, context) {
1467
+ if (!serializer) {
1468
+ return data.output;
1469
+ }
1470
+ const result = await serializer(data, context);
1471
+ if (result !== undefined && result !== null) {
1472
+ return result;
1473
+ }
1474
+ return data.output;
1475
+ }
1462
1476
  /**
1463
1477
  * Fabric a service function
1464
1478
  *
1465
- * Service builds a function that initiates a "controller" step that:
1479
+ * Service builds a function that:
1466
1480
  * - Parses the input if it is a string to object
1467
1481
  * - Fabrics each input field to its type
1468
1482
  * - Calls the validation function or regular expression or checks the array
1469
- * - Calls the service function and returns the response
1483
+ * - Calls the service function
1484
+ * - Calls the serializer hook (can transform output)
1485
+ * - Returns the response
1470
1486
  *
1471
1487
  * The returned function has config properties for introspection.
1472
1488
  */
1473
1489
  function fabricService(config) {
1474
- const { input: inputDefinitions, service } = config;
1490
+ const { input: inputDefinitions, serializer, service } = config;
1475
1491
  const handler = async (rawInput, context) => {
1476
1492
  // Parse input (handles string JSON)
1477
1493
  const parsedInput = parseInput(rawInput);
1478
1494
  // If no input definitions, pass through to service or return parsed input
1479
1495
  if (!inputDefinitions) {
1496
+ let output;
1480
1497
  if (service) {
1481
- return service(parsedInput, context);
1498
+ output = await service(parsedInput, context);
1499
+ }
1500
+ else {
1501
+ output = parsedInput;
1482
1502
  }
1483
- return parsedInput;
1503
+ // Run serializer
1504
+ return (await runSerializer({ input: parsedInput, output }, serializer, context));
1484
1505
  }
1485
1506
  // Process all fields in parallel
1486
1507
  const entries = Object.entries(inputDefinitions);
1487
1508
  const processedValues = await Promise.all(entries.map(([fieldName, definition]) => processField(fieldName, parsedInput[fieldName], definition)));
1488
1509
  // Build processed input object
1489
- const processedInput = {};
1510
+ const processedInputObj = {};
1490
1511
  entries.forEach(([fieldName], index) => {
1491
- processedInput[fieldName] = processedValues[index];
1512
+ processedInputObj[fieldName] = processedValues[index];
1492
1513
  });
1493
- // Return processed input if no service, otherwise call service
1514
+ // Call service or return processed input
1515
+ let output;
1494
1516
  if (service) {
1495
- return service(processedInput, context);
1517
+ output = await service(processedInputObj, context);
1518
+ }
1519
+ else {
1520
+ output = processedInputObj;
1496
1521
  }
1497
- return processedInput;
1522
+ // Run serializer hook
1523
+ return (await runSerializer({ input: processedInputObj, output }, serializer, context));
1498
1524
  };
1499
1525
  // Attach config properties directly to handler for flat access
1500
1526
  const typedHandler = handler;
@@ -1505,6 +1531,8 @@ function fabricService(config) {
1505
1531
  typedHandler.description = config.description;
1506
1532
  if (config.input !== undefined)
1507
1533
  typedHandler.input = config.input;
1534
+ if (config.serializer !== undefined)
1535
+ typedHandler.serializer = config.serializer;
1508
1536
  if (config.service !== undefined)
1509
1537
  typedHandler.service = config.service;
1510
1538
  return typedHandler;
@@ -1523,6 +1551,7 @@ function fabricService(config) {
1523
1551
  * - `alias` overrides service.alias
1524
1552
  * - `description` overrides service.description
1525
1553
  * - `input` overrides service.input
1554
+ * - `serializer` overrides service.serializer
1526
1555
  *
1527
1556
  * The original Service is never mutated - a new Service is created when overrides
1528
1557
  * are applied.
@@ -1546,7 +1575,7 @@ function fabricService(config) {
1546
1575
  * ```
1547
1576
  */
1548
1577
  function resolveService(config) {
1549
- const { alias, description, input, service } = config;
1578
+ const { alias, description, input, serializer, service } = config;
1550
1579
  if (isService(service)) {
1551
1580
  // Service is pre-instantiated - config fields act as overrides
1552
1581
  // Create new Service with merged properties (config overrides service)
@@ -1554,6 +1583,7 @@ function resolveService(config) {
1554
1583
  alias: alias ?? service.alias,
1555
1584
  description: description ?? service.description,
1556
1585
  input: input ?? service.input,
1586
+ serializer: serializer ?? service.serializer,
1557
1587
  service: service.service,
1558
1588
  });
1559
1589
  }
@@ -1562,6 +1592,7 @@ function resolveService(config) {
1562
1592
  alias,
1563
1593
  description,
1564
1594
  input,
1595
+ serializer,
1565
1596
  service,
1566
1597
  });
1567
1598
  }
@@ -1628,7 +1659,9 @@ function extractEnumValues(type) {
1628
1659
  return undefined;
1629
1660
  // Check if it's a validated string enum (array of strings, possibly with RegExp)
1630
1661
  const stringValues = type.filter((item) => typeof item === "string");
1631
- if (stringValues.length > 0 && stringValues.length === type.filter((item) => typeof item === "string").length) {
1662
+ if (stringValues.length > 0 &&
1663
+ stringValues.length ===
1664
+ type.filter((item) => typeof item === "string").length) {
1632
1665
  // All non-RegExp items are strings
1633
1666
  return stringValues;
1634
1667
  }
@@ -1667,7 +1700,6 @@ function hasRequiredInputs(inputs) {
1667
1700
  */
1668
1701
  function createServiceSuite(config) {
1669
1702
  const { name, version } = config;
1670
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
1671
1703
  const serviceRegistry = new Map();
1672
1704
  const categorySet = new Set();
1673
1705
  const suite = {
@@ -1694,9 +1726,8 @@ function createServiceSuite(config) {
1694
1726
  }
1695
1727
  return entry.service(inputs);
1696
1728
  },
1697
- register(
1698
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
1699
- service, category) {
1729
+ register(service, options) {
1730
+ const { category } = options;
1700
1731
  const serviceName = service.alias;
1701
1732
  if (!serviceName) {
1702
1733
  throw new Error("Service must have an alias to be registered");
@@ -1712,11 +1743,9 @@ function createServiceSuite(config) {
1712
1743
  serviceRegistry.set(serviceName, { service, meta });
1713
1744
  categorySet.add(category);
1714
1745
  },
1715
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
1716
1746
  getServiceFunctions() {
1717
1747
  return Array.from(serviceRegistry.values()).map((entry) => entry.service);
1718
1748
  },
1719
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
1720
1749
  getServiceFunction(serviceName) {
1721
1750
  return serviceRegistry.get(serviceName)?.service;
1722
1751
  },