@platformatic/service 2.0.0-alpha.7 → 2.0.0-alpha.8

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.
@@ -34,12 +34,19 @@ async function loadPlugins (app, opts) {
34
34
  isOutDirAccessible = await isFileAccessible(outDir)
35
35
  }
36
36
 
37
+ if (opts.context?.isProduction && !isOutDirAccessible) {
38
+ throw new Error(
39
+ `Cannot access directory '${outDir}'. Please run the 'build' command before running in production mode.`
40
+ )
41
+ }
42
+
37
43
  if (config.plugins.paths && isOutDirAccessible) {
38
- config.plugins.paths = config.plugins.paths.map((plugin) => {
44
+ config.plugins.paths = config.plugins.paths.map(plugin => {
39
45
  /* c8 ignore next 3 */
40
- const tmp = typeof plugin === 'string'
41
- ? getJSPluginPath(workingDir, plugin, outDir)
42
- : { ...plugin, path: getJSPluginPath(workingDir, plugin.path, outDir) }
46
+ const tmp =
47
+ typeof plugin === 'string'
48
+ ? getJSPluginPath(workingDir, plugin, outDir)
49
+ : { ...plugin, path: getJSPluginPath(workingDir, plugin.path, outDir) }
43
50
  return tmp
44
51
  })
45
52
  }
package/lib/schema.js CHANGED
@@ -5,7 +5,7 @@
5
5
  const pkg = require('../package.json')
6
6
  const openApiDefs = require('./openapi-schema-defs')
7
7
  const telemetry = require('@platformatic/telemetry').schema
8
- const { server, cors, watch } = require('@platformatic/utils').schemas
8
+ const { server, cors, watch } = require('@platformatic/utils').schemaComponents
9
9
 
10
10
  const plugins = {
11
11
  type: 'object',
@@ -15,23 +15,23 @@ const plugins = {
15
15
  items: {
16
16
  anyOf: [
17
17
  {
18
- type: 'string',
18
+ type: 'string'
19
19
  },
20
20
  {
21
21
  type: 'object',
22
22
  properties: {
23
23
  name: {
24
- type: 'string',
24
+ type: 'string'
25
25
  },
26
26
  options: {
27
27
  type: 'object',
28
- additionalProperties: true,
29
- },
28
+ additionalProperties: true
29
+ }
30
30
  },
31
- required: ['name'],
32
- },
33
- ],
34
- },
31
+ required: ['name']
32
+ }
33
+ ]
34
+ }
35
35
  },
36
36
  paths: {
37
37
  type: 'array',
@@ -39,63 +39,63 @@ const plugins = {
39
39
  anyOf: [
40
40
  {
41
41
  type: 'string',
42
- resolvePath: true,
42
+ resolvePath: true
43
43
  },
44
44
  {
45
45
  type: 'object',
46
46
  properties: {
47
47
  path: {
48
48
  type: 'string',
49
- resolvePath: true,
49
+ resolvePath: true
50
50
  },
51
51
  encapsulate: {
52
52
  type: 'boolean',
53
- default: true,
53
+ default: true
54
54
  },
55
55
  maxDepth: {
56
- type: 'integer',
56
+ type: 'integer'
57
57
  },
58
58
  autoHooks: {
59
- type: 'boolean',
59
+ type: 'boolean'
60
60
  },
61
61
  autoHooksPattern: {
62
- type: 'string',
62
+ type: 'string'
63
63
  },
64
64
  cascadeHooks: {
65
- type: 'boolean',
65
+ type: 'boolean'
66
66
  },
67
67
  overwriteHooks: {
68
- type: 'boolean',
68
+ type: 'boolean'
69
69
  },
70
70
  routeParams: {
71
- type: 'boolean',
71
+ type: 'boolean'
72
72
  },
73
73
  forceESM: {
74
- type: 'boolean',
74
+ type: 'boolean'
75
75
  },
76
76
  ignoreFilter: {
77
- type: 'string',
77
+ type: 'string'
78
78
  },
79
79
  matchFilter: {
80
- type: 'string',
80
+ type: 'string'
81
81
  },
82
82
  ignorePattern: {
83
- type: 'string',
83
+ type: 'string'
84
84
  },
85
85
  scriptPattern: {
86
- type: 'string',
86
+ type: 'string'
87
87
  },
88
88
  indexPattern: {
89
- type: 'string',
89
+ type: 'string'
90
90
  },
91
91
  options: {
92
92
  type: 'object',
93
- additionalProperties: true,
94
- },
95
- },
96
- },
97
- ],
98
- },
93
+ additionalProperties: true
94
+ }
95
+ }
96
+ }
97
+ ]
98
+ }
99
99
  },
