@platformatic/composer 2.40.0 → 2.41.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/index.js CHANGED
@@ -6,10 +6,9 @@ const { platformaticService, buildServer, buildStackable } = require('@platforma
6
6
 
7
7
  const { schema } = require('./lib/schema')
8
8
  const serviceProxy = require('./lib/proxy')
9
- const openapi = require('./lib/openapi.js')
10
9
  const graphql = require('./lib/graphql')
11
10
  const composerHook = require('./lib/composer-hook')
12
- const openapiGenerator = require('./lib/openapi-generator')
11
+ const { openApiGenerator, openApiComposer } = require('./lib/openapi-generator')
13
12
  const graphqlGenerator = require('./lib/graphql-generator')
14
13
  const { isSameGraphqlSchema, fetchGraphqlSubgraphs } = require('./lib/graphql-fetch')
15
14
  const notHostConstraints = require('./lib/proxy/not-host-constraints')
@@ -42,15 +41,18 @@ async function platformaticComposer (app, opts) {
42
41
  }
43
42
  }
44
43
 
44
+ await app.register(composerHook)
45
+
46
+ let generatedComposedOpenAPI = null
45
47
  if (hasOpenapiServices) {
46
- app.register(openapi, config.composer)
48
+ generatedComposedOpenAPI = await openApiGenerator(app, config.composer)
47
49
  }
50
+
48
51
  app.register(serviceProxy, { ...config.composer, context: opts.context })
49
- app.register(composerHook)
50
- await app.register(platformaticService, { config, context: opts.context })
52
+ await app.register(platformaticService, { config: { ...config, openapi: false }, context: opts.context })
51
53
 
