remult 0.14.29 → 0.14.32
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/esm/graphql.d.ts +2 -2
- package/esm/remult-express.d.ts +4 -9
- package/esm/remult-express.js +3 -2
- package/esm/remult-fastify.d.ts +2 -2
- package/esm/remult-fastify.js +6 -11
- package/esm/remult-fresh.d.ts +17 -0
- package/esm/remult-fresh.js +36 -0
- package/esm/remult-middleware.d.ts +4 -3
- package/esm/remult-middleware.js +1 -0
- package/esm/server/expressBridge.d.ts +10 -53
- package/esm/server/expressBridge.js +253 -131
- package/esm/server/index.d.ts +1 -3
- package/esm/server/index.js +1 -3
- package/esm/src/backend-tests/test-http-server.backend-spec.js +3 -5
- package/esm/src/context.d.ts +1 -6
- package/graphql.d.ts +2 -2
- package/package.json +8 -4
- package/readme.md +2 -2
- package/remult-express.d.ts +4 -9
- package/remult-express.js +3 -2
- package/remult-fastify.d.ts +2 -2
- package/remult-fastify.js +6 -11
- package/remult-fresh.d.ts +17 -0
- package/remult-fresh.js +58 -0
- package/remult-middleware.d.ts +4 -3
- package/remult-middleware.js +2 -1
- package/server/expressBridge.d.ts +10 -53
- package/server/expressBridge.js +361 -212
- package/server/index.d.ts +1 -3
- package/server/index.js +2 -6
- package/src/backend-tests/test-http-server.backend-spec.js +3 -5
- package/src/context.d.ts +1 -6
|
@@ -1,14 +1,12 @@
|
|
|
1
1
|
import { __decorate, __metadata } from "tslib";
|
|
2
|
-
import { registerActionsOnServer } from './register-actions-on-server';
|
|
3
|
-
import { registerEntitiesOnServer } from './register-entities-on-server';
|
|
4
2
|
import { JsonEntityFileStorage } from './JsonEntityFileStorage';
|
|
5
|
-
import { Action, actionInfo } from '../src/server-action';
|
|
3
|
+
import { Action, actionInfo, classBackendMethodsArray, serverActionField } from '../src/server-action';
|
|
6
4
|
import { DataApi, serializeError } from '../src/data-api';
|
|
7
5
|
import { allEntities, Remult } from '../src/context';
|
|
8
6
|
import { Entity, Fields, getEntityKey } from '../src/remult3';
|
|
9
7
|
import { JsonDataProvider } from '../src/data-providers/json-data-provider';
|
|
10
8
|
import { IdEntity } from '../src/id-entity';
|
|
11
|
-
export function buildRemultServer(
|
|
9
|
+
export function buildRemultServer(options) {
|
|
12
10
|
if (!options) {
|
|
13
11
|
options = {};
|
|
14
12
|
}
|
|
@@ -37,33 +35,158 @@ export function buildRemultServer(app, options) {
|
|
|
37
35
|
return dp;
|
|
38
36
|
});
|
|
39
37
|
}
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
options.rootPath = Remult.apiBaseUrl;
|
|
45
|
-
let apiArea = bridge.addArea(options.rootPath);
|
|
46
|
-
if (!options.disableAutoApi) {
|
|
47
|
-
let actions = [];
|
|
38
|
+
{
|
|
39
|
+
let allControllers = [];
|
|
40
|
+
if (!options.entities)
|
|
41
|
+
options.entities = [...allEntities];
|
|
48
42
|
if (options.entities)
|
|
49
|
-
|
|
43
|
+
allControllers.push(...options.entities);
|
|
50
44
|
if (options.controllers)
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
registerEntitiesOnServer(apiArea, options.entities);
|
|
45
|
+
allControllers.push(...options.controllers);
|
|
46
|
+
options.controllers = allControllers;
|
|
54
47
|
}
|
|
48
|
+
if (options.rootPath === undefined)
|
|
49
|
+
options.rootPath = Remult.apiBaseUrl;
|
|
50
|
+
actionInfo.runningOnServer = true;
|
|
51
|
+
let bridge = new RemultServerImplementation(new inProcessQueueHandler(options.queueStorage), options, dataProvider);
|
|
55
52
|
return bridge;
|
|
56
53
|
}
|
|
57
54
|
;
|
|
58
|
-
class
|
|
59
|
-
constructor(
|
|
60
|
-
this.app = app;
|
|
55
|
+
class RemultServerImplementation {
|
|
56
|
+
constructor(queue, options, dataProvider) {
|
|
61
57
|
this.queue = queue;
|
|
62
|
-
this.
|
|
58
|
+
this.options = options;
|
|
63
59
|
this.dataProvider = dataProvider;
|
|
60
|
+
this.registeredRouter = false;
|
|
61
|
+
this.hasQueue = false;
|
|
64
62
|
/* internal */
|
|
65
63
|
this.backendMethodsOpenApi = [];
|
|
66
|
-
|
|
64
|
+
}
|
|
65
|
+
handle(req, gRes) {
|
|
66
|
+
if (!this.routeImpl) {
|
|
67
|
+
this.routeImpl = new RouteImplementation();
|
|
68
|
+
this.registerRouter(this.routeImpl);
|
|
69
|
+
}
|
|
70
|
+
return this.routeImpl.handle(req, gRes);
|
|
71
|
+
}
|
|
72
|
+
registerRouter(r) {
|
|
73
|
+
if (this.registeredRouter)
|
|
74
|
+
throw "Router already registered";
|
|
75
|
+
this.registeredRouter = true;
|
|
76
|
+
{
|
|
77
|
+
for (const c of this.options.controllers) {
|
|
78
|
+
let z = c[classBackendMethodsArray];
|
|
79
|
+
if (z)
|
|
80
|
+
for (const a of z) {
|
|
81
|
+
let x = a[serverActionField];
|
|
82
|
+
if (!x) {
|
|
83
|
+
throw 'failed to set server action, did you forget the BackendMethod Decorator?';
|
|
84
|
+
}
|
|
85
|
+
this.addAction(x, r);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
if (this.hasQueue)
|
|
89
|
+
this.addAction({
|
|
90
|
+
__register: x => {
|
|
91
|
+
x(Action.apiUrlForJobStatus, false, () => true, async (data, req, res) => {
|
|
92
|
+
let job = await this.queue.getJobInfo(data.queuedJobId);
|
|
93
|
+
let userId = undefined;
|
|
94
|
+
if (req?.user)
|
|
95
|
+
userId = req.user.id;
|
|
96
|
+
if (job.userId == '')
|
|
97
|
+
job.userId = undefined;
|
|
98
|
+
if (userId != job.userId)
|
|
99
|
+
res.forbidden();
|
|
100
|
+
else
|
|
101
|
+
res.success(job.info);
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
}, r);
|
|
105
|
+
}
|
|
106
|
+
this.options.entities.forEach(e => {
|
|
107
|
+
let key = getEntityKey(e);
|
|
108
|
+
if (key != undefined)
|
|
109
|
+
this.add(key, c => {
|
|
110
|
+
return new DataApi(c.repo(e), c);
|
|
111
|
+
}, r);
|
|
112
|
+
});
|
|
113
|
+
}
|
|
114
|
+
add(key, dataApiFactory, r) {
|
|
115
|
+
let myRoute = this.options.rootPath + '/' + key;
|
|
116
|
+
if (this.options.logApiEndPoints)
|
|
117
|
+
console.log(myRoute);
|
|
118
|
+
r.route(myRoute)
|
|
119
|
+
.get(this.process((c, req, res) => dataApiFactory(c).httpGet(res, req))).put(this.process(async (c, req, res, orig) => dataApiFactory(c).put(res, '', orig.body)))
|
|
120
|
+
.delete(this.process(async (c, req, res, orig) => dataApiFactory(c).delete(res, '')))
|
|
121
|
+
.post(this.process(async (c, req, res, orig) => dataApiFactory(c).httpPost(res, req, orig.body)));
|
|
122
|
+
r.route(myRoute + '/:id')
|
|
123
|
+
//@ts-ignore
|
|
124
|
+
.get(this.process(async (c, req, res, orig) => dataApiFactory(c).get(res, orig.params.id)))
|
|
125
|
+
//@ts-ignore
|
|
126
|
+
.put(this.process(async (c, req, res, orig) => dataApiFactory(c).put(res, orig.params.id, orig.body)))
|
|
127
|
+
//@ts-ignore
|
|
128
|
+
.delete(this.process(async (c, req, res, orig) => dataApiFactory(c).delete(res, orig.params.id)));
|
|
129
|
+
}
|
|
130
|
+
process(what) {
|
|
131
|
+
return async (req, res) => {
|
|
132
|
+
let myReq = new ExpressRequestBridgeToDataApiRequest(req);
|
|
133
|
+
let myRes = new ExpressResponseBridgeToDataApiResponse(res, req);
|
|
134
|
+
let remult = new Remult();
|
|
135
|
+
remult.setDataProvider(await this.dataProvider);
|
|
136
|
+
if (req) {
|
|
137
|
+
let user;
|
|
138
|
+
if (this.options.getUser)
|
|
139
|
+
user = await this.options.getUser(req);
|
|
140
|
+
else {
|
|
141
|
+
user = req['user'];
|
|
142
|
+
if (!user)
|
|
143
|
+
user = req['auth'];
|
|
144
|
+
}
|
|
145
|
+
if (user)
|
|
146
|
+
remult.setUser(user);
|
|
147
|
+
}
|
|
148
|
+
if (this.options.initRequest) {
|
|
149
|
+
await this.options.initRequest(remult, req);
|
|
150
|
+
}
|
|
151
|
+
what(remult, myReq, myRes, req);
|
|
152
|
+
};
|
|
153
|
+
}
|
|
154
|
+
;
|
|
155
|
+
async getRemult(req) {
|
|
156
|
+
let remult;
|
|
157
|
+
await this.process(async (c) => {
|
|
158
|
+
remult = c;
|
|
159
|
+
})(req, undefined);
|
|
160
|
+
return remult;
|
|
161
|
+
}
|
|
162
|
+
addAction(action, r) {
|
|
163
|
+
action.__register((url, queue, allowed, what) => {
|
|
164
|
+
let myUrl = this.options.rootPath + '/' + url;
|
|
165
|
+
let tag = (() => {
|
|
166
|
+
let split = url.split('/');
|
|
167
|
+
if (split.length == 1)
|
|
168
|
+
return 'Static Backend Methods';
|
|
169
|
+
else
|
|
170
|
+
return split[0];
|
|
171
|
+
})();
|
|
172
|
+
this.backendMethodsOpenApi.push({ path: myUrl, allowed, tag });
|
|
173
|
+
if (this.options.logApiEndPoints)
|
|
174
|
+
console.log(myUrl);
|
|
175
|
+
if (queue) {
|
|
176
|
+
this.hasQueue = true;
|
|
177
|
+
this.queue.mapQueuedAction(myUrl, what);
|
|
178
|
+
}
|
|
179
|
+
r.route(myUrl).post(this.process(async (remult, req, res, orig) => {
|
|
180
|
+
if (queue) {
|
|
181
|
+
let r = {
|
|
182
|
+
queuedJobId: await this.queue.submitJob(myUrl, remult, orig.body)
|
|
183
|
+
};
|
|
184
|
+
res.success(r);
|
|
185
|
+
}
|
|
186
|
+
else
|
|
187
|
+
return what(orig.body, remult, res);
|
|
188
|
+
}));
|
|
189
|
+
});
|
|
67
190
|
}
|
|
68
191
|
openApiDoc(options) {
|
|
69
192
|
let r = new Remult();
|
|
@@ -115,7 +238,7 @@ class ExpressBridge {
|
|
|
115
238
|
return item;
|
|
116
239
|
}
|
|
117
240
|
};
|
|
118
|
-
for (const e of
|
|
241
|
+
for (const e of this.options.entities) {
|
|
119
242
|
let meta = r.repo(e).metadata;
|
|
120
243
|
let key = getEntityKey(e);
|
|
121
244
|
let parameters = [];
|
|
@@ -352,115 +475,6 @@ class ExpressBridge {
|
|
|
352
475
|
};
|
|
353
476
|
return spec;
|
|
354
477
|
}
|
|
355
|
-
addArea(rootUrl) {
|
|
356
|
-
var r = new SiteArea(this, this.app, rootUrl, this.logApiEndPoints);
|
|
357
|
-
if (!this.firstArea) {
|
|
358
|
-
this.firstArea = r;
|
|
359
|
-
}
|
|
360
|
-
return r;
|
|
361
|
-
}
|
|
362
|
-
async getRemult(req) {
|
|
363
|
-
return this.firstArea.getRemult(req);
|
|
364
|
-
}
|
|
365
|
-
}
|
|
366
|
-
export class SiteArea {
|
|
367
|
-
constructor(bridge, app, rootUrl, logApiEndpoints) {
|
|
368
|
-
this.bridge = bridge;
|
|
369
|
-
this.app = app;
|
|
370
|
-
this.rootUrl = rootUrl;
|
|
371
|
-
this.logApiEndpoints = logApiEndpoints;
|
|
372
|
-
}
|
|
373
|
-
add(key, dataApiFactory) {
|
|
374
|
-
let myRoute = this.rootUrl + '/' + key;
|
|
375
|
-
if (this.logApiEndpoints)
|
|
376
|
-
console.log(myRoute);
|
|
377
|
-
this.app.route(myRoute)
|
|
378
|
-
.get(this.process((c, req, res) => dataApiFactory(c).httpGet(res, req))).put(this.process(async (c, req, res, orig) => dataApiFactory(c).put(res, '', orig.body)))
|
|
379
|
-
.delete(this.process(async (c, req, res, orig) => dataApiFactory(c).delete(res, '')))
|
|
380
|
-
.post(this.process(async (c, req, res, orig) => dataApiFactory(c).httpPost(res, req, orig.body)));
|
|
381
|
-
this.app.route(myRoute + '/:id')
|
|
382
|
-
//@ts-ignore
|
|
383
|
-
.get(this.process(async (c, req, res, orig) => dataApiFactory(c).get(res, orig.params.id)))
|
|
384
|
-
//@ts-ignore
|
|
385
|
-
.put(this.process(async (c, req, res, orig) => dataApiFactory(c).put(res, orig.params.id, orig.body)))
|
|
386
|
-
//@ts-ignore
|
|
387
|
-
.delete(this.process(async (c, req, res, orig) => dataApiFactory(c).delete(res, orig.params.id)));
|
|
388
|
-
}
|
|
389
|
-
process(what) {
|
|
390
|
-
return async (req, res) => {
|
|
391
|
-
let myReq = new ExpressRequestBridgeToDataApiRequest(req);
|
|
392
|
-
let myRes = new ExpressResponseBridgeToDataApiResponse(res, req);
|
|
393
|
-
let remult = new Remult();
|
|
394
|
-
remult.setDataProvider(await this.bridge.dataProvider);
|
|
395
|
-
if (req) {
|
|
396
|
-
let user = req['user'];
|
|
397
|
-
if (!user)
|
|
398
|
-
user = req['auth'];
|
|
399
|
-
if (user)
|
|
400
|
-
remult.setUser(user);
|
|
401
|
-
}
|
|
402
|
-
if (this.bridge.initRequest) {
|
|
403
|
-
await this.bridge.initRequest(remult, req);
|
|
404
|
-
}
|
|
405
|
-
what(remult, myReq, myRes, req);
|
|
406
|
-
};
|
|
407
|
-
}
|
|
408
|
-
;
|
|
409
|
-
async getRemult(req) {
|
|
410
|
-
let remult;
|
|
411
|
-
await this.process(async (c) => {
|
|
412
|
-
remult = c;
|
|
413
|
-
})(req, undefined);
|
|
414
|
-
return remult;
|
|
415
|
-
}
|
|
416
|
-
initQueue() {
|
|
417
|
-
this.addAction({
|
|
418
|
-
__register: x => {
|
|
419
|
-
x(Action.apiUrlForJobStatus, false, () => true, async (data, req, res) => {
|
|
420
|
-
let job = await this.bridge.queue.getJobInfo(data.queuedJobId);
|
|
421
|
-
let userId = undefined;
|
|
422
|
-
if (req?.user)
|
|
423
|
-
userId = req.user.id;
|
|
424
|
-
if (job.userId == '')
|
|
425
|
-
job.userId = undefined;
|
|
426
|
-
if (userId != job.userId)
|
|
427
|
-
res.forbidden();
|
|
428
|
-
else
|
|
429
|
-
res.success(job.info);
|
|
430
|
-
});
|
|
431
|
-
}
|
|
432
|
-
});
|
|
433
|
-
this.initQueue = () => { };
|
|
434
|
-
}
|
|
435
|
-
addAction(action) {
|
|
436
|
-
action.__register((url, queue, allowed, what) => {
|
|
437
|
-
let myUrl = this.rootUrl + '/' + url;
|
|
438
|
-
let tag = (() => {
|
|
439
|
-
let split = url.split('/');
|
|
440
|
-
if (split.length == 1)
|
|
441
|
-
return 'Static Backend Methods';
|
|
442
|
-
else
|
|
443
|
-
return split[0];
|
|
444
|
-
})();
|
|
445
|
-
this.bridge.backendMethodsOpenApi.push({ path: myUrl, allowed, tag });
|
|
446
|
-
if (this.logApiEndpoints)
|
|
447
|
-
console.log(myUrl);
|
|
448
|
-
if (queue) {
|
|
449
|
-
this.initQueue();
|
|
450
|
-
this.bridge.queue.mapQueuedAction(myUrl, what);
|
|
451
|
-
}
|
|
452
|
-
this.app.route(myUrl).post(this.process(async (remult, req, res, orig) => {
|
|
453
|
-
if (queue) {
|
|
454
|
-
let r = {
|
|
455
|
-
queuedJobId: await this.bridge.queue.submitJob(myUrl, remult, orig.body)
|
|
456
|
-
};
|
|
457
|
-
res.success(r);
|
|
458
|
-
}
|
|
459
|
-
else
|
|
460
|
-
return what(orig.body, remult, res);
|
|
461
|
-
}));
|
|
462
|
-
});
|
|
463
|
-
}
|
|
464
478
|
}
|
|
465
479
|
export class ExpressRequestBridgeToDataApiRequest {
|
|
466
480
|
constructor(r) {
|
|
@@ -624,6 +638,114 @@ export class EntityQueueStorage {
|
|
|
624
638
|
return q.id;
|
|
625
639
|
}
|
|
626
640
|
}
|
|
641
|
+
class RouteImplementation {
|
|
642
|
+
constructor() {
|
|
643
|
+
this.map = new Map();
|
|
644
|
+
}
|
|
645
|
+
route(path) {
|
|
646
|
+
//consider using:
|
|
647
|
+
//* https://raw.githubusercontent.com/cmorten/opine/main/src/utils/pathToRegex.ts
|
|
648
|
+
//* https://github.com/pillarjs/path-to-regexp
|
|
649
|
+
let r = path.toLowerCase();
|
|
650
|
+
let m = new Map();
|
|
651
|
+
this.map.set(r, m);
|
|
652
|
+
const route = {
|
|
653
|
+
get: (h) => {
|
|
654
|
+
m.set("get", h);
|
|
655
|
+
return route;
|
|
656
|
+
},
|
|
657
|
+
put: (h) => {
|
|
658
|
+
m.set("put", h);
|
|
659
|
+
return route;
|
|
660
|
+
},
|
|
661
|
+
post: (h) => {
|
|
662
|
+
m.set("post", h);
|
|
663
|
+
return route;
|
|
664
|
+
},
|
|
665
|
+
delete: (h) => {
|
|
666
|
+
m.set("delete", h);
|
|
667
|
+
return route;
|
|
668
|
+
}
|
|
669
|
+
};
|
|
670
|
+
return route;
|
|
671
|
+
}
|
|
672
|
+
async handle(req, gRes) {
|
|
673
|
+
return new Promise(res => {
|
|
674
|
+
const response = new class {
|
|
675
|
+
constructor() {
|
|
676
|
+
this.statusCode = 200;
|
|
677
|
+
}
|
|
678
|
+
json(data) {
|
|
679
|
+
if (gRes !== undefined)
|
|
680
|
+
gRes.json(data);
|
|
681
|
+
res({ statusCode: this.statusCode, data });
|
|
682
|
+
}
|
|
683
|
+
status(statusCode) {
|
|
684
|
+
if (gRes !== undefined)
|
|
685
|
+
gRes.status(statusCode);
|
|
686
|
+
this.statusCode = statusCode;
|
|
687
|
+
return this;
|
|
688
|
+
}
|
|
689
|
+
end() {
|
|
690
|
+
if (gRes !== undefined)
|
|
691
|
+
gRes.end();
|
|
692
|
+
res({
|
|
693
|
+
statusCode: this.statusCode
|
|
694
|
+
});
|
|
695
|
+
}
|
|
696
|
+
};
|
|
697
|
+
this.middleware(req, response, () => res(undefined));
|
|
698
|
+
});
|
|
699
|
+
}
|
|
700
|
+
middleware(req, res, next) {
|
|
701
|
+
let theUrl = req.url;
|
|
702
|
+
if (theUrl.startsWith('/')) //next sends a partial url '/api/tasks' and not the full url
|
|
703
|
+
theUrl = 'http://stam' + theUrl;
|
|
704
|
+
const url = new URL(theUrl);
|
|
705
|
+
const path = url.pathname;
|
|
706
|
+
if (!req.query) {
|
|
707
|
+
let query = {};
|
|
708
|
+
url.searchParams.forEach((val, key) => {
|
|
709
|
+
let current = query[key];
|
|
710
|
+
if (!current) {
|
|
711
|
+
query[key] = val;
|
|
712
|
+
return;
|
|
713
|
+
}
|
|
714
|
+
if (Array.isArray(current)) {
|
|
715
|
+
current.push(val);
|
|
716
|
+
return;
|
|
717
|
+
}
|
|
718
|
+
query[key] = [current, val];
|
|
719
|
+
});
|
|
720
|
+
req.query = query;
|
|
721
|
+
}
|
|
722
|
+
let lowerPath = path.toLowerCase();
|
|
723
|
+
let m = this.map.get(lowerPath);
|
|
724
|
+
if (m) {
|
|
725
|
+
let h = m.get(req.method.toLowerCase());
|
|
726
|
+
if (h) {
|
|
727
|
+
h(req, res, next);
|
|
728
|
+
return;
|
|
729
|
+
}
|
|
730
|
+
}
|
|
731
|
+
let idPosition = path.lastIndexOf('/');
|
|
732
|
+
if (idPosition >= 0) {
|
|
733
|
+
lowerPath = path.substring(0, idPosition) + '/:id';
|
|
734
|
+
m = this.map.get(lowerPath);
|
|
735
|
+
if (m) {
|
|
736
|
+
let h = m.get(req.method.toLowerCase());
|
|
737
|
+
if (h) {
|
|
738
|
+
if (!req.params)
|
|
739
|
+
req.params = {};
|
|
740
|
+
req.params.id = path.substring(idPosition + 1);
|
|
741
|
+
h(req, res, next);
|
|
742
|
+
return;
|
|
743
|
+
}
|
|
744
|
+
}
|
|
745
|
+
}
|
|
746
|
+
next();
|
|
747
|
+
}
|
|
748
|
+
}
|
|
627
749
|
let JobsInQueueEntity = class JobsInQueueEntity extends IdEntity {
|
|
628
750
|
};
|
|
629
751
|
__decorate([
|
package/esm/server/index.d.ts
CHANGED
|
@@ -1,4 +1,2 @@
|
|
|
1
1
|
export { JsonEntityFileStorage } from './JsonEntityFileStorage';
|
|
2
|
-
export {
|
|
3
|
-
export { registerEntitiesOnServer } from './register-entities-on-server';
|
|
4
|
-
export { registerActionsOnServer } from './register-actions-on-server';
|
|
2
|
+
export { queuedJobInfo, QueueStorage, GenericRequest, GenericRequestHandler, GenericResponse, GenericRouter, buildRemultServer, RemultServerOptions, SpecificRoute, RemultServer } from './expressBridge';
|
package/esm/server/index.js
CHANGED
|
@@ -1,4 +1,2 @@
|
|
|
1
1
|
export { JsonEntityFileStorage } from './JsonEntityFileStorage';
|
|
2
|
-
export {
|
|
3
|
-
export { registerEntitiesOnServer } from './register-entities-on-server';
|
|
4
|
-
export { registerActionsOnServer } from './register-actions-on-server';
|
|
2
|
+
export { buildRemultServer } from './expressBridge';
|
|
@@ -6,14 +6,12 @@ import { Action, BackendMethod } from '../server-action';
|
|
|
6
6
|
Remult.apiBaseUrl = 'http://localhost:3003/api';
|
|
7
7
|
let path = Remult.apiBaseUrl + '/tasks';
|
|
8
8
|
const environments = [
|
|
9
|
-
["next", 3000],
|
|
10
|
-
["nest", 3001],
|
|
9
|
+
// ["next", 3000],
|
|
10
|
+
// ["nest", 3001],
|
|
11
11
|
["koa", 3002],
|
|
12
12
|
["fastify", 3003],
|
|
13
13
|
["express", 3004],
|
|
14
|
-
["
|
|
15
|
-
["optine", 3006],
|
|
16
|
-
["fresh", 8000],
|
|
14
|
+
["generic server", 3005],
|
|
17
15
|
];
|
|
18
16
|
function test(name, test) {
|
|
19
17
|
for (const [env, port] of environments) {
|
package/esm/src/context.d.ts
CHANGED
|
@@ -40,12 +40,7 @@ export declare class Remult {
|
|
|
40
40
|
/** Returns the current user's info */
|
|
41
41
|
get user(): UserInfo;
|
|
42
42
|
/** Set's the current user info */
|
|
43
|
-
setUser(info: UserInfo
|
|
44
|
-
sub?: string;
|
|
45
|
-
name?: string;
|
|
46
|
-
permissions?: string[];
|
|
47
|
-
username?: string;
|
|
48
|
-
}): Promise<void>;
|
|
43
|
+
setUser(info: UserInfo): Promise<void>;
|
|
49
44
|
private _user;
|
|
50
45
|
private _userChangeEvent;
|
|
51
46
|
/** Checks if a user was authenticated */
|
package/graphql.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
export declare function remultGraphql(api:
|
|
1
|
+
import { RemultServer } from "./server/expressBridge";
|
|
2
|
+
export declare function remultGraphql(api: RemultServer): {
|
|
3
3
|
rootValue: {};
|
|
4
4
|
schema: string;
|
|
5
5
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "remult",
|
|
3
|
-
"version": "0.14.
|
|
3
|
+
"version": "0.14.32",
|
|
4
4
|
"description": "A CRUD framework for full-stack TypeScript",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"types": "index.d.ts",
|
|
@@ -28,14 +28,18 @@
|
|
|
28
28
|
"require": "./remult-express.js",
|
|
29
29
|
"import": "./esm/remult-express.js"
|
|
30
30
|
},
|
|
31
|
-
"./
|
|
32
|
-
"require": "./
|
|
33
|
-
"import": "./esm/
|
|
31
|
+
"./server": {
|
|
32
|
+
"require": "./server/index.js",
|
|
33
|
+
"import": "./esm/server/index.js"
|
|
34
34
|
},
|
|
35
35
|
"./remult-fastify": {
|
|
36
36
|
"require": "./remult-fastify.js",
|
|
37
37
|
"import": "./esm/remult-fastify.js"
|
|
38
38
|
},
|
|
39
|
+
"./remult-fresh": {
|
|
40
|
+
"require": "./remult-fresh.js",
|
|
41
|
+
"import": "./esm/remult-fresh.js"
|
|
42
|
+
},
|
|
39
43
|
"./postgres": {
|
|
40
44
|
"require": "./postgres/index.js",
|
|
41
45
|
"import": "./esm/postgres/index.js"
|
package/readme.md
CHANGED
|
@@ -35,13 +35,13 @@
|
|
|
35
35
|
|
|
36
36
|
### Status
|
|
37
37
|
|
|
38
|
-
Remult is **production-ready** and, in fact, used in production apps since
|
|
38
|
+
Remult is **production-ready** and, in fact, used in production apps since 2018. However, we’re keeping the major version at zero so we can use community feedback to finalize the v1 API.
|
|
39
39
|
|
|
40
40
|
## Motivation
|
|
41
41
|
|
|
42
42
|
Full-stack web development is (still) too complicated. **Simple CRUD, a common requirement of any business application, should be simple to build, maintain, and extend** when the need arises.
|
|
43
43
|
|
|
44
|
-
Remult abstracts away repetitive, boilerplate, error-prone, and poorly designed code on the one hand, and enables total flexibility and control on the other. **Remult
|
|
44
|
+
Remult abstracts away repetitive, boilerplate, error-prone, and poorly designed code on the one hand, and enables total flexibility and control on the other. **Remult helps building fullstack apps using only TypeScript code you can easily follow and safely refactor**, and fits nicely into any existing or new project by being minimalistic and completely unopinionated regarding the developer’s choice of other frameworks and tools.
|
|
45
45
|
|
|
46
46
|
Other frameworks tend to fall into either too much abstraction (no-code, low-code, BaaS) or partial abstraction (MVC frameworks, GraphQL, ORMs, API generators, code generators), and tend to be opinionated regarding the development tool-chain, deployment environment, configuration/conventions or DSL. Remult attempts to strike a better balance.
|
|
47
47
|
|
package/remult-express.d.ts
CHANGED
|
@@ -1,11 +1,6 @@
|
|
|
1
|
-
import
|
|
2
|
-
|
|
1
|
+
import * as express from 'express';
|
|
2
|
+
import { RemultServer, RemultServerOptions } from './server/expressBridge';
|
|
3
|
+
export declare function remultExpress(options?: RemultServerOptions & {
|
|
3
4
|
bodyParser?: boolean;
|
|
4
5
|
bodySizeLimit?: string;
|
|
5
|
-
}):
|
|
6
|
-
getRemult: (req: any) => Promise<import(".").Remult>;
|
|
7
|
-
openApiDoc: (options: {
|
|
8
|
-
title: string;
|
|
9
|
-
}) => any;
|
|
10
|
-
addArea: (x: any) => void;
|
|
11
|
-
};
|
|
6
|
+
}): express.RequestHandler & RemultServer;
|
package/remult-express.js
CHANGED
|
@@ -15,11 +15,12 @@ function remultExpress(options) {
|
|
|
15
15
|
app.use(express.json({ limit: options.bodySizeLimit }));
|
|
16
16
|
app.use(express.urlencoded({ extended: true, limit: options.bodySizeLimit }));
|
|
17
17
|
}
|
|
18
|
-
var server = expressBridge_1.buildRemultServer(
|
|
18
|
+
var server = expressBridge_1.buildRemultServer(options);
|
|
19
|
+
server.registerRouter(app);
|
|
19
20
|
return Object.assign(app, {
|
|
20
21
|
getRemult: function (req) { return server.getRemult(req); },
|
|
21
22
|
openApiDoc: function (options) { return server.openApiDoc(options); },
|
|
22
|
-
|
|
23
|
+
registerRouter: function (x) { return server.registerRouter(x); }
|
|
23
24
|
});
|
|
24
25
|
}
|
|
25
26
|
exports.remultExpress = remultExpress;
|
package/remult-fastify.d.ts
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
import type { FastifyPluginCallback } from 'fastify';
|
|
2
|
-
import { RemultServer,
|
|
3
|
-
export declare function remultFastify(options:
|
|
2
|
+
import { RemultServer, RemultServerOptions } from './server/expressBridge';
|
|
3
|
+
export declare function remultFastify(options: RemultServerOptions): FastifyPluginCallback & RemultServer;
|
package/remult-fastify.js
CHANGED
|
@@ -23,8 +23,8 @@ function remultFastify(options) {
|
|
|
23
23
|
};
|
|
24
24
|
return response;
|
|
25
25
|
}
|
|
26
|
-
var api;
|
|
27
|
-
var pluginFunction = function (instance,
|
|
26
|
+
var api = expressBridge_1.buildRemultServer(options);
|
|
27
|
+
var pluginFunction = function (instance, op) { return tslib_1.__awaiter(_this, void 0, void 0, function () {
|
|
28
28
|
var fastifyRouter;
|
|
29
29
|
return tslib_1.__generator(this, function (_a) {
|
|
30
30
|
fastifyRouter = {
|
|
@@ -48,19 +48,14 @@ function remultFastify(options) {
|
|
|
48
48
|
return r;
|
|
49
49
|
},
|
|
50
50
|
};
|
|
51
|
-
api
|
|
51
|
+
api.registerRouter(fastifyRouter);
|
|
52
52
|
return [2 /*return*/];
|
|
53
53
|
});
|
|
54
54
|
}); };
|
|
55
|
-
var getApi = function () {
|
|
56
|
-
if (!api)
|
|
57
|
-
throw "Please call fastify's register before using this method";
|
|
58
|
-
return api;
|
|
59
|
-
};
|
|
60
55
|
return Object.assign(pluginFunction, {
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
56
|
+
getRemult: function (x) { return api.getRemult(x); },
|
|
57
|
+
openApiDoc: function (x) { return api.openApiDoc(x); },
|
|
58
|
+
handle: function (req, res) { return api.handle(req, res); }
|
|
64
59
|
});
|
|
65
60
|
}
|
|
66
61
|
exports.remultFastify = remultFastify;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { RemultServerOptions, RemultServer } from "./server/expressBridge";
|
|
2
|
+
export declare function remultFresh(options: RemultServerOptions, response: FreshResponse): RemultFresh;
|
|
3
|
+
export interface RemultFresh extends RemultServer {
|
|
4
|
+
freshHandler(req: FreshRequest, ctx: FreshContext): Promise<FreshResponse>;
|
|
5
|
+
}
|
|
6
|
+
export interface FreshRequest {
|
|
7
|
+
url: string;
|
|
8
|
+
method: string;
|
|
9
|
+
json: () => Promise<any>;
|
|
10
|
+
}
|
|
11
|
+
export interface FreshContext {
|
|
12
|
+
next: () => Promise<any>;
|
|
13
|
+
}
|
|
14
|
+
export interface FreshResponse {
|
|
15
|
+
new (body?: any | undefined, init?: ResponseInit): any;
|
|
16
|
+
json(data: unknown, init?: ResponseInit): any;
|
|
17
|
+
}
|