100
100
  typescript: {
101
101
  anyOf: [
@@ -105,47 +105,47 @@ const plugins = {
105
105
  enabled: {
106
106
  anyOf: [
107
107
  {
108
- type: 'boolean',
108
+ type: 'boolean'
109
109
  },
110
110
  {
111
- type: 'string',
112
- },
113
- ],
111
+ type: 'string'
112
+ }
113
+ ]
114
114
  },
115
115
  tsConfig: {
116
116
  type: 'string',
117
- resolvePath: true,
117
+ resolvePath: true
118
118
  },
119
119
  outDir: {
120
120
  type: 'string',
121
- resolvePath: true,
121
+ resolvePath: true
122
122
  },
123
123
  flags: {
124
124
  type: 'array',
125
125
  items: {
126
- type: 'string',
127
- },
128
- },
129
- },
126
+ type: 'string'
127
+ }
128
+ }
129
+ }
130
130
  },
131
131
  {
132
- type: 'boolean',
132
+ type: 'boolean'
133
133
  },
134
134
  {
135
- type: 'string',
136
- },
137
- ],
138
- },
135
+ type: 'string'
136
+ }
137
+ ]
138
+ }
139
139
  },
140
140
  additionalProperties: false,
141
141
  anyOf: [
142
142
  {
143
- required: ['paths'],
143
+ required: ['paths']
144
144
  },
145
145
  {
146
- required: ['packages'],
147
- },
148
- ],
146
+ required: ['packages']
147
+ }
148
+ ]
149
149
  }
150
150
 
151
151
  const metrics = {
@@ -155,143 +155,143 @@ const metrics = {
155
155
  type: 'object',
156
156
  properties: {
157
157
  port: {
158
- anyOf: [{ type: 'integer' }, { type: 'string' }],
158
+ anyOf: [{ type: 'integer' }, { type: 'string' }]
159
159
  },
160
160
  hostname: { type: 'string' },
161
161
  endpoint: { type: 'string' },
162
162
  server: {
163
163
  type: 'string',
164
- enum: ['own', 'parent', 'hide'],
164
+ enum: ['own', 'parent', 'hide']
165
165
  },
166
166
  defaultMetrics: {
167
167
  type: 'object',
168
168
  properties: {
169
- enabled: { type: 'boolean' },
169
+ enabled: { type: 'boolean' }
170
170
  },
171
171
  required: ['enabled'],
172
- additionalProperties: false,
172
+ additionalProperties: false
173
173
  },
174
174
  auth: {
175
175
  type: 'object',
176
176
  properties: {
177
177
  username: { type: 'string' },
178
- password: { type: 'string' },
178
+ password: { type: 'string' }
179
179
  },
180
180
  additionalProperties: false,
181
- required: ['username', 'password'],
181
+ required: ['username', 'password']
182
182
  },
183
183
  labels: {
184
184
  type: 'object',
185
- additionalProperties: { type: 'string' },
186
- },
185
+ additionalProperties: { type: 'string' }
186
+ }
187
187
  },
188
- additionalProperties: false,
189
- },
190
- ],
188
+ additionalProperties: false
189
+ }
190
+ ]
191
191
  }
192
192
 
