@lukoweb/apitogo 0.2.41 → 0.2.43
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/dist/cli/cli.js +330 -37
- package/dist/declarations/cli/platform/tools/lifecycle.d.ts +4 -0
- package/package.json +1 -1
- package/src/config/v2/full-server.ts +187 -0
- package/src/config/v2/manifest.ts +472 -452
- package/src/config/v2/services.ts +56 -20
- package/src/config/v2/wrapper.ts +60 -4
- package/src/vite/watch-ignore.ts +80 -70
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The backend of the full template: a small Node.js server with no dependencies, so the platform can build and run it
|
|
3
|
+
* as it is (`npm start`, port from `PORT`), and the OpenAPI file that describes it. The two must list the same
|
|
4
|
+
* endpoints: the gateway only forwards what the file names, and the API reference shows the file.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
/** The folder of the backend code, relative to the project. */
|
|
8
|
+
export const FULL_SERVER_SOURCE = "server";
|
|
9
|
+
export const FULL_SERVER_RUNTIME = "nodejs";
|
|
10
|
+
export const FULL_SERVER_RUNTIME_VERSION = "NODE_22_LTS";
|
|
11
|
+
export const FULL_SERVER_HEALTH_PATH = "/health";
|
|
12
|
+
|
|
13
|
+
const packageName = (name: string) =>
|
|
14
|
+
`${
|
|
15
|
+
name
|
|
16
|
+
.toLowerCase()
|
|
17
|
+
.replace(/[^a-z0-9-]+/g, "-")
|
|
18
|
+
.replace(/^-+|-+$/g, "") || "api"
|
|
19
|
+
}-server`;
|
|
20
|
+
|
|
21
|
+
/** The files of the server, by path relative to its folder. */
|
|
22
|
+
export function fullServerFiles(name: string): Record<string, string> {
|
|
23
|
+
return {
|
|
24
|
+
"package.json": `${JSON.stringify(
|
|
25
|
+
{
|
|
26
|
+
name: packageName(name),
|
|
27
|
+
version: "1.0.0",
|
|
28
|
+
private: true,
|
|
29
|
+
type: "module",
|
|
30
|
+
main: "index.js",
|
|
31
|
+
scripts: { start: "node index.js" },
|
|
32
|
+
engines: { node: ">=22" },
|
|
33
|
+
},
|
|
34
|
+
null,
|
|
35
|
+
2,
|
|
36
|
+
)}\n`,
|
|
37
|
+
"index.js": `// A small API for ${JSON.stringify(name)}. Every endpoint here is listed in apitogo/apis/openapi.yaml:
|
|
38
|
+
// add an endpoint in both places, then run \`apitogo deploy\`.
|
|
39
|
+
import { createServer } from "node:http";
|
|
40
|
+
|
|
41
|
+
const items = [
|
|
42
|
+
{ id: "1", name: "First item" },
|
|
43
|
+
{ id: "2", name: "Second item" },
|
|
44
|
+
{ id: "3", name: "Third item" },
|
|
45
|
+
];
|
|
46
|
+
|
|
47
|
+
// Lets the portal's API page call this server while you run it locally (\`apitogo dev\`). Once deployed, the gateway
|
|
48
|
+
// answers browsers itself and keeps its own list of allowed sites.
|
|
49
|
+
const cors = {
|
|
50
|
+
"access-control-allow-origin": "*",
|
|
51
|
+
"access-control-allow-methods": "GET, OPTIONS",
|
|
52
|
+
"access-control-allow-headers": "*",
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
function send(res, status, body) {
|
|
56
|
+
res.writeHead(status, { "content-type": "application/json", ...cors });
|
|
57
|
+
res.end(JSON.stringify(body));
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
const server = createServer((req, res) => {
|
|
61
|
+
const url = new URL(req.url ?? "/", "http://localhost");
|
|
62
|
+
const itemMatch = url.pathname.match(/^\\/items\\/([^/]+)$/);
|
|
63
|
+
|
|
64
|
+
if (req.method === "OPTIONS") {
|
|
65
|
+
res.writeHead(204, cors);
|
|
66
|
+
return res.end();
|
|
67
|
+
}
|
|
68
|
+
if (req.method !== "GET") return send(res, 405, { error: "Method not allowed" });
|
|
69
|
+
if (url.pathname === "/health") return send(res, 200, { status: "ok" });
|
|
70
|
+
if (url.pathname === "/hello") {
|
|
71
|
+
const who = url.searchParams.get("name") || "world";
|
|
72
|
+
return send(res, 200, { message: \`Hello, \${who}!\` });
|
|
73
|
+
}
|
|
74
|
+
if (url.pathname === "/items") return send(res, 200, items);
|
|
75
|
+
if (itemMatch) {
|
|
76
|
+
const item = items.find((candidate) => candidate.id === itemMatch[1]);
|
|
77
|
+
return item ? send(res, 200, item) : send(res, 404, { error: "Item not found" });
|
|
78
|
+
}
|
|
79
|
+
return send(res, 404, { error: "Not found" });
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
const port = Number(process.env.PORT) || 8080;
|
|
83
|
+
server.listen(port, () => console.log(\`API listening on port \${port}\`));
|
|
84
|
+
`,
|
|
85
|
+
"README.md": `# ${name} server
|
|
86
|
+
|
|
87
|
+
A small Node.js API with no dependencies, created by \`apitogo create --template full\`.
|
|
88
|
+
|
|
89
|
+
- Run it locally: \`npm start\` (port 8080, or \`PORT\`)
|
|
90
|
+
- Deploy it: \`apitogo deploy\` from the project folder
|
|
91
|
+
|
|
92
|
+
Every endpoint in \`index.js\` is also listed in \`apitogo/apis/openapi.yaml\`. Keep the two in step: the gateway only
|
|
93
|
+
forwards the endpoints the file names, and the API reference of the portal is built from it.
|
|
94
|
+
`,
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/** The OpenAPI file of the full template, matching `fullServerFiles`. */
|
|
99
|
+
export const FULL_SPEC = (name: string) => `openapi: 3.1.0
|
|
100
|
+
info:
|
|
101
|
+
title: ${JSON.stringify(name)}
|
|
102
|
+
version: 1.0.0
|
|
103
|
+
description: A small sample API. Edit server/index.js and this file together.
|
|
104
|
+
paths:
|
|
105
|
+
/health:
|
|
106
|
+
get:
|
|
107
|
+
operationId: getHealth
|
|
108
|
+
summary: Health check
|
|
109
|
+
responses:
|
|
110
|
+
"200":
|
|
111
|
+
description: The service is up.
|
|
112
|
+
content:
|
|
113
|
+
application/json:
|
|
114
|
+
schema:
|
|
115
|
+
type: object
|
|
116
|
+
properties:
|
|
117
|
+
status:
|
|
118
|
+
type: string
|
|
119
|
+
example: ok
|
|
120
|
+
/hello:
|
|
121
|
+
get:
|
|
122
|
+
operationId: getHello
|
|
123
|
+
summary: Say hello
|
|
124
|
+
parameters:
|
|
125
|
+
- name: name
|
|
126
|
+
in: query
|
|
127
|
+
required: false
|
|
128
|
+
description: Who to greet.
|
|
129
|
+
schema:
|
|
130
|
+
type: string
|
|
131
|
+
example: developer
|
|
132
|
+
responses:
|
|
133
|
+
"200":
|
|
134
|
+
description: A greeting.
|
|
135
|
+
content:
|
|
136
|
+
application/json:
|
|
137
|
+
schema:
|
|
138
|
+
type: object
|
|
139
|
+
properties:
|
|
140
|
+
message:
|
|
141
|
+
type: string
|
|
142
|
+
example: Hello, developer!
|
|
143
|
+
/items:
|
|
144
|
+
get:
|
|
145
|
+
operationId: listItems
|
|
146
|
+
summary: List items
|
|
147
|
+
responses:
|
|
148
|
+
"200":
|
|
149
|
+
description: All items.
|
|
150
|
+
content:
|
|
151
|
+
application/json:
|
|
152
|
+
schema:
|
|
153
|
+
type: array
|
|
154
|
+
items:
|
|
155
|
+
$ref: "#/components/schemas/Item"
|
|
156
|
+
/items/{id}:
|
|
157
|
+
get:
|
|
158
|
+
operationId: getItem
|
|
159
|
+
summary: Get one item
|
|
160
|
+
parameters:
|
|
161
|
+
- name: id
|
|
162
|
+
in: path
|
|
163
|
+
required: true
|
|
164
|
+
schema:
|
|
165
|
+
type: string
|
|
166
|
+
example: "1"
|
|
167
|
+
responses:
|
|
168
|
+
"200":
|
|
169
|
+
description: The item.
|
|
170
|
+
content:
|
|
171
|
+
application/json:
|
|
172
|
+
schema:
|
|
173
|
+
$ref: "#/components/schemas/Item"
|
|
174
|
+
"404":
|
|
175
|
+
description: No item has this id.
|
|
176
|
+
components:
|
|
177
|
+
schemas:
|
|
178
|
+
Item:
|
|
179
|
+
type: object
|
|
180
|
+
properties:
|
|
181
|
+
id:
|
|
182
|
+
type: string
|
|
183
|
+
example: "1"
|
|
184
|
+
name:
|
|
185
|
+
type: string
|
|
186
|
+
example: First item
|
|
187
|
+
`;
|