remult 0.13.22 → 0.13.25

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "remult",
3
- "version": "0.13.22",
3
+ "version": "0.13.25",
4
4
  "description": "A CRUD framework for full-stack TypeScript",
5
5
  "homepage": "https://remult.dev/",
6
6
  "repository": {
@@ -13,7 +13,6 @@
13
13
  },
14
14
  "dependencies": {
15
15
  "uuid": "^8.3.2",
16
- "body-parser": "^1.18.3",
17
16
  "reflect-metadata": "^0.1.13",
18
17
  "tslib": "^2.3.1"
19
18
  }
package/readme.md CHANGED
@@ -4,7 +4,7 @@
4
4
  </a>
5
5
  <h1>Remult</h1>
6
6
  <a href="https://circleci.com/gh/remult/remult/tree/master">
7
- <img alt="CircleCI" src="https://circleci.com/gh/remult/remult/tree/master.svg?style=svg">
7
+ <img alt="CircleCI" src="https://circleci.com/gh/remult/remult/tree/master.svg?style=shield">
8
8
  </a>
9
9
  <a href="https://codecov.io/gh/remult/remult">
10
10
  <img src="https://codecov.io/gh/remult/remult/branch/master/graph/badge.svg?token=LYWQRUN3D1"/>
@@ -18,11 +18,9 @@
18
18
  <a href="https://www.npmjs.com/package/remult">
19
19
  <img alt="npm downloads" src="https://img.shields.io/npm/dm/remult">
20
20
  </a>
21
- <a href="https://snyk.io/test/npm/remult">
22
- <img alt="snyk" src="https://snyk.io/test/npm/remult/badge.svg"/>
23
- </a>
24
- <a href="https://github.com/remult/remult/pulse" alt="Activity">
25
- <img src="https://img.shields.io/github/commit-activity/m/remult/remult" /></a>
21
+ <a href="https://discord.gg/GXHk7ZfuG5">
22
+ <img alt="chat on discord" src="https://img.shields.io/badge/chat-on%20discord-blueviolet"/>
23
+ </a>
26
24
  </div>
27
25
 
28
26
  ## What is Remult?
@@ -33,15 +31,15 @@
33
31
  * Type-safe frontend API client
34
32
  * Type-safe backend query builder
35
33
 
36
- #### Remult :heart: Monorepos
34
+ #### Remult :heart: Code Sharing
37
35
 
38
- Using a `monorepo` approach, with model types shared between frontend and backend code, Remult can enforce data validation and constraints, defined once, on both frontend and REST API levels.
36
+ With model types shared between frontend and backend code, Remult can **enforce data validation and constraints, defined once, both in the front-end and witin back-end API routes**.
39
37
 
40
38
  ## Getting started
41
39
  The best way to learn Remult is by following a tutorial of a simple Todo web app with a Node.js Express backend.
42
40
 
