@platformatic/runtime 2.7.1-alpha.2 → 2.8.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/lib/schema.js CHANGED
@@ -6,6 +6,16 @@ const {
6
6
  schemaComponents: { server, logger }
7
7
  } = require('@platformatic/utils')
8
8
 
9
+ const workers = {
10
+ anyOf: [
11
+ {
12
+ type: 'number',
13
+ minimum: 1
14
+ },
15
+ { type: 'string' }
16
+ ]
17
+ }
18
+
9
19
  const services = {
10
20
  type: 'array',
11
21
  items: {
@@ -27,7 +37,8 @@ const services = {
27
37
  },
28
38
  useHttp: {
29
39
  type: 'boolean'
30
- }
40
+ },
41
+ workers
31
42
  }
32
43
  }
33
44
  }
@@ -90,6 +101,7 @@ const platformaticRuntimeSchema = {
90
101
  }
91
102
  },
92
103
  services,
104
+ workers: { ...workers, default: 1 },
93
105
  web: services,
94
106
  logger,
95
107
  server,
@@ -103,6 +115,34 @@ const platformaticRuntimeSchema = {
103
115
  }
104
116
  ]
105
117
  },
118
+ gracefulShutdown: {
119
+ type: 'object',
120
+ properties: {
121
+ runtime: {
122
+ anyOf: [
123
+ {
124
+ type: 'number',
125
+ minimum: 1
126
+ },
127
+ { type: 'string' }
128
+ ],
129
+ default: 10000
130
+ },
131
+ service: {
132
+ anyOf: [
133
+ {
134
+ type: 'number',
135
+ minimum: 1
136
+ },
137
+ { type: 'string' }
138
+ ],
139
+ default: 10000
140
+ }
141
+ },
142
+ default: {},
143
+ required: ['runtime', 'service'],
144
+ additionalProperties: false
145
+ },
106
146
  undici: {
107
147
  type: 'object',
108
148
  properties: {
@@ -145,32 +185,6 @@ const platformaticRuntimeSchema = {
145
185
  }
146
186
  }
147
187
  },
