@platformatic/service 0.27.0 → 0.29.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.
Files changed (49) hide show
  1. package/fixtures/hello/platformatic.service.json +1 -2
  2. package/fixtures/hello/warn-log.service.json +1 -2
  3. package/fixtures/hello-client/platformatic.service.json +2 -3
  4. package/fixtures/hello-client-ts/platformatic.service.json +2 -3
  5. package/fixtures/hello-client-ts-without-deps/hello.d.ts +34 -0
  6. package/fixtures/hello-client-ts-without-deps/hello.openapi.json +22 -0
  7. package/fixtures/hello-client-ts-without-deps/platformatic.service.json +23 -0
  8. package/fixtures/hello-client-ts-without-deps/plugin.ts +8 -0
  9. package/fixtures/hello-client-ts-without-deps/tsconfig.json +22 -0
  10. package/fixtures/hello-client-without-deps/hello.d.ts +34 -0
  11. package/fixtures/hello-client-without-deps/hello.openapi.json +22 -0
  12. package/fixtures/hello-client-without-deps/platformatic.service.json +21 -0
  13. package/fixtures/hello-client-without-deps/plugin.js +8 -0
  14. package/help/compile.txt +2 -1
  15. package/index.d.ts +17 -11
  16. package/index.js +4 -21
  17. package/index.test-d.ts +14 -22
  18. package/lib/compile.js +0 -26
  19. package/lib/load-config.js +1 -2
  20. package/lib/plugins/clients.js +7 -3
  21. package/lib/plugins/plugins.js +17 -33
  22. package/lib/plugins/typescript.js +1 -31
  23. package/lib/root-endpoint/public/background_frame.svg +614 -0
  24. package/lib/root-endpoint/public/background_polygon_14.svg +3 -0
  25. package/lib/root-endpoint/public/background_polygon_28.svg +3 -0
  26. package/lib/root-endpoint/public/dark_mode.svg +3 -0
  27. package/lib/root-endpoint/public/index.html +164 -35
  28. package/lib/root-endpoint/public/light_mode.svg +11 -0
  29. package/lib/root-endpoint/public/platformatic-logo-dark.svg +8 -0
  30. package/lib/root-endpoint/public/platformatic-logo-light.svg +8 -0
  31. package/lib/schema.js +28 -14
  32. package/lib/start.js +2 -23
  33. package/package.json +17 -9
  34. package/test/autoload.test.js +0 -182
  35. package/test/cli/compile.test.mjs +98 -1
  36. package/test/clients.test.js +53 -0
  37. package/test/fixtures/bad-typescript-plugin/platformatic.service.json +1 -1
  38. package/test/fixtures/typescript-plugin-nocompile-string/platformatic.service.json +16 -0
  39. package/test/fixtures/typescript-plugin-nocompile-string/plugin.ts +5 -0
  40. package/test/fixtures/typescript-plugin-nocompile-string/tsconfig.json +22 -0
  41. package/test/fixtures/typescript-plugin-string/platformatic.service.json +16 -0
  42. package/test/fixtures/typescript-plugin-string/plugin.ts +5 -0
  43. package/test/fixtures/typescript-plugin-string/tsconfig.json +22 -0
  44. package/test/load-and-reload-files.test.js +7 -278
  45. package/tsconfig.json +12 -0
  46. package/lib/plugins/file-watcher.js +0 -44
  47. package/lib/root-endpoint/public/logo-512x512.png +0 -0
  48. package/test/cli/watch.test.mjs +0 -289
  49. package/test/watch.test.js +0 -248
@@ -8,8 +8,7 @@
8
8
  }
9
9
  },
10
10
  "plugins": {
11
- "paths": ["./plugin.js"],
12
- "hotReload": false
11
+ "paths": ["./plugin.js"]
13
12
  },
14
13
  "service": {
15
14
  "openapi": true
@@ -8,8 +8,7 @@
8
8
  }
9
9
  },
10
10
  "plugins": {
11
- "paths": ["./plugin.js"],
12
- "hotReload": false
11
+ "paths": ["./plugin.js"]
13
12
  },
14
13
  "service": {
15
14
  "openapi": true
@@ -8,11 +8,10 @@
8
8
  }
9
9
  },
