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.
- package/README.md +28 -0
- package/crudlify/index.mjs +4 -0
- package/crudlify/lib/schema/json-schema/index.mjs +35 -19
- package/index.js +76 -7
- package/openapi/crudlify-docs.mjs +823 -0
- package/openapi/generator.mjs +417 -0
- package/openapi/index.mjs +221 -0
- package/openapi/schema-converter.mjs +668 -0
- package/openapi/swagger-ui.mjs +92 -0
- package/package.json +12 -3
- package/types/index.d.ts +256 -0
|
@@ -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, '&')
|
|
75
|
+
.replace(/</g, '<')
|
|
76
|
+
.replace(/>/g, '>')
|
|
77
|
+
.replace(/"/g, '"')
|
|
78
|
+
.replace(/'/g, ''');
|
|
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
|
+
"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
|