@platformatic/runtime 0.30.0 → 0.31.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 (26) hide show
  1. package/fixtures/typescript/services/movies/.env +4 -0
  2. package/fixtures/typescript-custom-flags/platformatic.runtime.json +12 -0
  3. package/fixtures/typescript-custom-flags/services/composer/platformatic.composer.json +28 -0
  4. package/fixtures/typescript-custom-flags/services/movies/global.d.ts +24 -0
  5. package/fixtures/typescript-custom-flags/services/movies/migrations/001.do.sql +6 -0
  6. package/fixtures/typescript-custom-flags/services/movies/migrations/001.undo.sql +3 -0
  7. package/fixtures/typescript-custom-flags/services/movies/platformatic.db.json +35 -0
  8. package/fixtures/typescript-custom-flags/services/movies/plugin.ts +5 -0
  9. package/fixtures/typescript-custom-flags/services/movies/tsconfig.json +21 -0
  10. package/fixtures/typescript-custom-flags/services/movies/types/Movie.d.ts +9 -0
  11. package/fixtures/typescript-custom-flags/services/movies/types/index.d.ts +7 -0
  12. package/fixtures/typescript-custom-flags/services/titles/client/client.d.ts +141 -0
  13. package/fixtures/typescript-custom-flags/services/titles/client/client.openapi.json +630 -0
  14. package/fixtures/typescript-custom-flags/services/titles/client/package.json +4 -0
  15. package/fixtures/typescript-custom-flags/services/titles/platformatic.service.json +33 -0
  16. package/fixtures/typescript-custom-flags/services/titles/plugins/example.ts +6 -0
  17. package/fixtures/typescript-custom-flags/services/titles/routes/root.ts +21 -0
  18. package/fixtures/typescript-custom-flags/services/titles/tsconfig.json +21 -0
  19. package/index.js +2 -0
  20. package/lib/app.js +3 -2
  21. package/lib/compile.js +31 -24
  22. package/lib/unified-api.js +6 -1
  23. package/package.json +8 -8
  24. package/runtime.mjs +3 -1
  25. package/test/app.test.js +3 -1
  26. package/test/cli/compile.test.mjs +73 -14
