@platformatic/runtime 0.26.1 → 0.28.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/fixtures/composerApp/api1.json +65 -0
- package/fixtures/composerApp/platformatic.composer.json +23 -0
- package/fixtures/configs/invalid-schema-type.config.json +19 -0
- package/fixtures/configs/monorepo-client-without-id.json +24 -0
- package/fixtures/configs/no-schema.config.json +18 -0
- package/fixtures/dbApp/platformatic.db.json +22 -0
- package/fixtures/monorepo/serviceApp/platformatic.service-client-without-id.json +21 -0
- package/fixtures/monorepo/serviceApp/platformatic.service.json +1 -1
- package/fixtures/serviceAppThrowsOnStart/platformatic.service.json +0 -1
- package/fixtures/start-command-in-runtime.js +14 -0
- package/fixtures/start-command.js +9 -0
- package/fixtures/starter.js +9 -0
- package/index.js +5 -25
- package/lib/api.js +257 -0
- package/lib/app.js +62 -68
- package/lib/build-server.js +28 -0
- package/lib/config.js +36 -8
- package/lib/loader.mjs +21 -13
- package/lib/start.js +7 -19
- package/lib/unified-api.js +198 -0
- package/lib/worker.js +29 -53
- package/package.json +16 -13
- package/test/api.test.js +294 -0
- package/test/app.test.js +76 -13
- package/test/cli/start.test.mjs +4 -4
- package/test/config.test.js +9 -0
- package/test/unified-api.test.js +354 -0
- package/test/worker.test.js +0 -21
package/test/cli/start.test.mjs
CHANGED
|
@@ -29,14 +29,14 @@ test('handles startup errors', async (t) => {
|
|
|
29
29
|
const { execa } = await import('execa')
|
|
30
30
|
const config = join(import.meta.url, '..', '..', 'fixtures', 'configs', 'service-throws-on-start.json')
|
|
31
31
|
const child = execa(process.execPath, [cliPath, 'start', '-c', config], { encoding: 'utf8' })
|
|
32
|
-
let
|
|
32
|
+
let stdout = ''
|
|
33
33
|
let found = false
|
|
34
34
|
|
|
35
|
-
for await (const messages of on(child.
|
|
35
|
+
for await (const messages of on(child.stdout, 'data')) {
|
|
36
36
|
for (const message of messages) {
|
|
37
|
-
|
|
37
|
+
stdout += message
|
|
38
38
|
|
|
39
|
-
if (/Error: boom/.test(
|
|
39
|
+
if (/Error: boom/.test(stdout)) {
|
|
40
40
|
found = true
|
|
41
41
|
break
|
|
42
42
|
}
|
package/test/config.test.js
CHANGED
|
@@ -56,3 +56,12 @@ test('performs a topological sort on services depending on allowCycles', async (
|
|
|
56
56
|
})
|
|
57
57
|
})
|
|
58
58
|
})
|
|
59
|
+
|
|
60
|
+
test('can resolve service id from client package.json if not provided', async () => {
|
|
61
|
+
const configFile = join(fixturesDir, 'configs', 'monorepo-client-without-id.json')
|
|
62
|
+
const config = await loadConfig({}, ['-c', configFile], platformaticRuntime)
|
|
63
|
+
const entry = config.configManager.current.serviceMap.get('serviceApp')
|
|
64
|
+
|
|
65
|
+
assert.strictEqual(entry.dependencies.length, 1)
|
|
66
|
+
assert.strictEqual(entry.dependencies[0].id, 'with-logger')
|
|
67
|
+
})
|
|
@@ -0,0 +1,354 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
const assert = require('node:assert')
|
|
3
|
+
const { spawn } = require('node:child_process')
|
|
4
|
+
const { once } = require('node:events')
|
|
5
|
+
const { join } = require('node:path')
|
|
6
|
+
const { test } = require('node:test')
|
|
7
|
+
const {
|
|
8
|
+
buildServer,
|
|
9
|
+
getConfigType,
|
|
10
|
+
getCurrentSchema,
|
|
11
|
+
loadConfig
|
|
12
|
+
} = require('../lib/unified-api')
|
|
13
|
+
const { version } = require('../package.json')
|
|
14
|
+
const fixturesDir = join(__dirname, '..', 'fixtures')
|
|
15
|
+
|
|
16
|
+
test('getConfigType()', async (t) => {
|
|
17
|
+
await t.test('throws if there is no $schema', async () => {
|
|
18
|
+
const configFile = join(fixturesDir, 'configs', 'no-schema.config.json')
|
|
19
|
+
let err
|
|
20
|
+
|
|
21
|
+
try {
|
|
22
|
+
await getConfigType(['-c', configFile])
|
|
23
|
+
} catch (error) {
|
|
24
|
+
err = error
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
assert(err)
|
|
28
|
+
assert.strictEqual(err.cause.message, 'configuration is missing a schema')
|
|
29
|
+
})
|
|
30
|
+
|
|
31
|
+
await t.test('throws if the schema type is unsupported', async () => {
|
|
32
|
+
const configFile = join(fixturesDir, 'configs', 'invalid-schema-type.config.json')
|
|
33
|
+
let err
|
|
34
|
+
|
|
35
|
+
try {
|
|
36
|
+
await getConfigType(['-c', configFile])
|
|
37
|
+
} catch (error) {
|
|
38
|
+
err = error
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
assert(err)
|
|
42
|
+
assert.strictEqual(err.cause.message, 'unknown configuration type: \'trickortreat\'')
|
|
43
|
+
})
|
|
44
|
+
|
|
45
|
+
await t.test('gets type from config via args', async () => {
|
|
46
|
+
const configFile = join(fixturesDir, 'monorepo', 'serviceApp', 'platformatic.service.json')
|
|
47
|
+
const type = await getConfigType(['-c', configFile])
|
|
48
|
+
|
|
49
|
+
assert.strictEqual(type, 'service')
|
|
50
|
+
})
|
|
51
|
+
|
|
52
|
+
await t.test('gets type from config in provided directory', async () => {
|
|
53
|
+
const configDir = join(fixturesDir, 'monorepo', 'serviceApp')
|
|
54
|
+
const type = await getConfigType(undefined, configDir)
|
|
55
|
+
|
|
56
|
+
assert.strictEqual(type, 'service')
|
|
57
|
+
})
|
|
58
|
+
|
|
59
|
+
await t.test('gets db type from config in cwd', async (t) => {
|
|
60
|
+
const cwd = process.cwd()
|
|
61
|
+
|
|
62
|
+
t.after(() => {
|
|
63
|
+
process.chdir(cwd)
|
|
64
|
+
})
|
|
65
|
+
|
|
66
|
+
const configDir = join(fixturesDir, 'dbApp')
|
|
67
|
+
process.chdir(configDir)
|
|
68
|
+
const type = await getConfigType()
|
|
69
|
+
|
|
70
|
+
assert.strictEqual(type, 'db')
|
|
71
|
+
})
|
|
72
|
+
|
|
73
|
+
await t.test('gets composer type from config in cwd', async (t) => {
|
|
74
|
+
const cwd = process.cwd()
|
|
75
|
+
|
|
76
|
+
t.after(() => {
|
|
77
|
+
process.chdir(cwd)
|
|
78
|
+
})
|
|
79
|
+
|
|
80
|
+
const configDir = join(fixturesDir, 'monorepo', 'composerApp')
|
|
81
|
+
process.chdir(configDir)
|
|
82
|
+
const type = await getConfigType()
|
|
83
|
+
|
|
84
|
+
assert.strictEqual(type, 'composer')
|
|
85
|
+
})
|
|
86
|
+
})
|
|
87
|
+
|
|
88
|
+
test('getCurrentSchema()', async (t) => {
|
|
89
|
+
await t.test('gets service schema', async () => {
|
|
90
|
+
const schema = await getCurrentSchema('service')
|
|
91
|
+
|
|
92
|
+
assert(schema.$id.endsWith(`/v${version}/service`))
|
|
93
|
+
})
|
|
94
|
+
|
|
95
|
+
await t.test('gets db schema', async () => {
|
|
96
|
+
const schema = await getCurrentSchema('db')
|
|
97
|
+
|
|
98
|
+
assert(schema.$id.endsWith(`/v${version}/db`))
|
|
99
|
+
})
|
|
100
|
+
|
|
101
|
+
await t.test('gets composer schema', async () => {
|
|
102
|
+
const schema = await getCurrentSchema('composer')
|
|
103
|
+
|
|
104
|
+
assert(schema.$id.endsWith(`/v${version}/composer`))
|
|
105
|
+
})
|
|
106
|
+
|
|
107
|
+
await t.test('gets runtime schema', async () => {
|
|
108
|
+
const schema = await getCurrentSchema('runtime')
|
|
109
|
+
|
|
110
|
+
assert(schema.$id.endsWith(`/v${version}/runtime`))
|
|
111
|
+
})
|
|
112
|
+
|
|
113
|
+
await t.test('throws for unknown types', async () => {
|
|
114
|
+
await assert.rejects(async () => {
|
|
115
|
+
await getCurrentSchema('not-a-real-type')
|
|
116
|
+
}, /unknown configuration type/)
|
|
117
|
+
})
|
|
118
|
+
})
|
|
119
|
+
|
|
120
|
+
test('loadConfig()', async (t) => {
|
|
121
|
+
await t.test('can explicitly provide config type', async () => {
|
|
122
|
+
const configFile = join(fixturesDir, 'monorepo', 'serviceAppWithLogger', 'platformatic.service.json')
|
|
123
|
+
const config = await loadConfig({}, ['-c', configFile], undefined, 'service')
|
|
124
|
+
|
|
125
|
+
assert.strictEqual(config.args.config, configFile)
|
|
126
|
+
assert.strictEqual(config.configManager.fullPath, configFile)
|
|
127
|
+
assert.strictEqual(config.configManager.current.server.logger.name, 'service-with-logger')
|
|
128
|
+
assert.strictEqual(config.configManager.schemaOptions.useDefaults, true)
|
|
129
|
+
})
|
|
130
|
+
|
|
131
|
+
await t.test('throws if explicit type is wrong', async () => {
|
|
132
|
+
// Prevent the failed validation from logging and exiting the process.
|
|
133
|
+
t.mock.method(process, 'exit', () => {})
|
|
134
|
+
t.mock.method(console, 'table', () => {})
|
|
135
|
+
|
|
136
|
+
const configFile = join(fixturesDir, 'monorepo', 'serviceAppWithLogger', 'platformatic.service.json')
|
|
137
|
+
|
|
138
|
+
await assert.rejects(async () => {
|
|
139
|
+
await loadConfig({}, ['-c', configFile], 'kaboom')
|
|
140
|
+
})
|
|
141
|
+
})
|
|
142
|
+
|
|
143
|
+
await t.test('can load a platformatic service project', async () => {
|
|
144
|
+
const configFile = join(fixturesDir, 'monorepo', 'serviceAppWithLogger', 'platformatic.service.json')
|
|
145
|
+
const config = await loadConfig({}, ['-c', configFile])
|
|
146
|
+
|
|
147
|
+
assert.strictEqual(config.args.config, configFile)
|
|
148
|
+
assert.strictEqual(config.configManager.fullPath, configFile)
|
|
149
|
+
assert.strictEqual(config.configManager.current.server.logger.name, 'service-with-logger')
|
|
150
|
+
assert.strictEqual(config.configManager.schemaOptions.useDefaults, true)
|
|
151
|
+
})
|
|
152
|
+
|
|
153
|
+
await t.test('can load a platformatic db project', async () => {
|
|
154
|
+
const configFile = join(fixturesDir, 'dbApp', 'platformatic.db.json')
|
|
155
|
+
const config = await loadConfig({}, ['-c', configFile])
|
|
156
|
+
|
|
157
|
+
assert.strictEqual(config.args.config, configFile)
|
|
158
|
+
assert.strictEqual(config.configManager.fullPath, configFile)
|
|
159
|
+
assert.strictEqual(config.configManager.current.db.graphql, true)
|
|
160
|
+
})
|
|
161
|
+
|
|
162
|
+
await t.test('can load a platformatic composer project', async () => {
|
|
163
|
+
const configFile = join(fixturesDir, 'composerApp', 'platformatic.composer.json')
|
|
164
|
+
const config = await loadConfig({}, ['-c', configFile])
|
|
165
|
+
|
|
166
|
+
assert.strictEqual(config.args.config, configFile)
|
|
167
|
+
assert.strictEqual(config.configManager.fullPath, configFile)
|
|
168
|
+
assert.strictEqual(config.configManager.current.composer.refreshTimeout, 1000)
|
|
169
|
+
})
|
|
170
|
+
|
|
171
|
+
await t.test('can load a platformatic runtime project', async () => {
|
|
172
|
+
const configFile = join(fixturesDir, 'configs', 'monorepo.json')
|
|
173
|
+
const config = await loadConfig({}, ['-c', configFile])
|
|
174
|
+
|
|
175
|
+
assert.strictEqual(config.args.config, configFile)
|
|
176
|
+
assert.strictEqual(config.configManager.fullPath, configFile)
|
|
177
|
+
assert.strictEqual(config.configManager.current.entrypoint, 'serviceApp')
|
|
178
|
+
})
|
|
179
|
+
})
|
|
180
|
+
|
|
181
|
+
test('buildServer()', async (t) => {
|
|
182
|
+
await t.test('can build a service server', async (t) => {
|
|
183
|
+
const configFile = join(fixturesDir, 'monorepo', 'serviceAppWithLogger', 'platformatic.service.json')
|
|
184
|
+
const config = await loadConfig({}, ['-c', configFile])
|
|
185
|
+
const server = await buildServer(config.configManager.current)
|
|
186
|
+
|
|
187
|
+
t.after(async () => {
|
|
188
|
+
await server.close()
|
|
189
|
+
})
|
|
190
|
+
|
|
191
|
+
const address = await server.start()
|
|
192
|
+
// The address should be a valid URL.
|
|
193
|
+
new URL(address) // eslint-disable-line no-new
|
|
194
|
+
})
|
|
195
|
+
|
|
196
|
+
await t.test('can build a db server', async (t) => {
|
|
197
|
+
const configFile = join(fixturesDir, 'dbApp', 'platformatic.db.json')
|
|
198
|
+
const config = await loadConfig({}, ['-c', configFile])
|
|
199
|
+
const server = await buildServer(config.configManager.current)
|
|
200
|
+
|
|
201
|
+
t.after(async () => {
|
|
202
|
+
await server.close()
|
|
203
|
+
})
|
|
204
|
+
|
|
205
|
+
const address = await server.start()
|
|
206
|
+
// The address should be a valid URL.
|
|
207
|
+
new URL(address) // eslint-disable-line no-new
|
|
208
|
+
})
|
|
209
|
+
|
|
210
|
+
await t.test('can build a composer server', async (t) => {
|
|
211
|
+
const configFile = join(fixturesDir, 'composerApp', 'platformatic.composer.json')
|
|
212
|
+
const config = await loadConfig({}, ['-c', configFile])
|
|
213
|
+
const server = await buildServer(config.configManager.current)
|
|
214
|
+
|
|
215
|
+
t.after(async () => {
|
|
216
|
+
await server.close()
|
|
217
|
+
})
|
|
218
|
+
|
|
219
|
+
const address = await server.start()
|
|
220
|
+
// The address should be a valid URL.
|
|
221
|
+
new URL(address) // eslint-disable-line no-new
|
|
222
|
+
})
|
|
223
|
+
|
|
224
|
+
await t.test('can build a runtime application', async (t) => {
|
|
225
|
+
const configFile = join(fixturesDir, 'configs', 'monorepo.json')
|
|
226
|
+
const config = await loadConfig({}, ['-c', configFile])
|
|
227
|
+
const server = await buildServer(config.configManager.current)
|
|
228
|
+
|
|
229
|
+
t.after(async () => {
|
|
230
|
+
await server.close()
|
|
231
|
+
})
|
|
232
|
+
|
|
233
|
+
const address = await server.start()
|
|
234
|
+
// The address should be a valid URL.
|
|
235
|
+
new URL(address) // eslint-disable-line no-new
|
|
236
|
+
})
|
|
237
|
+
|
|
238
|
+
await t.test('input can be a filename', async (t) => {
|
|
239
|
+
const configFile = join(fixturesDir, 'monorepo', 'serviceAppWithLogger', 'platformatic.service.json')
|
|
240
|
+
const server = await buildServer(configFile)
|
|
241
|
+
|
|
242
|
+
t.after(async () => {
|
|
243
|
+
await server.close()
|
|
244
|
+
})
|
|
245
|
+
|
|
246
|
+
const address = await server.start()
|
|
247
|
+
// The address should be a valid URL.
|
|
248
|
+
new URL(address) // eslint-disable-line no-new
|
|
249
|
+
})
|
|
250
|
+
})
|
|
251
|
+
|
|
252
|
+
test('start()', async (t) => {
|
|
253
|
+
await t.test('can start a service server', async (t) => {
|
|
254
|
+
const scriptFile = join(fixturesDir, 'starter.js')
|
|
255
|
+
const configFile = join(fixturesDir, 'monorepo', 'serviceAppWithLogger', 'platformatic.service.json')
|
|
256
|
+
const child = spawn(process.execPath, [scriptFile, configFile])
|
|
257
|
+
child.stdout.pipe(process.stdout)
|
|
258
|
+
child.stderr.pipe(process.stderr)
|
|
259
|
+
const [exitCode] = await once(child, 'exit')
|
|
260
|
+
|
|
261
|
+
assert.strictEqual(exitCode, 42)
|
|
262
|
+
})
|
|
263
|
+
|
|
264
|
+
await t.test('can start a db server', async (t) => {
|
|
265
|
+
const scriptFile = join(fixturesDir, 'starter.js')
|
|
266
|
+
const configFile = join(fixturesDir, 'dbApp', 'platformatic.db.json')
|
|
267
|
+
const child = spawn(process.execPath, [scriptFile, configFile])
|
|
268
|
+
const [exitCode] = await once(child, 'exit')
|
|
269
|
+
|
|
270
|
+
assert.strictEqual(exitCode, 42)
|
|
271
|
+
})
|
|
272
|
+
|
|
273
|
+
await t.test('can start a composer server', async () => {
|
|
274
|
+
const scriptFile = join(fixturesDir, 'starter.js')
|
|
275
|
+
const configFile = join(fixturesDir, 'composerApp', 'platformatic.composer.json')
|
|
276
|
+
const child = spawn(process.execPath, [scriptFile, configFile])
|
|
277
|
+
const [exitCode] = await once(child, 'exit')
|
|
278
|
+
|
|
279
|
+
assert.strictEqual(exitCode, 42)
|
|
280
|
+
})
|
|
281
|
+
|
|
282
|
+
await t.test('can start a runtime application', async () => {
|
|
283
|
+
const scriptFile = join(fixturesDir, 'starter.js')
|
|
284
|
+
const configFile = join(fixturesDir, 'configs', 'monorepo.json')
|
|
285
|
+
const child = spawn(process.execPath, [scriptFile, configFile])
|
|
286
|
+
const [exitCode] = await once(child, 'exit')
|
|
287
|
+
|
|
288
|
+
assert.strictEqual(exitCode, 42)
|
|
289
|
+
})
|
|
290
|
+
})
|
|
291
|
+
|
|
292
|
+
test('startCommand()', async (t) => {
|
|
293
|
+
await t.test('can start a server', async (t) => {
|
|
294
|
+
const scriptFile = join(fixturesDir, 'start-command.js')
|
|
295
|
+
const configFile = join(fixturesDir, 'monorepo', 'serviceAppWithLogger', 'platformatic.service.json')
|
|
296
|
+
const child = spawn(process.execPath, [scriptFile, configFile])
|
|
297
|
+
child.stderr.pipe(process.stderr)
|
|
298
|
+
const [exitCode] = await once(child, 'exit')
|
|
299
|
+
|
|
300
|
+
assert.strictEqual(exitCode, 42)
|
|
301
|
+
})
|
|
302
|
+
|
|
303
|
+
await t.test('exits on error', async (t) => {
|
|
304
|
+
const scriptFile = join(fixturesDir, 'start-command.js')
|
|
305
|
+
const configFile = join(fixturesDir, 'serviceApp', 'platformatic.not-found.json')
|
|
306
|
+
const child = spawn(process.execPath, [scriptFile, configFile])
|
|
307
|
+
const [exitCode] = await once(child, 'exit')
|
|
308
|
+
|
|
309
|
+
assert.strictEqual(exitCode, 1)
|
|
310
|
+
})
|
|
311
|
+
|
|
312
|
+
await t.test('can start a runtime application', async (t) => {
|
|
313
|
+
const scriptFile = join(fixturesDir, 'start-command.js')
|
|
314
|
+
const configFile = join(fixturesDir, 'configs', 'monorepo.json')
|
|
315
|
+
const child = spawn(process.execPath, [scriptFile, configFile])
|
|
316
|
+
child.stderr.pipe(process.stderr)
|
|
317
|
+
const [exitCode] = await once(child, 'exit')
|
|
318
|
+
|
|
319
|
+
assert.strictEqual(exitCode, 42)
|
|
320
|
+
})
|
|
321
|
+
})
|
|
322
|
+
|
|
323
|
+
test('startCommandInRuntime()', async (t) => {
|
|
324
|
+
await t.test('can start a non-runtime application', async (t) => {
|
|
325
|
+
const scriptFile = join(fixturesDir, 'start-command-in-runtime.js')
|
|
326
|
+
const configFile = join(fixturesDir, 'monorepo', 'serviceAppWithLogger', 'platformatic.service.json')
|
|
327
|
+
const child = spawn(process.execPath, [scriptFile, configFile])
|
|
328
|
+
child.stdout.pipe(process.stdout)
|
|
329
|
+
child.stderr.pipe(process.stderr)
|
|
330
|
+
const [exitCode] = await once(child, 'exit')
|
|
331
|
+
|
|
332
|
+
assert.strictEqual(exitCode, 42)
|
|
333
|
+
})
|
|
334
|
+
|
|
335
|
+
await t.test('can start a runtime application', async (t) => {
|
|
336
|
+
const scriptFile = join(fixturesDir, 'start-command-in-runtime.js')
|
|
337
|
+
const configFile = join(fixturesDir, 'configs', 'monorepo.json')
|
|
338
|
+
const child = spawn(process.execPath, [scriptFile, configFile])
|
|
339
|
+
child.stdout.pipe(process.stdout)
|
|
340
|
+
child.stderr.pipe(process.stderr)
|
|
341
|
+
const [exitCode] = await once(child, 'exit')
|
|
342
|
+
|
|
343
|
+
assert.strictEqual(exitCode, 42)
|
|
344
|
+
})
|
|
345
|
+
|
|
346
|
+
await t.test('exits on error', async (t) => {
|
|
347
|
+
const scriptFile = join(fixturesDir, 'start-command-in-runtime.js')
|
|
348
|
+
const configFile = join(fixturesDir, 'serviceApp', 'platformatic.not-found.json')
|
|
349
|
+
const child = spawn(process.execPath, [scriptFile, configFile])
|
|
350
|
+
const [exitCode] = await once(child, 'exit')
|
|
351
|
+
|
|
352
|
+
assert.strictEqual(exitCode, 1)
|
|
353
|
+
})
|
|
354
|
+
})
|
package/test/worker.test.js
DELETED
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
'use strict'
|
|
2
|
-
|
|
3
|
-
const assert = require('node:assert')
|
|
4
|
-
const { once } = require('node:events')
|
|
5
|
-
const { join } = require('node:path')
|
|
6
|
-
const { test } = require('node:test')
|
|
7
|
-
const { Worker } = require('node:worker_threads')
|
|
8
|
-
|
|
9
|
-
test('throws if unknown messages are received', async (t) => {
|
|
10
|
-
const workerFile = join(__dirname, '..', 'lib', 'worker.js')
|
|
11
|
-
const worker = new Worker(workerFile, {
|
|
12
|
-
execArgv: [],
|
|
13
|
-
workerData: { config: { services: [] } }
|
|
14
|
-
})
|
|
15
|
-
|
|
16
|
-
const [msg] = await once(worker, 'message')
|
|
17
|
-
assert.strictEqual(msg, 'plt:init')
|
|
18
|
-
worker.postMessage({ msg: 'unknown-message-type' })
|
|
19
|
-
const [err] = await once(worker, 'error')
|
|
20
|
-
assert.strictEqual(err.message, 'unknown message type: \'unknown-message-type\'')
|
|
21
|
-
})
|