52
- if (hasOpenapiServices) {
53
- await app.register(openapiGenerator, config.composer)
54
+ if (generatedComposedOpenAPI) {
55
+ await app.register(openApiComposer, { opts: config.composer, generated: generatedComposedOpenAPI })
54
56
  }
55
57
 
56
58
  if (hasGraphqlServices) {
@@ -6,6 +6,7 @@ const errors = require('./errors')
6
6
  function composeOpenApi (apis, options = {}) {
7
7
  const mergedPaths = {}
8
8
  const mergedSchemas = {}
9
+ const mergedSecuritySchemes = {}
9
10
 
10
11
  for (const { id, prefix, schema } of apis) {
11
12
  const { paths, components } = clone(schema)
@@ -15,6 +16,18 @@ function composeOpenApi (apis, options = {}) {
15
16
  namespaceSchemaRefs(apiPrefix, pathSchema)
16
17
  namespaceSchemaOperationIds(apiPrefix, pathSchema)
17
18
 
19
+ for (const methodSchema of Object.values(pathSchema)) {
20
+ if (methodSchema.security) {
21
+ methodSchema.security = methodSchema.security.map(security => {
22
+ const newSecurity = {}
23
+ for (const [securityKey, securityValue] of Object.entries(security)) {
24
+ newSecurity[apiPrefix + securityKey] = securityValue
25
+ }
26
+ return newSecurity
27
+ })
28
+ }
29
+ }
30
+
18
31
  const mergedPath = prefix ? prefix + path : path
19
32
 
20
33
  if (mergedPaths[mergedPath]) {
@@ -23,13 +36,21 @@ function composeOpenApi (apis, options = {}) {
23
36
  mergedPaths[mergedPath] = pathSchema
24
37
  }
25
38
 
26
- if (components && components.schemas) {
27
- for (const [schemaKey, schema] of Object.entries(components.schemas)) {
28
- if (schema.title == null) {
29
- schema.title = schemaKey
39
+ if (components) {
40
+ if (components.schemas) {
41
+ for (const [schemaKey, schema] of Object.entries(components.schemas)) {
42
+ if (schema.title == null) {
43
+ schema.title = schemaKey
44
+ }
45
+ namespaceSchemaRefs(apiPrefix, schema)
46
+ mergedSchemas[apiPrefix + schemaKey] = schema
47
+ }
48
+ }
49
+
50
+ if (components.securitySchemes) {
51
+ for (const [securitySchemeKey, securityScheme] of Object.entries(components.securitySchemes)) {
52
+ mergedSecuritySchemes[apiPrefix + securitySchemeKey] = securityScheme
30
53
  }
31
- namespaceSchemaRefs(apiPrefix, schema)
32
- mergedSchemas[apiPrefix + schemaKey] = schema
33
54
  }
34
55
  }
35
56
  }
@@ -41,6 +62,7 @@ function composeOpenApi (apis, options = {}) {
41
62
  version: options.version || '1.0.0',
42
63
  },
43
64
  components: {
65
+ securitySchemes: mergedSecuritySchemes,
44
66
  schemas: mergedSchemas,
45
67
  },
46
68
  paths: mergedPaths,
@@ -3,12 +3,14 @@
3
3
  const { readFile } = require('node:fs/promises')
4
4
  const { request, getGlobalDispatcher } = require('undici')
5
5
  const fp = require('fastify-plugin')
6
- const errors = require('./errors')
6
+ const fastifySwagger = require('@fastify/swagger')
7
7
 
8
+ const errors = require('./errors')
8
9
  const { modifyOpenApiSchema, originPathSymbol } = require('./openapi-modifier')
9
10
  const composeOpenApi = require('./openapi-composer')
10
11
  const loadOpenApiConfig = require('./openapi-load-config.js')
11
12
  const { prefixWithSlash } = require('./utils.js')
13
+ const openApiScalar = require('./openapi-scalar')
12
14
 
13
15
  async function fetchOpenApiSchema (openApiUrl) {
14
16
  const { body } = await request(openApiUrl)
@@ -29,7 +31,7 @@ async function getOpenApiSchema (origin, openapi) {
29
31
  return readOpenApiSchema(openapi.file)
30
32
  }
31
33
 
32
- async function composeOpenAPI (app, opts) {
34
+ async function generateComposedOpenApi (app, opts) {
33
35
  if (!opts.services.some(s => s.openapi)) { return }
34
36
 
35
37
  const { services } = opts
@@ -72,9 +74,46 @@ async function composeOpenAPI (app, opts) {
72
74
  openApiSchemas.push({ id, prefix, schema, originSchema, config: openapiConfig })
73
75
  }
74
76
 
77
+ const composedOpenApiSchema = composeOpenApi(openApiSchemas, opts.openapi)
78
+
75
79
  app.decorate('openApiSchemas', openApiSchemas)
80
+ app.decorate('composedOpenApiSchema', composedOpenApiSchema)
81
+
82
+ await app.register(fastifySwagger, {
83
+ exposeRoute: true,
84
+ openapi: {
85
+ info: {
86
+ title: opts.openapi?.title || 'Platformatic Composer',
87
+ version: opts.openapi?.version || '1.0.0'
88
+ },
89
+ servers: [{ url: globalThis.platformatic?.runtimeBasePath ?? '/' }],
90
+ components: app.composedOpenApiSchema.components
91
+ },
92
+ transform ({ schema, url }) {
93
+ for (const service of opts.services) {
94
+ if (!service.proxy) continue
95
+
96
+ const prefix = service.proxy.prefix ?? ''
97
+ const proxyPrefix = prefix.at(-1) === '/' ? prefix.slice(0, -1) : prefix
98
+
99
+ const proxyUrls = [proxyPrefix + '/', proxyPrefix + '/*']
100
+ if (proxyUrls.includes(url)) {
101
+ schema = schema ?? {}
102
+ schema.hide = true
103
+ break
104
+ }
105
+ }
106
+ return { schema, url }
107
+ }
108
+ })
76
109
 
77
- const composedOpenApiSchema = composeOpenApi(openApiSchemas, opts.openapi)
110
+ await app.register(openApiScalar, opts)
111
+
112
+ return { apiByApiRoutes }
113
+ }
114
+
115
+ async function openApiComposer (app, { opts, generated }) {
116
+ const { apiByApiRoutes } = generated
78
117
 
79
118
  const dispatcher = getGlobalDispatcher()
80
119
 
@@ -84,7 +123,7 @@ async function composeOpenAPI (app, opts) {
84
123
  })
85
124
 
86
125
  await app.register(await import('@platformatic/fastify-openapi-glue'), {
87
- specification: composedOpenApiSchema,
126
+ specification: app.composedOpenApiSchema,
88
127
  addEmptySchema: opts.addEmptySchema,
89
128
  operationResolver: (operationId, method, openApiPath) => {
90
129
  const { origin, prefix, schema } = apiByApiRoutes[openApiPath]
@@ -167,4 +206,5 @@ function generateRenamedPath (renamedOpenApiPath, routeParams) {
167
206
  return renamedOpenApiPath.replace(/{(.*?)}/g, () => routeParams.shift())
168
207
  }
169
208
 
170
- module.exports = fp(composeOpenAPI)
209
+ module.exports.openApiGenerator = generateComposedOpenApi
210
+ module.exports.openApiComposer = fp(openApiComposer)
@@ -0,0 +1,23 @@
1
+ 'use strict'
2
+
3
+ const fp = require('fastify-plugin')
4
+
5
+ async function openApiScalar (app, opts) {
6
+ const { default: scalarTheme } = await import('@platformatic/scalar-theme')
7
+
8
+ /** Serve spec file in yaml and json */
9
+ app.get('/documentation/json', { schema: { hide: true } }, async () => app.swagger())
10
+ app.get('/documentation/yaml', { schema: { hide: true } }, async () => app.swagger({ yaml: true }))
11
+
12
+ const routePrefix = opts.openapi?.swaggerPrefix || '/documentation'
13
+
14
+ await app.register(require('@scalar/fastify-api-reference'), {
15
+ logLevel: 'warn',
16
+ routePrefix,
17
+ configuration: {
18
+ customCss: scalarTheme.theme
19
+ }
20
+ })
21
+ }
22
+
23
+ module.exports = fp(openApiScalar)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@platformatic/composer",
3
- "version": "2.40.0",
3
+ "version": "2.41.0",
4
4
  "description": "",
5
5
  "main": "index.js",
6
6
  "bin": {
@@ -31,9 +31,9 @@
31
31
  "typescript": "^5.5.4",
32
32
  "why-is-node-running": "2",
33
33
  "ws": "^8.16.0",
34
- "@platformatic/client": "2.40.0",
35
- "@platformatic/config": "2.40.0",
36
- "@platformatic/db": "2.40.0"
34
+ "@platformatic/client": "2.41.0",
35
+ "@platformatic/config": "2.41.0",
36
+ "@platformatic/db": "2.41.0"
37
37
  },
38
38
  "dependencies": {
39
39
  "@fastify/error": "^4.0.0",
@@ -42,7 +42,7 @@
42
42
  "@fastify/static": "^8.0.0",
43
43
  "@fastify/swagger": "^9.0.0",
44
44
  "@fastify/view": "^10.0.1",
45
- "@platformatic/fastify-openapi-glue": "^5.0.0",
45
+ "@platformatic/fastify-openapi-glue": "^5.1.0",
46
46
  "@platformatic/graphql-composer": "^0.10.0",
47
47
  "@scalar/fastify-api-reference": "^1.19.5",
48
48
  "ajv": "^8.12.0",
@@ -67,12 +67,12 @@
67
67
  "rfdc": "^1.3.1",
68
68
  "semgrator": "^0.3.0",
69
69
  "undici": "^7.0.0",
70
- "@platformatic/config": "2.40.0",
71
- "@platformatic/generators": "2.40.0",
72
- "@platformatic/scalar-theme": "2.40.0",
73
- "@platformatic/service": "2.40.0",
74
- "@platformatic/telemetry": "2.40.0",
75
- "@platformatic/utils": "^2.40.0"
70
+ "@platformatic/config": "2.41.0",
71
+ "@platformatic/scalar-theme": "2.41.0",
72
+ "@platformatic/generators": "2.41.0",
73
+ "@platformatic/utils": "^2.41.0",
74
+ "@platformatic/telemetry": "2.41.0",
75
+ "@platformatic/service": "2.41.0"
76
76
  },
77
77
  "scripts": {
78
78
  "test": "pnpm run lint && borp -T --timeout=300000 -c 1 && tsd",
package/schema.json CHANGED
@@ -1,5 +1,5 @@
1
1
  {
2
- "$id": "https://schemas.platformatic.dev/@platformatic/composer/2.40.0.json",
2
+ "$id": "https://schemas.platformatic.dev/@platformatic/composer/2.41.0.json",
3
3
  "$schema": "http://json-schema.org/draft-07/schema#",
4
4
  "title": "Platformatic Composer",
5
5
  "type": "object",
package/lib/openapi.js DELETED
@@ -1,50 +0,0 @@
1
- 'use strict'
2
-
3
- const fp = require('fastify-plugin')
4
-
5
- async function composeOpenAPI (app, opts) {
6
- await app.register(require('@fastify/swagger'), {
7
- exposeRoute: true,
8
- openapi: {
9
- info: {
10
- title: opts.openapi?.title || 'Platformatic Composer',
11
- version: opts.openapi?.version || '1.0.0'
12
- },
13
- servers: [{ url: globalThis.platformatic?.runtimeBasePath ?? '/' }],
14
- },
15
- transform: ({ schema, url }) => {
16
- for (const service of opts.services) {
17
- if (!service.proxy) continue
18
-
19
- const prefix = service.proxy.prefix ?? ''
20
- const proxyPrefix = prefix.at(-1) === '/' ? prefix.slice(0, -1) : prefix
21
-
22
- const proxyUrls = [proxyPrefix + '/', proxyPrefix + '/*']
23
- if (proxyUrls.includes(url)) {
24
- schema = schema ?? {}
25
- schema.hide = true
26
- break
27
- }
28
- }
29
- return { schema, url }
30
- }
31
- })
32
-
33
- const { default: scalarTheme } = await import('@platformatic/scalar-theme')
34
-
35
- /** Serve spec file in yaml and json */
36
- app.get('/documentation/json', { schema: { hide: true } }, async () => app.swagger())
37
- app.get('/documentation/yaml', { schema: { hide: true } }, async () => app.swagger({ yaml: true }))
38
-
39
- const routePrefix = opts.openapi?.swaggerPrefix || '/documentation'
40
-
41
- await app.register(require('@scalar/fastify-api-reference'), {
42
- logLevel: 'warn',
43
- routePrefix,
44
- configuration: {
45
- customCss: scalarTheme.theme
46
- }
47
- })
48
- }
49
-
50
- module.exports = fp(composeOpenAPI)