platformatic 2.0.0-alpha.5 → 2.0.0-alpha.7

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/cli.js CHANGED
@@ -1,32 +1,33 @@
1
1
  #! /usr/bin/env node
2
2
 
3
- import { createRequire } from 'node:module'
4
- import path from 'node:path'
5
- import { pathToFileURL } from 'node:url'
6
- import { readFile } from 'node:fs/promises'
7
- import commist from 'commist'
8
- import minimist from 'minimist'
9
- import { run as runRuntime, compile } from '@platformatic/runtime/runtime.mjs'
10
- import { startCommand } from '@platformatic/runtime'
11
3
  import { command as client } from '@platformatic/client-cli'
12
- import { join } from 'desm'
13
- import { isColorSupported } from 'colorette'
14
- import helpMe from 'help-me'
15
- import { upgrade } from './lib/upgrade.js'
16
- import { download } from './lib/download.js'
17
- import { logo } from './lib/ascii.js'
18
4
  import {
19
- runControl,
20
5
  getRuntimesCommand,
21
6
  injectRuntimeCommand,
22
- streamRuntimeLogsCommand,
7
+ runControl,
8
+ streamRuntimeLogsCommand
23
9
  } from '@platformatic/control/control.js'
10
+ import { startCommand } from '@platformatic/runtime'
11
+ import { compile, run as runRuntime } from '@platformatic/runtime/runtime.mjs'
12
+ import { isColorSupported } from 'colorette'
13
+ import commist from 'commist'
14
+ import { join } from 'desm'
15
+ import helpMe from 'help-me'
16
+ import minimist from 'minimist'
17
+ import { readFile } from 'node:fs/promises'
18
+ import { createRequire } from 'node:module'
19
+ import path from 'node:path'
20
+ import { pathToFileURL } from 'node:url'
21
+ import { logo } from './lib/ascii.js'
22
+ import { build } from './lib/build.js'
23
+ import { resolve } from './lib/resolve.js'
24
+ import { upgrade } from './lib/upgrade.js'
24
25
 
25
26
  const program = commist({ maxDistance: 2 })
26
27
  const help = helpMe({
27
28
  dir: join(import.meta.url, 'help'),
28
29
  // the default
29
- ext: '.txt',
30
+ ext: '.txt'
30
31
  })
31
32
 