10
10
  "plugins": {
11
- "paths": ["./plugin.js"],
12
- "hotReload": false
11
+ "paths": ["./plugin.js"]
13
12
  },
14
13
  "clients": [{
15
- "path": "./hello",
14
+ "path": "hello",
16
15
  "url": "{PLT_CLIENT_URL}"
17
16
  }],
18
17
  "metrics": false,
@@ -10,11 +10,10 @@
10
10
  },
11
11
  "plugins": {
12
12
  "paths": ["./plugin.ts"],
13
- "typescript": true,
14
- "hotReload": false
13
+ "typescript": true
15
14
  },
16
15
  "clients": [{
17
- "path": "./hello",
16
+ "path": "hello",
18
17
  "url": "{PLT_CLIENT_URL}"
19
18
  }],
20
19
  "metrics": false,
@@ -0,0 +1,34 @@
1
+ import { FastifyPluginAsync } from 'fastify'
2
+
3
+ interface GetRequest {
4
+ }
5
+
6
+ interface GetResponse {
7
+ }
8
+
9
+ interface Hello {
10
+ get(req: GetRequest): Promise<GetResponse>;
11
+ }
12
+
13
+ type HelloPlugin = FastifyPluginAsync<NonNullable<hello.HelloOptions>>
14
+
15
+ declare module 'fastify' {
16
+ interface FastifyInstance {
17
+ 'hello': Hello;
18
+ }
19
+
20
+ interface FastifyRequest {
21
+ 'hello': Hello;
22
+ }
23
+ }
24
+
25
+ declare namespace hello {
26
+ export interface HelloOptions {
27
+ url: string
28
+ }
29
+ export const hello: HelloPlugin;
30
+ export { hello as default };
31
+ }
32
+
33
+ declare function hello(...params: Parameters<HelloPlugin>): ReturnType<HelloPlugin>;
34
+ export = hello;
@@ -0,0 +1,22 @@
1
+ {
2
+ "openapi": "3.0.3",
3
+ "info": {
4
+ "title": "Platformatic",
5
+ "description": "This is a service built on top of Platformatic",
6
+ "version": "1.0.0"
7
+ },
8
+ "components": {
9
+ "schemas": {}
10
+ },
11
+ "paths": {
12
+ "/": {
13
+ "get": {
14
+ "responses": {
15
+ "200": {
16
+ "description": "Default Response"
17
+ }
18
+ }
19
+ }
20
+ }
21
+ }
22
+ }
@@ -0,0 +1,23 @@
1
+ {
2
+ "server": {
3
+ "hostname": "127.0.0.1",
4
+ "port": 0,
5
+ "logger": {
6
+ "level": "warn",
7
+ "name": "hello client ts"
8
+ },
9
+ "pluginTimeout": 30000
10
+ },
11
+ "plugins": {
12
+ "paths": ["./plugin.ts"],
13
+ "typescript": true
14
+ },
15
+ "clients": [{
16
+ "schema": "./hello.openapi.json",
17
+ "name": "hello",
18
+ "type": "openapi",
19
+ "url": "{PLT_CLIENT_URL}"
20
+ }],
21
+ "metrics": false,
22
+ "watch": false
23
+ }
@@ -0,0 +1,8 @@
1
+ import { FastifyInstance } from 'fastify'
2
+ /// <reference path="./hello" />
3
+
4
+ export default async function (app: FastifyInstance) {
5
+ app.get('/', async () => {
6
+ return app.hello.get({})
7
+ })
8
+ }
@@ -0,0 +1,22 @@
1
+ {
2
+ "compilerOptions": {
3
+ "module": "commonjs",
4
+ "esModuleInterop": true,
5
+ "target": "es6",
6
+ "moduleResolution": "node",
7
+ "sourceMap": true,
8
+ "pretty": true,
9
+ "noEmitOnError": true,
10
+ "outDir": "dist"
11
+ },
12
+ "watchOptions": {
13
+ "watchFile": "fixedPollingInterval",
14
+ "watchDirectory": "fixedPollingInterval",
15
+ "fallbackPolling": "dynamicPriority",
16
+ "synchronousWatchDirectory": true,
17
+ "excludeDirectories": [
18
+ "**/node_modules",
19
+ "dist"
20
+ ]
21
+ }
22
+ }
@@ -0,0 +1,34 @@
1
+ import { FastifyPluginAsync } from 'fastify'
2
+
3
+ interface GetRequest {
4
+ }
5
+
6
+ interface GetResponse {
7
+ }
8
+
9
+ interface Hello {
10
+ get(req: GetRequest): Promise<GetResponse>;
11
+ }
12
+
13
+ type HelloPlugin = FastifyPluginAsync<NonNullable<hello.HelloOptions>>
14
+
15
+ declare module 'fastify' {
16
+ interface FastifyInstance {
17
+ 'hello': Hello;
18
+ }
19
+
20
+ interface FastifyRequest {
21
+ 'hello': Hello;
22
+ }
23
+ }
24
+
25
+ declare namespace hello {
26
+ export interface HelloOptions {
27
+ url: string
28
+ }
29
+ export const hello: HelloPlugin;
30
+ export { hello as default };
31
+ }
32
+
33
+ declare function hello(...params: Parameters<HelloPlugin>): ReturnType<HelloPlugin>;
34
+ export = hello;
@@ -0,0 +1,22 @@
1
+ {
2
+ "openapi": "3.0.3",
3
+ "info": {
4
+ "title": "Platformatic",
5
+ "description": "This is a service built on top of Platformatic",
6
+ "version": "1.0.0"
7
+ },
8
+ "components": {
9
+ "schemas": {}
10
+ },
11
+ "paths": {
12
+ "/": {
13
+ "get": {
14
+ "responses": {
15
+ "200": {
16
+ "description": "Default Response"
17
+ }
18
+ }
19
+ }
20
+ }
21
+ }
22
+ }
@@ -0,0 +1,21 @@
1
+ {
2
+ "server": {
3
+ "hostname": "127.0.0.1",
4
+ "port": 0,
5
+ "logger": {
6
+ "level": "warn",
7
+ "name": "hello client"
8
+ }
9
+ },
10
+ "plugins": {
11
+ "paths": ["./plugin.js"]
12
+ },
13
+ "clients": [{
14
+ "schema": "./hello.openapi.json",
15
+ "name": "hello",
16
+ "type": "openapi",
17
+ "url": "{PLT_CLIENT_URL}"
18
+ }],
19
+ "metrics": false,
20
+ "watch": false
21
+ }
@@ -0,0 +1,8 @@
1
+ 'use default'
2
+
3
+ /** @type {import('fastify').FastifyPluginAsync<{ optionA: boolean, optionB: string }>} */
4
+ module.exports = async function (app) {
5
+ app.get('/', async () => {
6
+ return app.hello.get()
7
+ })
8
+ }
package/help/compile.txt CHANGED
@@ -1,9 +1,10 @@
1
1
  Compile typescript plugins.
