@platformatic/service 2.74.3 → 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.
Files changed (52) hide show
  1. package/config.d.ts +2 -30
  2. package/eslint.config.js +4 -6
  3. package/index.d.ts +55 -47
  4. package/index.js +44 -199
  5. package/lib/application.js +35 -0
  6. package/lib/compile.js +1 -52
  7. package/lib/generator.js +424 -0
  8. package/lib/plugins/cors.js +5 -8
  9. package/lib/plugins/graphql.js +16 -14
  10. package/lib/plugins/health-check.js +6 -8
  11. package/lib/plugins/openapi.js +40 -31
  12. package/lib/plugins/plugins.js +6 -53
  13. package/lib/{root-endpoint/index.js → plugins/root.js} +9 -8
  14. package/lib/plugins/sandbox-wrapper.js +62 -55
  15. package/lib/schema.js +1028 -203
  16. package/lib/stackable.js +171 -338
  17. package/lib/upgrade.js +6 -8
  18. package/lib/utils.js +30 -93
  19. package/lib/versions/0.16.0.js +14 -15
  20. package/lib/versions/{from-zero-twenty-eight-to-will-see.js → 0.28.0.js} +3 -6
  21. package/lib/versions/2.0.0.js +4 -7
  22. package/lib/versions/3.0.0.js +14 -0
  23. package/package.json +18 -25
  24. package/schema.json +10 -155
  25. package/tsconfig.json +16 -6
  26. package/.c8rc +0 -6
  27. package/help/compile.txt +0 -19
  28. package/help/create.txt +0 -11
  29. package/help/help.txt +0 -8
  30. package/help/schema.txt +0 -9
  31. package/help/start.txt +0 -23
  32. package/index.test-d.ts +0 -107
  33. package/lib/create.mjs +0 -85
  34. package/lib/gen-schema.js +0 -15
  35. package/lib/gen-types.mjs +0 -38
  36. package/lib/generator/README.md +0 -31
  37. package/lib/generator/service-generator.d.ts +0 -11
  38. package/lib/generator/service-generator.js +0 -126
  39. package/lib/openapi-schema-defs.js +0 -1108
  40. package/lib/plugins/clients.js +0 -16
  41. package/lib/plugins/metrics.js +0 -244
  42. package/lib/plugins/typescript.js +0 -20
  43. package/lib/start.js +0 -190
  44. package/service.mjs +0 -71
  45. /package/{lib/root-endpoint/public → public}/images/dark_mode.svg +0 -0
  46. /package/{lib/root-endpoint/public → public}/images/favicon.ico +0 -0
  47. /package/{lib/root-endpoint/public → public}/images/light_mode.svg +0 -0
  48. /package/{lib/root-endpoint/public → public}/images/platformatic-logo-dark.svg +0 -0
  49. /package/{lib/root-endpoint/public → public}/images/platformatic-logo-light.svg +0 -0
  50. /package/{lib/root-endpoint/public → public}/images/triangle_dark.svg +0 -0
  51. /package/{lib/root-endpoint/public → public}/images/triangle_light.svg +0 -0
  52. /package/{lib/root-endpoint/public → public}/index.html +0 -0