@@ -0,0 +1,4 @@
1
+ PLT_SERVER_HOSTNAME=127.0.0.1
2
+ PORT=3001
3
+ PLT_SERVER_LOGGER_LEVEL=info
4
+ DATABASE_URL=sqlite://./db.sqlite
@@ -0,0 +1,12 @@
1
+ {
2
+ "$schema": "https://platformatic.dev/schemas/v0.28.1/runtime",
3
+ "entrypoint": "composer",
4
+ "allowCycles": false,
5
+ "hotReload": true,
6
+ "autoload": {
7
+ "path": "services",
8
+ "exclude": [
9
+ "docs"
10
+ ]
11
+ }
12
+ }
@@ -0,0 +1,28 @@
1
+ {
2
+ "$schema": "https://platformatic.dev/schemas/v0.28.1/composer",
3
+ "server": {
4
+ "hostname": "{PLT_SERVER_HOSTNAME}",
5
+ "port": "{PORT}",
6
+ "logger": {
7
+ "level": "{PLT_SERVER_LOGGER_LEVEL}"
8
+ }
9
+ },
10
+ "composer": {
11
+ "services": [
12
+ {
13
+ "id": "movies",
14
+ "openapi": {
15
+ "url": "/documentation/json"
16
+ }
17
+ },
18
+ {
19
+ "id": "titles",
20
+ "openapi": {
21
+ "url": "/documentation/json"
22
+ }
23
+ }
24
+ ],
25
+ "refreshTimeout": 1000
26
+ },
27
+ "watch": true
28
+ }
@@ -0,0 +1,24 @@
1
+ import { Entity } from '@platformatic/sql-mapper';
2
+ import graphqlPlugin from '@platformatic/sql-graphql'
3
+ import { EntityTypes, Movie } from './types'
4
+
5
+ declare module 'fastify' {
6
+ interface FastifyInstance {
7
+ getSchema<T extends 'Movie'>(schemaId: T): {
8
+ '$id': string,
9
+ title: string,
10
+ description: string,
11
+ type: string,
12
+ properties: {
13
+ [x in keyof EntityTypes[T]]: { type: string, nullable?: boolean }
14
+ },
15
+ required: string[]
16
+ };
17
+ }
18
+ }
19
+
20
+ declare module '@platformatic/sql-mapper' {
21
+ interface Entities {
22
+ movie: Entity<Movie>,
23
+ }
24
+ }
@@ -0,0 +1,6 @@
1
+
2
+ -- Add SQL in this file to create the database tables for your API
3
+ CREATE TABLE IF NOT EXISTS movies (
4
+ id INTEGER PRIMARY KEY,
5
+ title TEXT NOT NULL
6
+ );
@@ -0,0 +1,3 @@
1
+
2
+ -- Add SQL in this file to drop the database tables
3
+ DROP TABLE movies;
@@ -0,0 +1,35 @@
1
+ {
2
+ "$schema": "https://platformatic.dev/schemas/v0.30.0/db",
3
+ "server": {
4
+ "hostname": "{PLT_SERVER_HOSTNAME}",
5
+ "port": "{PORT}",
6
+ "logger": {
7
+ "level": "{PLT_SERVER_LOGGER_LEVEL}"
8
+ }
9
+ },
10
+ "db": {
11
+ "connectionString": "{DATABASE_URL}",
12
+ "graphql": true,
13
+ "openapi": true
14
+ },
15
+ "watch": {
16
+ "ignore": [
17
+ "*.sqlite",
18
+ "*.sqlite-journal"
19
+ ]
20
+ },
21
+ "migrations": {
22
+ "dir": "migrations"
23
+ },
24
+ "plugins": {
25
+ "paths": [
26
+ "plugin.ts"
27
+ ],
28
+ "typescript": {
29
+ "flags": ["-b"]
30
+ }
31
+ },
32
+ "types": {
33
+ "autogenerate": true
34
+ }
35
+ }
@@ -0,0 +1,5 @@
1
+ /// <reference path="./global.d.ts" />
2
+ import { FastifyInstance } from 'fastify'
3
+
4
+ export default async function (app: FastifyInstance) {
5
+ }
@@ -0,0 +1,21 @@
1
+ {
2
+ "compilerOptions": {
3
+ "module": "commonjs",
4
+ "esModuleInterop": true,
5
+ "target": "es2019",
6
+ "sourceMap": true,
7
+ "pretty": true,
8
+ "noEmitOnError": true,
9
+ "outDir": "dist"
10
+ },
11
+ "watchOptions": {
12
+ "watchFile": "fixedPollingInterval",
13
+ "watchDirectory": "fixedPollingInterval",
14
+ "fallbackPolling": "dynamicPriority",
15
+ "synchronousWatchDirectory": true,
16
+ "excludeDirectories": [
17
+ "**/node_modules",
18
+ "dist"
19
+ ]
20
+ }
21
+ }
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Movie
3
+ * A Movie
4
+ */
5
+ declare interface Movie {
6
+ id?: number;
7
+ title: string;
8
+ }
9
+ export { Movie };
@@ -0,0 +1,7 @@
1
+ import { Movie } from './Movie'
2
+
3
+ interface EntityTypes {
4
+ Movie:Movie
5
+ }
6
+
7
+ export { EntityTypes ,Movie }
@@ -0,0 +1,141 @@
1
+ import { FastifyPluginAsync } from 'fastify'
2
+
3
+ interface GetMoviesRequest {
4
+ 'limit'?: number;
5
+ 'offset'?: number;
6
+ 'totalCount'?: boolean;
7
+ 'fields'?: Array<string>;
8
+ 'where.id.eq'?: number;
9
+ 'where.id.neq'?: number;
10
+ 'where.id.gt'?: number;
11
+ 'where.id.gte'?: number;
12
+ 'where.id.lt'?: number;
13
+ 'where.id.lte'?: number;
14
+ 'where.id.like'?: number;
15
+ 'where.id.in'?: string;
16
+ 'where.id.nin'?: string;
17
+ 'where.title.eq'?: string;
18
+ 'where.title.neq'?: string;
19
+ 'where.title.gt'?: string;
20
+ 'where.title.gte'?: string;
21
+ 'where.title.lt'?: string;
22
+ 'where.title.lte'?: string;
23
+ 'where.title.like'?: string;
24
+ 'where.title.in'?: string;
25
+ 'where.title.nin'?: string;
26
+ 'where.or'?: Array<string>;
27
+ 'orderby.id'?: string;
28
+ 'orderby.title'?: string;
29
+ }
30
+
31
+ interface GetMoviesResponseOK {
32
+ 'id'?: number;
33
+ 'title': string;
34
+ }
35
+
36
+ interface CreateMovieRequest {
37
+ 'id'?: number;
38
+ 'title': string;
39
+ }
40
+
41
+ interface CreateMovieResponseOK {
42
+ 'id'?: number;
43
+ 'title': string;
44
+ }
45
+
46
+ interface UpdateMoviesRequest {
47
+ 'fields'?: Array<string>;
48
+ 'where.id.eq'?: number;
49
+ 'where.id.neq'?: number;
50
+ 'where.id.gt'?: number;
51
+ 'where.id.gte'?: number;
52
+ 'where.id.lt'?: number;
53
+ 'where.id.lte'?: number;
54
+ 'where.id.like'?: number;
55
+ 'where.id.in'?: string;
56
+ 'where.id.nin'?: string;
57
+ 'where.title.eq'?: string;
58
+ 'where.title.neq'?: string;
59
+ 'where.title.gt'?: string;
60
+ 'where.title.gte'?: string;
61
+ 'where.title.lt'?: string;
62
+ 'where.title.lte'?: string;
63
+ 'where.title.like'?: string;
64
+ 'where.title.in'?: string;
65
+ 'where.title.nin'?: string;
66
+ 'where.or'?: Array<string>;
67
+ 'id'?: number;
68
+ 'title': string;
69
+ }
70
+
71
+ interface UpdateMoviesResponseOK {
72
+ 'id'?: number;
73
+ 'title': string;
74
+ }
75
+
76
+ interface GetMovieByIdRequest {
77
+ 'fields'?: Array<string>;
78
+ 'id': number;
79
+ }
80
+
81
+ interface GetMovieByIdResponseOK {
82
+ 'id'?: number;
83
+ 'title': string;
84
+ }
85
+
86
+ interface UpdateMovieRequest {
87
+ 'fields'?: Array<string>;
88
+ 'id': number;
89
+ 'title': string;
90
+ }
91
+
92
+ interface UpdateMovieResponseOK {
93
+ 'id'?: number;
94
+ 'title': string;
95
+ }
96
+
97
+ interface DeleteMoviesRequest {
98
+ 'fields'?: Array<string>;
99
+ 'id': number;
100
+ }
101
+
102
+ interface DeleteMoviesResponseOK {
103
+ 'id'?: number;
104
+ 'title': string;
105
+ }
106
+
107
+ interface Client {
108
+ getMovies(req: GetMoviesRequest): Promise<Array<GetMoviesResponseOK>>;
109
+ createMovie(req: CreateMovieRequest): Promise<CreateMovieResponseOK>;
110
+ updateMovies(req: UpdateMoviesRequest): Promise<Array<UpdateMoviesResponseOK>>;
111
+ getMovieById(req: GetMovieByIdRequest): Promise<GetMovieByIdResponseOK>;
112
+ updateMovie(req: UpdateMovieRequest): Promise<UpdateMovieResponseOK>;
113
+ deleteMovies(req: DeleteMoviesRequest): Promise<DeleteMoviesResponseOK>;
114
+ }
115
+
116
+ type ClientPlugin = FastifyPluginAsync<NonNullable<client.ClientOptions>>
117
+
118
+ declare module 'fastify' {
119
+ interface ConfigureClient {
120
+ getHeaders(req: FastifyRequest, reply: FastifyReply): Promise<Record<string,string>>;
121
+ }
122
+ interface FastifyInstance {
123
+ 'client': Client;
124
+ configureClient(opts: ConfigureClient): unknown
125
+ }
126
+
127
+ interface FastifyRequest {
128
+ 'client': Client;
129
+ }
130
+ }
131
+
132
+ declare namespace client {
133
+ export interface ClientOptions {
134
+ url: string
135
+ }
136
+ export const client: ClientPlugin;
137
+ export { client as default };
138
+ }
139
+
140
+ declare function client(...params: Parameters<ClientPlugin>): ReturnType<ClientPlugin>;
141
+ export = client;
@@ -0,0 +1,630 @@
1
+ {
2
+ "openapi": "3.0.3",
3
+ "info": {
4
+ "title": "Platformatic DB",
5
+ "description": "Exposing a SQL database as REST",
6
+ "version": "1.0.0"
7
+ },
8
+ "components": {
9
+ "schemas": {
10
+ "Movie": {
11
+ "title": "Movie",
12
+ "description": "A Movie",
13
+ "type": "object",
14
+ "properties": {
15
+ "id": {
16
+ "type": "integer"
17
+ },
18
+ "title": {
19
+ "type": "string"
20
+ }
21
+ },
22
+ "required": [
23
+ "title"
24
+ ]
25
+ }
26
+ }
27
+ },
28
+ "paths": {
29
+ "/movies/": {
30
+ "get": {
31
+ "operationId": "getMovies",
32
+ "parameters": [
33
+ {
34
+ "schema": {
35
+ "type": "integer"
36
+ },
37
+ "in": "query",
38
+ "name": "limit",
39
+ "required": false,
40
+ "description": "Limit will be applied by default if not passed. If the provided value exceeds the maximum allowed value a validation error will be thrown"
41
+ },
42
+ {
43
+ "schema": {
44
+ "type": "integer"
45
+ },
46
+ "in": "query",
47
+ "name": "offset",
48
+ "required": false
49
+ },
50
+ {
51
+ "schema": {
52
+ "type": "boolean",
53
+ "default": false
54
+ },
55
+ "in": "query",
56
+ "name": "totalCount",
57
+ "required": false
58
+ },
59
+ {
60
+ "schema": {
61
+ "type": "array",
62
+ "items": {
63
+ "type": "string",
64
+ "enum": [
65
+ "id",
66
+ "title"
67
+ ]
68
+ }
69
+ },
70
+ "in": "query",
71
+ "name": "fields",
72
+ "required": false
73
+ },
74
+ {
75
+ "schema": {
76
+ "type": "integer"
77
+ },
78
+ "in": "query",
79
+ "name": "where.id.eq",
80
+ "required": false
81
+ },
82
+ {
83
+ "schema": {
84
+ "type": "integer"
85
+ },
86
+ "in": "query",
87
+ "name": "where.id.neq",
88
+ "required": false
89
+ },
90
+ {
91
+ "schema": {
92
+ "type": "integer"
93
+ },
94
+ "in": "query",
95
+ "name": "where.id.gt",
96
+ "required": false
97
+ },
98
+ {
99
+ "schema": {
100
+ "type": "integer"
101
+ },
102
+ "in": "query",
103
+ "name": "where.id.gte",
104
+ "required": false
105
+ },
106
+ {
107
+ "schema": {
108
+ "type": "integer"
109
+ },
110
+ "in": "query",
111
+ "name": "where.id.lt",
112
+ "required": false
113
+ },
114
+ {
115
+ "schema": {
116
+ "type": "integer"
117
+ },
118
+ "in": "query",
119
+ "name": "where.id.lte",
120
+ "required": false
121
+ },
122
+ {
123
+ "schema": {
124
+ "type": "integer"
125
+ },
126
+ "in": "query",
127
+ "name": "where.id.like",
128
+ "required": false
129
+ },
130
+ {
131
+ "schema": {
132
+ "type": "string"
133
+ },
134
+ "in": "query",
135
+ "name": "where.id.in",
136
+ "required": false
137
+ },
138
+ {
139
+ "schema": {
140
+ "type": "string"
141
+ },
142
+ "in": "query",
143
+ "name": "where.id.nin",
144
+ "required": false
145
+ },
146
+ {
147
+ "schema": {
148
+ "type": "string"
149
+ },
150
+ "in": "query",
151
+ "name": "where.title.eq",
152
+ "required": false
153
+ },
154
+ {
155
+ "schema": {
156
+ "type": "string"
157
+ },
158
+ "in": "query",
159
+ "name": "where.title.neq",
160
+ "required": false
161
+ },
162
+ {
163
+ "schema": {
164
+ "type": "string"
165
+ },
166
+ "in": "query",
167
+ "name": "where.title.gt",
168
+ "required": false
169
+ },
170
+ {
171
+ "schema": {
172
+ "type": "string"
173
+ },
174
+ "in": "query",
175
+ "name": "where.title.gte",
176
+ "required": false
177
+ },
178
+ {
179
+ "schema": {
180
+ "type": "string"
181
+ },
182
+ "in": "query",
183
+ "name": "where.title.lt",
184
+ "required": false
185
+ },
186
+ {
187
+ "schema": {
188
+ "type": "string"
189
+ },
190
+ "in": "query",
191
+ "name": "where.title.lte",
192
+ "required": false
193
+ },
194
+ {
195
+ "schema": {
196
+ "type": "string"
197
+ },
198
+ "in": "query",
199
+ "name": "where.title.like",
200
+ "required": false
201
+ },
202
+ {
203
+ "schema": {
204
+ "type": "string"
205
+ },
206
+ "in": "query",
207
+ "name": "where.title.in",
208
+ "required": false
209
+ },
210
+ {
211
+ "schema": {
212
+ "type": "string"
213
+ },
214
+ "in": "query",
215
+ "name": "where.title.nin",
216
+ "required": false
217
+ },
218
+ {
219
+ "schema": {
220
+ "type": "array",
221
+ "items": {
222
+ "type": "string"
223
+ }
224
+ },
225
+ "in": "query",
226
+ "name": "where.or",
227
+ "required": false
228
+ },
229
+ {
230
+ "schema": {
231
+ "type": "string",
232
+ "enum": [
233
+ "asc",
234
+ "desc"
235
+ ]
236
+ },
237
+ "in": "query",
238
+ "name": "orderby.id",
239
+ "required": false
240
+ },
241
+ {
242
+ "schema": {
243
+ "type": "string",
244
+ "enum": [
245
+ "asc",
246
+ "desc"
247
+ ]
248
+ },
249
+ "in": "query",
250
+ "name": "orderby.title",
251
+ "required": false
252
+ }
253
+ ],
254
+ "responses": {
255
+ "200": {
256
+ "description": "Default Response",
257
+ "content": {
258
+ "application/json": {
259
+ "schema": {
260
+ "type": "array",
261
+ "items": {
262
+ "$ref": "#/components/schemas/Movie"
263
+ }
264
+ }
265
+ }
266
+ }
267
+ }
268
+ }
269
+ },
270
+ "post": {
271
+ "operationId": "createMovie",
272
+ "requestBody": {
273
+ "content": {
274
+ "application/json": {
275
+ "schema": {
276
+ "$ref": "#/components/schemas/Movie"
277
+ }
278
+ }
279
+ }
280
+ },
281
+ "responses": {
282
+ "200": {
283
+ "description": "Default Response",
284
+ "content": {
285
+ "application/json": {
286
+ "schema": {
287
+ "$ref": "#/components/schemas/Movie"
288
+ }
289
+ }
290
+ },
291
+ "links": {}
292
+ }
293
+ }
294
+ },
295
+ "put": {
296
+ "operationId": "updateMovies",
297
+ "requestBody": {
298
+ "content": {
299
+ "application/json": {
300
+ "schema": {
301
+ "$ref": "#/components/schemas/Movie"
302
+ }
303
+ }
304
+ }
305
+ },
306
+ "parameters": [
307
+ {
308
+ "schema": {
309
+ "type": "array",
310
+ "items": {
311
+ "type": "string",
312
+ "enum": [
313
+ "id",
314
+ "title"
315
+ ]
316
+ }
317
+ },
318
+ "in": "query",
319
+ "name": "fields",
320
+ "required": false
321
+ },
322
+ {
323
+ "schema": {
324
+ "type": "integer"
325
+ },
326
+ "in": "query",
327
+ "name": "where.id.eq",
328
+ "required": false
329
+ },
330
+ {
331
+ "schema": {
332
+ "type": "integer"
333
+ },
334
+ "in": "query",
335
+ "name": "where.id.neq",
336
+ "required": false
337
+ },
338
+ {
339
+ "schema": {
340
+ "type": "integer"
341
+ },
342
+ "in": "query",
343
+ "name": "where.id.gt",
344
+ "required": false
345
+ },
346
+ {
347
+ "schema": {
348
+ "type": "integer"
349
+ },
350
+ "in": "query",
351
+ "name": "where.id.gte",
352
+ "required": false
353
+ },
354
+ {
355
+ "schema": {
356
+ "type": "integer"
357
+ },
358
+ "in": "query",
359
+ "name": "where.id.lt",
360
+ "required": false
361
+ },
362
+ {
363
+ "schema": {
364
+ "type": "integer"
365
+ },
366
+ "in": "query",
367
+ "name": "where.id.lte",
368
+ "required": false
369
+ },
370
+ {
371
+ "schema": {
372
+ "type": "integer"
373
+ },
374
+ "in": "query",
375
+ "name": "where.id.like",
376
+ "required": false
377
+ },
378
+ {
379
+ "schema": {
380
+ "type": "string"
381
+ },
382
+ "in": "query",
383
+ "name": "where.id.in",
384
+ "required": false
385
+ },
386
+ {
387
+ "schema": {
388
+ "type": "string"
389
+ },
390
+ "in": "query",
391
+ "name": "where.id.nin",
392
+ "required": false
393
+ },
394
+ {
395
+ "schema": {
396
+ "type": "string"
397
+ },
398
+ "in": "query",
399
+ "name": "where.title.eq",
400
+ "required": false
401
+ },
402
+ {
403
+ "schema": {
404
+ "type": "string"
405
+ },
406
+ "in": "query",
407
+ "name": "where.title.neq",
408
+ "required": false
409
+ },
410
+ {
411
+ "schema": {
412
+ "type": "string"
413
+ },
414
+ "in": "query",
415
+ "name": "where.title.gt",
416
+ "required": false
417
+ },
418
+ {
419
+ "schema": {
420
+ "type": "string"
421
+ },
422
+ "in": "query",
423
+ "name": "where.title.gte",
424
+ "required": false
425
+ },
426
+ {
427
+ "schema": {
428
+ "type": "string"
429
+ },
430
+ "in": "query",
431
+ "name": "where.title.lt",
432
+ "required": false
433
+ },
434
+ {
435
+ "schema": {
436
+ "type": "string"
437
+ },
438
+ "in": "query",
439
+ "name": "where.title.lte",
440
+ "required": false
441
+ },
442
+ {
443
+ "schema": {
444
+ "type": "string"
445
+ },
446
+ "in": "query",
447
+ "name": "where.title.like",
448
+ "required": false
449
+ },
450
+ {
451
+ "schema": {
452
+ "type": "string"
453
+ },
454
+ "in": "query",
455
+ "name": "where.title.in",
456
+ "required": false
457
+ },
458
+ {
459
+ "schema": {
460
+ "type": "string"
461
+ },
462
+ "in": "query",
463
+ "name": "where.title.nin",
464
+ "required": false
465
+ },
466
+ {
467
+ "schema": {
468
+ "type": "array",
469
+ "items": {
470
+ "type": "string"
471
+ }
472
+ },
473
+ "in": "query",
474
+ "name": "where.or",
475
+ "required": false
476
+ }
477
+ ],
478
+ "responses": {
479
+ "200": {
480
+ "description": "Default Response",
481
+ "content": {
482
+ "application/json": {
483
+ "schema": {
484
+ "type": "array",
485
+ "items": {
486
+ "$ref": "#/components/schemas/Movie"
487
+ }
488
+ }
489
+ }
490
+ },
491
+ "links": {}
492
+ }
493
+ }
494
+ }
495
+ },
496
+ "/movies/{id}": {
497
+ "get": {
498
+ "operationId": "getMovieById",
499
+ "parameters": [
500
+ {
501
+ "schema": {
502
+ "type": "array",
503
+ "items": {
504
+ "type": "string",
505
+ "enum": [
506
+ "id",
507
+ "title"
508
+ ]
509
+ }
510
+ },
511
+ "in": "query",
512
+ "name": "fields",
513
+ "required": false
514
+ },
515
+ {
516
+ "schema": {
517
+ "type": "integer"
518
+ },
519
+ "in": "path",
520
+ "name": "id",
521
+ "required": true
522
+ }
523
+ ],
524
+ "responses": {
525
+ "200": {
526
+ "description": "Default Response",
527
+ "content": {
528
+ "application/json": {
529
+ "schema": {
530
+ "$ref": "#/components/schemas/Movie"
531
+ }
532
+ }
533
+ },
534
+ "links": {}
535
+ }
536
+ }
537
+ },
538
+ "put": {
539
+ "operationId": "updateMovie",
540
+ "requestBody": {
541
+ "content": {
542
+ "application/json": {
543
+ "schema": {
544
+ "$ref": "#/components/schemas/Movie"
545
+ }
546
+ }
547
+ }
548
+ },
549
+ "parameters": [
550
+ {
551
+ "schema": {
552
+ "type": "array",
553
+ "items": {
554
+ "type": "string",
555
+ "enum": [
556
+ "id",
557
+ "title"
558
+ ]
559
+ }
560
+ },
561
+ "in": "query",
562
+ "name": "fields",
563
+ "required": false
564
+ },
565
+ {
566
+ "schema": {
567
+ "type": "integer"
568
+ },
569
+ "in": "path",
570
+ "name": "id",
571
+ "required": true
572
+ }
573
+ ],
574
+ "responses": {
575
+ "200": {
576
+ "description": "Default Response",
577
+ "content": {
578
+ "application/json": {
579
+ "schema": {
580
+ "$ref": "#/components/schemas/Movie"
581
+ }
582
+ }
583
+ },
584
+ "links": {}
585
+ }
586
+ }
587
+ },
588
+ "delete": {
589
+ "operationId": "deleteMovies",
590
+ "parameters": [
591
+ {
592
+ "schema": {
593
+ "type": "array",
594
+ "items": {
595
+ "type": "string",
596
+ "enum": [
597
+ "id",
598
+ "title"
599
+ ]
600
+ }
601
+ },
602
+ "in": "query",
603
+ "name": "fields",
604
+ "required": false
605
+ },
606
+ {
607
+ "schema": {
608
+ "type": "integer"
609
+ },
610
+ "in": "path",
611
+ "name": "id",
612
+ "required": true
613
+ }
614
+ ],
615
+ "responses": {
616
+ "200": {
617
+ "description": "Default Response",
618
+ "content": {
619
+ "application/json": {
620
+ "schema": {
621
+ "$ref": "#/components/schemas/Movie"
622
+ }
623
+ }
624
+ }
625
+ }
626
+ }
627
+ }
628
+ }
629
+ }
630
+ }
@@ -0,0 +1,4 @@
1
+ {
2
+ "name": "client",
3
+ "types": "./client.d.ts"
4
+ }
@@ -0,0 +1,33 @@
1
+ {
2
+ "$schema": "https://platformatic.dev/schemas/v0.30.0/service",
3
+ "server": {
4
+ "hostname": "{PLT_SERVER_HOSTNAME}",
5
+ "port": "{PORT}",
6
+ "logger": {
7
+ "level": "{PLT_SERVER_LOGGER_LEVEL}"
8
+ }
9
+ },
10
+ "service": {
11
+ "openapi": true
12
+ },
13
+ "plugins": {
14
+ "paths": [
15
+ {
16
+ "path": "./plugins",
17
+ "encapsulate": false
18
+ },
19
+ "./routes"
20
+ ],
21
+ "typescript": {
22
+ "flags": ["-b"]
23
+ }
24
+ },
25
+ "clients": [
26
+ {
27
+ "schema": "client/client.openapi.json",
28
+ "name": "client",
29
+ "type": "openapi",
30
+ "serviceId": "movies"
31
+ }
32
+ ]
33
+ }
@@ -0,0 +1,6 @@
1
+ /// <reference types="@platformatic/service" />
2
+ import { FastifyInstance, FastifyPluginOptions } from 'fastify'
3
+
4
+ export default async function (fastify: FastifyInstance, opts: FastifyPluginOptions) {
5
+ fastify.decorate('example', 'foobar')
6
+ }
@@ -0,0 +1,21 @@
1
+ /// <reference types="@platformatic/service" />
2
+ /// <reference types="../client" />
3
+ import { FastifyInstance, FastifyPluginOptions } from 'fastify'
4
+
5
+ declare module 'fastify' {
6
+ interface FastifyInstance {
7
+ example: string
8
+ }
9
+ }
10
+
11
+ export default async function (fastify: FastifyInstance, opts: FastifyPluginOptions) {
12
+ fastify.get('/', async (request, reply) => {
13
+ return { hello: fastify.example }
14
+ })
15
+
16
+ fastify.get('/titles', async (request, reply) => {
17
+ const movies = await fastify.client.getMovies({})
18
+ const titles = movies.map((movie) => movie.title)
19
+ return { titles }
20
+ })
21
+ }
@@ -0,0 +1,21 @@
1
+ {
2
+ "compilerOptions": {
3
+ "module": "commonjs",
4
+ "esModuleInterop": true,
5
+ "target": "es2019",
6
+ "sourceMap": true,
7
+ "pretty": true,
8
+ "noEmitOnError": true,
9
+ "outDir": "dist"
10
+ },
11
+ "watchOptions": {
12
+ "watchFile": "fixedPollingInterval",
13
+ "watchDirectory": "fixedPollingInterval",
14
+ "fallbackPolling": "dynamicPriority",
15
+ "synchronousWatchDirectory": true,
16
+ "excludeDirectories": [
17
+ "**/node_modules",
18
+ "dist"
19
+ ]
20
+ }
21
+ }
package/index.js CHANGED
@@ -4,6 +4,7 @@ const { platformaticRuntime } = require('./lib/config')
4
4
  const { start } = require('./lib/start')
