@platformatic/composer 3.0.0-alpha.1 → 3.0.0-alpha.2

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/config.d.ts CHANGED
@@ -377,17 +377,7 @@ export interface PlatformaticComposerConfig {
377
377
  plugins?: {
378
378
  [k: string]: unknown;
379
379
  };
380
- clients?: {
381
- serviceId?: string;
382
- name?: string;
383
- type?: "openapi" | "graphql";
384
- path?: string;
385
- schema?: string;
386
- url?: string;
387
- fullResponse?: boolean;
388
- fullRequest?: boolean;
389
- validateResponse?: boolean;
390
- }[];
380
+ application?: {};
391
381
  runtime?: {
392
382
  preload?: string | string[];
393
383
  basePath?: string;
package/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import { resolve, validationOptions } from '@platformatic/basic'
2
+ import { kMetadata, loadConfiguration as utilsLoadConfiguration } from '@platformatic/foundation'
2
3
  import { transform } from '@platformatic/service'
3
- import { kMetadata, loadConfiguration as utilsLoadConfiguration } from '@platformatic/utils'
4
4
  import { schema } from './lib/schema.js'
5
5
  import { ComposerStackable } from './lib/stackable.js'
6
6
  import { upgrade } from './lib/upgrade.js'
@@ -1,5 +1,5 @@
1
+ import { isKeyEnabled } from '@platformatic/foundation'
1
2
  import { platformaticService } from '@platformatic/service'
2
- import { isKeyEnabled } from '@platformatic/utils'
3
3
  import deepEqual from 'fast-deep-equal'
4
4
  import { fetchOpenApiSchema } from './commands/openapi-fetch-schemas.js'
5
5
  import { composerHook } from './composer-hook.js'
@@ -1,4 +1,4 @@
1
- import { loadConfiguration } from '@platformatic/utils'
1
+ import { loadConfiguration } from '@platformatic/foundation'
2
2
  import { writeFile } from 'node:fs/promises'
3
3
  import { request } from 'undici'
4
4
  import { FailedToFetchOpenAPISchemaError } from '../errors.js'
package/lib/generator.js CHANGED
@@ -1,16 +1,16 @@
1
- import { BaseGenerator } from '@platformatic/generators'
1
+ import { Generator as ServiceGenerator } from '@platformatic/service'
2
2
 
3
- export class Generator extends BaseGenerator {
3
+ export class Generator extends ServiceGenerator {
4
4
  constructor (opts) {
5
5
  super({
6
6
  ...opts,
7
7
  module: '@platformatic/composer'
8
8
  })
9
- this.runtime = null
10
9
  }
11
10
 
12
11
  getDefaultConfig () {
13
12
  const defaultBaseConfig = super.getDefaultConfig()
13
+
14
14
  return {
15
15
  ...defaultBaseConfig,
16
16
  plugin: false,
@@ -19,94 +19,33 @@ export class Generator extends BaseGenerator {
19
19
  }
20
20
  }
21
21
 
22
- async _getConfigFileContents () {
23
- const template = {
24
- $schema: `https://schemas.platformatic.dev/@platformatic/composer/${this.platformaticVersion}.json`,
25
- composer: {
26
- services: [
27
- {
28
- id: 'example',
29
- origin: `{${this.getEnvVarName('PLT_EXAMPLE_ORIGIN')}}`,
30
- openapi: {
31
- url: '/documentation/json'
32
- }
33
- }
34
- ],
35
- refreshTimeout: 1000
36
- },
37
- watch: true
38
- }
39
- if (this.runtime !== null) {
40
- template.composer.services = this.runtime.services
41
- .filter(serviceMeta => serviceMeta.service.module !== '@platformatic/composer')
42
- .map(serviceMeta => {
43
- return {
44
- id: serviceMeta.name,
45
- openapi: {
46
- url: '/documentation/json',
47
- prefix: `/${serviceMeta.name}`
48
- }
49
- }
50
- })
51
- }
52
-
53
- if (this.config.plugin) {
54
- template.plugins = {
55
- paths: [
56
- {
57
- path: './plugins',
58
- encapsulate: false
59
- },
60
- './routes'
61
- ],
62
- typescript: `{${this.getEnvVarName('PLT_TYPESCRIPT')}}`
63
- }
22
+ async _beforePrepare () {
23
+ if (this.config.isUpdating) {
24
+ return
64
25
  }
65
26
 
66
- if (!this.config.isRuntimeContext) {
67
- template.server = {
68
- hostname: '{PLT_SERVER_HOSTNAME}',
69
- port: '{PORT}',
70
- logger: {
71
- level: '{PLT_SERVER_LOGGER_LEVEL}'
72
- }
73
- }
74
- }
27
+ await super._beforePrepare()
75
28
 
76
- return template
77
- }
29
+ this.addEnvVars(
30
+ {
31
+ PLT_EXAMPLE_ORIGIN: 'http://127.0.0.1:3043'
32
+ },
33
+ { overwrite: false, default: true }
34
+ )
78
35
 
79
- async _beforePrepare () {
80
- if (!this.config.isUpdating) {
81
- if (!this.config.isRuntimeContext) {
82
- this.addEnvVars(
83
- {
84
- PLT_SERVER_HOSTNAME: this.config.hostname,
85
- PLT_SERVER_LOGGER_LEVEL: 'info',
86
- PORT: 3042
87
- },
88
- { overwrite: false, default: true }
89
- )
90
- }
91
-
92
- this.addEnvVars(
93
- {
94
- PLT_TYPESCRIPT: this.config.typescript,
95
- PLT_EXAMPLE_ORIGIN: 'http://127.0.0.1:3043'
96
- },
97
- { overwrite: false, default: true }
98
- )
99
-
100
- this.config.dependencies = {
101
- '@platformatic/composer': `^${this.platformaticVersion}`
102
- }
36
+ this.config.dependencies = {
37
+ '@platformatic/composer': `^${this.platformaticVersion}`
103
38
  }
104
39
  }
105
40
 
106
41
  async _afterPrepare () {
107
- if (!this.config.isUpdating) {
108
- const PLT_ENVIRONMENT_TEMPLATE = `
109
- import { FastifyInstance } from 'fastify'
42
+ if (this.config.isUpdating) {
43
+ return
44
+ }
45
+
46
+ await super._afterPrepare()
47
+ const PLT_ENVIRONMENT_TEMPLATE = `
48
+ import { type FastifyInstance } from 'fastify'
110
49
  import { PlatformaticApplication, PlatformaticComposerConfig } from '@platformatic/composer'
111
50
 
112
51
  declare module 'fastify' {
@@ -116,7 +55,7 @@ declare module 'fastify' {
116
55
  }
117
56
  `
118
57
 
119
- const README = `
58
+ const README = `
120
59
  # Platformatic Composer API
121
60
 
122
61
  This is a generated [Platformatic Composer](https://docs.platformatic.dev/docs/composer/overview) application.
@@ -147,12 +86,42 @@ npm start
147
86
  - 📔 View the REST API's Swagger documentation at http://localhost:3042/documentation/
148
87
  `
149
88
 
150
- this.addFile({ path: '', file: 'plt-env.d.ts', contents: PLT_ENVIRONMENT_TEMPLATE })
151
- this.addFile({ path: '', file: 'README.md', contents: README })
152
- }
89
+ this.addFile({ path: '', file: 'plt-env.d.ts', contents: PLT_ENVIRONMENT_TEMPLATE })
90
+ this.addFile({ path: '', file: 'README.md', contents: README })
153
91
  }
154
92
 
155
- setRuntime (runtime) {
156
- this.runtime = runtime
93
+ async _getConfigFileContents () {
94
+ const config = await super._getConfigFileContents()
95
+ delete config.service
96
+ config.$schema = `https://schemas.platformatic.dev/@platformatic/composer/${this.platformaticVersion}.json`
97
+
98
+ config.composer = {
99
+ services: [
100
+ {
101
+ id: 'example',
102
+ origin: `{${this.getEnvVarName('PLT_EXAMPLE_ORIGIN')}}`,
103
+ openapi: {
104
+ url: '/documentation/json'
105
+ }
106
+ }
107
+ ],
108
+ refreshTimeout: 1000
109
+ }
110
+
111
+ if (this.runtime !== null) {
112
+ config.composer.services = this.runtime.services
113
+ .filter(serviceMeta => serviceMeta.service.module !== '@platformatic/composer')
114
+ .map(serviceMeta => {
115
+ return {
116
+ id: serviceMeta.name,
117
+ openapi: {
118
+ url: '/documentation/json',
119
+ prefix: `/${serviceMeta.name}`
120
+ }
121
+ }
122
+ })
123
+ }
124
+
125
+ return config
157
126
  }
158
127
  }
package/lib/metrics.js ADDED
@@ -0,0 +1,12 @@
1
+ export function initMetrics (prometheus) {
2
+ if (!prometheus?.registry || !prometheus?.client) return null
3
+ const { client, registry } = prometheus
4
+
5
+ return {
6
+ activeWsConnections: new client.Gauge({
7
+ name: 'active_ws_composer_connections',
8
+ help: 'Active Websocket composer connections in "@platformatic/composer"',
9
+ registers: [registry]
10
+ })
11
+ }
12
+ }
package/lib/proxy.js CHANGED
@@ -1,9 +1,10 @@
1
1
  import httpProxy from '@fastify/http-proxy'
2
- import { ensureLoggableError, loadModule } from '@platformatic/utils'
2
+ import { ensureLoggableError, loadModule } from '@platformatic/foundation'
3
3
  import fp from 'fastify-plugin'
4
4
  import { createRequire } from 'node:module'
5
5
  import { workerData } from 'node:worker_threads'
6
6
  import { getGlobalDispatcher } from 'undici'
7
+ import { initMetrics } from './metrics.js'
7
8
 
8
9
  const kITC = Symbol.for('plt.runtime.itc')
9
10
  const kProxyRoute = Symbol('plt.composer.proxy.route')
@@ -51,6 +52,8 @@ async function resolveServiceProxyParameters (service) {
51
52
  }
52
53
  }
53
54
 
55
+ let metrics
56
+
54
57
  async function proxyPlugin (app, opts) {
55
58
  const meta = { proxies: {} }
56
59
  const hostnameLessProxies = []
@@ -80,16 +83,16 @@ async function proxyPlugin (app, opts) {
80
83
  const basePath = `/${prefix ?? ''}`.replaceAll(/\/+/g, '/').replace(/\/$/, '')
81
84
  const dispatcher = getGlobalDispatcher()
82
85
 
86
+ let preRewrite = null
87
+
83
88
  if (needsRootTrailingSlash) {
84
- app.addHook('preHandler', function rootTrailingSlashPreHandler (req, reply, done) {
85
- if (req.url !== basePath) {
86
- done()
87
- return
89
+ preRewrite = function preRewrite (url) {
90
+ if (url === basePath) {
91
+ url += '/'
88
92
  }
89
93
 
90
- const { url, options } = reply.fromParameters(req.url + '/', req.params, prefix)
91
- reply.from(url.replace(/\/+$/, '/'), options)
92
- })
94
+ return url
95
+ }
93
96
  }
94
97
 
95
98
  /*
@@ -144,17 +147,28 @@ async function proxyPlugin (app, opts) {
144
147
  )
145
148
  : null
146
149
 
150
+ if (!metrics) {
151
+ metrics = initMetrics(globalThis.platformatic?.prometheus)
152
+ }
153
+
147
154
  const proxyOptions = {
148
155
  prefix,
149
156
  rewritePrefix,
150
157
  upstream: service.proxy?.upstream ?? origin,
158
+ preRewrite,
151
159
 
152
160
  websocket: true,
153
161
  wsUpstream: ws?.upstream ?? url ?? origin,
154
162
  wsReconnect: ws?.reconnect,
155
163
  wsHooks: {
156
- onConnect: ws?.hooks?.onConnect,
157
- onDisconnect: ws?.hooks?.onDisconnect,
164
+ onConnect: (...args) => {
165
+ metrics?.activeWsConnections?.inc()
166
+ ws?.hooks?.onConnect(...args)
167
+ },
168
+ onDisconnect: (...args) => {
169
+ metrics?.activeWsConnections?.dec()
170
+ ws?.hooks?.onDisconnect(...args)
171
+ },
158
172
  onReconnect: ws?.hooks?.onReconnect,
159
173
  onPong: ws?.hooks?.onPong,
160
174
  onIncomingMessage: ws?.hooks?.onIncomingMessage,
package/lib/schema.js CHANGED
@@ -1,11 +1,17 @@
1
1
  #! /usr/bin/env node
2
2
 
3
+ import { schemaComponents as basicSchemaComponents } from '@platformatic/basic'
4
+ import {
5
+ fastifyServer as server,
6
+ schemaComponents as utilsSchemaComponents,
7
+ watch,
8
+ wrappedRuntime
9
+ } from '@platformatic/foundation'
3
10
  import { schemaComponents as serviceSchemaComponents } from '@platformatic/service'
4
- import { fastifyServer as server, schemaComponents as utilsSchemaComponents, watch, wrappedRuntime } from '@platformatic/utils'
5
11
  import { readFileSync } from 'node:fs'
6
12
  import { resolve } from 'node:path'
7
13
 
8
- const { $defs, clients, graphqlBase, openApiBase, plugins } = serviceSchemaComponents
14
+ const { $defs, graphqlBase, openApiBase, plugins } = serviceSchemaComponents
9
15
 
10
16
  export const packageJson = JSON.parse(readFileSync(resolve(import.meta.dirname, '../package.json'), 'utf8'))
11
17
  export const version = packageJson.version
@@ -221,7 +227,7 @@ export const schema = {
221
227
  composer,
222
228
  types,
223
229
  plugins,
224
- clients,
230
+ application: basicSchemaComponents.application,
225
231
  runtime: wrappedRuntime,
226
232
  telemetry: utilsSchemaComponents.telemetry,
227
233
  watch: {
package/lib/stackable.js CHANGED
@@ -1,5 +1,5 @@
1
+ import { kMetadata, replaceEnv } from '@platformatic/foundation'
1
2
  import { ServiceStackable } from '@platformatic/service'
2
- import { kMetadata, replaceEnv } from '@platformatic/utils'
3
3
  import { ensureServices, platformaticComposer } from './application.js'
4
4
  import { notHostConstraints } from './not-host-constraints.js'
5
5
  import { packageJson } from './schema.js'
package/lib/upgrade.js CHANGED
@@ -1,4 +1,4 @@
1
- import { abstractLogger } from '@platformatic/utils'
1
+ import { abstractLogger } from '@platformatic/foundation'
2
2
  import { resolve } from 'node:path'
3
3
  import { semgrator } from 'semgrator'
4
4
 
@@ -0,0 +1,14 @@
1
+ export default {
2
+ version: '2.99.0',
3
+ up (config) {
4
+ if (typeof config.plugins?.typescript !== 'undefined') {
5
+ delete config.plugins.typescript
6
+ }
7
+
8
+ if (typeof config.clients !== 'undefined') {
9
+ delete config.clients
10
+ }
11
+
12
+ return config
13
+ }
14
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@platformatic/composer",
3
- "version": "3.0.0-alpha.1",
3
+ "version": "3.0.0-alpha.2",
4
4
  "description": "",
5
5
  "main": "index.js",
6
6
  "types": "index.d.ts",
@@ -24,6 +24,7 @@
24
24
  "neostandard": "^0.12.0",
25
25
  "openapi-schema-validator": "^12.1.3",
26
26
  "pino-test": "^1.0.1",
27
+ "prom-client": "^15.1.2",
27
28
  "self-cert": "^2.0.0",
28
29
  "single-user-cache": "^1.0.1",
29
30
  "split2": "^4.2.0",
@@ -31,23 +32,21 @@
31
32
  "typescript": "^5.5.4",
32
33
  "why-is-node-running": "2",
33
34
  "ws": "^8.16.0",
34
- "@platformatic/db": "3.0.0-alpha.1",
35
- "@platformatic/client": "3.0.0-alpha.1"
35
+ "@platformatic/client": "3.0.0-alpha.2",
36
+ "@platformatic/db": "3.0.0-alpha.2"
36
37
  },
37
38
  "dependencies": {
38
39
  "@fastify/error": "^4.0.0",
39
- "@fastify/http-proxy": "^11.2.0",
40
+ "@fastify/http-proxy": "^11.3.0",
40
41
  "@fastify/reply-from": "^12.0.0",
41
42
  "@fastify/static": "^8.0.0",
42
43
  "@fastify/swagger": "^9.0.0",
43
44
  "@fastify/view": "^10.0.1",
44
45
  "@platformatic/fastify-openapi-glue": "^5.1.0",
45
46
  "@platformatic/graphql-composer": "^0.10.0",
46
- "@scalar/fastify-api-reference": "1.31.14",
47
+ "@scalar/fastify-api-reference": "1.33.0",
47
48
  "ajv": "^8.12.0",
48
- "commist": "^3.2.0",
49
49
  "console-table-printer": "^2.12.0",
50
- "es-main": "^1.3.0",
51
50
  "execa": "^9.0.0",
52
51
  "fast-deep-equal": "^3.1.3",
53
52
  "fastify": "^5.0.0",
@@ -60,17 +59,19 @@
60
59
  "my-ua-parser": "^2.0.2",
61
60
  "nunjucks": "^3.2.4",
62
61
  "ora": "^6.3.1",
63
- "pino": "^9.0.0",
62
+ "pino": "^9.9.0",
64
63
  "pino-pretty": "^13.0.0",
65
64
  "rfdc": "^1.3.1",
66
65
  "semgrator": "^0.3.0",
67
66
  "undici": "^7.0.0",
68
- "@platformatic/basic": "3.0.0-alpha.1",
69
- "@platformatic/generators": "3.0.0-alpha.1",
70
- "@platformatic/scalar-theme": "3.0.0-alpha.1",
71
- "@platformatic/service": "3.0.0-alpha.1",
72
- "@platformatic/telemetry": "3.0.0-alpha.1",
73
- "@platformatic/utils": "^3.0.0-alpha.1"
67
+ "@platformatic/basic": "3.0.0-alpha.2",
68
+ "@platformatic/service": "3.0.0-alpha.2",
69
+ "@platformatic/scalar-theme": "3.0.0-alpha.2",
70
+ "@platformatic/telemetry": "3.0.0-alpha.2",
71
+ "@platformatic/foundation": "^3.0.0-alpha.2"
72
+ },
73
+ "engines": {
74
+ "node": ">=22.18.0"
74
75
  },
75
76
  "scripts": {
76
77
  "test": "pnpm run lint && borp -T --timeout 1200000 -c 1",
package/schema.json CHANGED
@@ -1,5 +1,5 @@
1
1
  {
2
- "$id": "https://schemas.platformatic.dev/@platformatic/composer/3.0.0-alpha.1.json",
2
+ "$id": "https://schemas.platformatic.dev/@platformatic/composer/3.0.0-alpha.2.json",
3
3
  "$schema": "http://json-schema.org/draft-07/schema#",
4
4
  "title": "Platformatic Composer Config",
5
5
  "type": "object",
@@ -1221,45 +1221,6 @@
1221
1221
  }
1222
1222
  ]
1223
1223
  }
1224
- },
1225
- "typescript": {
1226
- "anyOf": [
1227
- {
1228
- "type": "object",
1229
- "properties": {
1230
- "enabled": {
1231
- "anyOf": [
1232
- {
1233
- "type": "boolean"
1234
- },
1235
- {
1236
- "type": "string"
1237
- }
1238
- ]
1239
- },
1240
- "tsConfig": {
1241
- "type": "string",
1242
- "resolvePath": true
1243
- },
1244
- "outDir": {
1245
- "type": "string",
1246
- "resolvePath": true
1247
- },
1248
- "flags": {
1249
- "type": "array",
1250
- "items": {
1251
- "type": "string"
1252
- }
1253
- }
1254
- }
1255
- },
1256
- {
1257
- "type": "boolean"
1258
- },
1259
- {
1260
- "type": "string"
1261
- }
1262
- ]
1263
1224
  }
1264
1225
  },
1265
1226
  "additionalProperties": false,
@@ -1276,47 +1237,12 @@
1276
1237
  }
1277
1238
  ]
1278
1239
  },
1279
- "clients": {
1280
- "type": "array",
1281
- "items": {
1282
- "type": "object",
1283
- "properties": {
1284
- "serviceId": {
1285
- "type": "string"
1286
- },
1287
- "name": {
1288
- "type": "string"
1289
- },
1290
- "type": {
1291
- "type": "string",
1292
- "enum": [
1293
- "openapi",
1294
- "graphql"
1295
- ]
1296
- },
1297
- "path": {
1298
- "type": "string",
1299
- "resolvePath": true
1300
- },
1301
- "schema": {
1302
- "type": "string",
1303
- "resolvePath": true
1304
- },
1305
- "url": {
1306
- "type": "string"
1307
- },
1308
- "fullResponse": {
1309
- "type": "boolean"
1310
- },
1311
- "fullRequest": {
1312
- "type": "boolean"
1313
- },
1314
- "validateResponse": {
1315
- "type": "boolean"
1316
- }
1317
- },
1318
- "additionalProperties": false
1319
- }
1240
+ "application": {
1241
+ "type": "object",
1242
+ "properties": {},
1243
+ "additionalProperties": false,
1244
+ "required": [],
1245
+ "default": {}
1320
1246
  },
1321
1247
  "runtime": {
1322
1248
  "type": "object",