@platformatic/composer 3.4.1 → 3.5.1

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 (46) hide show
  1. package/LICENSE +1 -1
  2. package/config.d.ts +482 -131
  3. package/eslint.config.js +4 -2
  4. package/index.d.ts +1 -17
  5. package/index.js +9 -210
  6. package/package.json +18 -59
  7. package/schema.json +2121 -843
  8. package/scripts/schema.js +12 -0
  9. package/.c8rc +0 -6
  10. package/composer.mjs +0 -54
  11. package/help/create.txt +0 -11
  12. package/help/help.txt +0 -7
  13. package/help/openapi schemas fetch.txt +0 -9
  14. package/help/start.txt +0 -54
  15. package/index.test-d.ts +0 -23
  16. package/lib/composer-hook.js +0 -60
  17. package/lib/create.mjs +0 -84
  18. package/lib/errors.js +0 -13
  19. package/lib/generator/README.md +0 -30
  20. package/lib/generator/composer-generator.d.ts +0 -11
  21. package/lib/generator/composer-generator.js +0 -128
  22. package/lib/graphql-fetch.js +0 -85
  23. package/lib/graphql-generator.js +0 -31
  24. package/lib/graphql.js +0 -20
  25. package/lib/openapi-composer.js +0 -81
  26. package/lib/openapi-config-schema.js +0 -93
  27. package/lib/openapi-fetch-schemas.mjs +0 -61
  28. package/lib/openapi-generator.js +0 -167
  29. package/lib/openapi-load-config.js +0 -31
  30. package/lib/openapi-modifier.js +0 -137
  31. package/lib/openapi.js +0 -49
  32. package/lib/proxy.js +0 -161
  33. package/lib/root-endpoint/index.js +0 -28
  34. package/lib/root-endpoint/public/images/dark_mode.svg +0 -3
  35. package/lib/root-endpoint/public/images/favicon.ico +0 -0
  36. package/lib/root-endpoint/public/images/light_mode.svg +0 -11
  37. package/lib/root-endpoint/public/images/platformatic-logo-dark.svg +0 -30
  38. package/lib/root-endpoint/public/images/platformatic-logo-light.svg +0 -30
  39. package/lib/root-endpoint/public/images/triangle_dark.svg +0 -3
  40. package/lib/root-endpoint/public/images/triangle_light.svg +0 -3
  41. package/lib/root-endpoint/public/index.html +0 -237
  42. package/lib/schema.js +0 -210
  43. package/lib/stackable.js +0 -59
  44. package/lib/upgrade.js +0 -22
  45. package/lib/utils.js +0 -27
  46. package/lib/versions/2.0.0.js +0 -11
