remult 3.0.2 → 3.0.3-next.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.
@@ -14,17 +14,20 @@ export function TestApiDataProvider(options) {
14
14
  buildGenericRequestInfo: (req) => req,
15
15
  ignoreAsyncStorage: true,
16
16
  });
17
+ const lock = new AsyncLock();
17
18
  async function handleOnServer(req) {
18
- return await MakeServerCallWithDifferentStaticRemult(async () => {
19
- if (newEntities.length > 0 && options?.ensureSchema != false) {
20
- await (await dp).ensureSchema?.(newEntities);
21
- newEntities = [];
22
- }
23
- var result = await server.handle(req);
24
- if ((result?.statusCode ?? 200) >= 400) {
25
- throw { ...result?.data, status: result?.statusCode ?? 500 };
26
- }
27
- return result?.data;
19
+ return lock.runExclusive(async () => {
20
+ return await MakeServerCallWithDifferentStaticRemult(async () => {
21
+ if (newEntities.length > 0 && options?.ensureSchema != false) {
22
+ await (await dp).ensureSchema?.(newEntities);
23
+ newEntities = [];
24
+ }
25
+ var result = await server.handle(req);
26
+ if ((result?.statusCode ?? 200) >= 400) {
27
+ throw { ...result?.data, status: result?.statusCode ?? 500 };
28
+ }
29
+ return result?.data;
30
+ });
28
31
  });
29
32
  }
30
33
  const registeredEntities = new Set();
@@ -58,6 +61,24 @@ export function TestApiDataProvider(options) {
58
61
  }
59
62
  });
60
63
  }
64
+ export class AsyncLock {
65
+ static enabled = true;
66
+ current = Promise.resolve();
67
+ i = 0;
68
+ async runExclusive(fn) {
69
+ const previous = this.current;
70
+ let resolveNext;
71
+ this.current = new Promise((resolve) => (resolveNext = resolve));
72
+ if (AsyncLock.enabled)
73
+ await previous;
74
+ try {
75
+ return await fn();
76
+ }
77
+ finally {
78
+ resolveNext();
79
+ }
80
+ }
81
+ }
61
82
  async function MakeServerCallWithDifferentStaticRemult(what) {
62
83
  var x = remultStatic.asyncContext;
63
84
  var y = remultStatic.remultFactory;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "remult",
3
- "version": "3.0.2",
3
+ "version": "3.0.3-next.0",
4
4
  "description": "A CRUD framework for full-stack TypeScript",
5
5
  "homepage": "https://remult.dev",
6
6
  "repository": {
@@ -1,3 +1,9 @@
1
1
  import { RestDataProvider } from '../index.js';
2
2
  import type { RemultServerOptions } from './index.js';
3
3
  export declare function TestApiDataProvider(options?: Pick<RemultServerOptions<unknown>, 'ensureSchema' | 'dataProvider'>): RestDataProvider;
4
+ export declare class AsyncLock {
5
+ static enabled: boolean;
6
+ private current;
7
+ i: number;
8
+ runExclusive<T>(fn: () => Promise<T>): Promise<T>;
9
+ }
@@ -1,5 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.AsyncLock = void 0;
3
4
  exports.TestApiDataProvider = TestApiDataProvider;
4
5
  var tslib_1 = require("tslib");
5
6
  var index_js_1 = require("../index.js");
@@ -23,36 +24,42 @@ function TestApiDataProvider(options) {
23
24
  buildGenericRequestInfo: function (req) { return req; },
24
25
  ignoreAsyncStorage: true,
25
26
  });
27
+ var lock = new AsyncLock();
26
28
  function handleOnServer(req) {
27
29
  return tslib_1.__awaiter(this, void 0, void 0, function () {
28
30
  var _this = this;
29
31
  return tslib_1.__generator(this, function (_a) {
30
- switch (_a.label) {
31
- case 0: return [4 /*yield*/, MakeServerCallWithDifferentStaticRemult(function () { return tslib_1.__awaiter(_this, void 0, void 0, function () {
32
- var result;
33
- var _a, _b, _c, _d;
34
- return tslib_1.__generator(this, function (_e) {
35
- switch (_e.label) {
36
- case 0:
37
- if (!(newEntities.length > 0 && (options === null || options === void 0 ? void 0 : options.ensureSchema) != false)) return [3 /*break*/, 3];
38
- return [4 /*yield*/, dp];
39
- case 1: return [4 /*yield*/, ((_b = (_a = (_e.sent())).ensureSchema) === null || _b === void 0 ? void 0 : _b.call(_a, newEntities))];
40
- case 2:
41
- _e.sent();
42
- newEntities = [];
43
- _e.label = 3;
44
- case 3: return [4 /*yield*/, server.handle(req)];
45
- case 4:
46
- result = _e.sent();
47
- if (((_c = result === null || result === void 0 ? void 0 : result.statusCode) !== null && _c !== void 0 ? _c : 200) >= 400) {
48
- throw tslib_1.__assign(tslib_1.__assign({}, result === null || result === void 0 ? void 0 : result.data), { status: (_d = result === null || result === void 0 ? void 0 : result.statusCode) !== null && _d !== void 0 ? _d : 500 });
49
- }
50
- return [2 /*return*/, result === null || result === void 0 ? void 0 : result.data];
51
- }
52
- });
53
- }); })];
54
- case 1: return [2 /*return*/, _a.sent()];
55
- }
32
+ return [2 /*return*/, lock.runExclusive(function () { return tslib_1.__awaiter(_this, void 0, void 0, function () {
33
+ var _this = this;
34
+ return tslib_1.__generator(this, function (_a) {
35
+ switch (_a.label) {
36
+ case 0: return [4 /*yield*/, MakeServerCallWithDifferentStaticRemult(function () { return tslib_1.__awaiter(_this, void 0, void 0, function () {
37
+ var result;
38
+ var _a, _b, _c, _d;
39
+ return tslib_1.__generator(this, function (_e) {
40
+ switch (_e.label) {
41
+ case 0:
42
+ if (!(newEntities.length > 0 && (options === null || options === void 0 ? void 0 : options.ensureSchema) != false)) return [3 /*break*/, 3];
43
+ return [4 /*yield*/, dp];
44
+ case 1: return [4 /*yield*/, ((_b = (_a = (_e.sent())).ensureSchema) === null || _b === void 0 ? void 0 : _b.call(_a, newEntities))];
45
+ case 2:
46
+ _e.sent();
47
+ newEntities = [];
48
+ _e.label = 3;
49
+ case 3: return [4 /*yield*/, server.handle(req)];
50
+ case 4:
51
+ result = _e.sent();
52
+ if (((_c = result === null || result === void 0 ? void 0 : result.statusCode) !== null && _c !== void 0 ? _c : 200) >= 400) {
53
+ throw tslib_1.__assign(tslib_1.__assign({}, result === null || result === void 0 ? void 0 : result.data), { status: (_d = result === null || result === void 0 ? void 0 : result.statusCode) !== null && _d !== void 0 ? _d : 500 });
54
+ }
55
+ return [2 /*return*/, result === null || result === void 0 ? void 0 : result.data];
56
+ }
57
+ });
58
+ }); })];
59
+ case 1: return [2 /*return*/, _a.sent()];
60
+ }
61
+ });
62
+ }); })];
56
63
  });
57
64
  });
58
65
  }
@@ -95,6 +102,40 @@ function TestApiDataProvider(options) {
95
102
  }
96
103
  });
