@jaypie/fabric 0.1.0 → 0.1.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.
@@ -0,0 +1,58 @@
1
+ import type { Service } from "./types.js";
2
+ /**
3
+ * Describes a single input parameter for a service
4
+ */
5
+ export interface ServiceInput {
6
+ name: string;
7
+ type: string;
8
+ required: boolean;
9
+ description: string;
10
+ enum?: string[];
11
+ }
12
+ /**
13
+ * Describes a service's metadata for discovery and documentation
14
+ */
15
+ export interface ServiceMeta {
16
+ /** Service name (from alias) */
17
+ name: string;
18
+ /** Human-readable description */
19
+ description: string;
20
+ /** Category for grouping (e.g., "record", "aws", "docs") */
21
+ category: string;
22
+ /** Input parameter definitions */
23
+ inputs: ServiceInput[];
24
+ /** Whether the service can be executed with no inputs */
25
+ executable?: boolean;
26
+ }
27
+ /**
28
+ * A collection of services with metadata and execution capabilities
29
+ */
30
+ export interface ServiceSuite {
31
+ /** Suite name (e.g., "nostrus", "jaypie") */
32
+ name: string;
33
+ /** Suite version */
34
+ version: string;
35
+ /** Available categories */
36
+ categories: string[];
37
+ /** All registered services */
38
+ services: ServiceMeta[];
39
+ /** Get a service by name */
40
+ getService(name: string): ServiceMeta | undefined;
41
+ /** Get services by category */
42
+ getServicesByCategory(category: string): ServiceMeta[];
43
+ /** Execute a service by name */
44
+ execute(name: string, inputs: Record<string, unknown>): Promise<unknown>;
45
+ /** Register a fabricService into the suite */
46
+ register(service: Service<any, any>, category: string): void;
47
+ }
48
+ /**
49
+ * Configuration for creating a ServiceSuite
50
+ */
51
+ export interface CreateServiceSuiteConfig {
52
+ name: string;
53
+ version: string;
54
+ }
55
+ /**
56
+ * Create a ServiceSuite instance
57
+ */
58
+ export declare function createServiceSuite(config: CreateServiceSuiteConfig): ServiceSuite;
@@ -1566,6 +1566,156 @@ function resolveService(config) {
1566
1566
  });
1567
1567
  }
1568
1568
 