5
5
  const unifiedApi = require('./lib/unified-api')
6
6
  const RuntimeApi = require('./lib/api')
7
+ const { compile } = require('./lib/compile')
7
8
 
8
9
  module.exports.buildServer = buildServer
9
10
  module.exports.platformaticRuntime = platformaticRuntime
@@ -11,3 +12,4 @@ module.exports.schema = platformaticRuntime.schema
11
12
  module.exports.RuntimeApi = RuntimeApi
12
13
  module.exports.start = start
13
14
  module.exports.unifiedApi = unifiedApi
15
+ module.exports.compile = compile
package/lib/app.js CHANGED
@@ -167,13 +167,14 @@ class PlatformaticApp {
167
167
  const parts = key.split('.')
168
168
  let next = configManager.current
169
169
  let obj
170
+ let i
170
171
 
171
- for (let i = 0; next !== undefined && i < parts.length; ++i) {
172
+ for (i = 0; next !== undefined && i < parts.length; ++i) {
172
173
  obj = next
173
174
  next = obj[parts[i]]
174
175
  }
175
176
 
176
- if (next !== undefined) {
177
+ if (i === parts.length) {
177
178
  obj[parts.at(-1)] = value
178
179
  }
179
180
  })
package/lib/compile.js CHANGED
@@ -1,43 +1,50 @@
1
1
  'use strict'
2
2
 
3
- const { loadConfig, tsCompiler } = require('@platformatic/service')
4
- const { access } = require('node:fs/promises')
5
- const { join } = require('path')
3
+ const { tsCompiler } = require('@platformatic/service')
4
+ const { loadConfig } = require('./unified-api')
5
+ const { dirname } = require('node:path')
6
+
6
7
  const pino = require('pino')
7
8
  const pretty = require('pino-pretty')
8
9
  const { isatty } = require('node:tty')
9
10
 
10
- const { platformaticRuntime } = require('./config')
11
-
12
- async function compile (argv) {
13
- const { configManager } = await loadConfig({}, argv, platformaticRuntime, {
11
+ async function compile (argv, logger) {
12
+ const { configManager, configType } = await loadConfig({}, argv, undefined, {
14
13
  watch: false
15
14
  })
16
15
 
17
- let stream
16
+ /* c8 ignore next */
17
+ if (!logger) {
18
+ let stream
19
+
20
+ if (isatty(process.stdout.fd)) {
21
+ stream = pretty({
22
+ translateTime: 'SYS:HH:MM:ss',
23
+ ignore: 'hostname,pid'
24
+ })
25
+ }
18
26
 
19
- /* c8 ignore next 6 */
20
- if (isatty(process.stdout.fd)) {
21
- stream = pretty({
22
- translateTime: 'SYS:HH:MM:ss',
23
- ignore: 'hostname,pid'
24
- })
27
+ logger = pino(stream)
25
28
  }
26
29
 
27
- const logger = pino(stream)
30
+ let compiled = false
28
31
 
29
- for (const service of configManager.current.services) {
30
- const tsconfig = join(service.path, 'tsconfig.json')
32
+ if (configType === 'runtime') {
33
+ for (const service of configManager.current.services) {
34
+ const childLogger = logger.child({ name: service.id })
31
35
 
32
- try {
33
- await access(tsconfig)
34
- } catch {
35
- logger.trace(`No tsconfig.json found in ${service.path}, skipping...`)
36
- continue
37
- }
36
+ const serviceConfig = await loadConfig({}, argv, undefined, {
37
+ watch: false
38
+ })
38
39
 
39
- await tsCompiler.compile(service.path, {}, logger.child({ name: service.id }))
40
+ const serviceWasCompiled = await tsCompiler.compile(service.path, serviceConfig.config, childLogger)
41
+ compiled ||= serviceWasCompiled
42
+ }
43
+ } else {
44
+ compiled = await tsCompiler.compile(dirname(configManager.fullPath), configManager.current, logger)
40
45
  }
46
+
47
+ return compiled
41
48
  }
42
49
 
43
50
  module.exports.compile = compile
@@ -135,7 +135,12 @@ async function _loadConfig (minimistConfig, args, configType, overrides) {
135
135
  configType = await getConfigType(args)
136
136
  }
137
137
 
138
- return loadConfig(minimistConfig, args, getApp(configType), overrides)
138
+ const app = getApp(configType)
139
+ const res = await loadConfig(minimistConfig, args, app, overrides)
140
+ res.configType = configType
141
+ res.app = app
142
+
143
+ return res
139
144
  }
140
145
 
141
146
  async function _start (args) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@platformatic/runtime",
3
- "version": "0.30.0",
3
+ "version": "0.31.0",
4
4
  "description": "",
5
5
  "main": "index.js",
6
6
  "bin": {
@@ -24,8 +24,8 @@
24
24
  "standard": "^17.1.0",
25
25
  "tsd": "^0.28.1",
26
26
  "typescript": "^5.1.6",
27
- "@platformatic/sql-mapper": "0.30.0",
28
- "@platformatic/sql-graphql": "0.30.0"
27
+ "@platformatic/sql-mapper": "0.31.0",
28
+ "@platformatic/sql-graphql": "0.31.0"
29
29
  },
30
30
  "dependencies": {
31
31
  "@hapi/topo": "^6.0.2",
@@ -40,11 +40,11 @@
40
40
  "pino": "^8.14.1",
41
41
  "pino-pretty": "^10.0.0",
42
42
  "undici": "^5.22.1",
43
- "@platformatic/composer": "0.30.0",
44
- "@platformatic/config": "0.30.0",
45
- "@platformatic/db": "0.30.0",
46
- "@platformatic/service": "0.30.0",
47
- "@platformatic/utils": "0.30.0"
43
+ "@platformatic/composer": "0.31.0",
44
+ "@platformatic/config": "0.31.0",
45
+ "@platformatic/db": "0.31.0",
46
+ "@platformatic/service": "0.31.0",
47
+ "@platformatic/utils": "0.31.0"
48
48
  },
49
49
  "standard": {
50
50
  "ignore": [
package/runtime.mjs CHANGED
@@ -7,7 +7,9 @@ import isMain from 'es-main'
7
7
  import helpMe from 'help-me'
8
8
  import parseArgs from 'minimist'
9
9
  import { start } from './lib/start.js'
10
- import { compile } from './lib/compile.js'
10
+ import { compile as compileCmd } from './lib/compile.js'
11
+
12
+ export const compile = compileCmd
11
13
 
12
14
  const help = helpMe({
13
15
  dir: join(import.meta.url, 'help'),
package/test/app.test.js CHANGED
@@ -251,7 +251,8 @@ test('supports configuration overrides', async (t) => {
251
251
  const { logger } = getLoggerAndStream()
252
252
  config._configOverrides = new Map([
253
253
  ['server.keepAliveTimeout', 1],
254
- ['server.port', 0]
254
+ ['server.port', 0],
255
+ ['server.pluginTimeout', 99]
255
256
  ])
256
257
  const app = new PlatformaticApp(config, null, logger)
257
258
 
@@ -265,6 +266,7 @@ test('supports configuration overrides', async (t) => {
265
266
 
266
267
  await app.start()
267
268
  assert.strictEqual(app.config.configManager.current.server.keepAliveTimeout, 1)
269
+ assert.strictEqual(app.config.configManager.current.server.pluginTimeout, 99)
268
270
  })
269
271
  })
270
272
 
@@ -14,20 +14,8 @@ try {
14
14
  } catch {
15
15
  }
16
16
 
17
- test('compile without tsconfigs', async () => {
18
- const config = join(import.meta.url, '..', '..', 'fixtures', 'configs', 'monorepo.json')
19
- await execa(cliPath, ['compile', '-c', config])
20
- })
21
-
22
- test('compile with tsconfig', async (t) => {
23
- const tmpDir = await mkdtemp(path.join(base, 'test-runtime-compile-'))
24
- const prev = process.cwd()
25
- process.chdir(tmpDir)
26
- t.after(() => {
27
- process.chdir(prev)
28
- })
29
-
30
- t.after(async () => {
17
+ function delDir (tmpDir) {
18
+ return async function () {
31
19
  // We give up after 10s.
32
20
  // This is because on Windows, it's very hard to delete files if the file
33
21
  // system is not collaborating.
@@ -42,8 +30,24 @@ test('compile with tsconfig', async (t) => {
42
30
  }
43
31
  }
44
32
  }
33
+ }
34
+ }
35
+
36
+ test('compile without tsconfigs', async () => {
37
+ const config = join(import.meta.url, '..', '..', 'fixtures', 'configs', 'monorepo.json')
38
+ await execa(cliPath, ['compile', '-c', config])
39
+ })
40
+
41
+ test('compile with tsconfig', async (t) => {
42
+ const tmpDir = await mkdtemp(path.join(base, 'test-runtime-compile-'))
43
+ const prev = process.cwd()
44
+ process.chdir(tmpDir)
45
+ t.after(() => {
46
+ process.chdir(prev)
45
47
  })
46
48
 
49
+ t.after(delDir(tmpDir))
50
+
47
51
  const folder = join(import.meta.url, '..', '..', 'fixtures', 'typescript')
48
52
  await cp(folder, tmpDir, { recursive: true })
49
53
 
@@ -63,3 +67,58 @@ test('compile with tsconfig', async (t) => {
63
67
  assert.deepStrictEqual(lines[i].msg, expected[i].msg)
64
68
  }
65
69
  })
70
+
71
+ test('compile with tsconfig custom flags', async (t) => {
72
+ const tmpDir = await mkdtemp(path.join(base, 'test-runtime-compile-'))
73
+ const prev = process.cwd()
74
+ process.chdir(tmpDir)
75
+ t.after(() => {
76
+ process.chdir(prev)
77
+ })
78
+
79
+ t.after(delDir(tmpDir))
80
+
81
+ const folder = join(import.meta.url, '..', '..', 'fixtures', 'typescript-custom-flags')
82
+ await cp(folder, tmpDir, { recursive: true })
83
+
84
+ const { stdout } = await execa(cliPath, ['compile'])
85
+
86
+ const lines = stdout.split('\n').map(JSON.parse)
87
+ const expected = [{
88
+ name: 'movies',
89
+ msg: 'Typescript compilation completed successfully.'
90
+ }, {
91
+ name: 'titles',
92
+ msg: 'Typescript compilation completed successfully.'
93
+ }]
94
+
95
+ for (let i = 0; i < expected.length; i++) {
96
+ assert.deepStrictEqual(lines[i].name, expected[i].name)
97
+ assert.deepStrictEqual(lines[i].msg, expected[i].msg)
98
+ }
99
+ })
100
+
101
+ test('compile single service', async (t) => {
102
+ const tmpDir = await mkdtemp(path.join(base, 'test-runtime-compile-'))
103
+ const prev = process.cwd()
104
+ process.chdir(tmpDir)
105
+ t.after(() => {
106
+ process.chdir(prev)
107
+ })
108
+
109
+ t.after(delDir(tmpDir))
110
+
111
+ const folder = join(import.meta.url, '..', '..', 'fixtures', 'typescript', 'services', 'movies')
112
+ await cp(folder, tmpDir, { recursive: true })
113
+
114
+ const { stdout } = await execa(cliPath, ['compile'])
115
+
116
+ const lines = stdout.split('\n').map(JSON.parse)
117
+ const expected = [{
118
+ msg: 'Typescript compilation completed successfully.'
119
+ }]
120
+
121
+ for (let i = 0; i < expected.length; i++) {
122
+ assert.deepStrictEqual(lines[i].msg, expected[i].msg)
123
+ }
124
+ })