package/lib/proxy.js DELETED
@@ -1,161 +0,0 @@
1
- 'use strict'
2
-
3
- const { getGlobalDispatcher } = require('undici')
4
- const httpProxy = require('@fastify/http-proxy')
5
- const fp = require('fastify-plugin')
6
-
7
- const kITC = Symbol.for('plt.runtime.itc')
8
-
9
- async function resolveServiceProxyParameters (service) {
10
- // Get meta information from the service, if any, to eventually hook up to a TCP port
11
- const meta = (await globalThis[kITC]?.send('getServiceMeta', service.id))?.composer ?? { prefix: service.id }
12
- const origin = meta.tcp ? meta.url : service.origin
13
-
14
- // If no prefix could be found, assume the service id
15
- const prefix = (service.proxy?.prefix ?? meta.prefix ?? service.id).replace(/(\/$)/g, '')
16
-
17
- let rewritePrefix = ''
18
- let internalRewriteLocationHeader = true
19
-
20
- if (meta.wantsAbsoluteUrls) {
21
- // The rewritePrefix purposely ignores service.proxy?.prefix to let
22
- // the service always being able to configure their value
23
- rewritePrefix = meta.prefix ?? service.id
24
- internalRewriteLocationHeader = false
25
- }
26
-
27
- return { origin, prefix, rewritePrefix, internalRewriteLocationHeader, needsRootRedirect: meta.needsRootRedirect }
28
- }
29
-
30
- module.exports = fp(async function (app, opts) {
31
- const meta = { proxies: {} }
32
-
33
- for (const service of opts.services) {
34
- if (!service.proxy) {
35
- // When a service defines no expose config at all
36
- // we assume a proxy exposed with a prefix equals to its id or meta.prefix
37
- if (service.proxy === false || service.openapi || service.graphql) {
38
- continue
39
- }
40
- }
41
-
42
- const parameters = await resolveServiceProxyParameters(service)
43
- const { prefix, origin, rewritePrefix, internalRewriteLocationHeader, needsRootRedirect } = parameters
44
- meta.proxies[service.id] = parameters
45
-
46
- const basePath = `/${prefix ?? ''}`.replaceAll(/\/+/g, '/').replace(/\/$/, '')
47
- const dispatcher = getGlobalDispatcher()
48
-
49
- if (needsRootRedirect) {
50
- app.addHook('preHandler', (req, reply, done) => {
51
- if (req.url === basePath) {
52
- app.inject(
53
- {
54
- method: req.method,
55
- url: `${basePath}/`,
56
- headers: req.headers,
57
- payload: req.body
58
- },
59
- (err, result) => {
60
- if (err) {
61
- done(err)
62
- return
63
- }
64
-
65
- const replyHeaders = result.headers
66
- delete replyHeaders['content-length']
67
- delete replyHeaders['transfer-encoding']
68
-
69
- reply.code(result.statusCode).headers(replyHeaders).send(result.rawPayload)
70
- done()
71
- }
72
- )
73
- } else {
74
- done()
75
- }
76
- })
77
- }
78
- /*
79
- Some frontends, like Astro (https://github.com/withastro/astro/issues/11445)
80
- generate invalid paths in development mode which ignore the basePath.
81
- In that case we try to properly redirect the browser by trying to understand the prefix
82
- from the Referer header.
83
- */
84
- app.addHook('preHandler', (req, reply, done) => {
85
- // If the URL is already targeted to the service, do nothing
86
- if (req.url.startsWith(basePath)) {
87
- done()
88
- return
89
- }
90
-
91
- // Use the referer to understand the desired intent
92
- const referer = req.headers.referer
93
-
94
- if (!referer) {
95
- done()
96
- return
97
- }
98
-
99
- const path = new URL(referer).pathname
100
-
101
- // If we have a match redirect
102
- if (path.startsWith(basePath)) {
103
- reply.redirect(`${basePath}${req.url}`, 308)
104
- }
105
-
106
- done()
107
- })
108
-
109
- // Do not show proxied services in Swagger
110
- if (!service.openapi) {
111
- app.addHook('onRoute', routeOptions => {
112
- if (routeOptions.url.startsWith(basePath)) {
113
- routeOptions.schema ??= {}
114
- routeOptions.schema.hide = true
115
- }
116
- })
117
- }
118
-
119
- await app.register(httpProxy, {
120
- prefix,
121
- rewritePrefix,
122
- upstream: origin,
123
- websocket: true,
124
- undici: dispatcher,
125
- destroyAgent: false,
126
- internalRewriteLocationHeader,
127
- replyOptions: {
128
- rewriteRequestHeaders: (request, headers) => {
129
- const targetUrl = `${origin}${request.url}`
130
- const context = request.span?.context
131
- const { span, telemetryHeaders } = app.openTelemetry?.startHTTPSpanClient(
132
- targetUrl,
133
- request.method,
134
- context
135
- ) || { span: null, telemetryHeaders: {} }
136
- // We need to store the span in a different object
137
- // to correctly close it in the onResponse hook
138
- // Note that we have 2 spans:
139
- // - request.span: the span of the request to the proxy
140
- // - request.proxedCallSpan: the span of the request to the proxied service
141
- request.proxedCallSpan = span
142
-
143
- headers = {
144
- ...headers,
145
- ...telemetryHeaders,
146
- 'x-forwarded-for': request.ip,
147
- 'x-forwarded-host': request.host
148
- }
149
-
150
- return headers
151
- },
152
- onResponse: (request, reply, res) => {
153
- app.openTelemetry?.endHTTPSpanClient(reply.request.proxedCallSpan, { statusCode: reply.statusCode })
154
- reply.send(res.stream)
155
- }
156
- }
157
- })
158
- }
159
-
160
- opts.context?.stackable?.registerMeta(meta)
161
- })
@@ -1,28 +0,0 @@
1
- 'use strict'
2
-
3
- const { join } = require('node:path')
4
- const fastifyStatic = require('@fastify/static')
5
- const userAgentParser = require('my-ua-parser')
6
-
7
- module.exports = async (app, opts) => {
8
- app.register(fastifyStatic, {
9
- root: join(__dirname, 'public'),
10
- })
11
-
12
- // root endpoint
13
- app.route({
14
- method: 'GET',
15
- path: '/',
16
- schema: { hide: true },
17
- handler: (req, reply) => {
18
- const uaString = req.headers['user-agent']
19
- if (uaString) {
20
- const parsed = userAgentParser(uaString)
21
- if (parsed.browser.name !== undefined) {
22
- return reply.sendFile('./index.html')
23
- }
24
- }
25
- return { message: 'Welcome to Platformatic! Please visit https://docs.platformatic.dev' }
26
- },
27
- })
28
- }
@@ -1,3 +0,0 @@
1
- <svg width="40" height="40" viewBox="0 0 40 40" fill="none" xmlns="http://www.w3.org/2000/svg">
2
- <path d="M5.38034 22.9538C3.01077 12.1815 12.2916 6.49615 17.2282 5C14.7599 8.49103 11.3043 16.9692 17.2282 22.9538C23.1521 28.9385 31.5444 25.4474 35 22.9538C33.8152 32.5292 25.6205 34.9231 21.6712 34.9231C17.2282 35.4218 7.74991 33.7262 5.38034 22.9538Z" stroke="#00283D" stroke-width="2" stroke-linejoin="round"/>
3
- </svg>
@@ -1,11 +0,0 @@
1
- <svg width="40" height="40" viewBox="0 0 40 40" fill="none" xmlns="http://www.w3.org/2000/svg">
2
- <path d="M26 13L31 8" stroke="white" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
3
- <path d="M9 8L14 13" stroke="white" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
4
- <path d="M14 28L9 33" stroke="white" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
5
- <path d="M31 33L26 28" stroke="white" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
6
- <path d="M10.0713 20L5 20" stroke="white" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
7
- <circle cx="20.0713" cy="20" r="6" stroke="white" stroke-width="2"/>
8
- <path d="M30.0712 20.0001L35 20" stroke="white" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
9
- <path d="M20 29.9287L20 34.9999" stroke="white" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
10
- <path d="M20.0001 9.92876L20 4.99999" stroke="white" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
11
- </svg>
@@ -1,30 +0,0 @@
1
- <?xml version="1.0" encoding="UTF-8"?>
2
- <svg id="Logo" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 568.18 568.18">
3
- <defs>
4
- <style>
5
- .cls-1 {
6
- stroke: #00fe84;
7
- }
8
-
9
- .cls-1, .cls-2 {
10
- fill: none;
11
- stroke-linecap: round;
12
- stroke-linejoin: round;
13
- stroke-width: 16.34px;
14
- }
15
-
16
- .cls-2 {
17
- stroke: #fff;
18
- }
19
- </style>
20
- </defs>
21
- <g>
22
- <line class="cls-1" x1="148.26" y1="317.46" x2="148.26" y2="389.92"/>
23
- <polyline class="cls-1" points="176.75 303.19 234.68 336.63 321.11 286.74 321.11 186.94 234.68 137.04 148.26 186.94 148.26 273.55"/>
24
- <polyline class="cls-1" points="176.75 334.87 176.75 303.19 205.15 285.91"/>
25
- </g>
26
- <polyline class="cls-2" points="466.14 259.75 501.19 280.47 501.19 301.18 466.14 321.89"/>
27
- <polyline class="cls-2" points="106.23 210.58 66.98 233.24 66.98 334.38 105.4 356.56"/>
28
- <polyline class="cls-2" points="176.75 376.88 176.75 399.34 234.33 431.14 278.53 405.35 278.17 358.41"/>
29
- <polyline class="cls-2" points="321.66 332.06 321.66 356.76 363.05 380.98 423.55 344.88 423.55 246.39 364.01 212.25"/>
30
- </svg>
@@ -1,30 +0,0 @@
1
- <?xml version="1.0" encoding="UTF-8"?>
2
- <svg id="Logo" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 568.18 568.18">
3
- <defs>
4
- <style>
5
- .cls-1 {
6
- stroke: #00050b;
7
- }
8
-
9
- .cls-1, .cls-2 {
10
- fill: none;
11
- stroke-linecap: round;
12
- stroke-linejoin: round;
13
- stroke-width: 16.73px;
14
- }
15
-
16
- .cls-2 {
17
- stroke: #00fe84;
18
- }
19
- </style>
20
- </defs>
21
- <g>
22
- <line class="cls-2" x1="144.97" y1="318.27" x2="144.97" y2="392.48"/>
23
- <polyline class="cls-2" points="174.15 303.65 233.49 337.91 322.01 286.8 322.01 184.58 233.49 133.48 144.97 184.58 144.97 273.29"/>
24
- <polyline class="cls-2" points="174.15 336.1 174.15 303.66 203.24 285.96"/>
25
- </g>
26
- <polyline class="cls-1" points="470.56 259.16 506.46 280.38 506.46 301.59 470.56 322.81"/>
27
- <polyline class="cls-1" points="101.92 208.8 61.72 232.01 61.72 335.6 101.07 358.32"/>
28
- <polyline class="cls-1" points="174.15 379.13 174.15 402.14 233.12 434.7 278.4 408.29 278.03 360.22"/>
29
- <polyline class="cls-1" points="322.57 333.23 322.57 358.53 364.96 383.33 426.93 346.35 426.93 245.48 365.94 210.51"/>
30
- </svg>
@@ -1,3 +0,0 @@
1
- <svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg" class="svg">
2
- <path d="M2.34277 4.5L0.17771 0.75L4.50784 0.75L2.34277 4.5Z" fill="#00050B" />
3
- </svg>
@@ -1,3 +0,0 @@
1
- <svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg" class="svg">
2
- <path d="M2.34277 4.5L0.17771 0.75L4.50784 0.75L2.34277 4.5Z" fill="white" />
3
- </svg>
@@ -1,237 +0,0 @@
1
- <!DOCTYPE html>
2
- <html lang="en">
3
- <head>
4
- <meta charset="UTF-8" />
5
- <link rel="icon" type="image/svg+xml" href="./images/favicon.ico" />
6
- <link href="https://fonts.googleapis.com/css2?family=Inter:wght@100;200;300;400;500;600;700;800&display=swap" rel="stylesheet">
7
- <meta name="viewport" content="width=device-width, initial-scale=1.0" />
8
- <title>Platformatic Composer</title>
9
- <style>
10
- body {
11
- width: 100%;
12
- height: 100vh;
13
- overflow-y: auto;
14
- overflow-x: hidden;
15
- --secondary-color: #FFFFFF;
16
- --primary-color: #00050B;
17
- --primary-color-rgb: 0, 5, 11;
18
- --secondary-color-rgb: 255, 255, 255;
19
- --theme-img: url('./images/light_mode.svg');
20
- --triangle-url: url('./images/triangle_light.svg');
21
- }
22
-
23
- body.light-theme {
24
- --secondary-color: #001825;
25
- --primary-color: #FFFFFF;
26
- --secondary-color-rgb: 0, 5, 11;
27
- --primary-color-rgb: 255, 255, 255;
28
- --theme-img: url('./images/dark_mode.svg');
29
- --triangle-url: url('./images/triangle_dark.svg');
30
- }
31
-
32
- body {
33
- background: var(--primary-color);
34
- }
35
-
36
- :root {
37
- font-family: Montserrat, Inter, Avenir, Helvetica, Arial, sans-serif;
38
- font-size: 16px;
39
- line-height: 24px;
40
- font-weight: 400;
41
-
42
- color-scheme: light dark;
43
- color: inherit;
44
-
45
- position: relative;
46
- font-synthesis: none;
47
- text-rendering: optimizeLegibility;
48
- -webkit-font-smoothing: antialiased;
49
- -moz-osx-font-smoothing: grayscale;
50
- -webkit-text-size-adjust: 100%;
51
- }
52
-
53
-
54
- a {
55
- font-weight: 600;
56
- color: var(--secondary-color);
57
- text-decoration: inherit;
58
- width: 100%;
59
- text-align: center;
60
- padding: 4px 0px;
61
- }
62
- a:hover {
63
- background-color: rgba(var(--secondary-color-rgb), 0.3);
64
- }
65
-
66
- .text-opacque {
67
- opacity: 0.7;
68
- }
69
- .text-center {
70
- text-align: center;
71
- }
72
-
73
- .button-container {
74
- display: flex;
75
- column-gap: 0.5rem;
76
- justify-content: center;
77
- align-items: start;
78
- margin: 2rem 0;
79
- }
80
-
81
- .buttons-list-container {
82
- display: flex;
83
- flex-direction: column;
84
- row-gap: 1rem;
85
- justify-content: center;
86
- align-items: start;
87
- }
88
-
89
- .button-link {
90
- width: 246px;
91
- border: 1px solid var(--secondary-color);
92
- border-radius: 4px;
93
- padding: 8px 16px;
94
- cursor: pointer;
95
- }
96
-
97
- button {
98
- border-radius: 8px;
99
- border: 1px solid transparent;
100
- padding: 0.6em 1.2em;
101
- font-size: 1em;
102
- font-weight: 500;
103
- font-family: inherit;
104
- background-color: #1a1a1a;
105
- cursor: pointer;
106
- transition: border-color 0.25s;
107
- }
108
- button:hover {
109
- border-color: #646cff;
110
- }
111
- button:focus,
112
- button:focus-visible {
113
- outline: 4px auto -webkit-focus-ring-color;
114
- }
115
-
116
- #root {
117
- width: 100%;
118
- min-height: inherit;
119
- height: 100%;
120
- display: flex;
121
- position: relative;
122
- z-index: 20;
123
- }
124
-
125
- #content {
126
- display: flex;
127
- flex-direction: column;
128
- align-items: center;
129
- justify-content: center;
130
- margin: auto;
131
- position: relative;
132
- z-index: 20;
133
- color: var(--secondary-color);
134
- }
135
-
136
- .plt-triangle-container {
137
- position: absolute;
138
- top: 0;
139
- right: 0;
140
- width: 25%;
141
- height: 50vH;
142
- z-index: -1;
143
- content: '';
144
- background: var(--triangle-url) repeat;
145
- opacity: 0.25;
146
- }
147
-
148
- .plt-triangle-content-opacque {
149
- position: absolute;
150
- height: 100%;
151
- width: 100%;
152
- top: 0;
153
- left: 0;
154
- content: '';
155
- background: linear-gradient(to top, rgba(var(--primary-color-rgb), 1), rgba(var(--primary-color-rgb), 0.2) 43%);
156
- }
157
-
158
- #button-theme-selector {
159
- border: none;
160
- position: absolute;
161
- top: 2rem;
162
- right: 3rem;
163
- width: 40px;
164
- height: 40px;
165
- background: var(--theme-img);
166
- outline: none;
167
- z-index: 1;
168
- }
169
-
170
- .text-desktop-display {
171
- font-family: Inter;
172
- font-size: 4rem;
173
- font-weight: 600;
174
- line-height: 5rem;
175
- text-align: center;
176
- }
177
-
178
- .text-desktop-body-large {
179
- font-family: Inter;
180
- font-size: 1.125rem;
181
- font-weight: 300;
182
- line-height: 1.688rem;
183
- text-align: center;
184
- }
185
-
186
- </style>
187
- </head>
188
- <body>
189
- <div id="root">
190
- <div class="plt-triangle-container"><div class="plt-triangle-content-opacque"></div></div>
191
- <button id="button-theme-selector" type="button" class="theme-selector" alt="theme selector" onclick="toggleLightMode()"></button>
192
-
193
- <div id="content">
194
- <img id="logo" height="256" />
195
- <p class="text-desktop-display"><span>Welcome to</span><br/><span class="text-main-green">Platformatic Composer</span></p>
196
- <p class="text-desktop-body-large">Explore our flexible toolkit for building robust APIs.</p>
197
- <div class="button-container">
198
- <a href="https://docs.platformatic.dev" target="_blank" class="button-link">Documentation</a>
199
- <a id="openapi-link" target="_blank" class="button-link">OpenAPI Documentation</a>
200
- <a id="graphql-link" target="_blank" class="button-link">GraphiQL</a>
201
- </div>
202
- </div>
203
- </div>
204
-
205
- <script>
206
- let currentPath = window.location.pathname
207
-
208
- if (!currentPath.endsWith('/')) {
209
- currentPath += '/'
210
- }
211
-
212
- const openApiLink = document.getElementById('openapi-link')
213
- openApiLink.href = currentPath + 'documentation'
214
-
215
- const graphqlLink = document.getElementById('graphql-link')
216
- graphqlLink.href = currentPath + 'graphiql'
217
-
218
- const prefersLightScheme = window.matchMedia('(prefers-color-scheme: light)');
219
- if (prefersLightScheme.matches) {
220
- document.body.classList.add('light-theme');
221
- document.getElementById('logo').src = currentPath + 'images/platformatic-logo-light.svg'
222
- } else {
223
- document.body.classList.remove('light-theme');
224
- document.getElementById('logo').src = currentPath + 'images/platformatic-logo-dark.svg'
225
- }
226
-
227
- const toggleLightMode = function() {
228
- document.body.classList.toggle('light-theme');
229
- if (document.body.classList.contains('light-theme')) {
230
- document.getElementById('logo').src = currentPath + 'images/platformatic-logo-light.svg'
231
- } else {
232
- document.getElementById('logo').src = currentPath + 'images/platformatic-logo-dark.svg'
233
- }
234
- }
235
- </script>
236
- </body>
237
- </html>