2
+
2
3
  ``` bash
3
4
  $ platformatic service compile
4
5
  ```
5
6
 
6
- As a result of executing this command, the Platformatic DB will compile typescript
7
+ As a result of executing this command, Platformatic Service will compile typescript
7
8
  plugins in the `outDir` directory.
8
9
 
9
10
  If not specified, the configuration specified will be loaded from
package/index.d.ts CHANGED
@@ -1,15 +1,21 @@
1
- import { FastifyInstance } from "fastify"
1
+ /* eslint-disable @typescript-eslint/triple-slash-reference */
2
+ /// <reference types="@platformatic/types" />
3
+ /// <reference types="mercurius" />
4
+ /// <reference types="@fastify/swagger" />
5
+ import { FastifyInstance } from 'fastify'
6
+ import ConfigManager from '@platformatic/config'
2
7
 
3
- export type pltServiceHandlerBuildServer = {
4
- app: FastifyInstance
5
- address: string
6
- port: number
7
- restart: () => Promise<void>
8
- listen: FastifyInstance['listen']
9
- close: FastifyInstance['close']
10
- inject: FastifyInstance['inject']
8
+ declare module '@platformatic/types' {
9
+ interface PlatformaticApp {
10
+ configManager: ConfigManager
11
+ config: object
12
+ }
11
13
  }
12
14
 
13
- declare module '@platformatic/service' {
14
- export function buildServer(opts: object, app?: object, ConfigManagerContructor?: object): Promise<pltServiceHandlerBuildServer>
15
+ export function buildServer (opts: object, app?: object, ConfigManagerContructor?: object): Promise<FastifyInstance>
16
+
17
+ declare module 'fastify' {
18
+ interface FastifyInstance {
19
+ restart: () => Promise<void>
20
+ }
15
21
  }
package/index.js CHANGED
@@ -9,7 +9,6 @@ const setupGraphQL = require('./lib/plugins/graphql.js')
9
9
  const setupClients = require('./lib/plugins/clients')
10
10
  const setupMetrics = require('./lib/plugins/metrics')
11
11
  const setupTsCompiler = require('./lib/plugins/typescript')
12
- const setupFileWatcher = require('./lib/plugins/file-watcher')
13
12
  const setupHealthCheck = require('./lib/plugins/health-check')
14
13
  const loadPlugins = require('./lib/plugins/plugins')
15
14
 
@@ -54,7 +53,10 @@ async function platformaticService (app, opts, toLoad = []) {
54
53
  }
55
54
 
56
55
  if (isKeyEnabled('watch', config)) {
57
- await app.register(setupFileWatcher, { onFilesUpdated })
56
+ // If file watching is enabled here, that means the service was started
57
+ // without the runtime because the runtime explicitly disables watching on
58
+ // services that it starts. Warn the user that things will not go as planned.
59
+ app.log.warn('service was started with file watching enabled but watching is only available via the runtime')
58
60
  }
59
61
 
60
62
  if (config.server.cors) {
@@ -70,25 +72,6 @@ async function platformaticService (app, opts, toLoad = []) {
70
72
  }
71
73
  }
72
74
 
73
- async function onFilesUpdated (app) {
74
- // Reload the config as well, otherwise we will have problems
75
- // in case the files watcher triggers the config watcher too
76
- const configManager = app.platformatic.configManager
77
- try {
78
- app.log.debug('files changed')
79
- await configManager.parse()
80
- await app.restart()
81
- /* c8 ignore next 8 */
82
- } catch (err) {
83
- app.log.error({
84
- err: {
85
- message: err.message,
86
- stack: err.stack
87
- }
88
- }, 'failed to reload server')
89
- }
90
- }
91
-
92
75
  platformaticService[Symbol.for('skip-override')] = true
93
76
  platformaticService.schema = schema
94
77
  platformaticService.configType = 'service'
package/index.test-d.ts CHANGED
@@ -1,24 +1,16 @@
1
- import { expectError, expectType } from 'tsd';
2
- import { FastifyInstance } from 'fastify';
3
- import { pltServiceHandlerBuildServer } from '.';
1
+ import { expectType } from 'tsd'
2
+ import { FastifyInstance } from 'fastify'
3
+ import { buildServer } from '.'
4
+ import ConfigManager from '@platformatic/config'
5
+ import { OpenAPI } from 'openapi-types'
6
+ import type { MercuriusPlugin } from 'mercurius'
4
7
 
5
- const server: pltServiceHandlerBuildServer = {
6
- app: {} as FastifyInstance,
7
- address: 'localhost',
8
- port: 3000,
9
- restart: async () => {},
10
- listen: async () => '',
11
- close: (async () => undefined) as unknown as FastifyInstance['close'],
12
- inject: (async () => undefined) as unknown as FastifyInstance['inject']
13
- };
8
+ const server = await buildServer({
9
+ })
14
10
 
15
- expectType<pltServiceHandlerBuildServer>(server);
16
- expectError<pltServiceHandlerBuildServer>({...server, app: 'WRONG' });
17
- expectError<pltServiceHandlerBuildServer>({...server, address: 42 });
18
- expectError<pltServiceHandlerBuildServer>({...server, port: 'WRONG' });
19
- expectError<pltServiceHandlerBuildServer>({...server, restart: 'WRONG' });
20
- expectError<pltServiceHandlerBuildServer>({...server, listen: 'WRONG' });
21
- expectError<pltServiceHandlerBuildServer>({...server, listen: async () => ({ address: 42, port: 3000 }), });
22
- expectError<pltServiceHandlerBuildServer>({...server, listen: async () => ({ address: 'localhost', port: 'WRONG' }), });
23
- expectError<pltServiceHandlerBuildServer>({...server, stop: 'WRONG' });
24
- expectError<pltServiceHandlerBuildServer>({...server, inject: 'WRONG' });
11
+ expectType<FastifyInstance>(server)
12
+ expectType<ConfigManager>(server.platformatic.configManager)
13
+ expectType<ConfigManager>(server.platformatic.configManager)
14
+ expectType<OpenAPI.Document>(server.swagger())
15
+ expectType<MercuriusPlugin>(server.graphql)
16
+ expectType<Promise<void>>(server.restart())
package/lib/compile.js CHANGED
@@ -79,31 +79,6 @@ async function compile (cwd, config, originalLogger) {
79
79
  }
80
80
  }
81
81
 
82
- // This path is tested but C8 does not see it that way given it needs to work
83
- // through execa.
84
- /* c8 ignore next 20 */
85
- async function compileWatch (cwd, config, originalLogger) {
86
- const { execa, logger, tscExecutablePath } = await setup(cwd, config, originalLogger)
87
- if (!tscExecutablePath) {
88
- return false
89
- }
90
-
91
- try {
92
- await execa(tscExecutablePath, ['--project', 'tsconfig.json', '--incremental', '--rootDir', '.'], { cwd })
93
- logger.info('Typescript compilation completed successfully. Starting watch mode.')
94
- } catch (error) {
95
- throw new Error('Failed to compile typescript files: ' + error)
96
- }
97
-
98
- const child = execa(tscExecutablePath, ['--project', 'tsconfig.json', '--watch', '--incremental'], { cwd })
99
- child.stdout.resume()
100
- child.stderr.on('data', (data) => {
101
- logger.error(data.toString())
102
- })
103
-
104
- return { child }
105
- }
106
-
107
82
  function buildCompileCmd (app) {
108
83
  return async function compileCmd (_args) {
109
84
  let fullPath = null
@@ -126,5 +101,4 @@ function buildCompileCmd (app) {
126
101
  }
127
102
 
128
103
  module.exports.compile = compile
129
- module.exports.compileWatch = compileWatch
130
104
  module.exports.buildCompileCmd = buildCompileCmd
@@ -18,8 +18,7 @@ async function loadConfig (minimistConfig, _args, app, overrides = {}) {
18
18
  const args = parseArgs(_args, deepmerge({ all: true })({
19
19
  string: ['allow-env'],
20
20
  default: {
21
- allowEnv: '', // The default is set in ConfigManager
22
- hotReload: true
21
+ allowEnv: '' // The default is set in ConfigManager
23
22
  },
24
23
  alias: {
25
24
  v: 'version',
@@ -1,11 +1,15 @@
1
1
  'use strict'
2
2
 
3
3
  const fp = require('fastify-plugin')
4
+ const client = require('@platformatic/client')
4
5
 
5
6
  async function setupClients (app, opts) {
6
- const clientsConfig = opts
7
- for (const { path, url } of clientsConfig) {
8
- app.register(require(path), { url })
7
+ for (const { path, url, serviceId, name, schema, type } of opts) {
8
+ if (path) {
9
+ app.register(require(path), { url, serviceId })
10
+ } else {
11
+ app.register(client, { url, serviceId, name, path: schema, type })
12
+ }
9
13
  }
10
14
  }
11
15
 
@@ -2,8 +2,6 @@
2
2
 
3
3
  const { join, resolve } = require('path')
4
4
  const { readFile } = require('fs/promises')
5
-
6
- const sandbox = require('fastify-sandbox')
7
5
  const fp = require('fastify-plugin')
8
6
 
9
7
  const { getJSPluginPath, isFileAccessible } = require('../utils')
@@ -14,43 +12,29 @@ async function loadPlugins (app) {
14
12
  const configManager = app.platformatic.configManager
15
13
  const config = configManager.current
16
14
 
17
- if (config.plugins.typescript) {
18
- const workingDir = configManager.dirname
19
- const tsConfigPath = join(workingDir, 'tsconfig.json')
20
-
21
- const isTsConfigAccessible = await isFileAccessible(tsConfigPath)
22
- if (!isTsConfigAccessible) {
23
- throw new Error('Cannot load typescript plugin, tsconfig.json not found')
24
- }
15
+ const workingDir = configManager.dirname
16
+ const tsConfigPath = join(workingDir, 'tsconfig.json')
25
17
 
18
+ // If the tsconfig.json file exists, then we need to adjust the plugin paths
19
+ // to point to the compiled JS files.
20
+ const isTsConfigAccessible = await isFileAccessible(tsConfigPath)
21
+ if (isTsConfigAccessible) {
26
22
  const tsConfig = JSON.parse(await readFile(tsConfigPath, 'utf8'))
27
23
  const outDir = resolve(workingDir, tsConfig.compilerOptions.outDir)
28
24
 
29
- config.plugins.paths = config.plugins.paths.map((plugin) => {
30
- /* c8 ignore next 3 */
31
- return typeof plugin === 'string'
32
- ? getJSPluginPath(workingDir, plugin, outDir)
33
- : { ...plugin, path: getJSPluginPath(workingDir, plugin.path, outDir) }
34
- })
35
- }
25
+ const isOutDirAccessible = await isFileAccessible(outDir)
36
26
 
37
- if (config.plugins.hotReload !== false) {
38
- await app.register(sandbox, {
39
- path: wrapperPath,
40
- options: { paths: config.plugins.paths },
41
- customizeGlobalThis (_globalThis) {
42
- // Taken from https://github.com/nodejs/undici/blob/fa9fd9066569b6357acacffb806aa804b688c9d8/lib/global.js#L5
43
- const globalDispatcher = Symbol.for('undici.globalDispatcher.1')
44
- const dispatcher = globalThis[globalDispatcher]
45
- /* istanbul ignore else */
46
- if (dispatcher) {
47
- _globalThis[globalDispatcher] = dispatcher
48
- }
49
- }
50
- })
51
- } else {
52
- await app.register(require(wrapperPath), { paths: config.plugins.paths })
27
+ if (isOutDirAccessible) {
28
+ config.plugins.paths = config.plugins.paths.map((plugin) => {
29
+ /* c8 ignore next 3 */
30
+ return typeof plugin === 'string'
31
+ ? getJSPluginPath(workingDir, plugin, outDir)
32
+ : { ...plugin, path: getJSPluginPath(workingDir, plugin.path, outDir) }
33
+ })
34
+ }
53
35
  }
36
+
37
+ await app.register(require(wrapperPath), { paths: config.plugins.paths })
54
38
  }
55
39
 
56
40
  module.exports = fp(loadPlugins)
@@ -1,8 +1,6 @@
1
1
  'use strict'
2
2
 
3
- const { isKeyEnabled } = require('@platformatic/utils')
4
3
  const fp = require('fastify-plugin')
5
-
6
4
  const compiler = require('../compile')
7
5
 
8
6
  async function setupTsCompiler (app) {
@@ -10,37 +8,9 @@ async function setupTsCompiler (app) {
10
8
 
11
9
  const configManager = app.platformatic.configManager
12
10
  const config = configManager.current
13
-
14
- const isRestartableApp = app.restarted !== undefined
15
-
16
- // to run the plugin without restartable
17
- /* c8 ignore next 1 */
18
- const persistentRef = isRestartableApp ? app.persistentRef : app
19
-
20
11
  const workingDir = configManager.dirname
21
12
 
22
- if (isKeyEnabled('watch', config)) {
23
- let tsCompilerWatcher = persistentRef.tsCompilerWatcher
24
- if (!tsCompilerWatcher) {
25
- /* c8 ignore next 5 */
26
- const { child } = await compiler.compileWatch(workingDir, config, app.log)
27
- app.log.debug('start watching typescript files')
28
- tsCompilerWatcher = child
29
- }
30
- app.decorate('tsCompilerWatcher', tsCompilerWatcher)
31
- } else {
32
- await compiler.compile(workingDir, config, app.log)
33
- }
34
-
35
- app.addHook('onClose', async () => {
36
- if (!isRestartableApp || app.closingRestartable) {
37
- /* c8 ignore next 4 */
38
- if (app.tsCompilerWatcher) {
39
- app.tsCompilerWatcher.kill('SIGTERM')
40
- app.log.debug('stop watching typescript files')
41
- }
42
- }
43
- })
13
+ await compiler.compile(workingDir, config, app.log)
44
14
  }
45
15
 
46
16
  module.exports = fp(setupTsCompiler)