1569
+ // ServiceSuite for @jaypie/fabric
1570
+ // Groups fabricService instances for discovery, metadata export, and direct execution
1571
+ /**
1572
+ * Derive type string from InputFieldDefinition.type
1573
+ */
1574
+ function deriveTypeString(type) {
1575
+ // Handle constructors
1576
+ if (type === String || type === "string")
1577
+ return "string";
1578
+ if (type === Number || type === "number")
1579
+ return "number";
1580
+ if (type === Boolean || type === "boolean")
1581
+ return "boolean";
1582
+ if (type === Object || type === "object")
1583
+ return "object";
1584
+ if (type === Array || type === "array")
1585
+ return "array";
1586
+ if (type === Date)
1587
+ return "string"; // Dates are passed as strings
1588
+ // Handle typed arrays: [String], [Number], etc.
1589
+ if (Array.isArray(type)) {
1590
+ if (type.length === 0)
1591
+ return "array";
1592
+ const first = type[0];
1593
+ // If it's a type constructor, it's a typed array
1594
+ if (first === String ||
1595
+ first === Number ||
1596
+ first === Boolean ||
1597
+ first === Object ||
1598
+ first === "string" ||
1599
+ first === "number" ||
1600
+ first === "boolean" ||
1601
+ first === "object" ||
1602
+ first === "") {
1603
+ return "array";
1604
+ }
1605
+ // If all elements are strings (or RegExp), it's a validated string enum
1606
+ if (type.every((item) => typeof item === "string" || item instanceof RegExp)) {
1607
+ return "string";
1608
+ }
1609
+ // If all elements are numbers, it's a validated number enum
1610
+ if (type.every((item) => typeof item === "number")) {
1611
+ return "number";
1612
+ }
1613
+ return "array";
1614
+ }
1615
+ // Handle RegExp (validated string)
1616
+ if (type instanceof RegExp) {
1617
+ return "string";
1618
+ }
1619
+ return "string"; // Default fallback
1620
+ }
1621
+ /**
1622
+ * Extract enum values if the type is a validated string/number array
1623
+ */
1624
+ function extractEnumValues(type) {
1625
+ if (!Array.isArray(type))
1626
+ return undefined;
1627
+ if (type.length === 0)
1628
+ return undefined;
1629
+ // Check if it's a validated string enum (array of strings, possibly with RegExp)
1630
+ const stringValues = type.filter((item) => typeof item === "string");
1631
+ if (stringValues.length > 0 && stringValues.length === type.filter((item) => typeof item === "string").length) {
1632
+ // All non-RegExp items are strings
1633
+ return stringValues;
1634
+ }
1635
+ // Check if it's a validated number enum
1636
+ if (type.every((item) => typeof item === "number")) {
1637
+ return type.map((n) => String(n));
1638
+ }
1639
+ return undefined;
1640
+ }
1641
+ /**
1642
+ * Convert fabricService input definitions to ServiceInput array
1643
+ */
1644
+ function extractInputs(inputDefinitions) {
1645
+ if (!inputDefinitions)
1646
+ return [];
1647
+ return Object.entries(inputDefinitions).map(([name, def]) => {
1648
+ const required = def.required !== false && def.default === undefined;
1649
+ const enumValues = extractEnumValues(def.type);
1650
+ return {
1651
+ name,
1652
+ type: deriveTypeString(def.type),
1653
+ required,
1654
+ description: def.description || "",
1655
+ ...(enumValues && { enum: enumValues }),
1656
+ };
1657
+ });
1658
+ }
1659
+ /**
1660
+ * Check if a service has any required inputs
1661
+ */
1662
+ function hasRequiredInputs(inputs) {
1663
+ return inputs.some((input) => input.required);
1664
+ }
1665
+ /**
1666
+ * Create a ServiceSuite instance
1667
+ */
1668
+ function createServiceSuite(config) {
1669
+ const { name, version } = config;
1670
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
1671
+ const serviceRegistry = new Map();
1672
+ const categorySet = new Set();
1673
+ const suite = {
1674
+ name,
1675
+ version,
1676
+ get categories() {
1677
+ return Array.from(categorySet).sort();
1678
+ },
1679
+ get services() {
1680
+ return Array.from(serviceRegistry.values()).map((entry) => entry.meta);
1681
+ },
1682
+ getService(serviceName) {
1683
+ return serviceRegistry.get(serviceName)?.meta;
1684
+ },
1685
+ getServicesByCategory(category) {
1686
+ return Array.from(serviceRegistry.values())
1687
+ .filter((entry) => entry.meta.category === category)
1688
+ .map((entry) => entry.meta);
1689
+ },
1690
+ async execute(serviceName, inputs) {
1691
+ const entry = serviceRegistry.get(serviceName);
1692
+ if (!entry) {
1693
+ throw new Error(`Service "${serviceName}" not found in suite "${name}"`);
1694
+ }
1695
+ return entry.service(inputs);
1696
+ },
1697
+ register(
1698
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
1699
+ service, category) {
1700
+ const serviceName = service.alias;
1701
+ if (!serviceName) {
1702
+ throw new Error("Service must have an alias to be registered");
1703
+ }
1704
+ const inputs = extractInputs(service.input);
1705
+ const meta = {
1706
+ name: serviceName,
1707
+ description: service.description || "",
1708
+ category,
1709
+ inputs,
1710
+ executable: !hasRequiredInputs(inputs),
1711
+ };
1712
+ serviceRegistry.set(serviceName, { service, meta });
1713
+ categorySet.add(category);
1714
+ },
1715
+ };
1716
+ return suite;
1717
+ }
1718
+
1569
1719
  /**
1570
1720
  * Status Type for @jaypie/fabric
1571
1721
  *
@@ -1637,6 +1787,7 @@ exports.calculateScope = calculateScope;
1637
1787
  exports.clearRegistry = clearRegistry;
1638
1788
  exports.computeResolvedName = computeResolvedName;
1639
1789
  exports.createFabricModelInput = createFabricModelInput;
1790
+ exports.createServiceSuite = createServiceSuite;
1640
1791
  exports.fabric = fabric;
1641
1792
  exports.fabricArray = fabricArray;
1642
1793
  exports.fabricBoolean = fabricBoolean;