remult 0.26.0 → 0.26.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/README.md +7 -7
- package/esm/server/expressBridge.js +1 -1
- package/esm/server/initAsyncHooks.js +25 -7
- package/esm/src/context.js +3 -3
- package/esm/src/remult3/RepositoryImplementation.js +4 -2
- package/esm/src/remult3/remult3.js +21 -14
- package/package.json +1 -1
- package/server/expressBridge.js +1 -1
- package/server/initAsyncHooks.d.ts +7 -0
- package/server/initAsyncHooks.js +35 -7
- package/src/context.d.ts +14 -7
- package/src/context.js +20 -20
- package/src/remult3/RepositoryImplementation.js +31 -27
- package/src/remult3/remult3.js +21 -14
package/README.md
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
<div align="center">
|
|
2
2
|
<h1>Remult</h1>
|
|
3
3
|
<p>Full-stack CRUD, simplified, with SSOT TypeScript entities</p>
|
|
4
|
-
<a href="https://circleci.com/gh/remult/remult/tree/
|
|
5
|
-
<img alt="CircleCI" src="https://circleci.com/gh/remult/remult/tree/
|
|
4
|
+
<a href="https://circleci.com/gh/remult/remult/tree/main" rel="nofollow">
|
|
5
|
+
<img alt="CircleCI" src="https://circleci.com/gh/remult/remult/tree/main.svg?style=shield"></a>
|
|
6
6
|
<a href="https://codecov.io/gh/remult/remult" rel="nofollow">
|
|
7
|
-
<img src="https://codecov.io/gh/remult/remult/branch/
|
|
8
|
-
<a href="https://raw.githubusercontent.com/remult/remult/
|
|
7
|
+
<img src="https://codecov.io/gh/remult/remult/branch/main/graph/badge.svg?token=LYWQRUN3D1"/></a>
|
|
8
|
+
<a href="https://raw.githubusercontent.com/remult/remult/main/LICENSE" rel="nofollow">
|
|
9
9
|
<img alt="GitHub license" src="https://img.shields.io/badge/license-MIT-blue.svg"></a>
|
|
10
10
|
<a href="https://www.npmjs.com/package/remult" rel="nofollow">
|
|
11
11
|
<img alt="npm version" src="https://badge.fury.io/js/remult.svg"></a>
|
|
@@ -94,7 +94,7 @@ _Example:_
|
|
|
94
94
|
|
|
95
95
|
import express from 'express'
|
|
96
96
|
import { remultExpress } from 'remult/remult-express' // adapters for: Fastify, Next.js, Nuxt, SvelteKit, Nest, more...
|
|
97
|
-
import { createPostgresDataProvider } from
|
|
97
|
+
import { createPostgresDataProvider } from 'remult/postgres' // supported: PostgreSQL, MySQL, SQLite, MongoDB, MSSQL and Oracle
|
|
98
98
|
import { Product } from '../shared/product'
|
|
99
99
|
|
|
100
100
|
const app = express()
|
|
@@ -184,7 +184,7 @@ try {
|
|
|
184
184
|
await repo(Product).insert({ name: '', unitPrice: -1 })
|
|
185
185
|
} catch (e: any) {
|
|
186
186
|
console.error(e)
|
|
187
|
-
/* Detailed error object ->
|
|
187
|
+
/* Detailed error object ->
|
|
188
188
|
{
|
|
189
189
|
"modelState": {
|
|
190
190
|
"name": "Should not be empty",
|
|
@@ -311,7 +311,7 @@ with a Node.js Express backend.
|
|
|
311
311
|
|
|
312
312
|
<a href="https://www.youtube.com/watch?v=rEoScmSVNUE" target="_blank">
|
|
313
313
|
<p align="center">
|
|
314
|
-
<img src="https://github.com/remult/remult/raw/
|
|
314
|
+
<img src="https://github.com/remult/remult/raw/main/static/images/video-thumbnail.jpg" alt="Video thumbnail" />
|
|
315
315
|
</p>
|
|
316
316
|
</a>
|
|
317
317
|
|
|
@@ -764,7 +764,7 @@ class ExpressResponseBridgeToDataApiResponse {
|
|
|
764
764
|
this.setStatus(204).end();
|
|
765
765
|
}
|
|
766
766
|
notFound() {
|
|
767
|
-
this.error({ message: '
|
|
767
|
+
this.error({ message: 'NotFound' }, undefined, 404);
|
|
768
768
|
}
|
|
769
769
|
async error(exception, entity, httpStatusCode) {
|
|
770
770
|
let data = serializeError(exception);
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { AsyncLocalStorage } from 'async_hooks';
|
|
2
|
-
import { RemultAsyncLocalStorage } from '../src/context.js';
|
|
2
|
+
import { RemultAsyncLocalStorage, } from '../src/context.js';
|
|
3
3
|
import { remultStatic } from '../src/remult-static.js';
|
|
4
4
|
let init = false;
|
|
5
5
|
export function initAsyncHooks() {
|
|
@@ -11,7 +11,7 @@ export function initAsyncHooks() {
|
|
|
11
11
|
test.run(1, async () => {
|
|
12
12
|
await Promise.resolve();
|
|
13
13
|
if (test.getStore() === undefined) {
|
|
14
|
-
console.log("async_hooks.AsyncLocalStorage not working, using
|
|
14
|
+
console.log("async_hooks.AsyncLocalStorage not working, using stub implementation (You're probably running on stackblitz, this will work on a normal nodejs environment");
|
|
15
15
|
remultStatic.asyncContext = new RemultAsyncLocalStorage(new SequentialRemultAsyncLocalStorageCore());
|
|
16
16
|
}
|
|
17
17
|
});
|
|
@@ -37,16 +37,22 @@ export class AsyncLocalStorageBridgeToRemultAsyncLocalStorageCoreImpl {
|
|
|
37
37
|
return this.asyncLocalStorage.getStore();
|
|
38
38
|
}
|
|
39
39
|
}
|
|
40
|
-
const ignoreInStack = [
|
|
40
|
+
const ignoreInStack = [
|
|
41
|
+
'AsyncLocalStorageBridgeToRemultAsyncLocalStorageCore.run',
|
|
42
|
+
'RemultAsyncLocalStorage.run',
|
|
43
|
+
'Module.withRemult',
|
|
44
|
+
'RemultServerImplementation.runWithRemult',
|
|
45
|
+
];
|
|
41
46
|
export class SequentialRemultAsyncLocalStorageCore {
|
|
42
47
|
wasImplemented;
|
|
43
48
|
async run(store, callback) {
|
|
44
|
-
let log = (msg) => {
|
|
45
|
-
};
|
|
49
|
+
let log = (msg) => { };
|
|
46
50
|
if (false) {
|
|
47
51
|
let stack = new Error().stack;
|
|
48
52
|
let y = stack.split('\n');
|
|
49
|
-
while (y.length > 0 &&
|
|
53
|
+
while (y.length > 0 &&
|
|
54
|
+
(y[0].trim().startsWith('Error') ||
|
|
55
|
+
ignoreInStack.includes(y[0].trim().split(' ')[1]))) {
|
|
50
56
|
y.splice(0, 1);
|
|
51
57
|
}
|
|
52
58
|
stack = y.join('\n');
|
|
@@ -64,7 +70,7 @@ export class SequentialRemultAsyncLocalStorageCore {
|
|
|
64
70
|
return result;
|
|
65
71
|
});
|
|
66
72
|
this.lastPromise = nextPromise.catch(() => {
|
|
67
|
-
log(
|
|
73
|
+
log('Error on ');
|
|
68
74
|
return undefined;
|
|
69
75
|
});
|
|
70
76
|
try {
|
|
@@ -80,5 +86,17 @@ export class SequentialRemultAsyncLocalStorageCore {
|
|
|
80
86
|
lastPromise = Promise.resolve(undefined);
|
|
81
87
|
currentValue;
|
|
82
88
|
}
|
|
89
|
+
export class StubRemultAsyncLocalStorageCore {
|
|
90
|
+
wasImplemented;
|
|
91
|
+
async run(store, callback) {
|
|
92
|
+
this.currentValue = store;
|
|
93
|
+
return await callback();
|
|
94
|
+
}
|
|
95
|
+
getStore() {
|
|
96
|
+
return this.currentValue;
|
|
97
|
+
}
|
|
98
|
+
lastPromise = Promise.resolve(undefined);
|
|
99
|
+
currentValue;
|
|
100
|
+
}
|
|
83
101
|
export class AsyncLocalStorageBridgeToRemultAsyncLocalStorageCore extends AsyncLocalStorageBridgeToRemultAsyncLocalStorageCoreImpl {
|
|
84
102
|
}
|
package/esm/src/context.js
CHANGED
|
@@ -51,7 +51,7 @@ export class Remult {
|
|
|
51
51
|
* @param entity - the entity to use
|
|
52
52
|
* @param dataProvider - an optional alternative data provider to use. Useful for writing to offline storage or an alternative data provider
|
|
53
53
|
*/
|
|
54
|
-
repo(entity, dataProvider) {
|
|
54
|
+
repo = (entity, dataProvider) => {
|
|
55
55
|
if (dataProvider === undefined)
|
|
56
56
|
dataProvider = this.dataProvider;
|
|
57
57
|
let dpCache = this.repCache.get(dataProvider);
|
|
@@ -63,7 +63,7 @@ export class Remult {
|
|
|
63
63
|
verifyFieldRelationInfo(r, this, dataProvider);
|
|
64
64
|
}
|
|
65
65
|
return r;
|
|
66
|
-
}
|
|
66
|
+
};
|
|
67
67
|
/** Returns the current user's info */
|
|
68
68
|
user;
|
|
69
69
|
/** Checks if a user was authenticated */
|
|
@@ -286,5 +286,5 @@ export function withRemult(callback, options) {
|
|
|
286
286
|
const remult = new Remult();
|
|
287
287
|
if (options?.dataProvider)
|
|
288
288
|
remult.dataProvider = options.dataProvider;
|
|
289
|
-
return remultStatic.asyncContext.run(remult, r => callback(r));
|
|
289
|
+
return remultStatic.asyncContext.run(remult, (r) => callback(r));
|
|
290
290
|
}
|
|
@@ -1373,14 +1373,16 @@ export class rowHelperImplementation extends rowHelperBase {
|
|
|
1373
1373
|
}
|
|
1374
1374
|
async delete() {
|
|
1375
1375
|
this.__clearErrorsAndReportChanged();
|
|
1376
|
-
let
|
|
1376
|
+
let doDelete = true;
|
|
1377
|
+
let e = this.buildLifeCycleEvent(() => (doDelete = false));
|
|
1377
1378
|
if (!this.repository._dataProvider.isProxy) {
|
|
1378
1379
|
if (this.info.entityInfo.deleting)
|
|
1379
1380
|
await this.info.entityInfo.deleting(this.instance, e);
|
|
1380
1381
|
}
|
|
1381
1382
|
this.__assertValidity();
|
|
1382
1383
|
try {
|
|
1383
|
-
|
|
1384
|
+
if (doDelete)
|
|
1385
|
+
await this.edp.delete(this.id);
|
|
1384
1386
|
if (!this.repository._dataProvider.isProxy) {
|
|
1385
1387
|
if (this.info.entityInfo.deleted)
|
|
1386
1388
|
await this.info.entityInfo.deleted(this.instance, e);
|
|
@@ -1,40 +1,47 @@
|
|
|
1
1
|
export {};
|
|
2
|
+
//y1 - https://discord.com/channels/975754286384418847/1230386433093533698/1230386433093533698
|
|
3
|
+
//y1 - fix async hooks - was it fixed?
|
|
4
|
+
//p1 - release solid start with example project
|
|
2
5
|
//p1 - add documentation for bun sqlite
|
|
3
|
-
//
|
|
4
|
-
//
|
|
5
|
-
//
|
|
6
|
-
//
|
|
6
|
+
//p1 - fix dark background to also work on groups
|
|
7
|
+
//p1 - describe entity
|
|
8
|
+
//p1 - prepare the createEntity discussion
|
|
9
|
+
//p1 - fix async hooks
|
|
10
|
+
//p1 - write active record article
|
|
11
|
+
//p1 - maybe add decorator comment in the readme as well (I heard you've lost me in decorators) - and improve the describeClass function
|
|
12
|
+
//p1 - return error on connection error
|
|
13
|
+
//p1 - reconsider update many, maybe the second parameter should be in a set option - break existing
|
|
14
|
+
//p1 - consider upsert (where,set)
|
|
15
|
+
//p1 - consider id to also support keyof (id:['company','index'])
|
|
16
|
+
//p1 - consider including the admin in the tutorial - and maybe even in the demo when we setup the api
|
|
17
|
+
//y2 - JY suggestion of having generate as part of the ensure schema - not sure
|
|
18
|
+
//y2 - currently for string fields we default for 255 in knex (which is their default) why not just use text (varchar max) - and only use exact length when one is provided?
|
|
7
19
|
//p2 - create foreign key constraints in user code - https://codesandbox.io/p/devbox/fk-validator-tdshcs
|
|
8
20
|
//p1 - admin url1 - pocketbase use /_ for the admin //{allowed?:Allowed,url?:string}
|
|
9
|
-
//
|
|
10
|
-
//
|
|
21
|
+
//p1 - article auth.js with express - played with it, requires type="module" and a few more configurations - https://github.com/noam-honig/express-auth
|
|
22
|
+
//y2 - fix validators cache
|
|
11
23
|
//y2 - should we validate relations
|
|
12
|
-
//y1 - dependency of live query tables
|
|
24
|
+
//y1 - dependency of live query tables live query refresh of view on table update
|
|
13
25
|
//p1 - see why mongo tests do not run anymore
|
|
14
|
-
//
|
|
15
|
-
//y1 - consider replacing all errors with error classes that extend the base Error class
|
|
26
|
+
//y2 - consider replacing all errors with error classes that extend the base Error class
|
|
16
27
|
//y2 - should enforce integer - currently we probably round / truncate it
|
|
17
28
|
//y1 - talk about filter on objects that are not loaded - {
|
|
18
29
|
//category: repo(CompoundId).create({ company: 7, index: 3, name: '' }),
|
|
19
30
|
// }
|
|
20
|
-
//y1 - consider id to also support keyof (id:['company','index'])
|
|
21
31
|
/*y1 - talk about modules in init express with entities/controllers,initRequest,initApi
|
|
22
32
|
- support get with backend method, with url search params as the first parameter, & url as second parameter
|
|
23
33
|
- support returning redirect, and plain html (For sign in scenarios)
|
|
24
34
|
|
|
25
35
|
*/
|
|
26
36
|
//p1 - in this video I'll use remult to turn a frontend app to a fullstack app
|
|
27
|
-
/*
|
|
37
|
+
/*y2 - Talk JYC - JYC - add some integrity checks on delete
|
|
28
38
|
- soft delete
|
|
29
39
|
- delete restrict (implicit, or user selected - and if so, how) (delete & update of id)
|
|
30
40
|
|
|
31
41
|
*/
|
|
32
42
|
//y1 - consider sql expression gets a dbnames of it's own (that already has the "tableName" defined correctly) maybe also the filter translator
|
|
33
43
|
//y1 - tried to upgrade vitest, nuxt tests are failing with loading uuid - sounds familiar?
|
|
34
|
-
//y1 - I think that the tests you've setup don't cover next app router - I added to the setup, but not sure where else
|
|
35
44
|
//y1 - talk about the parameter issue with backend methods
|
|
36
|
-
//y1 - select data provider per entity https://discord.com/channels/975754286384418847/976006081748807690/1201415305885397003
|
|
37
|
-
//y1 - live query refresh of view on table update
|
|
38
45
|
//y1 - main vs master
|
|
39
46
|
//y2 - livequery for findfirst (@JY)
|
|
40
47
|
/*y2 -
|
package/package.json
CHANGED
package/server/expressBridge.js
CHANGED
|
@@ -1086,7 +1086,7 @@ var ExpressResponseBridgeToDataApiResponse = /** @class */ (function () {
|
|
|
1086
1086
|
this.setStatus(204).end();
|
|
1087
1087
|
};
|
|
1088
1088
|
ExpressResponseBridgeToDataApiResponse.prototype.notFound = function () {
|
|
1089
|
-
this.error({ message: '
|
|
1089
|
+
this.error({ message: 'NotFound' }, undefined, 404);
|
|
1090
1090
|
};
|
|
1091
1091
|
ExpressResponseBridgeToDataApiResponse.prototype.error = function (exception, entity, httpStatusCode) {
|
|
1092
1092
|
var _a;
|
|
@@ -13,5 +13,12 @@ export declare class SequentialRemultAsyncLocalStorageCore<T> implements RemultA
|
|
|
13
13
|
lastPromise: Promise<T>;
|
|
14
14
|
currentValue: T;
|
|
15
15
|
}
|
|
16
|
+
export declare class StubRemultAsyncLocalStorageCore<T> implements RemultAsyncLocalStorageCore<T> {
|
|
17
|
+
wasImplemented: 'yes';
|
|
18
|
+
run<R>(store: T, callback: () => Promise<R>): Promise<R>;
|
|
19
|
+
getStore(): T;
|
|
20
|
+
lastPromise: Promise<T>;
|
|
21
|
+
currentValue: T;
|
|
22
|
+
}
|
|
16
23
|
export declare class AsyncLocalStorageBridgeToRemultAsyncLocalStorageCore<T> extends AsyncLocalStorageBridgeToRemultAsyncLocalStorageCoreImpl<T> {
|
|
17
24
|
}
|
package/server/initAsyncHooks.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.AsyncLocalStorageBridgeToRemultAsyncLocalStorageCore = exports.SequentialRemultAsyncLocalStorageCore = exports.AsyncLocalStorageBridgeToRemultAsyncLocalStorageCoreImpl = exports.initAsyncHooks = void 0;
|
|
3
|
+
exports.AsyncLocalStorageBridgeToRemultAsyncLocalStorageCore = exports.StubRemultAsyncLocalStorageCore = exports.SequentialRemultAsyncLocalStorageCore = exports.AsyncLocalStorageBridgeToRemultAsyncLocalStorageCoreImpl = exports.initAsyncHooks = void 0;
|
|
4
4
|
var tslib_1 = require("tslib");
|
|
5
5
|
var async_hooks_1 = require("async_hooks");
|
|
6
6
|
var context_js_1 = require("../src/context.js");
|
|
@@ -20,7 +20,7 @@ function initAsyncHooks() {
|
|
|
20
20
|
case 1:
|
|
21
21
|
_a.sent();
|
|
22
22
|
if (test.getStore() === undefined) {
|
|
23
|
-
console.log("async_hooks.AsyncLocalStorage not working, using
|
|
23
|
+
console.log("async_hooks.AsyncLocalStorage not working, using stub implementation (You're probably running on stackblitz, this will work on a normal nodejs environment");
|
|
24
24
|
remult_static_js_1.remultStatic.asyncContext = new context_js_1.RemultAsyncLocalStorage(new SequentialRemultAsyncLocalStorageCore());
|
|
25
25
|
}
|
|
26
26
|
return [2 /*return*/];
|
|
@@ -65,7 +65,12 @@ var AsyncLocalStorageBridgeToRemultAsyncLocalStorageCoreImpl = /** @class */ (fu
|
|
|
65
65
|
return AsyncLocalStorageBridgeToRemultAsyncLocalStorageCoreImpl;
|
|
66
66
|
}());
|
|
67
67
|
exports.AsyncLocalStorageBridgeToRemultAsyncLocalStorageCoreImpl = AsyncLocalStorageBridgeToRemultAsyncLocalStorageCoreImpl;
|
|
68
|
-
var ignoreInStack = [
|
|
68
|
+
var ignoreInStack = [
|
|
69
|
+
'AsyncLocalStorageBridgeToRemultAsyncLocalStorageCore.run',
|
|
70
|
+
'RemultAsyncLocalStorage.run',
|
|
71
|
+
'Module.withRemult',
|
|
72
|
+
'RemultServerImplementation.runWithRemult',
|
|
73
|
+
];
|
|
69
74
|
var SequentialRemultAsyncLocalStorageCore = /** @class */ (function () {
|
|
70
75
|
function SequentialRemultAsyncLocalStorageCore() {
|
|
71
76
|
this.lastPromise = Promise.resolve(undefined);
|
|
@@ -77,12 +82,13 @@ var SequentialRemultAsyncLocalStorageCore = /** @class */ (function () {
|
|
|
77
82
|
return tslib_1.__generator(this, function (_a) {
|
|
78
83
|
switch (_a.label) {
|
|
79
84
|
case 0:
|
|
80
|
-
log = function (msg) {
|
|
81
|
-
};
|
|
85
|
+
log = function (msg) { };
|
|
82
86
|
if (false) {
|
|
83
87
|
stack_1 = new Error().stack;
|
|
84
88
|
y = stack_1.split('\n');
|
|
85
|
-
while (y.length > 0 &&
|
|
89
|
+
while (y.length > 0 &&
|
|
90
|
+
(y[0].trim().startsWith('Error') ||
|
|
91
|
+
ignoreInStack.includes(y[0].trim().split(' ')[1]))) {
|
|
86
92
|
y.splice(0, 1);
|
|
87
93
|
}
|
|
88
94
|
stack_1 = y.join('\n');
|
|
@@ -108,7 +114,7 @@ var SequentialRemultAsyncLocalStorageCore = /** @class */ (function () {
|
|
|
108
114
|
});
|
|
109
115
|
}); });
|
|
110
116
|
this.lastPromise = nextPromise.catch(function () {
|
|
111
|
-
log(
|
|
117
|
+
log('Error on ');
|
|
112
118
|
return undefined;
|
|
113
119
|
});
|
|
114
120
|
_a.label = 1;
|
|
@@ -130,6 +136,28 @@ var SequentialRemultAsyncLocalStorageCore = /** @class */ (function () {
|
|
|
130
136
|
return SequentialRemultAsyncLocalStorageCore;
|
|
131
137
|
}());
|
|
132
138
|
exports.SequentialRemultAsyncLocalStorageCore = SequentialRemultAsyncLocalStorageCore;
|
|
139
|
+
var StubRemultAsyncLocalStorageCore = /** @class */ (function () {
|
|
140
|
+
function StubRemultAsyncLocalStorageCore() {
|
|
141
|
+
this.lastPromise = Promise.resolve(undefined);
|
|
142
|
+
}
|
|
143
|
+
StubRemultAsyncLocalStorageCore.prototype.run = function (store, callback) {
|
|
144
|
+
return tslib_1.__awaiter(this, void 0, void 0, function () {
|
|
145
|
+
return tslib_1.__generator(this, function (_a) {
|
|
146
|
+
switch (_a.label) {
|
|
147
|
+
case 0:
|
|
148
|
+
this.currentValue = store;
|
|
149
|
+
return [4 /*yield*/, callback()];
|
|
150
|
+
case 1: return [2 /*return*/, _a.sent()];
|
|
151
|
+
}
|
|
152
|
+
});
|
|
153
|
+
});
|
|
154
|
+
};
|
|
155
|
+
StubRemultAsyncLocalStorageCore.prototype.getStore = function () {
|
|
156
|
+
return this.currentValue;
|
|
157
|
+
};
|
|
158
|
+
return StubRemultAsyncLocalStorageCore;
|
|
159
|
+
}());
|
|
160
|
+
exports.StubRemultAsyncLocalStorageCore = StubRemultAsyncLocalStorageCore;
|
|
133
161
|
var AsyncLocalStorageBridgeToRemultAsyncLocalStorageCore = /** @class */ (function (_super) {
|
|
134
162
|
tslib_1.__extends(AsyncLocalStorageBridgeToRemultAsyncLocalStorageCore, _super);
|
|
135
163
|
function AsyncLocalStorageBridgeToRemultAsyncLocalStorageCore() {
|
package/src/context.d.ts
CHANGED
|
@@ -26,7 +26,7 @@ export declare class Remult {
|
|
|
26
26
|
* @param entity - the entity to use
|
|
27
27
|
* @param dataProvider - an optional alternative data provider to use. Useful for writing to offline storage or an alternative data provider
|
|
28
28
|
*/
|
|
29
|
-
repo<T>(entity: ClassType<T>, dataProvider?: DataProvider)
|
|
29
|
+
repo: <T>(entity: ClassType<T>, dataProvider?: DataProvider) => Repository<T>;
|
|
30
30
|
/** Returns the current user's info */
|
|
31
31
|
user?: UserInfo;
|
|
32
32
|
/** Checks if a user was authenticated */
|
|
@@ -102,15 +102,22 @@ export interface ApiClient {
|
|
|
102
102
|
*
|
|
103
103
|
* @example
|
|
104
104
|
* // Adding bearer token authorization
|
|
105
|
-
* remult.apiClient.httpClient = (
|
|
105
|
+
* remult.apiClient.httpClient = (
|
|
106
|
+
* input: RequestInfo | URL,
|
|
107
|
+
* init?: RequestInit
|
|
108
|
+
* ) => {
|
|
106
109
|
* return fetch(input, {
|
|
107
110
|
* ...init,
|
|
108
|
-
* headers:
|
|
109
|
-
*
|
|
110
|
-
*
|
|
111
|
+
* headers: authToken
|
|
112
|
+
* ? {
|
|
113
|
+
* ...init?.headers,
|
|
114
|
+
* authorization: 'Bearer ' + authToken,
|
|
115
|
+
* }
|
|
116
|
+
* : init?.headers,
|
|
117
|
+
*
|
|
111
118
|
* cache: 'no-store',
|
|
112
|
-
* })
|
|
113
|
-
* }
|
|
119
|
+
* })
|
|
120
|
+
* }
|
|
114
121
|
*/
|
|
115
122
|
httpClient?: ExternalHttpProvider | typeof fetch;
|
|
116
123
|
/**
|
package/src/context.js
CHANGED
|
@@ -57,6 +57,26 @@ exports.isBackend = isBackend;
|
|
|
57
57
|
var Remult = /** @class */ (function () {
|
|
58
58
|
function Remult(provider) {
|
|
59
59
|
var _this = this;
|
|
60
|
+
/**Return's a `Repository` of the specific entity type
|
|
61
|
+
* @example
|
|
62
|
+
* const taskRepo = remult.repo(Task);
|
|
63
|
+
* @see [Repository](https://remult.dev/docs/ref_repository.html)
|
|
64
|
+
* @param entity - the entity to use
|
|
65
|
+
* @param dataProvider - an optional alternative data provider to use. Useful for writing to offline storage or an alternative data provider
|
|
66
|
+
*/
|
|
67
|
+
this.repo = function (entity, dataProvider) {
|
|
68
|
+
if (dataProvider === undefined)
|
|
69
|
+
dataProvider = _this.dataProvider;
|
|
70
|
+
var dpCache = _this.repCache.get(dataProvider);
|
|
71
|
+
if (!dpCache)
|
|
72
|
+
_this.repCache.set(dataProvider, (dpCache = new Map()));
|
|
73
|
+
var r = dpCache.get(entity);
|
|
74
|
+
if (!r) {
|
|
75
|
+
dpCache.set(entity, (r = new RepositoryImplementation_js_1.RepositoryImplementation(entity, _this, dataProvider, (0, RepositoryImplementation_js_1.createOldEntity)(entity, _this))));
|
|
76
|
+
(0, relationInfoMember_js_1.verifyFieldRelationInfo)(r, _this, dataProvider);
|
|
77
|
+
}
|
|
78
|
+
return r;
|
|
79
|
+
};
|
|
60
80
|
/** The current data provider */
|
|
61
81
|
this.dataProvider = new rest_data_provider_js_1.RestDataProvider(function () { return _this.apiClient; });
|
|
62
82
|
/* @internal */
|
|
@@ -97,26 +117,6 @@ var Remult = /** @class */ (function () {
|
|
|
97
117
|
this.apiClient.wrapMessageHandling = apiClient.wrapMessageHandling;
|
|
98
118
|
}
|
|
99
119
|
}
|
|
100
|
-
/**Return's a `Repository` of the specific entity type
|
|
101
|
-
* @example
|
|
102
|
-
* const taskRepo = remult.repo(Task);
|
|
103
|
-
* @see [Repository](https://remult.dev/docs/ref_repository.html)
|
|
104
|
-
* @param entity - the entity to use
|
|
105
|
-
* @param dataProvider - an optional alternative data provider to use. Useful for writing to offline storage or an alternative data provider
|
|
106
|
-
*/
|
|
107
|
-
Remult.prototype.repo = function (entity, dataProvider) {
|
|
108
|
-
if (dataProvider === undefined)
|
|
109
|
-
dataProvider = this.dataProvider;
|
|
110
|
-
var dpCache = this.repCache.get(dataProvider);
|
|
111
|
-
if (!dpCache)
|
|
112
|
-
this.repCache.set(dataProvider, (dpCache = new Map()));
|
|
113
|
-
var r = dpCache.get(entity);
|
|
114
|
-
if (!r) {
|
|
115
|
-
dpCache.set(entity, (r = new RepositoryImplementation_js_1.RepositoryImplementation(entity, this, dataProvider, (0, RepositoryImplementation_js_1.createOldEntity)(entity, this))));
|
|
116
|
-
(0, relationInfoMember_js_1.verifyFieldRelationInfo)(r, this, dataProvider);
|
|
117
|
-
}
|
|
118
|
-
return r;
|
|
119
|
-
};
|
|
120
120
|
/** Checks if a user was authenticated */
|
|
121
121
|
Remult.prototype.authenticated = function () {
|
|
122
122
|
var _a;
|
|
@@ -2316,13 +2316,14 @@ var rowHelperImplementation = /** @class */ (function (_super) {
|
|
|
2316
2316
|
};
|
|
2317
2317
|
rowHelperImplementation.prototype.delete = function () {
|
|
2318
2318
|
return tslib_1.__awaiter(this, void 0, void 0, function () {
|
|
2319
|
-
var e, _a, _b, listener, e_36_1, err_2;
|
|
2319
|
+
var doDelete, e, _a, _b, listener, e_36_1, err_2;
|
|
2320
2320
|
var e_36, _c;
|
|
2321
2321
|
return tslib_1.__generator(this, function (_d) {
|
|
2322
2322
|
switch (_d.label) {
|
|
2323
2323
|
case 0:
|
|
2324
2324
|
this.__clearErrorsAndReportChanged();
|
|
2325
|
-
|
|
2325
|
+
doDelete = true;
|
|
2326
|
+
e = this.buildLifeCycleEvent(function () { return (doDelete = false); });
|
|
2326
2327
|
if (!!this.repository._dataProvider.isProxy) return [3 /*break*/, 2];
|
|
2327
2328
|
if (!this.info.entityInfo.deleting) return [3 /*break*/, 2];
|
|
2328
2329
|
return [4 /*yield*/, this.info.entityInfo.deleting(this.instance, e)];
|
|
@@ -2333,56 +2334,59 @@ var rowHelperImplementation = /** @class */ (function (_super) {
|
|
|
2333
2334
|
this.__assertValidity();
|
|
2334
2335
|
_d.label = 3;
|
|
2335
2336
|
case 3:
|
|
2336
|
-
_d.trys.push([3,
|
|
2337
|
+
_d.trys.push([3, 17, , 19]);
|
|
2338
|
+
if (!doDelete) return [3 /*break*/, 5];
|
|
2337
2339
|
return [4 /*yield*/, this.edp.delete(this.id)];
|
|
2338
2340
|
case 4:
|
|
2339
2341
|
_d.sent();
|
|
2340
|
-
|
|
2341
|
-
if (!this.info.entityInfo.deleted) return [3 /*break*/, 6];
|
|
2342
|
-
return [4 /*yield*/, this.info.entityInfo.deleted(this.instance, e)];
|
|
2342
|
+
_d.label = 5;
|
|
2343
2343
|
case 5:
|
|
2344
|
-
|
|
2345
|
-
|
|
2344
|
+
if (!!this.repository._dataProvider.isProxy) return [3 /*break*/, 7];
|
|
2345
|
+
if (!this.info.entityInfo.deleted) return [3 /*break*/, 7];
|
|
2346
|
+
return [4 /*yield*/, this.info.entityInfo.deleted(this.instance, e)];
|
|
2346
2347
|
case 6:
|
|
2347
|
-
|
|
2348
|
+
_d.sent();
|
|
2348
2349
|
_d.label = 7;
|
|
2349
2350
|
case 7:
|
|
2350
|
-
|
|
2351
|
-
_a = tslib_1.__values(this.repository.listeners.filter(function (x) { return x.deleted; })), _b = _a.next();
|
|
2351
|
+
if (!this.repository.listeners) return [3 /*break*/, 15];
|
|
2352
2352
|
_d.label = 8;
|
|
2353
2353
|
case 8:
|
|
2354
|
-
|
|
2354
|
+
_d.trys.push([8, 13, 14, 15]);
|
|
2355
|
+
_a = tslib_1.__values(this.repository.listeners.filter(function (x) { return x.deleted; })), _b = _a.next();
|
|
2356
|
+
_d.label = 9;
|
|
2357
|
+
case 9:
|
|
2358
|
+
if (!!_b.done) return [3 /*break*/, 12];
|
|
2355
2359
|
listener = _b.value;
|
|
2356
2360
|
return [4 /*yield*/, listener.deleted(this.instance)];
|
|
2357
|
-
case 9:
|
|
2358
|
-
_d.sent();
|
|
2359
|
-
_d.label = 10;
|
|
2360
2361
|
case 10:
|
|
2362
|
+
_d.sent();
|
|
2363
|
+
_d.label = 11;
|
|
2364
|
+
case 11:
|
|
2361
2365
|
_b = _a.next();
|
|
2362
|
-
return [3 /*break*/,
|
|
2363
|
-
case
|
|
2364
|
-
case
|
|
2366
|
+
return [3 /*break*/, 9];
|
|
2367
|
+
case 12: return [3 /*break*/, 15];
|
|
2368
|
+
case 13:
|
|
2365
2369
|
e_36_1 = _d.sent();
|
|
2366
2370
|
e_36 = { error: e_36_1 };
|
|
2367
|
-
return [3 /*break*/,
|
|
2368
|
-
case
|
|
2371
|
+
return [3 /*break*/, 15];
|
|
2372
|
+
case 14:
|
|
2369
2373
|
try {
|
|
2370
2374
|
if (_b && !_b.done && (_c = _a.return)) _c.call(_a);
|
|
2371
2375
|
}
|
|
2372
2376
|
finally { if (e_36) throw e_36.error; }
|
|
2373
2377
|
return [7 /*endfinally*/];
|
|
2374
|
-
case
|
|
2375
|
-
case
|
|
2378
|
+
case 15: return [4 /*yield*/, this.repository._remult.liveQueryPublisher.itemChanged(this.repository.metadata.key, [{ id: this.getId(), oldId: this.getOriginalId(), deleted: true }])];
|
|
2379
|
+
case 16:
|
|
2376
2380
|
_d.sent();
|
|
2377
2381
|
this._wasDeleted = true;
|
|
2378
|
-
return [3 /*break*/,
|
|
2379
|
-
case
|
|
2382
|
+
return [3 /*break*/, 19];
|
|
2383
|
+
case 17:
|
|
2380
2384
|
err_2 = _d.sent();
|
|
2381
2385
|
return [4 /*yield*/, this.catchSaveErrors(err_2)];
|
|
2382
|
-
case
|
|
2386
|
+
case 18:
|
|
2383
2387
|
_d.sent();
|
|
2384
|
-
return [3 /*break*/,
|
|
2385
|
-
case
|
|
2388
|
+
return [3 /*break*/, 19];
|
|
2389
|
+
case 19: return [2 /*return*/];
|
|
2386
2390
|
}
|
|
2387
2391
|
});
|
|
2388
2392
|
});
|
package/src/remult3/remult3.js
CHANGED
|
@@ -1,41 +1,48 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
//y1 - https://discord.com/channels/975754286384418847/1230386433093533698/1230386433093533698
|
|
4
|
+
//y1 - fix async hooks - was it fixed?
|
|
5
|
+
//p1 - release solid start with example project
|
|
3
6
|
//p1 - add documentation for bun sqlite
|
|
4
|
-
//
|
|
5
|
-
//
|
|
6
|
-
//
|
|
7
|
-
//
|
|
7
|
+
//p1 - fix dark background to also work on groups
|
|
8
|
+
//p1 - describe entity
|
|
9
|
+
//p1 - prepare the createEntity discussion
|
|
10
|
+
//p1 - fix async hooks
|
|
11
|
+
//p1 - write active record article
|
|
12
|
+
//p1 - maybe add decorator comment in the readme as well (I heard you've lost me in decorators) - and improve the describeClass function
|
|
13
|
+
//p1 - return error on connection error
|
|
14
|
+
//p1 - reconsider update many, maybe the second parameter should be in a set option - break existing
|
|
15
|
+
//p1 - consider upsert (where,set)
|
|
16
|
+
//p1 - consider id to also support keyof (id:['company','index'])
|
|
17
|
+
//p1 - consider including the admin in the tutorial - and maybe even in the demo when we setup the api
|
|
18
|
+
//y2 - JY suggestion of having generate as part of the ensure schema - not sure
|
|
19
|
+
//y2 - currently for string fields we default for 255 in knex (which is their default) why not just use text (varchar max) - and only use exact length when one is provided?
|
|
8
20
|
//p2 - create foreign key constraints in user code - https://codesandbox.io/p/devbox/fk-validator-tdshcs
|
|
9
21
|
//p1 - admin url1 - pocketbase use /_ for the admin //{allowed?:Allowed,url?:string}
|
|
10
|
-
//
|
|
11
|
-
//
|
|
22
|
+
//p1 - article auth.js with express - played with it, requires type="module" and a few more configurations - https://github.com/noam-honig/express-auth
|
|
23
|
+
//y2 - fix validators cache
|
|
12
24
|
//y2 - should we validate relations
|
|
13
|
-
//y1 - dependency of live query tables
|
|
25
|
+
//y1 - dependency of live query tables live query refresh of view on table update
|
|
14
26
|
//p1 - see why mongo tests do not run anymore
|
|
15
|
-
//
|
|
16
|
-
//y1 - consider replacing all errors with error classes that extend the base Error class
|
|
27
|
+
//y2 - consider replacing all errors with error classes that extend the base Error class
|
|
17
28
|
//y2 - should enforce integer - currently we probably round / truncate it
|
|
18
29
|
//y1 - talk about filter on objects that are not loaded - {
|
|
19
30
|
//category: repo(CompoundId).create({ company: 7, index: 3, name: '' }),
|
|
20
31
|
// }
|
|
21
|
-
//y1 - consider id to also support keyof (id:['company','index'])
|
|
22
32
|
/*y1 - talk about modules in init express with entities/controllers,initRequest,initApi
|
|
23
33
|
- support get with backend method, with url search params as the first parameter, & url as second parameter
|
|
24
34
|
- support returning redirect, and plain html (For sign in scenarios)
|
|
25
35
|
|
|
26
36
|
*/
|
|
27
37
|
//p1 - in this video I'll use remult to turn a frontend app to a fullstack app
|
|
28
|
-
/*
|
|
38
|
+
/*y2 - Talk JYC - JYC - add some integrity checks on delete
|
|
29
39
|
- soft delete
|
|
30
40
|
- delete restrict (implicit, or user selected - and if so, how) (delete & update of id)
|
|
31
41
|
|
|
32
42
|
*/
|
|
33
43
|
//y1 - consider sql expression gets a dbnames of it's own (that already has the "tableName" defined correctly) maybe also the filter translator
|
|
34
44
|
//y1 - tried to upgrade vitest, nuxt tests are failing with loading uuid - sounds familiar?
|
|
35
|
-
//y1 - I think that the tests you've setup don't cover next app router - I added to the setup, but not sure where else
|
|
36
45
|
//y1 - talk about the parameter issue with backend methods
|
|
37
|
-
//y1 - select data provider per entity https://discord.com/channels/975754286384418847/976006081748807690/1201415305885397003
|
|
38
|
-
//y1 - live query refresh of view on table update
|
|
39
46
|
//y1 - main vs master
|
|
40
47
|
//y2 - livequery for findfirst (@JY)
|
|
41
48
|
/*y2 -
|