43
41
  * [Tutorial with React](https://remult.dev/tutorials/react/)
44
- * [Tutorial with Angular](https://remult.dev/tutorials/tutorial-angular.html)
42
+ * [Tutorial with Angular](https://remult.dev/tutorials/angular/)
45
43
 
46
44
  ## Installation
47
45
  ```sh
@@ -123,7 +121,7 @@ export class Product {
123
121
  @Fields.string<Product>({
124
122
  validate: product => {
125
123
  if (product.name.trim().length == 0)
126
- product.$.name.error = 'required';
124
+ throw 'required';
127
125
  }
128
126
  })
129
127
  name = '';
@@ -131,7 +129,7 @@ export class Product {
131
129
  @Fields.number({
132
130
  validate: (_, field) => {
133
131
  if (field.value < 0)
134
- field.error = "must not be less than 0";
132
+ throw "must not be less than 0";
135
133
  }
136
134
  })
137
135
  unitPrice = 0;
@@ -145,14 +143,14 @@ const product = productsRepo.create();
145
143
  try {
146
144
  await productsRepo.save(product);
147
145
  }
148
- catch (e: ErrorInfo<Product>) {
146
+ catch (e: any) {
149
147
  console.error(e.message); // Browser console will display - "Name: required"
150
148
  }
151
149
  ```
152
150
 
153
151
  ### Enforced in backend:
154
152
  ```sh
155
- > curl -d "{""unitPrice"":-1}" -H "Content-Type: application/json" -X POST http://localhost:3001/api/products
153
+ > curl http://localhost:3001/api/products -H "Content-Type: application/json" -d "{""unitPrice"":-1}"
156
154
 
157
155
  {"modelState":{"unitPrice":"must not be less than 0","name":"required"},"message":"Name: required"}
158
156
  ```
@@ -176,6 +174,10 @@ export class Article {
176
174
  }
177
175
  ```
178
176
 
177
+ ## Example App
178
+
179
+ [CRM demo](https://github.com/remult/crm-demo) with a React + [MUI](https://mui.com) front-end and Postgres database.
180
+
179
181
  ## Contributing
180
182
  Contributions are welcome. See [CONTRIBUTING](CONTRIBUTING.md).
181
183
 
@@ -20,6 +20,7 @@ export declare function remultExpress(options?: {
20
20
  defaultGetLimit?: number;
21
21
  entities?: ClassType<any>[];
22
22
  controllers?: ClassType<any>[];
23
+ bodyParser?: boolean;
23
24
  }): RemultExpressBridge;
24
25
  export interface RemultExpressBridge extends express.RequestHandler {
25
26
  getRemult(req: express.Request): Promise<Remult>;
@@ -4,7 +4,6 @@ exports.JobsInQueueEntity = exports.EntityQueueStorage = exports.ExpressRequestB
4
4
  var tslib_1 = require("tslib");
5
5
  var __1 = require("../");
6
6
  var express = require("express");
7
- var bodyParser = require("body-parser");
8
7
  var register_actions_on_server_1 = require("./register-actions-on-server");
9
8
  var register_entities_on_server_1 = require("./register-entities-on-server");
10
9
  var JsonEntityFileStorage_1 = require("./JsonEntityFileStorage");
@@ -29,8 +28,10 @@ function remultExpress(options) {
29
28
  if (!options.queueStorage) {
30
29
  options.queueStorage = new InMemoryQueueStorage();
31
30
  }
32
- app.use(bodyParser.json({ limit: options.bodySizeLimit }));
33
- app.use(bodyParser.urlencoded({ extended: true, limit: options.bodySizeLimit }));
31
+ if ((options === null || options === void 0 ? void 0 : options.bodyParser) !== false) {
32
+ app.use(express.json({ limit: options.bodySizeLimit }));
33
+ app.use(express.urlencoded({ extended: true, limit: options.bodySizeLimit }));
34
+ }
34
35
  var dataProvider;
35
36
  if (typeof options.dataProvider === "function") {
36
37
  dataProvider = options.dataProvider();
@@ -62,8 +63,13 @@ function remultExpress(options) {
62
63
  bridge.logApiEndPoints = options.logApiEndPoints;
63
64
  var apiArea = bridge.addArea(__1.Remult.apiBaseUrl);
64
65
  if (!options.disableAutoApi) {
65
- register_actions_on_server_1.registerActionsOnServer(apiArea);
66
- register_entities_on_server_1.registerEntitiesOnServer(apiArea);
66
+ var actions = [];
67
+ if (options.entities)
68
+ actions.push.apply(actions, tslib_1.__spread(options.entities));
69
+ if (options.controllers)
70
+ actions.push.apply(actions, tslib_1.__spread(options.controllers));
71
+ register_actions_on_server_1.registerActionsOnServer(apiArea, actions);
72
+ register_entities_on_server_1.registerEntitiesOnServer(apiArea, options.entities);
67
73
  }
68
74
  return Object.assign(app, {
69
75
  getRemult: function (req) { return bridge.getRemult(req); },
@@ -576,7 +582,10 @@ var ExpressResponseBridgeToDataApiResponse = /** @class */ (function () {
576
582
  this.req = req;
577
583
  }
578
584
  ExpressResponseBridgeToDataApiResponse.prototype.forbidden = function () {
579
- this.r.sendStatus(403);
585
+ this.sendStatus(403);
586
+ };
587
+ ExpressResponseBridgeToDataApiResponse.prototype.sendStatus = function (status) {
588
+ this.r.writeHead(status).end();
580
589
  };
581
590
  ExpressResponseBridgeToDataApiResponse.prototype.progress = function (progress) {
582
591
  };
@@ -588,10 +597,10 @@ var ExpressResponseBridgeToDataApiResponse = /** @class */ (function () {
588
597
  this.r.json(data);
589
598
  };
590
599
  ExpressResponseBridgeToDataApiResponse.prototype.deleted = function () {
591
- this.r.sendStatus(204);
600
+ this.sendStatus(204);
592
601
  };
593
602
  ExpressResponseBridgeToDataApiResponse.prototype.notFound = function () {
594
- this.r.sendStatus(404);
603
+ this.sendStatus(404);
595
604
  };
596
605
  ExpressResponseBridgeToDataApiResponse.prototype.error = function (data) {
597
606
  var _a, _b;
@@ -1,2 +1,3 @@
1
1
  import { SiteArea } from "./expressBridge";
2
- export declare function registerActionsOnServer(area: SiteArea): void;
2
+ import { ClassType } from "../classType";
3
+ export declare function registerActionsOnServer(area: SiteArea, controllers?: ClassType<any>[]): void;
@@ -1,8 +1,10 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.registerActionsOnServer = void 0;
4
+ var tslib_1 = require("tslib");
4
5
  var server_action_1 = require("../src/server-action");
5
- function registerActionsOnServer(area) {
6
+ function registerActionsOnServer(area, controllers) {
7
+ var e_1, _a, e_2, _b;
6
8
  var addAction = function (a) {
7
9
  var x = a[server_action_1.serverActionField];
8
10
  if (!x) {
@@ -11,8 +13,38 @@ function registerActionsOnServer(area) {
11
13
  area.addAction(x);
12
14
  };
13
15
  server_action_1.actionInfo.runningOnServer = true;
14
- server_action_1.actionInfo.allActions.forEach(function (a) {
15
- addAction(a);
16
- });
16
+ if (controllers && controllers.length > 0) {
17
+ try {
18
+ for (var controllers_1 = tslib_1.__values(controllers), controllers_1_1 = controllers_1.next(); !controllers_1_1.done; controllers_1_1 = controllers_1.next()) {
19
+ var c = controllers_1_1.value;
20
+ var z = c[server_action_1.classBackendMethodsArray];
21
+ if (z)
22
+ try {
23
+ for (var z_1 = (e_2 = void 0, tslib_1.__values(z)), z_1_1 = z_1.next(); !z_1_1.done; z_1_1 = z_1.next()) {
24
+ var a = z_1_1.value;
25
+ addAction(a);
26
+ }
27
+ }
28
+ catch (e_2_1) { e_2 = { error: e_2_1 }; }
29
+ finally {
30
+ try {
31
+ if (z_1_1 && !z_1_1.done && (_b = z_1.return)) _b.call(z_1);
32
+ }
33
+ finally { if (e_2) throw e_2.error; }
34
+ }
35
+ }
36
+ }
37
+ catch (e_1_1) { e_1 = { error: e_1_1 }; }
38
+ finally {
39
+ try {
40
+ if (controllers_1_1 && !controllers_1_1.done && (_a = controllers_1.return)) _a.call(controllers_1);
41
+ }
42
+ finally { if (e_1) throw e_1.error; }
43
+ }
44
+ }
45
+ else
46
+ server_action_1.actionInfo.allActions.forEach(function (a) {
47
+ addAction(a);
48
+ });
17
49
  }
18
50
  exports.registerActionsOnServer = registerActionsOnServer;
@@ -1,2 +1,3 @@
1
1
  import { SiteArea } from "./expressBridge";
2
- export declare function registerEntitiesOnServer(area: SiteArea): void;
2
+ import { ClassType } from "../classType";
3
+ export declare function registerEntitiesOnServer(area: SiteArea, entities?: ClassType<any>[]): void;
@@ -4,9 +4,11 @@ exports.registerEntitiesOnServer = void 0;
4
4
  var remult3_1 = require("../src/remult3");
5
5
  var context_1 = require("../src/context");
6
6
  var data_api_1 = require("../src/data-api");
7
- function registerEntitiesOnServer(area) {
7
+ function registerEntitiesOnServer(area, entities) {
8
+ if (!entities)
9
+ entities = context_1.allEntities;
8
10
  //add Api Entries
9
- context_1.allEntities.forEach(function (e) {
11
+ entities.forEach(function (e) {
10
12
  var key = remult3_1.getEntityKey(e);
11
13
  if (key != undefined)
12
14
  area.add(key, function (c) {
@@ -6,7 +6,7 @@ export declare class WebSqlDataProvider implements SqlImplementation, __RowsOfDa
6
6
  rows: {
7
7
  [tableName: string]: any;
8
8
  };
9
- constructor(databaseName: string);
9
+ constructor(databaseName: string, databaseSize?: number);
10
10
  getLimitSqlSyntax(limit: number, offset: number): string;
11
11
  entityIsUsedForTheFirstTime(entity: EntityMetadata): Promise<void>;
12
12
  dropTable(entity: EntityMetadata): Promise<void>;
@@ -7,10 +7,11 @@ var sql_database_1 = require("./sql-database");
7
7
  var filter_consumer_bridge_to_sql_request_1 = require("../filter/filter-consumer-bridge-to-sql-request");
8
8
  //SqlDatabase.LogToConsole = true;
9
9
  var WebSqlDataProvider = /** @class */ (function () {
10
- function WebSqlDataProvider(databaseName) {
10
+ function WebSqlDataProvider(databaseName, databaseSize) {
11
+ if (databaseSize === void 0) { databaseSize = 2 * 1024 * 1024; }
11
12
  this.databaseName = databaseName;
12
13
  //@ts-ignore
13
- this.db = window.openDatabase(databaseName, '1.0', databaseName, 2 * 1024 * 1024);
14
+ this.db = window.openDatabase(databaseName, '1.0', databaseName, databaseSize);
14
15
  }
15
16
  WebSqlDataProvider.prototype.getLimitSqlSyntax = function (limit, offset) {
16
17
  return ' limit ' + limit + ' offset ' + offset;
@@ -224,7 +224,7 @@ export declare function isAutoIncrement(f: FieldMetadata): boolean;
224
224
  export interface StringFieldOptions<entityType = any> extends FieldOptions<entityType, string> {
225
225
  maxLength?: number;
226
226
  }
227
- export declare function ValueListFieldType<entityType = any, valueType extends ValueListItem = any>(...options: (ValueListFieldOptions<entityType, valueType> | ((options: FieldOptions<entityType, valueType>, remult: Remult) => void))[]): (type: ClassType<valueType>) => void;
227
+ export declare function ValueListFieldType<valueType extends ValueListItem = any>(...options: (ValueListFieldOptions<any, valueType> | ((options: FieldOptions<any, valueType>, remult: Remult) => void))[]): (type: ClassType<valueType>) => void;
228
228
  export interface ValueListFieldOptions<entityType, valueType> extends FieldOptions<entityType, valueType> {
229
229
  getValues?: () => valueType[];
230
230
  }
@@ -66,4 +66,5 @@ export declare class ProgressListener {
66
66
  }
67
67
  export declare function prepareArgsToSend(types: any[], args: any[]): any[];
68
68
  export declare function prepareReceivedArgs(types: any[], args: any[], remult: Remult, ds: DataProvider, res: DataApiResponse): Promise<any[]>;
69
+ export declare const classBackendMethodsArray: unique symbol;
69
70
  export {};
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.prepareReceivedArgs = exports.prepareArgsToSend = exports.ProgressListener = exports.BackendMethod = exports.Controller = exports.serverActionField = exports.actionInfo = exports.myServerAction = exports.Action = void 0;
3
+ exports.classBackendMethodsArray = exports.prepareReceivedArgs = exports.prepareArgsToSend = exports.ProgressListener = exports.BackendMethod = exports.Controller = exports.serverActionField = exports.actionInfo = exports.myServerAction = exports.Action = void 0;
4
4
  var tslib_1 = require("tslib");
5
5
  require("reflect-metadata");
6
6
  var context_1 = require("./context");
@@ -216,7 +216,7 @@ function BackendMethod(options) {
216
216
  });
217
217
  });
218
218
  };
219
- exports.actionInfo.allActions.push(descriptor.value);
219
+ registerAction(target, descriptor);
220
220
  descriptor.value[exports.serverActionField] = serverAction_1;
221
221
  return descriptor;
222
222
  }
@@ -479,7 +479,7 @@ function BackendMethod(options) {
479
479
  });
480
480
  });
481
481
  };
482
- exports.actionInfo.allActions.push(descriptor.value);
482
+ registerAction(target.constructor, descriptor);
483
483
  descriptor.value[exports.serverActionField] = serverAction;
484
484
  return descriptor;
485
485
  };
@@ -488,6 +488,10 @@ exports.BackendMethod = BackendMethod;
488
488
  var customUndefined = {
489
489
  _isUndefined: true
490
490
  };
491
+ function registerAction(target, descriptor) {
492
+ (target[exports.classBackendMethodsArray] || (target[exports.classBackendMethodsArray] = [])).push(descriptor.value);
493
+ exports.actionInfo.allActions.push(descriptor.value);
494
+ }
491
495
  function isCustomUndefined(x) {
492
496
  return x && x._isUndefined;
493
497
  }
@@ -592,3 +596,4 @@ function prepareReceivedArgs(types, args, remult, ds, res) {
592
596
  });
593
597
  }
594
598
  exports.prepareReceivedArgs = prepareReceivedArgs;
599
+ exports.classBackendMethodsArray = Symbol('classBackendMethodsArray');