148
- httpCache: {
149
- oneOf: [
150
- {
151
- type: 'boolean'
152
- },
153
- {
154
- type: 'object',
155
- properties: {
156
- store: {
157
- type: 'string'
158
- },
159
- methods: {
160
- type: 'array',
161
- items: {
162
- type: 'string'
163
- },
164
- default: ['GET', 'HEAD'],
165
- minItems: 1
166
- },
167
- cacheTagsHeader: {
168
- type: 'string'
169
- }
170
- }
171
- }
172
- ]
173
- },
174
188
  watch: {
175
189
  anyOf: [
176
190
  {
package/lib/start.js CHANGED
@@ -18,6 +18,16 @@ const { Runtime } = require('./runtime')
18
18
  const errors = require('./errors')
19
19
  const { getRuntimeLogsDir, loadConfig } = require('./utils')
20
20
 
21
+ async function restartRuntime (runtime) {
22
+ runtime.logger.info('Received SIGUSR2, restarting all services ...')
23
+
24
+ try {
25
+ await runtime.restart()
26
+ } catch (err) {
27
+ runtime.logger.error({ err: ensureLoggableError(err) }, 'Failed to restart services.')
28
+ }
29
+ }
30
+
21
31
  async function buildRuntime (configManager, env) {
22
32
  env = env || process.env
23
33
 
@@ -35,14 +45,10 @@ async function buildRuntime (configManager, env) {
35
45
  const runtime = new Runtime(configManager, runtimeLogsDir, env)
36
46
 
37
47
  /* c8 ignore next 3 */
38
- process.on('SIGUSR2', async () => {
39
- runtime.logger.info('Received SIGUSR2, restarting all services ...')
40
-
41
- try {
42
- await runtime.restart()
43
- } catch (err) {
44
- runtime.logger.error({ err: ensureLoggableError(err) }, 'Failed to restart services.')
45
- }
48
+ const restartListener = restartRuntime.bind(null, runtime)
49
+ process.on('SIGUSR2', restartListener)
50
+ runtime.on('closed', () => {
51
+ process.removeListener('SIGUSR2', restartListener)
46
52
  })
47
53
 
48
54
  try {
@@ -109,7 +115,7 @@ async function setupAndStartRuntime (config) {
109
115
  })
110
116
  )
111
117
  logger.warn(`Port: ${originalPort} is already in use!`)
112
- logger.warn(`Starting service on port: ${runtimeConfig.current.server.port}`)
118
+ logger.warn(`Changing the port to ${runtimeConfig.current.server.port}`)
113
119
  }
114
120
  return { address, runtime }
115
121
  }
package/lib/worker/app.js CHANGED
@@ -3,6 +3,7 @@
3
3
  const { existsSync } = require('node:fs')
4
4
  const { EventEmitter } = require('node:events')
5
5
  const { resolve } = require('node:path')
6
+ const { workerData } = require('node:worker_threads')
6
7
  const { ConfigManager } = require('@platformatic/config')
7
8
  const { FileWatcher } = require('@platformatic/utils')
8
9
  const { getGlobalDispatcher, setGlobalDispatcher } = require('undici')
@@ -21,9 +22,20 @@ class PlatformaticApp extends EventEmitter {
21
22
  #debouncedRestart
22
23
  #context
23
24
 
24
- constructor (appConfig, telemetryConfig, loggerConfig, serverConfig, metricsConfig, hasManagementApi, watch) {
25
+ constructor (
26
+ appConfig,
27
+ workerId,
28
+ telemetryConfig,
29
+ loggerConfig,
30
+ serverConfig,
31
+ metricsConfig,
32
+ hasManagementApi,
33
+ watch
34
+ ) {
25
35
  super()
26
36
  this.appConfig = appConfig
37
+ this.serviceId = this.appConfig.id
38
+ this.workerId = workerId
27
39
  this.#watch = watch
28
40
  this.#starting = false
29
41
  this.#started = false
@@ -32,7 +44,8 @@ class PlatformaticApp extends EventEmitter {
32
44
  this.#fileWatcher = null
33
45
 
34
46
  this.#context = {
35
- serviceId: this.appConfig.id,
47
+ serviceId: this.serviceId,
48
+ workerId: this.workerId,
36
49
  directory: this.appConfig.path,
37
50
  isEntrypoint: this.appConfig.entrypoint,
38
51
  isProduction: this.appConfig.isProduction,
@@ -40,6 +53,7 @@ class PlatformaticApp extends EventEmitter {
40
53
  metricsConfig,
41
54
  loggerConfig,
42
55
  serverConfig,
56
+ worker: workerData?.worker,
43
57
  hasManagementApi: !!hasManagementApi,
44
58
  localServiceEnvVars: this.appConfig.localServiceEnvVars
45
59
  }
package/lib/worker/itc.js CHANGED
@@ -7,7 +7,7 @@ const { ITC } = require('@platformatic/itc')
7
7
  const { Unpromise } = require('@watchable/unpromise')
8
8
 
9
9
  const errors = require('../errors')
10
- const { kITC, kId } = require('./symbols')
10
+ const { kITC, kId, kServiceId, kWorkerId } = require('./symbols')
11
11
 
12
12
  async function safeHandleInITC (worker, fn) {
13
13
  try {
@@ -23,7 +23,11 @@ async function safeHandleInITC (worker, fn) {
23
23
  ])
24
24
 
25
25
  if (typeof exitCode === 'number') {
26
- throw new errors.ServiceExitedError(worker[kId], exitCode)
26
+ if (typeof worker[kWorkerId] !== 'undefined') {
27
+ throw new errors.WorkerExitedError(worker[kWorkerId], worker[kServiceId], exitCode)
28
+ } else {
29
+ throw new errors.ServiceExitedError(worker[kId], exitCode)
30
+ }
27
31
  } else {
28
32
  ac.abort()
29
33
  }
@@ -156,6 +160,7 @@ function setupITC (app, service, dispatcher) {
156
160
  itc.notify('changed')
157
161
  })
158
162
 
163
+ itc.listen()
159
164
  return itc
160
165
  }
161
166
 
@@ -1,6 +1,7 @@
1
1
  'use strict'
2
2
 
3
3
  const { createRequire } = require('node:module')
4
+ const { hostname } = require('node:os')
4
5
  const { join } = require('node:path')
5
6
  const { parentPort, workerData, threadId } = require('node:worker_threads')
6
7
  const { pathToFileURL } = require('node:url')
@@ -9,11 +10,9 @@ const diagnosticChannel = require('node:diagnostics_channel')
9
10
  const { ServerResponse } = require('node:http')
10
11
 
11
12
  const pino = require('pino')
12
- const { fetch, setGlobalDispatcher, getGlobalDispatcher, Agent } = require('undici')
13
+ const { fetch, setGlobalDispatcher, Agent } = require('undici')
13
14
  const { wire } = require('undici-thread-interceptor')
14
- const undici = require('undici')
15
15
 
16
- const RemoteCacheStore = require('./http-cache')
17
16
  const { PlatformaticApp } = require('./app')
18
17
  const { setupITC } = require('./itc')
19
18
  const loadInterceptors = require('./interceptors')
@@ -32,14 +31,17 @@ globalThis.fetch = fetch
32
31
  globalThis[kId] = threadId
33
32
 
34
33
  let app
34
+
35
35
  const config = workerData.config
36
36
  globalThis.platformatic = Object.assign(globalThis.platformatic ?? {}, { logger: createLogger() })
37
37
 
38
38
  function handleUnhandled (type, err) {
39
- globalThis.platformatic.logger.error(
40
- { err: ensureLoggableError(err) },
41
- `Service ${workerData.serviceConfig.id} threw an ${type}.`
42
- )
39
+ const label =
40
+ workerData.worker.count > 1
41
+ ? `worker ${workerData.worker.index} of the service "${workerData.serviceConfig.id}"`
42
+ : `service "${workerData.serviceConfig.id}"`
43
+
44
+ globalThis.platformatic.logger.error({ err: ensureLoggableError(err) }, `The ${label} threw an ${type}.`)
43
45
 
44
46
  executeWithTimeout(app?.stop(), 1000)
45
47
  .catch()
@@ -50,7 +52,13 @@ function handleUnhandled (type, err) {
50
52
 
51
53
  function createLogger () {
52
54
  const destination = new MessagePortWritable({ port: workerData.loggingPort })
53
- const loggerInstance = pino({ level: 'trace', name: workerData.serviceConfig.id }, destination)
55
+ const pinoOptions = { level: 'trace', name: workerData.serviceConfig.id }
56
+
57
+ if (typeof workerData.worker?.index !== 'undefined') {
58
+ pinoOptions.base = { pid: process.pid, hostname: hostname(), worker: workerData.worker.index }
59
+ }
60
+
61
+ const loggerInstance = pino(pinoOptions, destination)
54
62
 
55
63
  Reflect.defineProperty(process, 'stdout', { value: createPinoWritable(loggerInstance, 'info') })
56
64
  Reflect.defineProperty(process, 'stderr', { value: createPinoWritable(loggerInstance, 'error') })
@@ -82,34 +90,10 @@ async function main () {
82
90
  }
83
91
  }
84
92
 
85
- const dispatcherOpts = { ...config.undici }
86
-
87
- if (Object.keys(interceptors).length > 0) {
88
- const clientInterceptors = []
89
- const poolInterceptors = []
90
-
91
- if (interceptors.Agent) {
92
- clientInterceptors.push(...interceptors.Agent)
93
- poolInterceptors.push(...interceptors.Agent)
94
- }
95
-
96
- if (interceptors.Pool) {
97
- poolInterceptors.push(...interceptors.Pool)
98
- }
99
-
100
- if (interceptors.Client) {
101
- clientInterceptors.push(...interceptors.Client)
102
- }
103
-
104
- dispatcherOpts.factory = (origin, opts) => {
105
- return opts && opts.connections === 1
106
- ? new undici.Client(origin, opts).compose(clientInterceptors)
107
- : new undici.Pool(origin, opts).compose(poolInterceptors)
108
- }
109
- }
110
-
111
- const globalDispatcher = new Agent(dispatcherOpts)
112
- .compose(composedInterceptors)
93
+ const globalDispatcher = new Agent({
94
+ ...config.undici,
95
+ interceptors
96
+ }).compose(composedInterceptors)
113
97
 
114
98
  setGlobalDispatcher(globalDispatcher)
115
99
 
@@ -118,15 +102,6 @@ async function main () {
118
102
  // TODO: make this configurable
119
103
  const threadDispatcher = wire({ port: parentPort, useNetwork: service.useHttp, timeout: 5 * 60 * 1000 })
120
104
 
121
- if (config.httpCache) {
122
- setGlobalDispatcher(
123
- getGlobalDispatcher().compose(undici.interceptors.cache({
124
- store: new RemoteCacheStore(),
125
- methods: config.httpCache.methods ?? ['GET', 'HEAD']
126
- }))
127
- )
128
- }
129
-
130
105
  // If the service is an entrypoint and runtime server config is defined, use it.
131
106
  let serverConfig = null
132
107
  if (config.server && service.entrypoint) {
@@ -168,6 +143,7 @@ async function main () {
168
143
  // Create the application
169
144
  app = new PlatformaticApp(
170
145
  service,
146
+ workerData.worker.count > 1 ? workerData.worker.index : undefined,
171
147
  telemetryConfig,
172
148
  config.logger,
173
149
  serverConfig,
@@ -187,13 +163,11 @@ async function main () {
187
163
 
188
164
  // Setup interaction with parent port
189
165
  const itc = setupITC(app, service, threadDispatcher)
166
+ globalThis[kITC] = itc
190
167
 
191
168
  // Get the dependencies
192
169
  const dependencies = config.autoload ? await app.getBootstrapDependencies() : []
193
170
  itc.notify('init', { dependencies })
194
- itc.listen()
195
-
196
- globalThis[kITC] = itc
197
171
  }
198
172
 
199
173
  function stripBasePath (basePath) {
@@ -0,0 +1,61 @@
1
+ 'use strict'
2
+
3
+ class RoundRobinMap extends Map {
4
+ #instances
5
+
6
+ constructor (iterable, instances) {
7
+ super(iterable)
8
+ this.#instances = instances
9
+ }
10
+
11
+ get configuration () {
12
+ return { ...this.#instances }
13
+ }
14
+
15
+ // In development or for the entrypoint always use 1 worker
16
+ configure (services, defaultInstances, production) {
17
+ this.#instances = {}
18
+
19
+ for (const service of services) {
20
+ let count = service.workers ?? defaultInstances
21
+
22
+ if (service.entrypoint || !production) {
23
+ count = 1
24
+ }
25
+
26
+ this.#instances[service.id] = { next: 0, count }
27
+ }
28
+ }
29
+
30
+ getCount (service) {
31
+ return this.#instances[service].count
32
+ }
33
+
34
+ next (service) {
35
+ if (!this.#instances[service]) {
36
+ return undefined
37
+ }
38
+
39
+ let worker
40
+ let { next, count } = this.#instances[service]
41
+
42
+ // Try count times to get the next worker. This is to handle the case where a worker is being restarted.
43
+ for (let i = 0; i < count; i++) {
44
+ const current = next++
45
+ if (next >= count) {
46
+ next = 0
47
+ }
48
+
49
+ worker = this.get(`${service}:${current}`)
50
+
51
+ if (worker) {
52
+ break
53
+ }
54
+ }
55
+
56
+ this.#instances[service].next = next
57
+ return worker
58
+ }
59
+ }
60
+
61
+ module.exports = { RoundRobinMap }
@@ -2,6 +2,11 @@
2
2
 
3
3
  const kConfig = Symbol.for('plt.runtime.config')
4
4
  const kId = Symbol.for('plt.runtime.id') // This is also used to detect if we are running in a Platformatic runtime thread
5
+ const kServiceId = Symbol.for('plt.runtime.service.id')
6
+ const kWorkerId = Symbol.for('plt.runtime.worker.id')
5
7
  const kITC = Symbol.for('plt.runtime.itc')
8
+ const kLoggerDestination = Symbol.for('plt.runtime.loggerDestination')
9
+ const kLoggingPort = Symbol.for('plt.runtime.logginPort')
10
+ const kWorkerStatus = Symbol('plt.runtime.worker.status')
6
11
 
7
- module.exports = { kConfig, kId, kITC }
12
+ module.exports = { kConfig, kId, kServiceId, kWorkerId, kITC, kLoggerDestination, kLoggingPort, kWorkerStatus }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@platformatic/runtime",
3
- "version": "2.7.1-alpha.2",
3
+ "version": "2.8.0-alpha.2",
4
4
  "description": "",
5
5
  "main": "index.js",
6
6
  "bin": {
@@ -35,19 +35,18 @@
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/db": "2.7.1-alpha.2",
39
- "@platformatic/composer": "2.7.1-alpha.2",
40
- "@platformatic/service": "2.7.1-alpha.2",
41
- "@platformatic/node": "2.7.1-alpha.2",
42
- "@platformatic/sql-graphql": "2.7.1-alpha.2",
43
- "@platformatic/sql-mapper": "2.7.1-alpha.2"
38
+ "@platformatic/composer": "2.8.0-alpha.2",
39
+ "@platformatic/db": "2.8.0-alpha.2",
40
+ "@platformatic/service": "2.8.0-alpha.2",
41
+ "@platformatic/node": "2.8.0-alpha.2",
42
+ "@platformatic/sql-mapper": "2.8.0-alpha.2",
43
+ "@platformatic/sql-graphql": "2.8.0-alpha.2"
44
44
  },
45
45
  "dependencies": {
46
46
  "@fastify/error": "^4.0.0",
47
47
  "@fastify/websocket": "^11.0.0",
48
48
  "@hapi/topo": "^6.0.2",
49
49
  "@platformatic/http-metrics": "^0.2.1",
50
- "@platformatic/undici-cache-memory": "^0.3.0",
51
50
  "@watchable/unpromise": "^1.0.2",
52
51
  "boring-name-generator": "^1.0.3",
53
52
  "change-case-all": "^2.1.0",
@@ -69,20 +68,26 @@
69
68
  "semgrator": "^0.3.0",
70
69
  "tail-file-stream": "^0.2.0",
71
70
  "thread-cpu-usage": "^0.2.0",
72
- "undici": "7.0.0-alpha.3",
71
+ "undici": "^6.9.0",
73
72
  "undici-thread-interceptor": "^0.7.0",
74
73
  "ws": "^8.16.0",
75
- "@platformatic/basic": "2.7.1-alpha.2",
76
- "@platformatic/config": "2.7.1-alpha.2",
77
- "@platformatic/itc": "2.7.1-alpha.2",
78
- "@platformatic/ts-compiler": "2.7.1-alpha.2",
79
- "@platformatic/telemetry": "2.7.1-alpha.2",
80
- "@platformatic/generators": "2.7.1-alpha.2",
81
- "@platformatic/utils": "2.7.1-alpha.2"
74
+ "@platformatic/config": "2.8.0-alpha.2",
75
+ "@platformatic/generators": "2.8.0-alpha.2",
76
+ "@platformatic/basic": "2.8.0-alpha.2",
77
+ "@platformatic/itc": "2.8.0-alpha.2",
78
+ "@platformatic/telemetry": "2.8.0-alpha.2",
79
+ "@platformatic/ts-compiler": "2.8.0-alpha.2",
80
+ "@platformatic/utils": "2.8.0-alpha.2"
82
81
  },
83
82
  "scripts": {
84
- "test": "npm run lint && borp --concurrency=1 --timeout=180000 && tsd",
85
- "coverage": "npm run lint && borp -X fixtures -X test -C --concurrency=1 --timeout=180000 && tsd",
83
+ "test": "npm run lint && borp --concurrency=1 --timeout=300000 && tsd",
84
+ "test:main": "borp --concurrency=1 --timeout=300000 test/*.test.js test/versions/*.test.js",
85
+ "test:api": "borp --concurrency=1 --timeout=300000 test/api/*.test.js test/management-api/*.test.js",
86
+ "test:cli": "borp --concurrency=1 --timeout=300000 test/cli/*.test.js test/cli/**/*.test.js",
87
+ "test:start": "borp --concurrency=1 --timeout=300000 test/start/*.test.js",
88
+ "test:multiple-workers": "borp --concurrency=1 --timeout=300000 test/multiple-workers/*.test.js",
89
+ "test:types": "tsd",
90
+ "coverage": "npm run lint && borp -X fixtures -X test -C --concurrency=1 --timeout=300000 && tsd",
86
91
  "gen-schema": "node lib/schema.js > schema.json",
87
92
  "gen-types": "json2ts > config.d.ts < schema.json",
88
93
  "build": "pnpm run gen-schema && pnpm run gen-types",
package/schema.json CHANGED
@@ -1,5 +1,5 @@
1
1
  {
2
- "$id": "https://schemas.platformatic.dev/@platformatic/runtime/2.7.1-alpha.2.json",
2
+ "$id": "https://schemas.platformatic.dev/@platformatic/runtime/2.8.0-alpha.2.json",
3
3
  "$schema": "http://json-schema.org/draft-07/schema#",
4
4
  "type": "object",
5
5
  "properties": {
@@ -91,10 +91,33 @@
91
91
  },
92
92
  "useHttp": {
93
93
  "type": "boolean"
94
+ },
95
+ "workers": {
96
+ "anyOf": [
97
+ {
98
+ "type": "number",
99
+ "minimum": 1
100
+ },
101
+ {
102
+ "type": "string"
103
+ }
104
+ ]
94
105
  }
95
106
  }
96
107
  }
97
108
  },
109
+ "workers": {
110
+ "anyOf": [
111
+ {
112
+ "type": "number",
113
+ "minimum": 1
114
+ },
115
+ {
116
+ "type": "string"
117
+ }
118
+ ],
119
+ "default": 1
120
+ },
98
121
  "web": {
99
122
  "type": "array",
100
123
  "items": {
@@ -129,6 +152,17 @@
129
152
  },
130
153
  "useHttp": {
131
154
  "type": "boolean"
155
+ },
156
+ "workers": {
157
+ "anyOf": [
158
+ {
159
+ "type": "number",
160
+ "minimum": 1
161
+ },
162
+ {
163
+ "type": "string"
164
+ }
165
+ ]
132
166
  }
133
167
  }
134
168
  }
@@ -340,6 +374,41 @@
340
374
  }
341
375
  ]
342
376
  },
377
+ "gracefulShutdown": {
378
+ "type": "object",
379
+ "properties": {
380
+ "runtime": {
381
+ "anyOf": [
382
+ {
383
+ "type": "number",
384
+ "minimum": 1
385
+ },
386
+ {
387
+ "type": "string"
388
+ }
389
+ ],
390
+ "default": 10000
391
+ },
392
+ "service": {
393
+ "anyOf": [
394
+ {
395
+ "type": "number",
396
+ "minimum": 1
397
+ },
398
+ {
399
+ "type": "string"
400
+ }
401
+ ],
402
+ "default": 10000
403
+ }
404
+ },
405
+ "default": {},
406
+ "required": [
407
+ "runtime",
408
+ "service"
409
+ ],
410
+ "additionalProperties": false
411
+ },
343
412
  "undici": {
344
413
  "type": "object",
345
414
  "properties": {
@@ -382,35 +451,6 @@
382
451
  }
383
452
  }
384
453
  },
385
- "httpCache": {
386
- "oneOf": [
387
- {
388
- "type": "boolean"
389
- },
390
- {
391
- "type": "object",
392
- "properties": {
393
- "store": {
394
- "type": "string"
395
- },
396
- "methods": {
397
- "type": "array",
398
- "items": {
399
- "type": "string"
400
- },
401
- "default": [
402
- "GET",
403
- "HEAD"
404
- ],
405
- "minItems": 1
406
- },
407
- "cacheTagsHeader": {
408
- "type": "string"
409
- }
410
- }
411
- }
412
- ]
413
- },
414
454
  "watch": {
415
455
  "anyOf": [
416
456
  {
@@ -1,45 +0,0 @@
1
- 'use strict'
2
-
3
- const { join } = require('node:path')
4
- const { createRequire } = require('node:module')
5
- const MemoryCacheStore = require('@platformatic/undici-cache-memory')
6
-
7
- function createSharedStore (projectDir, httpCacheConfig = {}) {
8
- const runtimeRequire = createRequire(join(projectDir, 'file'))
9
-
10
- const { store, ...storeConfig } = httpCacheConfig
11
- const CacheStore = store ? runtimeRequire(store) : MemoryCacheStore
12
-
13
- class SharedCacheStore extends CacheStore {
14
- async getValue (req) {
15
- const readStream = await this.createReadStream(req)
16
- if (!readStream) return null
17
-
18
- let payload = ''
19
- for await (const chunk of readStream) {
20
- payload += chunk
21
- }
22
-
23
- const response = this.#sanitizeResponse(readStream.value)
24
- return { response, payload }
25
- }
26
-
27
- setValue (req, opts, data) {
28
- const writeStream = this.createWriteStream(req, opts)
29
- writeStream.write(data)
30
- writeStream.end()
31
- return null
32
- }
33
-
34
- #sanitizeResponse (response) {
35
- return {
36
- ...response,
37
- rawHeaders: response.rawHeaders.map(header => header.toString())
38
- }
39
- }
40
- }
41
-
42
- return new SharedCacheStore(storeConfig)
43
- }
44
-
45
- module.exports = { createSharedStore }