97
104
  }
105
+ var AsyncLock = /** @class */ (function () {
106
+ function AsyncLock() {
107
+ this.current = Promise.resolve();
108
+ this.i = 0;
109
+ }
110
+ AsyncLock.prototype.runExclusive = function (fn) {
111
+ return tslib_1.__awaiter(this, void 0, void 0, function () {
112
+ var previous, resolveNext;
113
+ return tslib_1.__generator(this, function (_a) {
114
+ switch (_a.label) {
115
+ case 0:
116
+ previous = this.current;
117
+ this.current = new Promise(function (resolve) { return (resolveNext = resolve); });
118
+ if (!AsyncLock.enabled) return [3 /*break*/, 2];
119
+ return [4 /*yield*/, previous];
120
+ case 1:
121
+ _a.sent();
122
+ _a.label = 2;
123
+ case 2:
124
+ _a.trys.push([2, , 4, 5]);
125
+ return [4 /*yield*/, fn()];
126
+ case 3: return [2 /*return*/, _a.sent()];
127
+ case 4:
128
+ resolveNext();
129
+ return [7 /*endfinally*/];
130
+ case 5: return [2 /*return*/];
131
+ }
132
+ });
133
+ });
134
+ };
135
+ AsyncLock.enabled = true;
136
+ return AsyncLock;
137
+ }());
138
+ exports.AsyncLock = AsyncLock;
98
139
  function MakeServerCallWithDifferentStaticRemult(what) {
99
140
  return tslib_1.__awaiter(this, void 0, void 0, function () {
100
141
  var x, y, user, store;
@@ -35,6 +35,10 @@ export interface FieldOptions<entityType = unknown, valueType = unknown> {
35
35
  * // Prevent API from updating this field
36
36
  * @Fields.string({ allowApiUpdate: false })
37
37
  * createdBy = remult.user?.id;
38
+ * @example
39
+ * // Allow API update only on new items
40
+ * @Fields.string<Category>({ allowApiUpdate: (c) => getEntityRef(c).isNew() })
41
+ * Description = ""
38
42
  * @see [allowed](https://remult.dev/docs/allowed.html)
39
43
  * @see [Access Control](https://remult.dev/docs/access-control)
40
44
  * @type {AllowedForInstance<entityType>}