193
193
  const openApiBase = {
194
194
  type: 'object',
195
195
  properties: {
196
196
  info: {
197
- $ref: '#/$defs/info',
197
+ $ref: '#/$defs/info'
198
198
  },
199
199
  jsonSchemaDialect: {
200
200
  type: 'string',
201
201
 
202
- default: 'https://spec.openapis.org/oas/3.1/dialect/base',
202
+ default: 'https://spec.openapis.org/oas/3.1/dialect/base'
203
203
  },
204
204
  servers: {
205
205
  type: 'array',
206
206
  items: {
207
- $ref: '#/$defs/server',
207
+ $ref: '#/$defs/server'
208
208
  },
209
209
  default: [
210
210
  {
211
- url: '/',
212
- },
213
- ],
211
+ url: '/'
212
+ }
213
+ ]
214
214
  },
215
215
  paths: {
216
- $ref: '#/$defs/paths',
216
+ $ref: '#/$defs/paths'
217
217
  },
218
218
  webhooks: {
219
219
  type: 'object',
220
220
  additionalProperties: {
221
- $ref: '#/$defs/path-item-or-reference',
222
- },
221
+ $ref: '#/$defs/path-item-or-reference'
222
+ }
223
223
  },
224
224
  components: {
225
- $ref: '#/$defs/components',
225
+ $ref: '#/$defs/components'
226
226
  },
227
227
  security: {
228
228
  type: 'array',
229
229
  items: {
230
- $ref: '#/$defs/security-requirement',
231
- },
230
+ $ref: '#/$defs/security-requirement'
231
+ }
232
232
  },
233
233
  tags: {
234
234
  type: 'array',
235
235
  items: {
236
- $ref: '#/$defs/tag',
237
- },
236
+ $ref: '#/$defs/tag'
237
+ }
238
238
  },
239
239
  externalDocs: {
240
- $ref: '#/$defs/external-documentation',
240
+ $ref: '#/$defs/external-documentation'
241
241
  },
242
242
  swaggerPrefix: {
243
243
  type: 'string',
244
- description: 'Base URL for the OpenAPI Swagger Documentation',
244
+ description: 'Base URL for the OpenAPI Swagger Documentation'
245
245
  },
246
246
  path: {
247
247
  type: 'string',
248
248
  description: 'Path to an OpenAPI spec file',
249
- resolvePath: true,
250
- },
251
- },
249
+ resolvePath: true
250
+ }
251
+ }
252
252
  }
253
253
 
254
254
  const openapi = {
255
255
  anyOf: [
256
256
  {
257
257
  ...openApiBase,
258
- additionalProperties: false,
258
+ additionalProperties: false
259
259
  },
260
260
  {
261
- type: 'boolean',
262
- },
263
- ],
261
+ type: 'boolean'
262
+ }
263
+ ]
264
264
  }
265
265
 
266
266
  const graphqlBase = {
267
267
  type: 'object',
268
268
  properties: {
269
269
  graphiql: {
270
- type: 'boolean',
271
- },
270
+ type: 'boolean'
271
+ }
272
272
  },
273
- additionalProperties: false,
273
+ additionalProperties: false
274
274
  }
275
275
 
276
276
  const graphql = {
277
277
  anyOf: [
278
278
  {
279
279
  ...graphqlBase,
280
- additionalProperties: false,
280
+ additionalProperties: false
281
281
  },
282
282
  {
283
- type: 'boolean',
284
- },
285
- ],
283
+ type: 'boolean'
284
+ }
285
+ ]
286
286
  }
287
287
 
288
288
  const service = {
289
289
  type: 'object',
290
290
  properties: {
291
291
  openapi,
292
- graphql,
292
+ graphql
293
293
  },
294
- additionalProperties: false,
294
+ additionalProperties: false
295
295
  }
296
296
 