package/lib/stackable.js CHANGED
@@ -1,414 +1,229 @@
1
- 'use strict'
2
-
3
- const { hostname } = require('node:os')
4
- const { dirname } = require('node:path')
5
- const { pathToFileURL } = require('node:url')
6
- const { workerData } = require('node:worker_threads')
7
- const { printSchema } = require('graphql')
8
- const pino = require('pino')
9
- const { client, collectMetrics } = require('@platformatic/metrics')
10
- const { extractTypeScriptCompileOptionsFromConfig } = require('./compile')
11
- const { compile } = require('@platformatic/ts-compiler')
12
- const { deepmerge, buildPinoFormatters, buildPinoTimestamp } = require('@platformatic/utils')
13
-
14
- const kITC = Symbol.for('plt.runtime.itc')
15
-
16
- class ServiceStackable {
17
- constructor (options) {
18
- this.app = null
19
- this._init = options.init
20
- this.stackable = options.stackable
21
- this.metricsRegistry = new client.Registry()
22
-
23
- this.configManager = options.configManager
24
- this.context = options.context ?? {}
25
- this.context.stackable = this
26
-
27
- this.serviceId = this.context.serviceId
28
- this.context.worker ??= { count: 1, index: 0 }
29
- this.workerId = this.context.worker.count > 1 ? this.context.worker.index : undefined
30
-
31
- this.runtimeConfig = deepmerge(this.context.runtimeConfig ?? {}, workerData?.config ?? {})
32
-
33
- this.customHealthCheck = null
34
-
35
- this.configManager.on('error', err => {
36
- /* c8 ignore next */
37
- this.stackable.log({
38
- message: 'error reloading the configuration' + err,
39
- level: 'error'
40
- })
41
- })
42
-
43
- this.#updateConfig()
44
-
45
- // Setup globals
46
- this.registerGlobals({
47
- serviceId: this.serviceId,
48
- workerId: this.workerId,
49
- // Always use URL to avoid serialization problem in Windows
50
- root: this.context.directory ? pathToFileURL(this.context.directory).toString() : undefined,
51
- setOpenapiSchema: this.setOpenapiSchema.bind(this),
52
- setGraphqlSchema: this.setGraphqlSchema.bind(this),
53
- setConnectionString: this.setConnectionString.bind(this),
54
- setBasePath: this.setBasePath.bind(this),
55
- runtimeBasePath: this.runtimeConfig?.basePath ?? null,
56
- invalidateHttpCache: this.#invalidateHttpCache.bind(this),
57
- prometheus: { client, registry: this.metricsRegistry },
58
- setCustomHealthCheck: this.setCustomHealthCheck.bind(this),
59
- setCustomReadinessCheck: this.setCustomReadinessCheck.bind(this)
60
- })
1
+ import { BaseStackable, cleanBasePath, ensureTrailingSlash, getServerUrl } from '@platformatic/basic'
2
+ import { buildPinoFormatters, buildPinoTimestamp, deepmerge, features, isKeyEnabled } from '@platformatic/foundation'
3
+ import { telemetry } from '@platformatic/telemetry'
4
+ import fastify from 'fastify'
5
+ import { printSchema } from 'graphql'
6
+ import { randomUUID } from 'node:crypto'
7
+ import { hostname } from 'node:os'
8
+ import pino from 'pino'
9
+ import { platformaticService } from './application.js'
10
+ import { setupRoot } from './plugins/root.js'
11
+ import { version } from './schema.js'
12
+ import { sanitizeHTTPSArgument } from './utils.js'
13
+
14
+ export class ServiceStackable extends BaseStackable {
15
+ #app
16
+ #basePath
17
+
18
+ constructor (root, config, context) {
19
+ super('service', version, root, config, context)
20
+ this.applicationFactory = this.context.applicationFactory ?? platformaticService
61
21
  }
62
22
 
63
23
  async init () {
64
- this.#initLogger()
65
-
66
- if (this.app === null) {
67
- this.app = await this._init()
68
- await this.#collectMetrics()
69
- }
70
- return this.app
71
- }
72
-
73
- async start (options = {}) {
74
- await this.init()
24
+ await super.init()
75
25
 
76
- if (options.listen === false) {
77
- await this.app.ready()
26
+ if (this.#app) {
78
27
  return
79
28
  }
80
- await this.app.start()
81
- }
82
29
 
83
- async stop () {
84
- if (this.app === null) return
85
- await this.app.close()
86
- }
30
+ const config = this.config
31
+ this.#basePath = ensureTrailingSlash(cleanBasePath(config.basePath ?? this.serviceId))
87
32
 
88
- async build () {
89
- this.#initLogger()
90
- const typeScriptCompileOptions = extractTypeScriptCompileOptionsFromConfig(this.configManager.current)
91
- const cwd = dirname(this.configManager.fullPath)
92
- const compileOptions = {
93
- ...typeScriptCompileOptions,
94
- cwd,
95
- logger: this.logger
33
+ // Create the application
34
+ this.#app = fastify({
35
+ ...this.serverConfig,
36
+ ...this.fastifyOptions,
37
+ genReqId () {
38
+ return randomUUID()
39
+ }
40
+ })
41
+
42
+ // This must be done before loading the plugins, so they can inspect if the
43
+ // openTelemetry decorator exists and then configure accordingly.
44
+ if (isKeyEnabled('telemetry', config)) {
45
+ await this.#app.register(telemetry, config.telemetry)
96
46
  }
97
47
 
98
- await compile(compileOptions)
99
- }
48
+ this.#app.decorate('platformatic', { config: this.config })
100
49
 
101
- getUrl () {
102
- return this.app !== null ? this.app.url : null
103
- }
50
+ await this.#app.register(this.applicationFactory, this)
104
51
 
105
- async getInfo () {
106
- const type = this.stackable.configType
107
- const version = this.stackable.configManagerConfig.version ?? null
108
- return { type, version }
109
- }
52
+ if (Array.isArray(this.context.fastifyPlugins)) {
53
+ for (const plugin of this.context.fastifyPlugins) {
54
+ await this.#app.register(plugin)
55
+ }
56
+ }
110
57
 
111
- async getConfig () {
112
- const config = Object.assign({}, this.configManager.current)
113
- config.server = Object.assign({}, config.server)
58
+ if (!this.#app.hasRoute({ url: '/', method: 'GET' }) && !this.#app.hasRoute({ url: '/*', method: 'GET' })) {
59
+ await this.#app.register(setupRoot)
60
+ }
61
+ }
114
62
 
115
- const logger = config.server.loggerInstance
63
+ async start (startOptions) {
64
+ // Compatibility with v2 service
65
+ const { listen } = startOptions ?? { listen: true }
116
66
 
117
- if (logger) {
118
- config.server.logger = {}
67
+ // Make this idempotent
68
+ if (this.url) {
69
+ return this.url
70
+ }
119
71
 
120
- if (logger.level) {
121
- config.server.logger.level = logger.level
122
- }
72
+ // Create the application if needed
73
+ if (!this.#app) {
74
+ await this.init()
75
+ await this.#app.ready()
123
76
  }
124
77
 
125
- delete config.server.loggerInstance
78
+ if (listen) {
79
+ await this._listen()
80
+ }
126
81
 
127
- return config
82
+ await this._collectMetrics()
83
+ return this.url
128
84
  }
129
85
 
130
- async getEnv () {
131
- return this.configManager.env
86
+ async stop () {
87
+ return this.#app?.close()
132
88
  }
133
89
 
134
- getMeta () {
135
- const config = this.configManager.current
90
+ async inject (injectParams, onInject) {
91
+ const response = await this.#app.inject(injectParams, onInject)
136
92
 
137
- return {
138
- composer: {
139
- prefix: config.basePath ?? this.basePath ?? this.context?.serviceId,
140
- wantsAbsoluteUrls: false,
141
- needsRootTrailingSlash: false,
142
- tcp: !!this.app?.url,
143
- url: this.app?.url
144
- },
145
- connectionStrings: [this.connectionString]
93
+ if (onInject) {
94
+ return
146
95
  }
147
- }
148
-
149
- async getWatchConfig () {
150
- const config = this.configManager.current
151
96
 
152
- const enabled = config.watch?.enabled !== false && config.plugins !== undefined
97
+ const { statusCode, statusMessage, headers, body } = response
98
+ return { statusCode, statusMessage, headers, body }
99
+ }
153
100
 
154
- return {
155
- enabled,
156
- path: this.configManager.dirname ?? dirname(this.configManager.fullPath),
157
- allow: config.watch?.allow,
158
- ignore: config.watch?.ignore
159
- }
101
+ getApplication () {
102
+ return this.#app
160
103
  }
161
104
 
162
105
  async getDispatchFunc () {
163
106
  await this.init()
164
- return this.app
107
+ return this.#app
165
108
  }
166
109
 
167
- async getDispatchTarget () {
168
- return this.getUrl() ?? (await this.getDispatchFunc())
169
- }
110
+ async getConfig (includeMeta = false) {
111
+ let config = await super.getConfig(includeMeta)
112
+ const loggerInstance = this.serverConfig?.loggerInstance
170
113
 
171
- async getOpenapiSchema () {
172
- await this.init()
173
- await this.app.ready()
174
- return this.app.swagger ? this.app.swagger() : null
175
- }
176
-
177
- async getGraphqlSchema () {
178
- await this.init()
179
- await this.app.ready()
180
- return this.app.graphql ? printSchema(this.app.graphql.schema) : null
181
- }
114
+ if (loggerInstance) {
115
+ config = Object.assign({}, config)
116
+ const { loggerInstance: _, ...serverConfig } = this.serverConfig
117
+ config.server = { ...serverConfig, logger: { level: loggerInstance.level } }
118
+ }
182
119
 
183
- setCustomHealthCheck (fn) {
184
- this.customHealthCheck = fn
120
+ return config
185
121
  }
186
122
 
187
- async getCustomHealthCheck () {
188
- if (!this.customHealthCheck) {
189
- return true
190
- }
191
- return await this.customHealthCheck()
192
- }
123
+ async getWatchConfig () {
124
+ const config = this.config
193
125
 
194
- setCustomReadinessCheck (fn) {
195
- this.customReadinessCheck = fn
196
- }
126
+ const enabled = config.watch?.enabled !== false && config.plugins !== undefined
197
127
 
198
- async getCustomReadinessCheck () {
199
- if (!this.customReadinessCheck) {
200
- return true
128
+ if (!enabled) {
129
+ return { enabled, path: this.root }
201
130
  }
202
- return await this.customReadinessCheck()
203
- }
204
131
 
205
- // This method is not a part of Stackable interface because we need to register
206
- // fastify metrics before the server is started.
207
- async #collectMetrics () {
208
- const metricsConfig = this.context.metricsConfig
209
-
210
- if (metricsConfig !== false) {
211
- await collectMetrics(
212
- this.serviceId,
213
- this.workerId,
214
- {
215
- defaultMetrics: true,
216
- httpMetrics: true,
217
- ...metricsConfig
218
- },
219
- this.metricsRegistry
220
- )
221
-
222
- this.#setHttpCacheMetrics()
132
+ return {
133
+ enabled,
134
+ path: this.root,
135
+ allow: config.watch?.allow,
136
+ ignore: config.watch?.ignore
223
137
  }
224
138
  }
225
139
 
226
- async getMetrics (opts) {
227
- const format = opts?.format
228
- return format === 'json' ? await this.metricsRegistry.getMetricsAsJSON() : await this.metricsRegistry.metrics()
140
+ getMeta () {
141
+ return {
142
+ composer: {
143
+ tcp: typeof this.url !== 'undefined',
144
+ url: this.url,
145
+ prefix: this.basePath ?? this.#basePath,
146
+ wantsAbsoluteUrls: false,
147
+ needsRootTrailingSlash: false
148
+ },
149
+ connectionStrings: [this.connectionString]
150
+ }
229
151
  }
230
152
 
231
- async inject (injectParams) {
153
+ async getOpenapiSchema () {
232
154
  await this.init()
233
-
234
- const { statusCode, statusMessage, headers, body } = await this.app.inject(injectParams)
235
- return { statusCode, statusMessage, headers, body }
155
+ await this.#app.ready()
156
+ return this.#app.swagger ? this.#app.swagger() : null
236
157
  }
237
158
 
238
- async log (options = {}) {
159
+ async getGraphqlSchema () {
239
160
  await this.init()
240
-
241
- const logLevel = options.level ?? 'info'
242
-
243
- const message = options.message
244
- if (!message) return
245
-
246
- this.app.log[logLevel](message)
161
+ await this.#app.ready()
162
+ return this.#app.graphql ? printSchema(this.#app.graphql.schema) : null
247
163
  }
248
164
 
249
165
  async updateContext (context) {
250
- this.context = { ...this.context, ...context }
251
- this.#updateConfig()
252
- }
253
-
254
- setOpenapiSchema (schema) {
255
- this.openapiSchema = schema
256
- }
257
-
258
- setGraphqlSchema (schema) {
259
- this.graphqlSchema = schema
260
- }
261
-
262
- setConnectionString (connectionString) {
263
- this.connectionString = connectionString
264
- }
265
-
266
- setBasePath (basePath) {
267
- this.basePath = basePath
268
- }
269
-
270
- registerGlobals (globals) {
271
- globalThis.platformatic = Object.assign(globalThis.platformatic ?? {}, globals)
272
- }
273
-
274
- async #invalidateHttpCache (opts = {}) {
275
- await globalThis[kITC].send('invalidateHttpCache', opts)
276
- }
277
-
278
- #setHttpCacheMetrics () {
279
- const { client, registry } = globalThis.platformatic.prometheus
280
-
281
- const cacheHitMetric = new client.Counter({
282
- name: 'http_cache_hit_count',
283
- help: 'Number of http cache hits',
284
- registers: [registry]
285
- })
286
-
287
- const cacheMissMetric = new client.Counter({
288
- name: 'http_cache_miss_count',
289
- help: 'Number of http cache misses',
290
- registers: [registry]
291
- })
292
-
293
- globalThis.platformatic.onHttpCacheHit = () => {
294
- cacheHitMetric.inc()
295
- }
296
- globalThis.platformatic.onHttpCacheMiss = () => {
297
- cacheMissMetric.inc()
298
- }
299
-
300
- const httpStatsFreeMetric = new client.Gauge({
301
- name: 'http_client_stats_free',
302
- help: 'Number of free (idle) http clients (sockets)',
303
- labelNames: ['dispatcher_stats_url'],
304
- registers: [registry]
305
- })
306
- globalThis.platformatic.onHttpStatsFree = (url, val) => {
307
- httpStatsFreeMetric.set({ dispatcher_stats_url: url }, val)
308
- }
309
-
310
- const httpStatsConnectedMetric = new client.Gauge({
311
- name: 'http_client_stats_connected',
312
- help: 'Number of open socket connections',
313
- labelNames: ['dispatcher_stats_url'],
314
- registers: [registry]
315
- })
316
- globalThis.platformatic.onHttpStatsConnected = (url, val) => {
317
- httpStatsConnectedMetric.set({ dispatcher_stats_url: url }, val)
318
- }
319
-
320
- const httpStatsPendingMetric = new client.Gauge({
321
- name: 'http_client_stats_pending',
322
- help: 'Number of pending requests across all clients',
323
- labelNames: ['dispatcher_stats_url'],
324
- registers: [registry]
325
- })
326
- globalThis.platformatic.onHttpStatsPending = (url, val) => {
327
- httpStatsPendingMetric.set({ dispatcher_stats_url: url }, val)
328
- }
166
+ super.updateContext(context)
329
167
 
330
- const httpStatsQueuedMetric = new client.Gauge({
331
- name: 'http_client_stats_queued',
332
- help: 'Number of queued requests across all clients',
333
- labelNames: ['dispatcher_stats_url'],
334
- registers: [registry]
335
- })
336
- globalThis.platformatic.onHttpStatsQueued = (url, val) => {
337
- httpStatsQueuedMetric.set({ dispatcher_stats_url: url }, val)
338
- }
339
-
340
- const httpStatsRunningMetric = new client.Gauge({
341
- name: 'http_client_stats_running',
342
- help: 'Number of currently active requests across all clients',
343
- labelNames: ['dispatcher_stats_url'],
344
- registers: [registry]
345
- })
346
- globalThis.platformatic.onHttpStatsRunning = (url, val) => {
347
- httpStatsRunningMetric.set({ dispatcher_stats_url: url }, val)
348
- }
168
+ this.context = { ...this.context, ...context }
349
169
 
350
- const httpStatsSizeMetric = new client.Gauge({
351
- name: 'http_client_stats_size',
352
- help: 'Number of active, pending, or queued requests across all clients',
353
- labelNames: ['dispatcher_stats_url'],
354
- registers: [registry]
355
- })
356
- globalThis.platformatic.onHttpStatsSize = (url, val) => {
357
- httpStatsSizeMetric.set({ dispatcher_stats_url: url }, val)
170
+ if (!this.context) {
171
+ return
358
172
  }
359
- }
360
173
 
361
- #updateConfig () {
362
- if (!this.context) return
174
+ const { telemetryConfig, serverConfig, isEntrypoint, isProduction, logger } = this.context
363
175
 
364
- const { serviceId, telemetryConfig, metricsConfig, serverConfig, hasManagementApi, isEntrypoint, isProduction } =
365
- this.context
366
-
367
- const config = this.configManager.current
176
+ const config = { ...this.config }
368
177
 
369
178
  if (telemetryConfig) {
370
179
  config.telemetry = telemetryConfig
371
180
  }
372
- if (metricsConfig) {
373
- config.metrics = metricsConfig
374
- }
181
+
182
+ const loggerInstance = logger ?? serverConfig?.loggerInstance ?? this.serverConfig?.loggerInstance
183
+
375
184
  if (serverConfig) {
376
- config.server = deepmerge(config.server ?? {}, serverConfig ?? {})
185
+ config.server = deepmerge(this.serverConfig, serverConfig ?? {})
377
186
  }
378
187
 
379
- if ((hasManagementApi && config.metrics === undefined) || config.metrics) {
380
- const labels = config.metrics?.labels || {}
381
- config.metrics = {
382
- server: 'hide',
383
- defaultMetrics: { enabled: isEntrypoint },
384
- ...config.metrics,
385
- labels: { serviceId, ...labels }
188
+ config.server ??= {}
189
+
190
+ if (isProduction) {
191
+ if (config.plugins) {
192
+ config.plugins.typescript = false
386
193
  }
194
+ config.watch = { enabled: false }
387
195
  }
388
196
 
197
+ // Adjust server options
389
198
  if (!isEntrypoint) {
390
- config.server = config.server ?? {}
391
199
  config.server.trustProxy = true
392
200
  }
393
201
 
394
- if (isProduction) {
395
- if (config.plugins) {
396
- config.plugins.typescript = false
397
- }
398
- config.watch = { enabled: false }
202
+ if (config.server.https) {
203
+ config.server.https.key = await sanitizeHTTPSArgument(config.server.https.key)
204
+ config.server.https.cert = await sanitizeHTTPSArgument(config.server.https.cert)
399
205
  }
400
206
 
401
- this.configManager.update(config)
207
+ // Assign the logger instance if it exists
208
+ if (loggerInstance) {
209
+ config.server = { ...config.server }
210
+ config.server.loggerInstance = loggerInstance
211
+ delete config.server.logger
212
+ }
213
+
214
+ this.serverConfig = config.server
215
+ this.config = config
402
216
  }
403
217
 
404
- #initLogger () {
405
- if (this.configManager.current.server?.loggerInstance) {
406
- this.logger = this.configManager.current.server?.loggerInstance
407
- return
218
+ _initializeLogger () {
219
+ if (this.context?.logger) {
220
+ return this.context.logger
221
+ } else if (this.config.server?.loggerInstance) {
222
+ return this.config.server?.loggerInstance
408
223
  }
409
224
 
410
- this.configManager.current.server ??= {}
411
- this.loggerConfig = deepmerge(this.context.loggerConfig ?? {}, this.configManager.current.server?.logger ?? {})
225
+ this.serverConfig ??= {}
226
+ this.loggerConfig = deepmerge(this.context.loggerConfig ?? {}, this.serverConfig?.logger ?? {})
412
227
 
413
228
  const pinoOptions = {
414
229
  ...(this.loggerConfig ?? {}),
@@ -436,12 +251,30 @@ class ServiceStackable {
436
251
  pinoOptions.timestamp = buildPinoTimestamp(this.loggerConfig?.timestamp)
437
252
  }
438
253
 
439
- this.logger = pino(pinoOptions)
254
+ const logger = pino(pinoOptions)
440
255
 
441
256
  // Only one of logger and loggerInstance should be set
442
- delete this.configManager.current.server.logger
443
- this.configManager.current.server.loggerInstance = this.logger
257
+ this.serverConfig.loggerInstance = logger
258
+ delete this.serverConfig.logger
259
+
260
+ return logger
444
261
  }
445
- }
446
262
 
447
- module.exports = { ServiceStackable }
263
+ async _listen () {
264
+ const serverOptions = this.serverConfig
265
+ const listenOptions = { host: serverOptions?.hostname || '127.0.0.1', port: serverOptions?.port || 0 }
266
+
267
+ if (this.isProduction && features.node.reusePort) {
268
+ listenOptions.reusePort = true
269
+ }
270
+
271
+ await this.#app.listen(listenOptions)
272
+ this.url = getServerUrl(this.#app.server)
273
+
274
+ if (this.serverConfig.http2 || this.serverConfig.https?.key) {
275
+ this.url = this.url.replace('http://', 'https://')
276
+ }
277
+
278
+ return this.url
279
+ }
280
+ }
package/lib/upgrade.js CHANGED
@@ -1,15 +1,13 @@
1
- 'use strict'
2
-
3
- const { join } = require('path')
4
-
5
- module.exports = async function upgrade (config, version) {
6
- const { semgrator } = await import('semgrator')
1
+ import { abstractLogger } from '@platformatic/foundation'
2
+ import { resolve } from 'node:path'
3
+ import { semgrator } from 'semgrator'
7
4
 
5
+ export async function upgrade (logger, config, version) {
8
6
  const iterator = semgrator({
9
7
  version,
10
- path: join(__dirname, 'versions'),
8
+ path: resolve(import.meta.dirname, 'versions'),
11
9
  input: config,
12
- logger: this.logger.child({ name: '@platformatic/service' }),
10
+ logger: logger?.child({ name: '@platformatic/service' }) ?? abstractLogger
13
11
  })
14
12
 
15
13
  let result