32
33
  async function load (moduleName) {
@@ -48,36 +49,37 @@ const ensureCommand = async ({ output, help }) => {
48
49
  process.exit(1)
49
50
  }
50
51
 
51
- program.register('db', async (args) => {
52
+ program.register('db', async args => {
52
53
  const { runDB } = await load('@platformatic/db/db.mjs')
53
54
  return ensureCommand(await runDB(args))
54
55
  })
55
- program.register('runtime', async (args) => ensureCommand(await runRuntime(args)))
56
- program.register('service', async (args) => {
56
+ program.register('runtime', async args => ensureCommand(await runRuntime(args)))
57
+ program.register('service', async args => {
57
58
  const { runService } = await load('@platformatic/service/service.mjs')
58
59
  return ensureCommand(await runService(args))
59
60
  })
60
- program.register('composer', async (args) => {
61
+ program.register('composer', async args => {
61
62
  const { runComposer } = await load('@platformatic/composer/composer.mjs')
62
63
  return ensureCommand(await runComposer(args))
63
64
  })
64
- program.register('start', async (args) => ensureCommand(await startCommand(args)))
65
- program.register('ctl', async (args) => ensureCommand(await runControl(args)))
66
- program.register('ps', async (args) => getRuntimesCommand(args))
67
- program.register('inject', async (args) => injectRuntimeCommand(args))
68
- program.register('logs', async (args) => streamRuntimeLogsCommand(args))
65
+ program.register('start', async args => ensureCommand(await startCommand(args)))
66
+ program.register('ctl', async args => ensureCommand(await runControl(args)))
67
+ program.register('ps', async args => getRuntimesCommand(args))
68
+ program.register('inject', async args => injectRuntimeCommand(args))
69
+ program.register('logs', async args => streamRuntimeLogsCommand(args))
69
70
  program.register('upgrade', upgrade)
70
- program.register('download', download)
71
+ program.register('resolve', resolve)
71
72
  program.register('client', client)
72
- program.register('compile', async (args) => await compile(args) ? null : process.exit(1))
73
+ program.register('build', build)
74
+ program.register('compile', async args => ((await compile(args)) ? null : process.exit(1)))
73
75
  program.register('help', help.toStdout)
74
- program.register('help db', async (args) => {
76
+ program.register('help db', async args => {
75
77
  const { runDB } = await load('@platformatic/db/db.mjs')
76
78
  return runDB(['help', ...args])
77
79
  })
78
80
  program.register('help client', () => client([]))
79
- program.register('help runtime', async (args) => runRuntime(['help', ...args]))
80
- program.register('help service', async (args) => {
81
+ program.register('help runtime', async args => runRuntime(['help', ...args]))
82
+ program.register('help service', async args => {
81
83
  const { runService } = await load('@platformatic/service/service.mjs')
82
84
  return runService(['help', ...args])
83
85
  })
@@ -86,8 +88,8 @@ const args = minimist(process.argv.slice(2), {
86
88
  boolean: ['help', 'version'],
87
89
  alias: {
88
90
  help: 'h',
89
- version: 'v',
90
- },
91
+ version: 'v'
92
+ }
91
93
  })
92
94
 
93
95
  if (args.version && !args._.includes('inject')) {
@@ -101,7 +103,7 @@ if (args.help) {
101
103
  } else if (process.argv.length > 2) {
102
104
  const output = await program.parseAsync(process.argv.slice(2))
103
105
  await ensureCommand({ output, help })
104
- /* c8 ignore start */
106
+ /* c8 ignore start */
105
107
  } else {
106
108
  if (isColorSupported && process.stdout.isTTY) {
107
109
  console.log(logo)
package/eslint.config.js CHANGED
@@ -1,3 +1,3 @@
1
1
  import neostandard from 'neostandard'
2
2
 
3
- export default neostandard({})
3
+ export default neostandard({ ignores: ['**/.astro', '**/.next', '**/.vite', '**/dist'] })
package/help/help.txt CHANGED
@@ -1,15 +1,18 @@
1
1
  Welcome to Platformatic. Available commands are:
2
2
 
3
- * `help` - display this message.
4
- * `help <command>` - show more information about a command.
5
3
  * `db` - start Platformatic DB; type `platformatic db help` to know more.
6
- * `service` - start Platformatic Service; type `platformatic service help` to know more.
7
- * `upgrade` - upgrade the Platformatic configuration to the latest version.
8
- * `gh` - create a new gh action for Platformatic deployments.
9
4
  * `runtime` - start Platformatic Runtime; type `platformatic runtime help` to know more.
5
+ * `service` - start Platformatic Service; type `platformatic service help` to know more.
6
+ * `composer` - start Platformatic Composer; type `platformatic composer help` to know more.
10
7
  * `start` - start a Platformatic application.
11
- * `client` - generate a Platformatic client.
8
+ * `ctl` - Platformatic Control commands; `platformatic ctl help` to know more.
12
9
  * `ps` - list all Platformatic runtime applications.
13
- * `logs` - stream logs for a Platformatic runtime application.
14
10
  * `inject` - inject a request into a Platformatic runtime application.
15
- * `ctl` - Platformatic Control commands; `platformatic ctl help` to know more.
11
+ * `logs` - stream logs for a Platformatic runtime application.
12
+ * `upgrade` - upgrade the Platformatic configuration to the latest version.
13
+ * `resolve` - resolve Platformatic Runtime external services
14
+ * `client` - generate a Platformatic client.
15
+ * `build` - builds all services.
16
+ * `compile` - compile all typescript plugins.
17
+ * `help` - display this message.
18
+ * `help <command>` - show more information about a command.
@@ -1,18 +1,20 @@
1
- Download Platformatic Runtime external services
1
+ Resolve Platformatic Runtime external services
2
2
 
3
3
  ``` bash
4
- $ platformatic download
4
+ $ platformatic resolve
5
5
  ```
6
6
 
7
7
  Options:
8
8
 
9
9
  * `-c, --config FILE` - Path to the runtime configuration file.
10
+ * `-u, --username string` - Username for the service repository.
11
+ * `-p, --password string` - Password for the service repository.
10
12
 
11
- Platformatic download command downloads runtime services that have the `url` in their configuration.
13
+ Platformatic resolve command resolves runtime services that have the `url` in their configuration.
12
14
  By default services are cloned with `git` to the `external` directory inside the runtime directory.
13
15
  To change the directory where a service is cloned, you can set the `path` property in the service configuration.
14
16
 
15
- After cloning the service, the download command will set the relative path to the service in the runtime configuration file.
17
+ After cloning the service, the resolve command will set the relative path to the service in the runtime configuration file.
16
18
 
17
19
  Example of the runtime platformatic.json configuration file:
18
20
 
package/lib/build.js ADDED
@@ -0,0 +1,80 @@
1
+ import platformaticBasic from '@platformatic/basic'
2
+ import { Store, loadConfig as pltConfigLoadConfig } from '@platformatic/config'
3
+ import { buildRuntime, platformaticRuntime } from '@platformatic/runtime'
4
+ import { execa, parseCommandString } from 'execa'
5
+ import { once } from 'node:events'
6
+ import split from 'split2'
7
+
8
+ async function loadConfig (minimistConfig, args, overrides, replaceEnv = true) {
9
+ const store = new Store()
10
+ store.add(platformaticRuntime)
11
+ store.add(platformaticBasic)
12
+
13
+ return pltConfigLoadConfig(minimistConfig, args, store, overrides, replaceEnv)
14
+ }
15
+
16
+ async function buildService (logger, id, cwd, command) {
17
+ const [executable, ...args] = parseCommandString(command)
18
+ const subprocess = execa(executable, args, {
19
+ all: true,
20
+ lines: false,
21
+ stripFinalNewline: false,
22
+ reject: false,
23
+ preferLocal: true,
24
+ cwd
25
+ })
26
+
27
+ const exitPromise = once(subprocess, 'exit')
28
+
29
+ const output = []
30
+ for await (const line of subprocess.all.pipe(split())) {
31
+ logger.debug(` ${line}`)
32
+ output.push(line)
33
+ }
34
+ logger.debug('')
35
+ output.push('')
36
+
37
+ const [exitCode] = await exitPromise
38
+
39
+ if (exitCode !== 0) {
40
+ logger.error(`❌ Building service ${id} (${command}) failed with exit code ${exitCode}: `)
41
+
42
+ for (const line of output) {
43
+ logger.error(` ${line}`)
44
+ }
45
+
46
+ process.exit(1)
47
+ }
48
+ }
49
+
50
+ export async function build (args) {
51
+ const config = await loadConfig({}, args)
52
+ config.configManager.args = config.args
53
+
54
+ const runtimeConfig = config.configManager
55
+ const runtime = await buildRuntime(runtimeConfig)
56
+ const logger = runtime.logger
57
+
58
+ // Gather informations for all services before starting
59
+ const toBuild = new Map()
60
+ const { services } = await runtime.getServices()
61
+
62
+ for (const { id } of services) {
63
+ const { path } = runtimeConfig.current.serviceMap.get(id)
64
+ const meta = await runtime.getServiceMeta(id)
65
+
66
+ if (meta?.deploy?.buildCommand) {
67
+ toBuild.set(id, [path, meta.deploy.buildCommand])
68
+ }
69
+ }
70
+
71
+ // Build all services
72
+ for (const [id, [cwd, command]] of toBuild) {
73
+ logger.info(`Building service "${id}" (${command}) ...`)
74
+
75
+ await buildService(logger, id, cwd, command)
76
+ }
77
+
78
+ logger.info('✅ All external services have been built.')
79
+ await runtime.close(false, true)
80
+ }
@@ -1,21 +1,23 @@
1
- import { join, relative } from 'node:path'
2
- import { access, writeFile, mkdir, readdir } from 'node:fs/promises'
3
- import { Store, getStringifier } from '@platformatic/config'
1
+ import { join, relative, resolve as resolvePath } from 'node:path'
2
+ import { access, writeFile, readFile, mkdir, readdir } from 'node:fs/promises'
3
+ import { Store, getParser, getStringifier } from '@platformatic/config'
4
4
  import { platformaticRuntime } from '@platformatic/runtime'
5
5
  import parseArgs from 'minimist'
6
6
  import pino from 'pino'
7
7
  import pretty from 'pino-pretty'
8
8
  import { execa } from 'execa'
9
- import fjs from 'fast-json-stringify'
10
9
 
11
- const DOWNLOAD_SERVICES_DIRNAME = 'external'
10
+ const RESOLVED_SERVICES_DIRNAME = 'external'
12
11
 
13
- export async function download (argv) {
12
+ export async function resolve (argv) {
14
13
  const args = parseArgs(argv, {
15
14
  alias: {
16
15
  config: 'c',
16
+ username: 'u',
17
+ password: 'p',
17
18
  },
18
19
  boolean: ['test'],
20
+ string: ['config', 'username', 'password'],
19
21
  default: { test: false },
20
22
  })
21
23
 
@@ -24,14 +26,18 @@ export async function download (argv) {
24
26
  ignore: 'hostname,pid',
25
27
  }))
26
28
  try {
27
- await downloadServices(args.config, logger, args.test)
29
+ await resolveServices(args.config, logger, {
30
+ test: args.test,
31
+ username: args.username,
32
+ password: args.password,
33
+ })
28
34
  } catch (err) {
29
35
  console.log(err)
30
36
  process.exit(1)
31
37
  }
32
38
  }
33
39
 
34
- async function downloadServices (config, logger, isTest = false) {
40
+ async function resolveServices (configPath, logger, options = {}) {
35
41
  const store = new Store({
36
42
  cwd: process.cwd(),
37
43
  logger,
@@ -39,42 +45,47 @@ async function downloadServices (config, logger, isTest = false) {
39
45
  store.add(platformaticRuntime)
40
46
 
41
47
  const { configManager } = await store.loadConfig({
42
- config,
48
+ config: configPath,
43
49
  overrides: {
44
- fixPaths: false,
45
50
  onMissingEnv (key) {
46
51
  return '{' + key + '}'
47
52
  },
48
53
  },
49
54
  })
50
55
 
51
- await configManager.parseAndValidate(true)
52
- config = configManager.current
56
+ configPath = configManager.fullPath
53
57
 
54
- // If the schema is present, we use it to format the config
55
- if (configManager.schema) {
56
- const stringify = fjs(configManager.schema)
57
- config = JSON.parse(stringify(config))
58
- }
59
-
60
- const projectDir = configManager.dirname
61
- const externalDir = join(projectDir, DOWNLOAD_SERVICES_DIRNAME)
58
+ const parseConfig = getParser(configPath)
59
+ const configFile = await readFile(configPath, 'utf8')
60
+ const config = await parseConfig(configFile)
62
61
 
63
62
  if (!config.services || config.services.length === 0) {
64
- logger.info('No external services to download')
63
+ logger.info('No external services to resolve')
65
64
  return
66
65
  }
67
66
 
67
+ const projectDir = configManager.dirname
68
+ const externalDir = join(projectDir, RESOLVED_SERVICES_DIRNAME)
69
+
68
70
  const services = config.services || []
69
71
  for (const service of services) {
70
72
  if (service.url) {
71
73
  let path = service.path
72
- if (!path || (path.startsWith('{') && path.endsWith('}'))) {
74
+ if (path && path.startsWith('{') && path.endsWith('}')) {
75
+ path = await configManager.replaceEnv(path)
76
+
77
+ // Failed to resolve the path
78
+ if (path.startsWith('{') && path.endsWith('}')) {
79
+ path = null
80
+ }
81
+ }
82
+
83
+ if (!path) {
73
84
  await mkdir(externalDir, { recursive: true })
74
85
  path = join(externalDir, service.id)
75
86
  service.path = relative(projectDir, path)
76
87
  } else {
77
- path = join(projectDir, path)
88
+ path = resolvePath(projectDir, path)
78
89
  }
79
90
 
80
91
  const isNotEmpty = await isDirectoryNotEmpty(path)
@@ -86,13 +97,22 @@ async function downloadServices (config, logger, isTest = false) {
86
97
  const relativePath = relative(projectDir, path)
87
98
 
88
99
  logger.info(`Cloning ${service.url} into ${relativePath}`)
89
- if (!isTest) {
90
- await execa('git', ['clone', service.url, path])
100
+ if (!options.test) {
101
+ let url = service.url
102
+ if (options.username && options.password) {
103
+ const urlObj = new URL(service.url)
104
+ if (!urlObj.username && !urlObj.password) {
105
+ urlObj.username = options.username
106
+ urlObj.password = options.password
107
+ }
108
+ url = urlObj.href
109
+ }
110
+ await execa('git', ['clone', url, path])
91
111
  }
92
112
 
93
113
  // TODO: replace it with a proper runtime build step
94
- logger.info(`Downloading dependencies for service "${service.id}"`)
95
- if (!isTest) {
114
+ logger.info(`Resolving dependencies for service "${service.id}"`)
115
+ if (!options.test) {
96
116
  await execa('npm', ['i'], { cwd: path })
97
117
  }
98
118
 
@@ -102,12 +122,12 @@ async function downloadServices (config, logger, isTest = false) {
102
122
  }
103
123
  }
104
124
 
105
- const stringify = getStringifier(configManager.fullPath)
106
- const newConfig = stringify(config)
125
+ const stringifyConfig = getStringifier(configPath)
126
+ const newConfig = stringifyConfig(config)
107
127
 
108
128
  await writeFile(configManager.fullPath, newConfig, 'utf8')
109
129
 
110
- logger.info('✅ All external services have been downloaded')
130
+ logger.info('✅ All external services have been resolved')
111
131
  }
112
132
 
113
133
  async function isDirectoryNotEmpty (directoryPath) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "platformatic",
3
- "version": "2.0.0-alpha.5",
3
+ "version": "2.0.0-alpha.7",
4
4
  "description": "Platformatic CLI",
5
5
  "main": "cli.js",
6
6
  "type": "module",
@@ -34,12 +34,18 @@
34
34
  "fastify": "^4.26.2",
35
35
  "license-checker": "^25.0.1",
36
36
  "mkdirp": "^2.1.6",
37
+ "minimatch": "^10.0.1",
37
38
  "neostandard": "^0.11.1",
38
39
  "split2": "^4.2.0",
39
40
  "typescript": "^5.5.3",
40
- "@platformatic/composer": "2.0.0-alpha.5",
41
- "@platformatic/service": "2.0.0-alpha.5",
42
- "@platformatic/db": "2.0.0-alpha.5"
41
+ "@platformatic/astro": "2.0.0-alpha.7",
42
+ "@platformatic/composer": "2.0.0-alpha.7",
43
+ "@platformatic/db": "2.0.0-alpha.7",
44
+ "@platformatic/next": "2.0.0-alpha.7",
45
+ "@platformatic/remix": "2.0.0-alpha.7",
46
+ "@platformatic/service": "2.0.0-alpha.7",
47
+ "@platformatic/node": "2.0.0-alpha.7",
48
+ "@platformatic/vite": "2.0.0-alpha.7"
43
49
  },
44
50
  "dependencies": {
45
51
  "@fastify/error": "^3.4.1",
@@ -47,7 +53,7 @@
47
53
  "commist": "^3.2.0",
48
54
  "desm": "^1.3.1",
49
55
  "dotenv": "^16.4.5",
50
- "execa": "^8.0.1",
56
+ "execa": "^9.3.1",
51
57
  "fast-json-stringify": "^5.14.1",
52
58
  "graphql": "^16.8.1",
53
59
  "help-me": "^5.0.0",
@@ -55,18 +61,20 @@
55
61
  "minimist": "^1.2.8",
56
62
  "pino": "^8.19.0",
57
63
  "pino-pretty": "^11.0.0",
64
+ "split2": "^4.2.0",
58
65
  "undici": "^6.9.0",
59
- "@platformatic/client-cli": "2.0.0-alpha.5",
60
- "@platformatic/control": "2.0.0-alpha.5",
61
- "@platformatic/db": "2.0.0-alpha.5",
62
- "@platformatic/frontend-template": "2.0.0-alpha.5",
63
- "@platformatic/runtime": "2.0.0-alpha.5",
64
- "create-platformatic": "2.0.0-alpha.5",
65
- "@platformatic/utils": "2.0.0-alpha.5",
66
- "@platformatic/config": "2.0.0-alpha.5"
66
+ "@platformatic/control": "2.0.0-alpha.7",
67
+ "@platformatic/client-cli": "2.0.0-alpha.7",
68
+ "@platformatic/db": "2.0.0-alpha.7",
69
+ "@platformatic/config": "2.0.0-alpha.7",
70
+ "@platformatic/frontend-template": "2.0.0-alpha.7",
71
+ "@platformatic/basic": "2.0.0-alpha.7",
72
+ "@platformatic/runtime": "2.0.0-alpha.7",
73
+ "@platformatic/utils": "2.0.0-alpha.7",
74
+ "create-platformatic": "2.0.0-alpha.7"
67
75
  },
68
76
  "scripts": {
69
- "test": "pnpm run lint && borp --timeout=180000 --concurrency 1",
77
+ "test": "pnpm run lint && borp --timeout=600000 --concurrency 1",
70
78
  "lint": "eslint",
71
79
  "license": "license-checker --production --onlyAllow 'Apache-2.0;MIT;ISC;BSD-2-Clause;BSD-3-Clause;CC-BY-4.0'"
72
80
  }