297
297
  const clients = {
@@ -300,32 +300,32 @@ const clients = {
300
300
  type: 'object',
301
301
  properties: {
302
302
  serviceId: {
303
- type: 'string',
303
+ type: 'string'
304
304
  },
305
305
  name: {
306
- type: 'string',
306
+ type: 'string'
307
307
  },
308
308
  type: {
309
309
  type: 'string',
310
- enum: ['openapi', 'graphql'],
310
+ enum: ['openapi', 'graphql']
311
311
  },
312
312
  path: {
313
313
  type: 'string',
314
- resolvePath: true,
314
+ resolvePath: true
315
315
  },
316
316
  schema: {
317
317
  type: 'string',
318
- resolvePath: true,
318
+ resolvePath: true
319
319
  },
320
320
  url: {
321
- type: 'string',
321
+ type: 'string'
322
322
  },
323
323
  fullResponse: { type: 'boolean' },
324
324
  fullRequest: { type: 'boolean' },
325
- validateResponse: { type: 'boolean' },
325
+ validateResponse: { type: 'boolean' }
326
326
  },
327
- additionalProperties: false,
328
- },
327
+ additionalProperties: false
328
+ }
329
329
  }
330
330
 
331
331
  const platformaticServiceSchema = {
@@ -342,24 +342,24 @@ const platformaticServiceSchema = {
342
342
  anyOf: [
343
343
  watch,
344
344
  {
345
- type: 'boolean',
345
+ type: 'boolean'
346
346
  },
347
347
  {
348
- type: 'string',
349
- },
350
- ],
348
+ type: 'string'
349
+ }
350
+ ]
351
351
  },
352
352
  $schema: {
353
- type: 'string',
353
+ type: 'string'
354
354
  },
355
355
  module: {
356
- type: 'string',
356
+ type: 'string'
357
357
  },
358
358
  service,
359
- clients,
359
+ clients
360
360
  },
361
361
  additionalProperties: false,
362
- $defs: openApiDefs,
362
+ $defs: openApiDefs
363
363
  }
364
364
 
365
365
  /*
@@ -368,52 +368,52 @@ const platformaticServiceSchema = {
368
368
  */
369
369
  Object.defineProperty(platformaticServiceSchema, 'schema', {
370
370
  enumerable: false,
371
- value: platformaticServiceSchema,
371
+ value: platformaticServiceSchema
372
372
  })
373
373
 
374
374
  Object.defineProperty(platformaticServiceSchema, 'server', {
375
375
  enumerable: false,
376
- value: server,
376
+ value: server
377
377
  })
378
378
 
379
379
  Object.defineProperty(platformaticServiceSchema, 'cors', {
380
380
  enumerable: false,
381
- value: cors,
381
+ value: cors
382
382
  })
383
383
 
384
384
  Object.defineProperty(platformaticServiceSchema, 'metrics', {
385
385
  enumerable: false,
386
- value: metrics,
386
+ value: metrics
387
387
  })
388
388
 
389
389
  Object.defineProperty(platformaticServiceSchema, 'plugins', {
390
390
  enumerable: false,
391
- value: plugins,
391
+ value: plugins
392
392
  })
393
393
 
394
394
  Object.defineProperty(platformaticServiceSchema, 'watch', {
395
395
  enumerable: false,
396
- value: watch,
396
+ value: watch
397
397
  })
398
398
 
399
399
  Object.defineProperty(platformaticServiceSchema, 'openApiDefs', {
400
400
  enumerable: false,
401
- value: openApiDefs,
401
+ value: openApiDefs
402
402
  })
403
403
 
404
404
  Object.defineProperty(platformaticServiceSchema, 'openApiBase', {
405
405
  enumerable: false,
406
- value: openApiBase,
406
+ value: openApiBase
407
407
  })
408
408
 
409
409
  Object.defineProperty(platformaticServiceSchema, 'graphqlBase', {
410
410
  enumerable: false,
411
- value: graphqlBase,
411
+ value: graphqlBase
412
412
  })
413
413
 
414
414
  Object.defineProperty(platformaticServiceSchema, 'clients', {
415
415
  enumerable: false,
416
- value: clients,
416
+ value: clients
417
417
  })
