@platformatic/basic 2.6.1 → 2.7.1-alpha.1

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/lib/base.js CHANGED
@@ -3,6 +3,7 @@ import { collectMetrics } from '@platformatic/metrics'
3
3
  import { parseCommandString } from 'execa'
4
4
  import { spawn } from 'node:child_process'
5
5
  import { once } from 'node:events'
6
+ import { workerData } from 'node:worker_threads'
6
7
  import { existsSync } from 'node:fs'
7
8
  import { platform } from 'node:os'
8
9
  import { pathToFileURL } from 'node:url'
@@ -12,6 +13,8 @@ import { NonZeroExitCode } from './errors.js'
12
13
  import { cleanBasePath } from './utils.js'
13
14
  import { ChildManager } from './worker/child-manager.js'
14
15
 
16
+ const kITC = Symbol.for('plt.runtime.itc')
17
+
15
18
  export class BaseStackable {
16
19
  childManager
17
20
  #subprocess
@@ -34,6 +37,7 @@ export class BaseStackable {
34
37
  this.startHttpTimer = null
35
38
  this.endHttpTimer = null
36
39
  this.clientWs = null
40
+ this.runtimeConfig = workerData?.config ?? null
37
41
 
38
42
  // Setup the logger
39
43
  const pinoOptions = {
@@ -49,7 +53,8 @@ export class BaseStackable {
49
53
  this.registerGlobals({
50
54
  setOpenapiSchema: this.setOpenapiSchema.bind(this),
51
55
  setGraphqlSchema: this.setGraphqlSchema.bind(this),
52
- setBasePath: this.setBasePath.bind(this)
56
+ setBasePath: this.setBasePath.bind(this),
57
+ invalidateHttpCache: this.#invalidateHttpCache.bind(this)
53
58
  })
54
59
  }
55
60
 
@@ -134,20 +139,12 @@ export class BaseStackable {
134
139
 
135
140
  this.logger.debug(`Executing "${command}" ...`)
136
141
 
142
+ const context = await this.#getChildManagerContext(basePath)
137
143
  this.childManager = new ChildManager({
138
144
  logger: this.logger,
139
145
  loader,
140
146
  scripts,
141
- context: {
142
- id: this.id,
143
- // Always use URL to avoid serialization problem in Windows
144
- root: pathToFileURL(this.root).toString(),
145
- basePath,
146
- logLevel: this.logger.level,
147
- /* c8 ignore next 2 */
148
- port: (this.isEntrypoint ? this.serverConfig?.port || 0 : undefined) ?? true,
149
- host: (this.isEntrypoint ? this.serverConfig?.hostname : undefined) ?? true
150
- }
147
+ context
151
148
  })
152
149
 
153
150
  try {
@@ -188,20 +185,12 @@ export class BaseStackable {
188
185
  async startWithCommand (command, loader) {
189
186
  const config = this.configManager.current
190
187
  const basePath = config.application?.basePath ? cleanBasePath(config.application?.basePath) : ''
188
+
189
+ const context = await this.#getChildManagerContext(basePath)
191
190
  this.childManager = new ChildManager({
192
191
  logger: this.logger,
193
192
  loader,
194
- context: {
195
- id: this.id,
196
- // Always use URL to avoid serialization problem in Windows
197
- root: pathToFileURL(this.root).toString(),
198
- basePath,
199
- logLevel: this.logger.level,
200
- /* c8 ignore next 2 */
201
- port: (this.isEntrypoint ? this.serverConfig?.port || 0 : undefined) ?? true,
202
- host: (this.isEntrypoint ? this.serverConfig?.hostname : undefined) ?? true,
203
- telemetry: this.telemetryConfig
204
- }
193
+ context
205
194
  })
206
195
 
207
196
  this.childManager.on('config', config => {
@@ -312,4 +301,35 @@ export class BaseStackable {
312
301
  ? await this.metricsRegistry.getMetricsAsJSON()
313
302
  : await this.metricsRegistry.metrics()
314
303
  }
304
+
305
+ async #invalidateHttpCache (opts = {}) {
306
+ await globalThis[kITC].send('invalidateHttpCache', opts)
307
+ }
308
+
309
+ getMeta () {
310
+ return {
311
+ composer: {
312
+ wantsAbsoluteUrls: false
313
+ }
314
+ }
315
+ }
316
+
317
+ async #getChildManagerContext (basePath) {
318
+ const meta = await this.getMeta()
319
+
320
+ return {
321
+ id: this.id,
322
+ // Always use URL to avoid serialization problem in Windows
323
+ root: pathToFileURL(this.root).toString(),
324
+ basePath,
325
+ logLevel: this.logger.level,
326
+ isEntrypoint: this.isEntrypoint,
327
+ runtimeBasePath: this.runtimeConfig?.basePath ?? null,
328
+ wantsAbsoluteUrls: meta.composer?.wantsAbsoluteUrls ?? false,
329
+ /* c8 ignore next 2 */
330
+ port: (this.isEntrypoint ? this.serverConfig?.port || 0 : undefined) ?? true,
331
+ host: (this.isEntrypoint ? this.serverConfig?.hostname : undefined) ?? true,
332
+ telemetry: this.telemetryConfig
333
+ }
334
+ }
315
335
  }
@@ -16,6 +16,8 @@ import { WebSocket } from 'ws'
16
16
  import { exitCodes } from '../errors.js'
17
17
  import { importFile } from '../utils.js'
18
18
  import { getSocketPath, isWindows } from './child-manager.js'
19
+ import diagnosticChannel from 'node:diagnostics_channel'
20
+ import { ServerResponse } from 'node:http'
19
21
 
20
22
  function createInterceptor (itc) {
21
23
  return function (dispatch) {
@@ -248,6 +250,11 @@ export class ChildProcess extends ITC {
248
250
  }
249
251
 
250
252
  tracingChannel('net.server.listen').subscribe(subscribers)
253
+
254
+ const { isEntrypoint, runtimeBasePath, wantsAbsoluteUrls } = globalThis.platformatic
255
+ if (isEntrypoint && runtimeBasePath && !wantsAbsoluteUrls) {
256
+ stripBasePath(runtimeBasePath)
257
+ }
251
258
  }
252
259
 
253
260
  #setupInterceptors () {
@@ -270,6 +277,56 @@ export class ChildProcess extends ITC {
270
277
  }
271
278
  }
272
279
 
280
+ function stripBasePath (basePath) {
281
+ const kBasePath = Symbol('kBasePath')
282
+
283
+ diagnosticChannel.subscribe('http.server.request.start', ({ request, response }) => {
284
+ if (request.url.startsWith(basePath)) {
285
+ request.url = request.url.slice(basePath.length)
286
+
287
+ if (request.url.charAt(0) !== '/') {
288
+ request.url = '/' + request.url
289
+ }
290
+
291
+ response[kBasePath] = basePath
292
+ }
293
+ })
294
+
295
+ const originWriteHead = ServerResponse.prototype.writeHead
296
+ const originSetHeader = ServerResponse.prototype.setHeader
297
+
298
+ ServerResponse.prototype.writeHead = function (statusCode, statusMessage, headers) {
299
+ if (this[kBasePath] !== undefined) {
300
+ if (headers === undefined && typeof statusMessage === 'object') {
301
+ headers = statusMessage
302
+ statusMessage = undefined
303
+ }
304
+
305
+ if (headers) {
306
+ for (const key in headers) {
307
+ if (
308
+ key.toLowerCase() === 'location' &&
309
+ !headers[key].startsWith(basePath)
310
+ ) {
311
+ headers[key] = basePath + headers[key]
312
+ }
313
+ }
314
+ }
315
+ }
316
+
317
+ return originWriteHead.call(this, statusCode, statusMessage, headers)
318
+ }
319
+
320
+ ServerResponse.prototype.setHeader = function (name, value) {
321
+ if (this[kBasePath]) {
322
+ if (name.toLowerCase() === 'location' && !value.startsWith(basePath)) {
323
+ value = basePath + value
324
+ }
325
+ }
326
+ originSetHeader.call(this, name, value)
327
+ }
328
+ }
329
+
273
330
  async function main () {
274
331
  const dataPath = resolve(tmpdir(), 'platformatic', 'runtimes', `${process.env.PLT_MANAGER_ID}.json`)
275
332
  const { data, loader, scripts } = JSON.parse(await readFile(dataPath))
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@platformatic/basic",
3
- "version": "2.6.1",
3
+ "version": "2.7.1-alpha.1",
4
4
  "description": "",
5
5
  "main": "index.js",
6
6
  "type": "module",
@@ -23,11 +23,11 @@
23
23
  "split2": "^4.2.0",
24
24
  "undici": "^6.19.5",
25
25
  "ws": "^8.18.0",
26
- "@platformatic/config": "2.6.1",
27
- "@platformatic/itc": "2.6.1",
28
- "@platformatic/telemetry": "2.6.1",
29
- "@platformatic/metrics": "2.6.1",
30
- "@platformatic/utils": "2.6.1"
26
+ "@platformatic/config": "2.7.1-alpha.1",
27
+ "@platformatic/itc": "2.7.1-alpha.1",
28
+ "@platformatic/telemetry": "2.7.1-alpha.1",
29
+ "@platformatic/utils": "2.7.1-alpha.1",
30
+ "@platformatic/metrics": "2.7.1-alpha.1"
31
31
  },
32
32
  "devDependencies": {
33
33
  "borp": "^0.18.0",
package/schema.json CHANGED
@@ -1,5 +1,5 @@
1
1
  {
2
- "$id": "https://schemas.platformatic.dev/@platformatic/basic/2.6.1.json",
2
+ "$id": "https://schemas.platformatic.dev/@platformatic/basic/2.7.1-alpha.1.json",
3
3
  "$schema": "http://json-schema.org/draft-07/schema#",
4
4
  "title": "Platformatic Stackable",
5
5
  "type": "object",