codehooks-js 1.3.25 → 1.4.0

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,92 @@
1
+ /**
2
+ * Swagger UI HTML generator
3
+ * Generates HTML that loads Swagger UI from CDN
4
+ */
5
+
6
+ const SWAGGER_UI_VERSION = '5.11.0';
7
+
8
+ /**
9
+ * Generate Swagger UI HTML page
10
+ * @param {string} specUrl - URL to the OpenAPI JSON spec
11
+ * @param {object} config - Configuration options
12
+ * @param {string} [config.title] - Page title
13
+ * @param {string} [config.oauth2RedirectUrl] - OAuth2 redirect URL
14
+ * @param {string|null} [config.validatorUrl] - Validator URL (null to disable)
15
+ * @param {string} [config.favicon] - Favicon URL
16
+ * @returns {string} HTML string
17
+ */
18
+ export function generateSwaggerHtml(specUrl, config = {}) {
19
+ const title = config.title || 'API Documentation';
20
+ const favicon = config.favicon || 'https://unpkg.com/swagger-ui-dist@' + SWAGGER_UI_VERSION + '/favicon-32x32.png';
21
+
22
+ return `<!DOCTYPE html>
23
+ <html lang="en">
24
+ <head>
25
+ <meta charset="UTF-8">
26
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
27
+ <title>${escapeHtml(title)}</title>
28
+ <link rel="icon" type="image/png" href="${escapeHtml(favicon)}">
29
+ <link rel="stylesheet" href="https://unpkg.com/swagger-ui-dist@${SWAGGER_UI_VERSION}/swagger-ui.css">
30
+ <style>
31
+ html { box-sizing: border-box; overflow-y: scroll; }
32
+ *, *:before, *:after { box-sizing: inherit; }
33
+ body { margin: 0; padding: 0; background: #fafafa; }
34
+ .swagger-ui .topbar { display: none; }
35
+ .swagger-ui .info { margin: 30px 0; }
36
+ .swagger-ui .info .title { font-size: 2em; }
37
+ </style>
38
+ </head>
39
+ <body>
40
+ <div id="swagger-ui"></div>
41
+ <script src="https://unpkg.com/swagger-ui-dist@${SWAGGER_UI_VERSION}/swagger-ui-bundle.js" crossorigin></script>
42
+ <script src="https://unpkg.com/swagger-ui-dist@${SWAGGER_UI_VERSION}/swagger-ui-standalone-preset.js" crossorigin></script>
43
+ <script>
44
+ window.onload = function() {
45
+ const ui = SwaggerUIBundle({
46
+ url: "${escapeJs(specUrl)}",
47
+ dom_id: '#swagger-ui',
48
+ deepLinking: true,
49
+ presets: [
50
+ SwaggerUIBundle.presets.apis,
51
+ SwaggerUIStandalonePreset
52
+ ],
53
+ plugins: [
54
+ SwaggerUIBundle.plugins.DownloadUrl
55
+ ],
56
+ layout: "StandaloneLayout"${config.oauth2RedirectUrl ? `,
57
+ oauth2RedirectUrl: "${escapeJs(config.oauth2RedirectUrl)}"` : ''}${config.validatorUrl !== undefined ? `,
58
+ validatorUrl: ${config.validatorUrl === null ? 'null' : `"${escapeJs(config.validatorUrl)}"`}` : ''}
59
+ });
60
+ window.ui = ui;
61
+ };
62
+ </script>
63
+ </body>
64
+ </html>`;
65
+ }
66
+
67
+ /**
68
+ * Escape HTML special characters
69
+ * @param {string} str
70
+ * @returns {string}
71
+ */
72
+ function escapeHtml(str) {
73
+ return String(str)
74
+ .replace(/&/g, '&amp;')
75
+ .replace(/</g, '&lt;')
76
+ .replace(/>/g, '&gt;')
77
+ .replace(/"/g, '&quot;')
78
+ .replace(/'/g, '&#039;');
79
+ }
80
+
81
+ /**
82
+ * Escape string for JavaScript
83
+ * @param {string} str
84
+ * @returns {string}
85
+ */
86
+ function escapeJs(str) {
87
+ return String(str)
88
+ .replace(/\\/g, '\\\\')
89
+ .replace(/"/g, '\\"')
90
+ .replace(/\n/g, '\\n')
91
+ .replace(/\r/g, '\\r');
92
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "codehooks-js",
3
- "version": "1.3.25",
3
+ "version": "1.4.0",
4
4
  "type": "module",
5
5
  "description": "Codehooks.io official library - provides express.JS like syntax",
6
6
  "main": "index.js",
@@ -18,6 +18,11 @@
18
18
  "./crudlify/lib/schema/zod/index.mjs",
19
19
  "./workflow/index.mjs",
20
20
  "./workflow/engine.mjs",
21
+ "./openapi/index.mjs",
22
+ "./openapi/generator.mjs",
23
+ "./openapi/schema-converter.mjs",
24
+ "./openapi/swagger-ui.mjs",
25
+ "./openapi/crudlify-docs.mjs",
21
26
  "./types",
22
27
  "tsconfig.json"
23
28
  ],
@@ -44,7 +49,9 @@
44
49
  "queue",
45
50
  "cron",
46
51
  "schedule",
47
- "mongodb"
52
+ "mongodb",
53
+ "openapi",
54
+ "swagger"
48
55
  ],
49
56
  "dependencies": {
50
57
  "lodash": "^4.17.21",
@@ -53,6 +60,8 @@
53
60
  },
54
61
  "devDependencies": {
55
62
  "@types/mime": "^3.0.4",
56
- "@types/node": "^22.15.19"
63
+ "@types/node": "^22.15.19",
64
+ "yup": "^1.7.1",
65
+ "zod": "^4.3.6"
57
66
  }
58
67
  }
package/types/index.d.ts CHANGED
@@ -1085,6 +1085,22 @@ export class Codehooks {
1085
1085
  * @returns Promise with the fetched data
1086
1086
  */
1087
1087
  internalFetch: (url: string, options?: any) => Promise<any>;
1088
+ /**
1089
+ * Enable OpenAPI documentation
1090
+ * @param config - OpenAPI configuration
1091
+ * @param uiPath - Path to serve Swagger UI (default: '/docs')
1092
+ * @returns this for chaining
1093
+ * @example
1094
+ * app.openapi({
1095
+ * info: {
1096
+ * title: "My API",
1097
+ * version: "1.0.0"
1098
+ * }
1099
+ * }, '/docs');
1100
+ */
1101
+ openapi: (config?: OpenAPIConfig, uiPath?: string) => Codehooks;
1102
+ /** Stored OpenAPI metadata for routes */
1103
+ openApiMeta: Record<string, OpenAPIRouteSpec>;
1088
1104
  }
1089
1105
  declare const _coho: Codehooks;
1090
1106
 
@@ -1504,4 +1520,244 @@ export type WorkflowEventData = {
1504
1520
  [key: string]: any;
1505
1521
  };
1506
1522
 
1523
+ // ============================================
1524
+ // OpenAPI Documentation Types
1525
+ // ============================================
1526
+
1527
+ /**
1528
+ * OpenAPI JSON Schema type (subset)
1529
+ */
1530
+ export type OpenAPISchema = {
1531
+ type?: 'string' | 'number' | 'integer' | 'boolean' | 'array' | 'object';
1532
+ format?: string;
1533
+ items?: OpenAPISchema;
1534
+ properties?: Record<string, OpenAPISchema>;
1535
+ required?: string[];
1536
+ $ref?: string;
1537
+ enum?: any[];
1538
+ default?: any;
1539
+ example?: any;
1540
+ description?: string;
1541
+ nullable?: boolean;
1542
+ allOf?: OpenAPISchema[];
1543
+ oneOf?: OpenAPISchema[];
1544
+ anyOf?: OpenAPISchema[];
1545
+ [key: string]: any;
1546
+ };
1547
+
1548
+ /**
1549
+ * OpenAPI Parameter specification
1550
+ */
1551
+ export type OpenAPIParameter = {
1552
+ name: string;
1553
+ in: 'path' | 'query' | 'header' | 'cookie';
1554
+ description?: string;
1555
+ required?: boolean;
1556
+ schema: OpenAPISchema;
1557
+ example?: any;
1558
+ };
1559
+
1560
+ /**
1561
+ * OpenAPI Request Body specification
1562
+ */
1563
+ export type OpenAPIRequestBody = {
1564
+ description?: string;
1565
+ required?: boolean;
1566
+ content: Record<string, { schema: OpenAPISchema; example?: any }>;
1567
+ };
1568
+
1569
+ /**
1570
+ * OpenAPI Response specification
1571
+ */
1572
+ export type OpenAPIResponse = {
1573
+ description: string;
1574
+ content?: Record<string, { schema: OpenAPISchema; example?: any }>;
1575
+ headers?: Record<string, { description?: string; schema: OpenAPISchema }>;
1576
+ };
1577
+
1578
+ /**
1579
+ * OpenAPI Route specification for openapi() wrapper
1580
+ */
1581
+ export type OpenAPIRouteSpec = {
1582
+ /** Short summary of what the operation does */
1583
+ summary?: string;
1584
+ /** Verbose explanation of the operation */
1585
+ description?: string;
1586
+ /** Tags for API documentation grouping */
1587
+ tags?: string[];
1588
+ /** Unique operation identifier for code generation */
1589
+ operationId?: string;
1590
+ /** Parameters (path, query, header, cookie) */
1591
+ parameters?: OpenAPIParameter[];
1592
+ /** Request body specification */
1593
+ requestBody?: OpenAPIRequestBody;
1594
+ /** Response specifications by status code */
1595
+ responses?: Record<string, OpenAPIResponse>;
1596
+ /** Security requirements for this operation */
1597
+ security?: Array<Record<string, string[]>>;
1598
+ /** Whether this operation is deprecated */
1599
+ deprecated?: boolean;
1600
+ };
1601
+
1602
+ /**
1603
+ * OpenAPI Info object
1604
+ */
1605
+ export type OpenAPIInfo = {
1606
+ title?: string;
1607
+ description?: string;
1608
+ version?: string;
1609
+ termsOfService?: string;
1610
+ contact?: { name?: string; url?: string; email?: string };
1611
+ license?: { name: string; url?: string };
1612
+ };
1613
+
1614
+ /**
1615
+ * OpenAPI Server object
1616
+ */
1617
+ export type OpenAPIServer = {
1618
+ url: string;
1619
+ description?: string;
1620
+ variables?: Record<string, { default: string; enum?: string[]; description?: string }>;
1621
+ };
1622
+
1623
+ /**
1624
+ * OpenAPI Tag object
1625
+ */
1626
+ export type OpenAPITag = {
1627
+ name: string;
1628
+ description?: string;
1629
+ externalDocs?: { url: string; description?: string };
1630
+ };
1631
+
1632
+ /**
1633
+ * Filter operation object passed to the filter function
1634
+ */
1635
+ export type OpenAPIFilterOperation = {
1636
+ /** HTTP method (lowercase): 'get', 'post', 'put', 'patch', 'delete' */
1637
+ method: string;
1638
+ /** Route path: '/todos', '/todos/{ID}' */
1639
+ path: string;
1640
+ /** Operation ID if set */
1641
+ operationId?: string;
1642
+ /** Array of tags */
1643
+ tags: string[];
1644
+ /** Operation summary */
1645
+ summary?: string;
1646
+ };
1647
+
1648
+ /**
1649
+ * OpenAPI Configuration for app.openapi()
1650
+ */
1651
+ export type OpenAPIConfig = {
1652
+ /** OpenAPI Info object */
1653
+ info?: OpenAPIInfo;
1654
+ /** Server definitions */
1655
+ servers?: OpenAPIServer[];
1656
+ /** Custom schemas to add to components */
1657
+ components?: {
1658
+ schemas?: Record<string, OpenAPISchema>;
1659
+ securitySchemes?: Record<string, any>;
1660
+ };
1661
+ /** Global security requirements */
1662
+ security?: Array<Record<string, string[]>>;
1663
+ /** Path to serve the OpenAPI JSON spec (default: '/openapi.json') */
1664
+ specPath?: string;
1665
+ /** Swagger UI configuration */
1666
+ swaggerUi?: {
1667
+ oauth2RedirectUrl?: string;
1668
+ validatorUrl?: string | null;
1669
+ favicon?: string;
1670
+ };
1671
+ /** Tags for grouping endpoints */
1672
+ tags?: OpenAPITag[];
1673
+ /** External documentation */
1674
+ externalDocs?: { url: string; description?: string };
1675
+ /**
1676
+ * Filter function to control which operations appear in the documentation.
1677
+ * Return true to include the operation, false to exclude it.
1678
+ * @example
1679
+ * // Exclude DELETE operations
1680
+ * filter: (op) => op.method !== 'delete'
1681
+ *
1682
+ * // Exclude internal routes
1683
+ * filter: (op) => !op.path.startsWith('/internal')
1684
+ *
1685
+ * // Only include specific tags
1686
+ * filter: (op) => op.tags.includes('Public')
1687
+ */
1688
+ filter?: (op: OpenAPIFilterOperation) => boolean;
1689
+ };
1690
+
1691
+ /**
1692
+ * Wrap a route handler with OpenAPI documentation
1693
+ * @param spec - OpenAPI specification for this route
1694
+ * @returns Middleware function with attached metadata
1695
+ * @example
1696
+ * app.get('/users/:id',
1697
+ * openapi({
1698
+ * summary: "Get user by ID",
1699
+ * tags: ["Users"],
1700
+ * responses: { 200: { description: "Success" } }
1701
+ * }),
1702
+ * (req, res) => res.json({ id: req.params.id })
1703
+ * );
1704
+ */
1705
+ export function openapi(spec: OpenAPIRouteSpec): (
1706
+ req: httpRequest,
1707
+ res: httpResponse,
1708
+ next: nextFunction
1709
+ ) => void;
1710
+
1711
+ /**
1712
+ * Helper to create response specification
1713
+ * @param description - Response description
1714
+ * @param schema - Response schema (JSON Schema or Zod/Yup)
1715
+ * @param contentType - Content type (default: 'application/json')
1716
+ */
1717
+ export function response(
1718
+ description: string,
1719
+ schema?: OpenAPISchema,
1720
+ contentType?: string
1721
+ ): OpenAPIResponse;
1722
+
1723
+ /**
1724
+ * Helper to create request body specification
1725
+ * @param schema - Request body schema
1726
+ * @param options - Additional options
1727
+ */
1728
+ export function body(
1729
+ schema: OpenAPISchema,
1730
+ options?: { required?: boolean; description?: string; contentType?: string }
1731
+ ): OpenAPIRequestBody;
1732
+
1733
+ /**
1734
+ * Helper to create path parameter specification
1735
+ * @param name - Parameter name
1736
+ * @param options - Parameter options
1737
+ */
1738
+ export function param(
1739
+ name: string,
1740
+ options?: { description?: string; schema?: OpenAPISchema; example?: any }
1741
+ ): OpenAPIParameter;
1742
+
1743
+ /**
1744
+ * Helper to create query parameter specification
1745
+ * @param name - Parameter name
1746
+ * @param options - Parameter options
1747
+ */
1748
+ export function query(
1749
+ name: string,
1750
+ options?: { description?: string; required?: boolean; schema?: OpenAPISchema; example?: any }
1751
+ ): OpenAPIParameter;
1752
+
1753
+ /**
1754
+ * Helper to create header parameter specification
1755
+ * @param name - Header name
1756
+ * @param options - Parameter options
1757
+ */
1758
+ export function header(
1759
+ name: string,
1760
+ options?: { description?: string; required?: boolean; schema?: OpenAPISchema; example?: any }
1761
+ ): OpenAPIParameter;
1762
+
1507
1763
  //# sourceMappingURL=index.d.ts.map