@platformatic/runtime 2.21.1 → 2.23.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/config.d.ts CHANGED
@@ -5,7 +5,7 @@
5
5
  * and run json-schema-to-typescript to regenerate this file.
6
6
  */
7
7
 
8
- export type HttpsSchemasPlatformaticDevPlatformaticRuntime2211Json = {
8
+ export type HttpsSchemasPlatformaticDevPlatformaticRuntime2230Json = {
9
9
  [k: string]: unknown;
10
10
  } & {
11
11
  $schema?: string;
@@ -177,6 +177,10 @@ export type HttpsSchemasPlatformaticDevPlatformaticRuntime2211Json = {
177
177
  };
178
178
  serviceTimeout?: number | string;
179
179
  resolvedServicesBasePath?: string;
180
+ env?: {
181
+ [k: string]: string;
182
+ };
183
+ sourceMaps?: boolean;
180
184
  };
181
185
 
182
186
  export interface UndiciInterceptor {
@@ -1,9 +1,9 @@
1
1
  'use strict'
2
2
 
3
- const { createRequire } = require('node:module')
4
3
  const { join } = require('node:path')
5
4
 
6
5
  const ConfigManager = require('@platformatic/config')
6
+ const { createRequire } = require('@platformatic/utils')
7
7
 
8
8
  const { platformaticRuntime } = require('./config')
9
9
  const { buildRuntime } = require('./start')
package/lib/compile.js CHANGED
@@ -1,6 +1,6 @@
1
1
  'use strict'
2
2
 
3
- const { createRequire } = require('node:module')
3
+ const { createRequire } = require('@platformatic/utils')
4
4
  const { dirname, join } = require('node:path')
5
5
  const { isatty } = require('node:tty')
6
6
  const { pathToFileURL } = require('node:url')
@@ -12,9 +12,14 @@ const pretty = require('pino-pretty')
12
12
  const { loadConfig } = require('./utils')
13
13
 
14
14
  async function compile (argv, logger) {
15
- const { configManager, configType, app } = await loadConfig({}, argv, {
16
- watch: false,
17
- }, false)
15
+ const { configManager, configType, app } = await loadConfig(
16
+ {},
17
+ argv,
18
+ {
19
+ watch: false
20
+ },
21
+ false
22
+ )
18
23
  /* c8 ignore next */
19
24
  if (!logger) {
20
25
  let stream
@@ -22,7 +27,7 @@ async function compile (argv, logger) {
22
27
  if (isatty(process.stdout.fd)) {
23
28
  stream = pretty({
24
29
  translateTime: 'SYS:HH:MM:ss',
25
- ignore: 'hostname,pid',
30
+ ignore: 'hostname,pid'
26
31
  })
27
32
  }
28
33
 
@@ -31,19 +36,24 @@ async function compile (argv, logger) {
31
36
 
32
37
  let compiled = false
33
38
  const compileOptions = {
34
- clean: argv.includes('--clean'),
39
+ clean: argv.includes('--clean')
35
40
  }
36
41
  if (configType === 'runtime') {
37
42
  for (const service of configManager.current.services) {
38
43
  const childLogger = logger.child({ name: service.id })
39
44
 
40
45
  const serviceConfigPath = service.config
41
- const { configManager, app } = await loadConfig({}, ['-c', serviceConfigPath], {
42
- onMissingEnv (key) {
43
- return service.localServiceEnvVars.get(key)
46
+ const { configManager, app } = await loadConfig(
47
+ {},
48
+ ['-c', serviceConfigPath],
49
+ {
50
+ onMissingEnv (key) {
51
+ return service.localServiceEnvVars.get(key)
52
+ },
53
+ watch: false
44
54
  },
45
- watch: false,
46
- }, false)
55
+ false
56
+ )
47
57
 
48
58
  const tsOptions = await extract(configManager, app)
49
59
 
@@ -52,7 +62,7 @@ async function compile (argv, logger) {
52
62
  ...compileOptions,
53
63
  ...tsOptions,
54
64
  cwd: service.path,
55
- logger: childLogger,
65
+ logger: childLogger
56
66
  })
57
67
  compiled ||= serviceWasCompiled
58
68
  }
@@ -64,7 +74,7 @@ async function compile (argv, logger) {
64
74
  ...compileOptions,
65
75
  ...tsOptions,
66
76
  cwd: dirname(configManager.fullPath),
67
- logger,
77
+ logger
68
78
  })
69
79
  }
70
80
  }
@@ -81,9 +91,9 @@ async function extract (configManager, app) {
81
91
  const _require = createRequire(join(configManager.dirname, 'package.json'))
82
92
  const toLoad = _require.resolve('@platformatic/service')
83
93
  try {
84
- extractTypeScriptCompileOptionsFromConfig = (await import(pathToFileURL(toLoad))).extractTypeScriptCompileOptionsFromConfig
85
- } catch {
86
- }
94
+ extractTypeScriptCompileOptionsFromConfig = (await import(pathToFileURL(toLoad)))
95
+ .extractTypeScriptCompileOptionsFromConfig
96
+ } catch {}
87
97
  // If we can't load `@platformatic/service` we just return null
88
98
  // and we won't be compiling typescript
89
99
  }
@@ -2,7 +2,6 @@
2
2
 
3
3
  const { BaseGenerator } = require('@platformatic/generators')
4
4
  const { NoEntryPointError, NoServiceNamedError } = require('./errors')
5
- const generateName = require('boring-name-generator')
6
5
  const { join } = require('node:path')
7
6
  const { envObjectToString } = require('@platformatic/generators/lib/utils')
8
7
  const { readFile, readdir, stat } = require('node:fs/promises')
@@ -11,15 +10,14 @@ const { platformaticRuntime } = require('../config')
11
10
  const { getServiceTemplateFromSchemaUrl } = require('@platformatic/generators/lib/utils')
12
11
  const { DotEnvTool } = require('dotenv-tool')
13
12
  const { getArrayDifference } = require('../utils')
14
- const { createRequire } = require('node:module')
15
13
  const { pathToFileURL } = require('node:url')
16
- const { safeRemove } = require('@platformatic/utils')
14
+ const { createRequire, safeRemove, generateDashedName } = require('@platformatic/utils')
17
15
 
18
16
  class RuntimeGenerator extends BaseGenerator {
19
17
  constructor (opts) {
20
18
  super({
21
19
  ...opts,
22
- module: '@platformatic/runtime',
20
+ module: '@platformatic/runtime'
23
21
  })
24
22
  this.runtimeName = opts.name
25
23
  this.services = []
@@ -29,18 +27,18 @@ class RuntimeGenerator extends BaseGenerator {
29
27
  async addService (service, name) {
30
28
  // ensure service config is correct
31
29
  const originalConfig = service.config
32
- const serviceName = name || generateName().dashed
30
+ const serviceName = name || generateDashedName()
33
31
  const newConfig = {
34
32
  ...originalConfig,
35
33
  isRuntimeContext: true,
36
- serviceName,
34
+ serviceName
37
35
  }
38
36
  // reset all files previously generated by the service
39
37
  service.reset()
40
38
  service.setConfig(newConfig)
41
39
  this.services.push({
42
40
  name: serviceName,
43
- service,
41
+ service
44
42
  })
45
43
 
46
44
  if (typeof service.setRuntime === 'function') {
@@ -61,20 +59,20 @@ class RuntimeGenerator extends BaseGenerator {
61
59
  name: `${this.runtimeName}`,
62
60
  workspaces: ['services/*'],
63
61
  scripts: {
64
- start: 'platformatic start',
62
+ start: 'platformatic start'
65
63
  },
66
64
  devDependencies: {
67
65
  fastify: `^${this.fastifyVersion}`,
68
- borp: `${this.pkgData.devDependencies.borp}`,
66
+ borp: `${this.pkgData.devDependencies.borp}`
69
67
  },
70
68
  dependencies: {
71
69
  '@platformatic/runtime': `^${this.platformaticVersion}`,
72
70
  platformatic: `^${this.platformaticVersion}`,
73
- ...this.config.dependencies,
71
+ ...this.config.dependencies
74
72
  },
75
73
  engines: {
76
- node: '^18.8.0 || >=20.6.0',
77
- },
74
+ node: '^18.8.0 || >=20.6.0'
75
+ }
78
76
  }
79
77
  if (this.config.typescript) {
80
78
  const typescriptVersion = JSON.parse(await readFile(join(__dirname, '..', '..', 'package.json'), 'utf-8'))
@@ -96,7 +94,7 @@ class RuntimeGenerator extends BaseGenerator {
96
94
  PLT_SERVER_HOSTNAME: '127.0.0.1',
97
95
  PORT: this.config.port || 3042,
98
96
  PLT_SERVER_LOGGER_LEVEL: this.config.logLevel || 'info',
99
- PLT_MANAGEMENT_API: true,
97
+ PLT_MANAGEMENT_API: true
100
98
  },
101
99
  { overwrite: false, default: true }
102
100
  )
@@ -121,7 +119,7 @@ class RuntimeGenerator extends BaseGenerator {
121
119
  if (existingConfigFile) {
122
120
  const configManager = new ConfigManager({
123
121
  ...platformaticRuntime.configManagerConfig,
124
- source: join(this.targetDirectory, existingConfigFile),
122
+ source: join(this.targetDirectory, existingConfigFile)
125
123
  })
126
124
  await configManager.parse()
127
125
  this.existingConfig = configManager.current
@@ -139,7 +137,7 @@ class RuntimeGenerator extends BaseGenerator {
139
137
  await this._afterPrepare()
140
138
  return {
141
139
  env: this.config.env,
142
- targetDirectory: this.targetDirectory,
140
+ targetDirectory: this.targetDirectory
143
141
  }
144
142
  } else {
145
143
  return await super.prepare()
@@ -163,16 +161,16 @@ class RuntimeGenerator extends BaseGenerator {
163
161
  watch: true,
164
162
  autoload: {
165
163
  path: this.config.autoload || 'services',
166
- exclude: ['docs'],
164
+ exclude: ['docs']
167
165
  },
168
166
  logger: {
169
- level: '{PLT_SERVER_LOGGER_LEVEL}',
167
+ level: '{PLT_SERVER_LOGGER_LEVEL}'
170
168
  },
171
169
  server: {
172
170
  hostname: '{PLT_SERVER_HOSTNAME}',
173
171
  port: '{PORT}'
174
172
  },
175
- managementApi: '{PLT_MANAGEMENT_API}',
173
+ managementApi: '{PLT_MANAGEMENT_API}'
176
174
  }
177
175
 
178
176
  return config
@@ -186,19 +184,19 @@ class RuntimeGenerator extends BaseGenerator {
186
184
  this.addEnvVars({
187
185
  ...this.config.env,
188
186
  ...this.getRuntimeEnv(),
189
- ...servicesEnv,
187
+ ...servicesEnv
190
188
  })
191
189
 
192
190
  this.addFile({
193
191
  path: '',
194
192
  file: '.env',
195
- contents: envObjectToString(this.config.env),
193
+ contents: envObjectToString(this.config.env)
196
194
  })
197
195
 
198
196
  this.addFile({
199
197
  path: '',
200
198
  file: '.env.sample',
201
- contents: envObjectToString(this.config.env),
199
+ contents: envObjectToString(this.config.env)
202
200
  })
203
201
 
204
202
  if (!this.existingConfig) {
@@ -207,7 +205,7 @@ class RuntimeGenerator extends BaseGenerator {
207
205
 
208
206
  return {
209
207
  targetDirectory: this.targetDirectory,
210
- env: servicesEnv,
208
+ env: servicesEnv
211
209
  }
212
210
  }
213
211
 
@@ -231,8 +229,8 @@ class RuntimeGenerator extends BaseGenerator {
231
229
  default: false,
232
230
  choices: [
233
231
  { name: 'yes', value: true },
234
- { name: 'no', value: false },
235
- ],
232
+ { name: 'no', value: false }
233
+ ]
236
234
  })
237
235
 
238
236
  if (this.existingConfig) {
@@ -244,7 +242,7 @@ class RuntimeGenerator extends BaseGenerator {
244
242
  type: 'input',
245
243
  name: 'port',
246
244
  default: 3042,
247
- message: 'What port do you want to use?',
245
+ message: 'What port do you want to use?'
248
246
  })
249
247
  }
250
248
 
@@ -269,7 +267,7 @@ class RuntimeGenerator extends BaseGenerator {
269
267
  const originalConfig = service.config
270
268
  service.setConfig({
271
269
  ...originalConfig,
272
- ...configToOverride,
270
+ ...configToOverride
273
271
  })
274
272
  })
275
273
  }
@@ -280,12 +278,12 @@ class RuntimeGenerator extends BaseGenerator {
280
278
  // Propagate TypeScript
281
279
  svc.service.setConfig({
282
280
  ...svc.service.config,
283
- typescript: this.config.typescript,
281
+ typescript: this.config.typescript
284
282
  })
285
283
  const svcEnv = await svc.service.prepare()
286
284
  servicesEnv = {
287
285
  ...servicesEnv,
288
- ...svcEnv.env,
286
+ ...svcEnv.env
289
287
  }
290
288
  }
291
289
  return servicesEnv
@@ -301,7 +299,7 @@ class RuntimeGenerator extends BaseGenerator {
301
299
 
302
300
  getRuntimeEnv () {
303
301
  return {
304
- PORT: this.config.port,
302
+ PORT: this.config.port
305
303
  }
306
304
  }
307
305
 
@@ -319,7 +317,7 @@ class RuntimeGenerator extends BaseGenerator {
319
317
 
320
318
  async loadFromDir () {
321
319
  const output = {
322
- services: [],
320
+ services: []
323
321
  }
324
322
  const runtimePkgConfigFileData = JSON.parse(
325
323
  await readFile(join(this.targetDirectory, 'platformatic.json'), 'utf-8')
@@ -339,7 +337,7 @@ class RuntimeGenerator extends BaseGenerator {
339
337
  const template = servicePltJson.module || getServiceTemplateFromSchemaUrl(servicePltJson.$schema)
340
338
  const Generator = await this._getGeneratorForTemplate(currentServicePath, template)
341
339
  const instance = new Generator({
342
- logger: this.logger,
340
+ logger: this.logger
343
341
  })
344
342
  this.addService(instance, s)
345
343
  output.services.push(await instance.loadFromDir(s, this.targetDirectory))
@@ -360,7 +358,7 @@ class RuntimeGenerator extends BaseGenerator {
360
358
  const allNewServicesNames = newConfig.services.map(s => s.name)
361
359
  // load dotenv tool
362
360
  const envTool = new DotEnvTool({
363
- path: join(this.targetDirectory, '.env'),
361
+ path: join(this.targetDirectory, '.env')
364
362
  })
365
363
 
366
364
  await envTool.load()
@@ -402,13 +400,13 @@ class RuntimeGenerator extends BaseGenerator {
402
400
  newService.template
403
401
  )
404
402
  const serviceInstance = new ServiceGenerator({
405
- logger: this.logger,
403
+ logger: this.logger
406
404
  })
407
405
  const baseConfig = {
408
406
  isRuntimeContext: true,
409
407
  targetDirectory: join(this.targetDirectory, 'services', newService.name),
410
408
  serviceName: newService.name,
411
- plugin: true,
409
+ plugin: true
412
410
  }
413
411
  if (allCurrentServicesNames.includes(newService.name)) {
414
412
  // update existing services env values
@@ -425,7 +423,7 @@ class RuntimeGenerator extends BaseGenerator {
425
423
  // add service to the generator
426
424
  this.services.push({
427
425
  name: newService.name,
428
- service: serviceInstance,
426
+ service: serviceInstance
429
427
  })
430
428
  }
431
429
  serviceInstance.setConfig(baseConfig)
@@ -464,12 +462,12 @@ class RuntimeGenerator extends BaseGenerator {
464
462
  // update runtime package.json dependencies
465
463
  currrentPackageJson.dependencies = {
466
464
  ...currrentPackageJson.dependencies,
467
- ...allServicesDependencies,
465
+ ...allServicesDependencies
468
466
  }
469
467
  this.addFile({
470
468
  path: '',
471
469
  file: 'package.json',
472
- contents: JSON.stringify(currrentPackageJson, null, 2),
470
+ contents: JSON.stringify(currrentPackageJson, null, 2)
473
471
  })
474
472
 
475
473
  // set new entrypoint if specified
@@ -485,7 +483,7 @@ class RuntimeGenerator extends BaseGenerator {
485
483
  this.addFile({
486
484
  path: '',
487
485
  file: 'platformatic.json',
488
- contents: JSON.stringify(runtimePkgConfigFileData, null, 2),
486
+ contents: JSON.stringify(runtimePkgConfigFileData, null, 2)
489
487
  })
490
488
  }
491
489
  await this.writeFiles()
package/lib/runtime.js CHANGED
@@ -3,10 +3,12 @@
3
3
  const { once, EventEmitter } = require('node:events')
4
4
  const { createReadStream, watch, existsSync } = require('node:fs')
5
5
  const { readdir, readFile, stat, access } = require('node:fs/promises')
6
+ const { STATUS_CODES } = require('node:http')
6
7
  const { join } = require('node:path')
7
8
  const { setTimeout: sleep } = require('node:timers/promises')
8
9
  const { Worker } = require('node:worker_threads')
9
10
  const { ITC } = require('@platformatic/itc')
11
+ const { Agent, interceptors: undiciInterceptors, request } = require('undici')
10
12
  const { ensureLoggableError, executeWithTimeout, deepmerge } = require('@platformatic/utils')
11
13
  const ts = require('tail-file-stream')
12
14
  const { createThreadInterceptor } = require('undici-thread-interceptor')
@@ -61,7 +63,8 @@ class Runtime extends EventEmitter {
61
63
  #metrics
62
64
  #metricsTimeout
63
65
  #status
64
- #interceptor
66
+ #meshInterceptor
67
+ #dispatcher
65
68
  #managementApi
66
69
  #prometheusServer
67
70
  #inspectorServer
@@ -80,8 +83,7 @@ class Runtime extends EventEmitter {
80
83
  this.#workers = new RoundRobinMap()
81
84
  this.#servicesIds = []
82
85
  this.#url = undefined
83
- // Note: nothing hits the main thread so there is no reason to set the globalDispatcher here
84
- this.#interceptor = createThreadInterceptor({
86
+ this.#meshInterceptor = createThreadInterceptor({
85
87
  domain: '.plt.local',
86
88
  timeout: this.#configManager.current.serviceTimeout
87
89
  })
@@ -182,10 +184,17 @@ class Runtime extends EventEmitter {
182
184
  throw e
183
185
  }
184
186
 
185
- this.#sharedHttpCache = createSharedStore(
186
- this.#configManager.dirname,
187
- config.httpCache
188
- )
187
+ const dispatcherOpts = { ...config.undici }
188
+ const interceptors = [this.#meshInterceptor]
189
+
190
+ if (config.httpCache) {
191
+ this.#sharedHttpCache = await createSharedStore(this.#configManager.dirname, config.httpCache)
192
+ interceptors.push(
193
+ undiciInterceptors.cache({ store: this.#sharedHttpCache, methods: config.httpCache.methods ?? ['GET', 'HEAD'] })
194
+ )
195
+ }
196
+
197
+ this.#dispatcher = new Agent(dispatcherOpts).compose(interceptors)
189
198
 
190
199
  this.#updateStatus('init')
191
200
  }
@@ -375,8 +384,48 @@ class Runtime extends EventEmitter {
375
384
  }
376
385
 
377
386
  async inject (id, injectParams) {
378
- const service = await this.#getServiceById(id, true)
379
- return sendViaITC(service, 'inject', injectParams)
387
+ // Make sure the service exists
388
+ await this.#getServiceById(id, true)
389
+
390
+ if (typeof injectParams === 'string') {
391
+ injectParams = { url: injectParams }
392
+ }
393
+
394
+ let { method, headers, body } = injectParams
395
+ const url = new URL(injectParams.url, `http://${id}.plt.local`)
396
+
397
+ if (injectParams.query) {
398
+ for (const [k, v] of Object.entries(injectParams.query)) {
399
+ url.searchParams.append(k, v)
400
+ }
401
+ }
402
+
403
+ // Stringify the body as JSON if needed
404
+ if (
405
+ body &&
406
+ typeof body === 'object' &&
407
+ headers &&
408
+ Object.entries(headers).some(([k, v]) => k.toLowerCase() === 'content-type' && v.includes('application/json'))
409
+ ) {
410
+ body = JSON.stringify(body)
411
+ }
412
+
413
+ const {
414
+ statusCode: responseStatus,
415
+ headers: responseHeaders,
416
+ body: responseRawBody
417
+ } = await request(url.toString(), { method, headers, body, dispatcher: this.#dispatcher })
418
+ const responsePayload = await responseRawBody.arrayBuffer()
419
+ const responseBody = Buffer.from(responsePayload).toString('utf-8')
420
+
421
+ return {
422
+ statusCode: responseStatus,
423
+ statusMessage: STATUS_CODES[responseStatus] || 'unknown',
424
+ headers: responseHeaders,
425
+ body: responseBody,
426
+ payload: responseBody,
427
+ rawPayload: responsePayload
428
+ }
380
429
  }
381
430
 
382
431
  startCollectingMetrics () {
@@ -520,7 +569,11 @@ class Runtime extends EventEmitter {
520
569
  }
521
570
 
522
571
  getInterceptor () {
523
- return this.#interceptor
572
+ return this.#meshInterceptor
573
+ }
574
+
575
+ getDispatcher () {
576
+ return this.#dispatcher
524
577
  }
525
578
 
526
579
  getManagementApi () {
@@ -781,10 +834,36 @@ class Runtime extends EventEmitter {
781
834
  return createReadStream(filePath)
782
835
  }
783
836
 
784
- async invalidateHttpCache (options = {}) {
837
+ #getHttpCacheValue ({ request }) {
838
+ if (!this.#sharedHttpCache) {
839
+ return
840
+ }
841
+
842
+ return this.#sharedHttpCache.getValue(request)
843
+ }
844
+
845
+ #setHttpCacheValue ({ request, response, payload }) {
846
+ if (!this.#sharedHttpCache) {
847
+ return
848
+ }
849
+
850
+ return this.#sharedHttpCache.setValue(request, response, payload)
851
+ }
852
+
853
+ #deleteHttpCacheValue ({ request }) {
854
+ if (!this.#sharedHttpCache) {
855
+ return
856
+ }
857
+
858
+ return this.#sharedHttpCache.delete(request)
859
+ }
860
+
861
+ invalidateHttpCache (options = {}) {
785
862
  const { keys, tags } = options
786
863
 
787
- if (!this.#sharedHttpCache) return
864
+ if (!this.#sharedHttpCache) {
865
+ return
866
+ }
788
867
 
789
868
  const promises = []
790
869
  if (keys && keys.length > 0) {
@@ -795,7 +874,7 @@ class Runtime extends EventEmitter {
795
874
  promises.push(this.#sharedHttpCache.deleteTags(tags))
796
875
  }
797
876
 
798
- await Promise.all(promises)
877
+ return Promise.all(promises)
799
878
  }
800
879
 
801
880
  async sendCommandToService (id, name, message) {
@@ -862,6 +941,16 @@ class Runtime extends EventEmitter {
862
941
  const errorLabel = this.#workerExtendedLabel(serviceId, index, workersCount)
863
942
  const health = deepmerge(config.health ?? {}, serviceConfig.health ?? {})
864
943
 
944
+ const execArgv = []
945
+
946
+ if (!serviceConfig.isPLTService) {
947
+ execArgv.push('--require', openTelemetrySetupPath)
948
+ }
949
+
950
+ if ((serviceConfig.sourceMaps ?? config.sourceMaps) === true) {
951
+ execArgv.push('--enable-source-maps')
952
+ }
953
+
865
954
  const worker = new Worker(kWorkerFile, {
866
955
  workerData: {
867
956
  config,
@@ -879,7 +968,7 @@ class Runtime extends EventEmitter {
879
968
  runtimeLogsDir: this.#runtimeLogsDir,
880
969
  loggingPort
881
970
  },
882
- execArgv: serviceConfig.isPLTService ? [] : ['--require', openTelemetrySetupPath],
971
+ execArgv,
883
972
  env: this.#env,
884
973
  transferList: [loggingPort],
885
974
  resourceLimits: {
@@ -956,16 +1045,10 @@ class Runtime extends EventEmitter {
956
1045
  getServiceMeta: this.getServiceMeta.bind(this),
957
1046
  listServices: () => this.#servicesIds,
958
1047
  getServices: this.getServices.bind(this),
959
- getHttpCacheValue: opts => this.#sharedHttpCache.getValue(opts.request),
960
- setHttpCacheValue: opts => this.#sharedHttpCache.setValue(
961
- opts.request,
962
- opts.response,
963
- opts.payload
964
- ),
965
- deleteHttpCacheValue: opts => this.#sharedHttpCache.delete(
966
- opts.request
967
- ),
968
- invalidateHttpCache: opts => this.invalidateHttpCache(opts),
1048
+ getHttpCacheValue: this.#getHttpCacheValue.bind(this),
1049
+ setHttpCacheValue: this.#setHttpCacheValue.bind(this),
1050
+ deleteHttpCacheValue: this.#deleteHttpCacheValue.bind(this),
1051
+ invalidateHttpCache: this.invalidateHttpCache.bind(this)
969
1052
  }
970
1053
  })
971
1054
  worker[kITC].listen()
@@ -1004,7 +1087,7 @@ class Runtime extends EventEmitter {
1004
1087
  }
1005
1088
 
1006
1089
  // Setup the interceptor
1007
- this.#interceptor.route(serviceId, worker)
1090
+ this.#meshInterceptor.route(serviceId, worker)
1008
1091
 
1009
1092
  // Store dependencies
1010
1093
  const [{ dependencies }] = await waitEventFromITC(worker, 'init')
package/lib/schema.js CHANGED
@@ -6,6 +6,13 @@ const {
6
6
  schemaComponents: { server, logger, health }
7
7
  } = require('@platformatic/utils')
8
8
 
9
+ const env = {
10
+ type: 'object',
11
+ additionalProperties: {
12
+ type: 'string'
13
+ }
14
+ }
15
+
9
16
  const workers = {
10
17
  anyOf: [
11
18
  {
@@ -37,11 +44,23 @@ const services = {
37
44
  url: {
38
45
  type: 'string'
39
46
  },
47
+ gitBranch: {
48
+ type: 'string',
49
+ default: 'main'
50
+ },
40
51
  useHttp: {
41
52
  type: 'boolean'
42
53
  },
43
54
  workers,
44
- health: { ...health, default: undefined }
55
+ health: { ...health, default: undefined },
56
+ env,
57
+ envfile: {
58
+ type: 'string'
59
+ },
60
+ sourceMaps: {
61
+ type: 'boolean',
62
+ default: false
63
+ }
45
64
  }
46
65
  }
47
66
  }
@@ -316,6 +335,11 @@ const platformaticRuntimeSchema = {
316
335
  resolvedServicesBasePath: {
317
336
  type: 'string',
318
337
  default: 'external'
338
+ },
339
+ env,
340
+ sourceMaps: {
341
+ type: 'boolean',
342
+ default: false
319
343
  }
320
344
  },
321
345
  anyOf: [{ required: ['autoload'] }, { required: ['services'] }, { required: ['web'] }],
@@ -1,14 +1,14 @@
1
1
  'use strict'
2
2
 
3
3
  const { join } = require('node:path')
4
- const { createRequire } = require('node:module')
4
+ const { createRequire, loadModule } = require('@platformatic/utils')
5
5
  const MemoryCacheStore = require('@platformatic/undici-cache-memory')
6
6
 
7
- function createSharedStore (projectDir, httpCacheConfig = {}) {
7
+ async function createSharedStore (projectDir, httpCacheConfig = {}) {
8
8
  const runtimeRequire = createRequire(join(projectDir, 'file'))
9
9
 
10
10
  const { store, ...storeConfig } = httpCacheConfig
11
- const CacheStore = store ? runtimeRequire(store) : MemoryCacheStore
11
+ const CacheStore = store ? await loadModule(runtimeRequire, store) : MemoryCacheStore
12
12
 
13
13
  class SharedCacheStore extends CacheStore {
14
14
  async getValue (req) {
@@ -9,9 +9,11 @@ async function loadInterceptor (_require, module, options) {
9
9
  }
10
10
 
11
11
  function loadInterceptors (_require, interceptors) {
12
- return Promise.all(interceptors.map(async ({ module, options }) => {
13
- return loadInterceptor(_require, module, options)
14
- }))
12
+ return Promise.all(
13
+ interceptors.map(async ({ module, options }) => {
14
+ return loadInterceptor(_require, module, options)
15
+ })
16
+ )
15
17
  }
16
18
 
17
- module.exports = loadInterceptors
19
+ module.exports = { loadInterceptors }
@@ -1,15 +1,16 @@
1
1
  'use strict'
2
2
 
3
3
  const { EventEmitter } = require('node:events')
4
- const { createRequire } = require('node:module')
4
+ const { createRequire } = require('@platformatic/utils')
5
5
  const { hostname } = require('node:os')
6
- const { join } = require('node:path')
6
+ const { join, resolve } = require('node:path')
7
7
  const { parentPort, workerData, threadId } = require('node:worker_threads')
8
8
  const { pathToFileURL } = require('node:url')
9
9
  const inspector = require('node:inspector')
10
10
  const diagnosticChannel = require('node:diagnostics_channel')
11
11
  const { ServerResponse } = require('node:http')
12
12
 
13
+ const dotenv = require('dotenv')
13
14
  const pino = require('pino')
14
15
  const { fetch, setGlobalDispatcher, getGlobalDispatcher, Agent } = require('undici')
15
16
  const { wire } = require('undici-thread-interceptor')
@@ -18,7 +19,7 @@ const undici = require('undici')
18
19
  const RemoteCacheStore = require('./http-cache')
19
20
  const { PlatformaticApp } = require('./app')
20
21
  const { setupITC } = require('./itc')
21
- const loadInterceptors = require('./interceptors')
22
+ const { loadInterceptors } = require('./interceptors')
22
23
  const { createTelemetryThreadInterceptorHooks } = require('@platformatic/telemetry')
23
24
 
24
25
  const {
@@ -81,6 +82,22 @@ async function main () {
81
82
 
82
83
  const service = workerData.serviceConfig
83
84
 
85
+ // Load env file and mixin env vars from service config
86
+ if (service.envfile) {
87
+ const envfile = resolve(workerData.dirname, service.envfile)
88
+ globalThis.platformatic.logger.info({ envfile }, 'Loading envfile...')
89
+
90
+ dotenv.config({
91
+ path: envfile
92
+ })
93
+ }
94
+ if (config.env) {
95
+ Object.assign(process.env, config.env)
96
+ }
97
+ if (service.env) {
98
+ Object.assign(process.env, service.env)
99
+ }
100
+
84
101
  // Setup undici
85
102
  const interceptors = {}
86
103
  const composedInterceptors = []
@@ -124,8 +141,7 @@ async function main () {
124
141
  }
125
142
  }
126
143
 
127
- const globalDispatcher = new Agent(dispatcherOpts)
128
- .compose(composedInterceptors)
144
+ const globalDispatcher = new Agent(dispatcherOpts).compose(composedInterceptors)
129
145
 
130
146
  setGlobalDispatcher(globalDispatcher)
131
147
 
@@ -141,10 +157,12 @@ async function main () {
141
157
 
142
158
  if (config.httpCache) {
143
159
  setGlobalDispatcher(
144
- getGlobalDispatcher().compose(undici.interceptors.cache({
145
- store: new RemoteCacheStore(),
146
- methods: config.httpCache.methods ?? ['GET', 'HEAD']
147
- }))
160
+ getGlobalDispatcher().compose(
161
+ undici.interceptors.cache({
162
+ store: new RemoteCacheStore(),
163
+ methods: config.httpCache.methods ?? ['GET', 'HEAD']
164
+ })
165
+ )
148
166
  )
149
167
  }
150
168
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@platformatic/runtime",
3
- "version": "2.21.1",
3
+ "version": "2.23.0",
4
4
  "description": "",
5
5
  "main": "index.js",
6
6
  "bin": {
@@ -26,21 +26,21 @@
26
26
  "express": "^4.18.3",
27
27
  "fast-jwt": "^5.0.0",
28
28
  "get-port": "^7.1.0",
29
- "inspector-client": "^0.1.2",
29
+ "inspector-client": "^0.2.0",
30
30
  "json-schema-to-typescript": "^15.0.0",
31
- "neostandard": "^0.11.1",
31
+ "neostandard": "^0.12.0",
32
32
  "pino-abstract-transport": "^2.0.0",
33
33
  "split2": "^4.2.0",
34
34
  "tsd": "^0.31.0",
35
35
  "typescript": "^5.5.4",
36
36
  "undici-oidc-interceptor": "^0.5.0",
37
37
  "why-is-node-running": "^2.2.2",
38
- "@platformatic/composer": "2.21.1",
39
- "@platformatic/db": "2.21.1",
40
- "@platformatic/node": "2.21.1",
41
- "@platformatic/sql-graphql": "2.21.1",
42
- "@platformatic/service": "2.21.1",
43
- "@platformatic/sql-mapper": "2.21.1"
38
+ "@platformatic/composer": "2.23.0",
39
+ "@platformatic/db": "2.23.0",
40
+ "@platformatic/node": "2.23.0",
41
+ "@platformatic/service": "2.23.0",
42
+ "@platformatic/sql-graphql": "2.23.0",
43
+ "@platformatic/sql-mapper": "2.23.0"
44
44
  },
45
45
  "dependencies": {
46
46
  "@fastify/error": "^4.0.0",
@@ -49,12 +49,12 @@
49
49
  "@platformatic/http-metrics": "^0.2.1",
50
50
  "@platformatic/undici-cache-memory": "^0.8.1",
51
51
  "@watchable/unpromise": "^1.0.2",
52
- "boring-name-generator": "^1.0.3",
53
52
  "change-case-all": "^2.1.0",
54
53
  "close-with-grace": "^2.0.0",
55
54
  "commist": "^3.2.0",
56
55
  "debounce": "^2.0.0",
57
56
  "desm": "^1.3.1",
57
+ "dotenv": "^16.4.5",
58
58
  "dotenv-tool": "^0.1.1",
59
59
  "es-main": "^1.3.0",
60
60
  "fastest-levenshtein": "^1.0.16",
@@ -72,13 +72,13 @@
72
72
  "undici": "^7.0.0",
73
73
  "undici-thread-interceptor": "^0.10.0",
74
74
  "ws": "^8.16.0",
75
- "@platformatic/basic": "2.21.1",
76
- "@platformatic/itc": "2.21.1",
77
- "@platformatic/config": "2.21.1",
78
- "@platformatic/telemetry": "2.21.1",
79
- "@platformatic/utils": "2.21.1",
80
- "@platformatic/generators": "2.21.1",
81
- "@platformatic/ts-compiler": "2.21.1"
75
+ "@platformatic/basic": "2.23.0",
76
+ "@platformatic/config": "2.23.0",
77
+ "@platformatic/itc": "2.23.0",
78
+ "@platformatic/generators": "2.23.0",
79
+ "@platformatic/telemetry": "2.23.0",
80
+ "@platformatic/ts-compiler": "2.23.0",
81
+ "@platformatic/utils": "2.23.0"
82
82
  },
83
83
  "scripts": {
84
84
  "test": "npm run lint && borp --concurrency=1 --timeout=300000 && tsd",
package/schema.json CHANGED
@@ -1,5 +1,5 @@
1
1
  {
2
- "$id": "https://schemas.platformatic.dev/@platformatic/runtime/2.21.1.json",
2
+ "$id": "https://schemas.platformatic.dev/@platformatic/runtime/2.23.0.json",
3
3
  "$schema": "http://json-schema.org/draft-07/schema#",
4
4
  "type": "object",
5
5
  "properties": {
@@ -192,6 +192,10 @@
192
192
  "url": {
193
193
  "type": "string"
194
194
  },
195
+ "gitBranch": {
196
+ "type": "string",
197
+ "default": "main"
198
+ },
195
199
  "useHttp": {
196
200
  "type": "boolean"
197
201
  },
@@ -296,6 +300,19 @@
296
300
  }
297
301
  },
298
302
  "additionalProperties": false
303
+ },
304
+ "env": {
305
+ "type": "object",
306
+ "additionalProperties": {
307
+ "type": "string"
308
+ }
309
+ },
310
+ "envfile": {
311
+ "type": "string"
312
+ },
313
+ "sourceMaps": {
314
+ "type": "boolean",
315
+ "default": false
299
316
  }
300
317
  }
301
318
  }
@@ -345,6 +362,10 @@
345
362
  "url": {
346
363
  "type": "string"
347
364
  },
365
+ "gitBranch": {
366
+ "type": "string",
367
+ "default": "main"
368
+ },
348
369
  "useHttp": {
349
370
  "type": "boolean"
350
371
  },
@@ -449,6 +470,19 @@
449
470
  }
450
471
  },
451
472
  "additionalProperties": false
473
+ },
474
+ "env": {
475
+ "type": "object",
476
+ "additionalProperties": {
477
+ "type": "string"
478
+ }
479
+ },
480
+ "envfile": {
481
+ "type": "string"
482
+ },
483
+ "sourceMaps": {
484
+ "type": "boolean",
485
+ "default": false
452
486
  }
453
487
  }
454
488
  }
@@ -1113,6 +1147,16 @@
1113
1147
  "resolvedServicesBasePath": {
1114
1148
  "type": "string",
1115
1149
  "default": "external"
1150
+ },
1151
+ "env": {
1152
+ "type": "object",
1153
+ "additionalProperties": {
1154
+ "type": "string"
1155
+ }
1156
+ },
1157
+ "sourceMaps": {
1158
+ "type": "boolean",
1159
+ "default": false
1116
1160
  }
1117
1161
  },
1118
1162
  "anyOf": [