418
418
 
419
419
  /* end */
package/lib/stackable.js CHANGED
@@ -4,6 +4,8 @@ const { dirname } = require('node:path')
4
4
  const { printSchema } = require('graphql')
5
5
  const pino = require('pino')
6
6
  const httpMetrics = require('@platformatic/fastify-http-metrics')
7
+ const { extractTypeScriptCompileOptionsFromConfig } = require('./compile')
8
+ const { compile } = require('@platformatic/ts-compiler')
7
9
 
8
10
  class ServiceStackable {
9
11
  constructor (options) {
@@ -13,13 +15,14 @@ class ServiceStackable {
13
15
  this.metricsRegistry = null
14
16
 
15
17
  this.configManager = options.configManager
16
- this.context = options.context
18
+ this.context = options.context ?? {}
19
+ this.context.stackable = this
17
20
 
18
- this.configManager.on('error', (err) => {
21
+ this.configManager.on('error', err => {
19
22
  /* c8 ignore next */
20
23
  this.stackable.log({
21
24
  message: 'error reloading the configuration' + err,
22
- level: 'error',
25
+ level: 'error'
23
26
  })
24
27
  })
25
28
 
@@ -54,6 +57,20 @@ class ServiceStackable {
54
57
  await this.app.close()
55
58
  }
56
59
 
60
+ async build () {
61
+ this.#initLogger()
62
+ const typeScriptCompileOptions = extractTypeScriptCompileOptionsFromConfig(this.configManager.current)
63
+ const cwd = dirname(this.configManager.fullPath)
64
+ const compileOptions = {
65
+ ...typeScriptCompileOptions,
66
+ cwd,
67
+ logger: this.configManager.current.server.logger,
68
+ }
69
+ if (!await compile(compileOptions)) {
70
+ throw new Error(`Failed to compile ${cwd}`)
71
+ }
72
+ }
73
+
57
74
  getUrl () {
58
75
  return this.app !== null ? this.app.url : null
59
76
  }
@@ -79,26 +96,16 @@ class ServiceStackable {
79
96
  return config
80
97
  }
81
98
 
82
- getMeta () {
83
- return {
84
- deploy: {
85
- buildCommand: 'platformatic compile'
86
- }
87
- }
88
- }
89
-
90
99
  async getWatchConfig () {
91
100
  const config = this.configManager.current
92
101
 
93
- const enabled =
94
- config.watch?.enabled !== false &&
95
- config.plugins !== undefined
102
+ const enabled = config.watch?.enabled !== false && config.plugins !== undefined
96
103
 
97
104
  return {
98
105
  enabled,
99
106
  path: dirname(this.configManager.fullPath),
100
107
  allow: config.watch?.allow,
101
- ignore: config.watch?.ignore,
108
+ ignore: config.watch?.ignore
102
109
  }
103
110
  }
104
111
 
@@ -155,16 +162,16 @@ class ServiceStackable {
155
162
  this.app.register(httpMetrics, {
156
163
  registry: this.metricsRegistry,
157
164
  customLabels: ['telemetry_id'],
158
- getCustomLabels: (req) => {
165
+ getCustomLabels: req => {
159
166
  const telemetryId = req.headers['x-plt-telemetry-id'] ?? 'unknown'
160
167
  return { telemetry_id: telemetryId }
161
- },
168
+ }
162
169
  })
163
170
 
164
171
  this.app.register(httpMetrics, {
165
172
  registry: this.metricsRegistry,
166
173
  customLabels: ['telemetry_id'],
167
- getCustomLabels: (req) => {
174
+ getCustomLabels: req => {
168
175
  const telemetryId = req.headers['x-plt-telemetry-id'] ?? 'unknown'
169
176
  return { telemetry_id: telemetryId }
170
177
  },
@@ -173,30 +180,23 @@ class ServiceStackable {
173
180
  help: 'request duration in seconds summary for all requests',
174
181
  collect: function () {
175
182
  process.nextTick(() => this.reset())
176
- },
183
+ }
177
184
  },
178
185
  summary: {
179
186
  name: 'http_request_all_summary_seconds',
180
187
  help: 'request duration in seconds histogram for all requests',
181
188
  collect: function () {
182
189
  process.nextTick(() => this.reset())
183
- },
184
- },
190
+ }
191
+ }
185
192
  })
186
193
  }
187
194
 
188
195
  #updateConfig () {
189
196
  if (!this.context) return
190
197
 
191
- const {
192
- serviceId,
193
- telemetryConfig,
194
- metricsConfig,
195
- serverConfig,
196
- hasManagementApi,
197
- isEntrypoint,
198
- isProduction,
199
- } = this.context
198
+ const { serviceId, telemetryConfig, metricsConfig, serverConfig, hasManagementApi, isEntrypoint, isProduction } =
199
+ this.context
200
200
 
201
201
  const config = this.configManager.current
202
202
 
@@ -210,15 +210,13 @@ class ServiceStackable {
210
210
  config.server = serverConfig
211
211
  }
212
212
 
213
- if (
214
- (hasManagementApi && config.metrics === undefined) || config.metrics
215
- ) {
213
+ if ((hasManagementApi && config.metrics === undefined) || config.metrics) {
216
214
  const labels = config.metrics?.labels || {}
217
215
  config.metrics = {
218
216
  server: 'hide',
219
217
  defaultMetrics: { enabled: isEntrypoint },
220
218
  ...config.metrics,
221
- labels: { serviceId, ...labels },
219
+ labels: { serviceId, ...labels }
222
220
  }
223
221
  }
224
222
 
@@ -242,7 +240,7 @@ class ServiceStackable {
242
240
  const level = this.configManager.current.server.logger?.level
243
241
 
244
242
  const pinoOptions = {
245
- level: level ?? 'trace',
243
+ level: level ?? 'trace'
246
244
  }
247
245
 
248
246
  if (this.context?.serviceId) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@platformatic/service",
3
- "version": "2.0.0-alpha.7",
3
+ "version": "2.0.0-alpha.8",
4
4
  "description": "",
5
5
  "main": "index.js",
6
6
  "bin": {
@@ -77,13 +77,13 @@
77
77
  "rfdc": "^1.3.1",
78
78
  "semgrator": "^0.3.0",
79
79
  "undici": "^6.9.0",
80
- "@platformatic/client": "2.0.0-alpha.7",
81
- "@platformatic/scalar-theme": "2.0.0-alpha.7",
82
- "@platformatic/generators": "2.0.0-alpha.7",
83
- "@platformatic/config": "2.0.0-alpha.7",
84
- "@platformatic/telemetry": "2.0.0-alpha.7",
85
- "@platformatic/ts-compiler": "2.0.0-alpha.7",
86
- "@platformatic/utils": "2.0.0-alpha.7"
80
+ "@platformatic/client": "2.0.0-alpha.8",
81
+ "@platformatic/generators": "2.0.0-alpha.8",
82
+ "@platformatic/scalar-theme": "2.0.0-alpha.8",
83
+ "@platformatic/config": "2.0.0-alpha.8",
84
+ "@platformatic/telemetry": "2.0.0-alpha.8",
85
+ "@platformatic/ts-compiler": "2.0.0-alpha.8",
86
+ "@platformatic/utils": "2.0.0-alpha.8"
87
87
  },
88
88
  "scripts": {
89
89
  "test": "pnpm run lint && borp -T --concurrency=1 --timeout=180000 && tsd",
package/schema.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
- "$id": "https://schemas.platformatic.dev/@platformatic/service/2.0.0-alpha.7.json",
3
- "version": "2.0.0-alpha.7",
2
+ "$id": "https://schemas.platformatic.dev/@platformatic/service/2.0.0-alpha.8.json",
3
+ "version": "2.0.0-alpha.8",
4
4
  "title": "Platformatic Service",
5
5
  "type": "object",
6
6
  "properties": {