remult 0.27.15 → 0.27.17

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.
@@ -216,6 +216,7 @@ export class RemultServerImplementation {
216
216
  r.route(this.options.rootPath + '/admin/').get(admin);
217
217
  r.route(this.options.rootPath + '/admin').get(admin);
218
218
  }
219
+ r.route(this.options.rootPath + '/me').get(this.process(async (remult, req, res) => res.success(remult.user ?? null)));
219
220
  if (this.options.subscriptionServer instanceof SseSubscriptionServer) {
220
221
  const streamPath = this.options.rootPath + '/' + streamUrl;
221
222
  r.route(streamPath).get(this.process(async (remult, req, res, origReq, origRes) => {
@@ -332,7 +333,7 @@ export class RemultServerImplementation {
332
333
  await what(remult, myReq, myRes, genReq, origRes, req);
333
334
  }
334
335
  finally {
335
- remultStatic.asyncContext.setInInitRequest(false);
336
+ // remultStatic.asyncContext.setInInitRequest(false)
336
337
  }
337
338
  }
338
339
  });
@@ -78,7 +78,7 @@ export function toPromise(p) {
78
78
  (x.status == 200 || x.status == 201) &&
79
79
  x.headers &&
80
80
  x.request &&
81
- x.data)
81
+ x.data !== undefined)
82
82
  //for axios
83
83
  return x.data;
84
84
  return x;
@@ -1,4 +1,4 @@
1
- import { RestDataProvider } from './data-providers/rest-data-provider.js';
1
+ import { buildFullUrl, RestDataProvider, } from './data-providers/rest-data-provider.js';
2
2
  import { LiveQueryClient } from './live-query/LiveQueryClient.js';
3
3
  import { SseSubscriptionClient } from './live-query/SseSubscriptionClient.js';
4
4
  import { remult } from './remult-proxy.js';
@@ -16,7 +16,7 @@ export class RemultAsyncLocalStorage {
16
16
  if (r)
17
17
  return r.remult;
18
18
  else
19
- throw new Error('remult object was requested outside of a valid context, try running it within initApi or a remult request cycle');
19
+ throw new Error('remult object was requested outside of a valid request cycle.valid context, try running `withRemult` or run within initApi or a remult request cycle');
20
20
  };
21
21
  }
22
22
  static disable() {
@@ -76,6 +76,18 @@ export class Remult {
76
76
  };
77
77
  /** Returns the current user's info */
78
78
  user;
79
+ /**
80
+ * Fetches user information from the backend and updates the `remult.user` object.
81
+ * Typically used during application initialization and user authentication.
82
+ *
83
+ * @returns {Promise<UserInfo | undefined>} A promise that resolves to the user's information or `undefined` if unavailable.
84
+ */
85
+ async initUser() {
86
+ const dp = buildRestDataProvider(this.apiClient.httpClient);
87
+ const data = await dp.get(buildFullUrl(this.apiClient.url, 'me'));
88
+ this.user = data ?? undefined;
89
+ return this.user;
90
+ }
79
91
  /** Checks if a user was authenticated */
80
92
  authenticated() {
81
93
  return this.user?.id !== undefined;
@@ -10,10 +10,7 @@ export class RestDataProvider {
10
10
  }
11
11
  getEntityDataProvider(entity) {
12
12
  return new RestEntityDataProvider(() => {
13
- let url = this.apiProvider()?.url;
14
- if (url === undefined || url === null)
15
- url = '/api';
16
- return url + '/' + entity.key;
13
+ return buildFullUrl(this.apiProvider()?.url, entity.key);
17
14
  }, () => {
18
15
  return buildRestDataProvider(this.apiProvider().httpClient);
19
16
  }, entity);
@@ -23,6 +20,11 @@ export class RestDataProvider {
23
20
  }
24
21
  isProxy = true;
25
22
  }
23
+ export function buildFullUrl(httpClientUrl, entityKey) {
24
+ if (httpClientUrl === undefined || httpClientUrl === null)
25
+ httpClientUrl = '/api';
26
+ return httpClientUrl + '/' + entityKey;
27
+ }
26
28
  //@internal
27
29
  export function findOptionsToJson(options, meta) {
28
30
  if (options.include) {
@@ -28,6 +28,9 @@ export class RemultProxy {
28
28
  set liveQueryPublisher(val) {
29
29
  remultStatic.remultFactory().liveQueryPublisher = val;
30
30
  }
31
+ initUser() {
32
+ return remultStatic.remultFactory().initUser();
33
+ }
31
34
  call(backendMethod, self, ...args) {
32
35
  return remultStatic.remultFactory().call(backendMethod, self, ...args);
33
36
  }
@@ -27,14 +27,18 @@ import { remultStatic } from '../remult-static.js';
27
27
  */
28
28
  export function Entity(key, ...options) {
29
29
  return (target, info) => {
30
- for (const rawFilterMember in target) {
31
- if (Object.prototype.hasOwnProperty.call(target, rawFilterMember)) {
32
- const element = target[rawFilterMember];
33
- if (element?.rawFilterInfo) {
34
- if (!element.rawFilterInfo.key)
35
- element.rawFilterInfo.key = rawFilterMember;
30
+ let theClass = target;
31
+ while (theClass != null) {
32
+ for (const rawFilterMember in theClass) {
33
+ if (Object.prototype.hasOwnProperty.call(theClass, rawFilterMember)) {
34
+ const element = target[rawFilterMember];
35
+ if (element?.rawFilterInfo) {
36
+ if (!element.rawFilterInfo.key)
37
+ element.rawFilterInfo.key = rawFilterMember;
38
+ }
36
39
  }
37
40
  }
41
+ theClass = Object.getPrototypeOf(theClass);
38
42
  }
39
43
  let factory = (remult) => {
40
44
  let r = {};
@@ -17,6 +17,45 @@ const wnn = [
17
17
  export const flags = {
18
18
  error500RetryCount: 4,
19
19
  };
20
+ /*p1 - create-remult discussion
21
+
22
+ p1 - should we add to remult some init code that populates remult based on a built in server route for current user.
23
+ - yes, `remult.initUser` - the url will be /api/me
24
+ - ask to add a todo example
25
+ - admin question
26
+ - ask to add a user table + password hash
27
+
28
+ - changeOrigin false to vite config
29
+ - test angular with auth
30
+ - check nextauth if the env variable should be called NEXTAUTH_SECRET or just AUTH_SECRET
31
+ /** @type {import('next').NextConfig}
32
+ const nextConfig = {
33
+ experimental: {
34
+ serverComponentsExternalPackages: ["knex"],
35
+ },
36
+ };
37
+
38
+ export default nextConfig;
39
+
40
+ p1 - Landing page:
41
+ - p2 include the selections (react,vite, postgres,auth)
42
+ - include server is alive test (remind to run dev-node)
43
+ - include the authenticated user with links to sign in & sign out
44
+ - include link to admin
45
+ - include todo
46
+
47
+ p1 - README:
48
+ - the selections
49
+ - how to run dev
50
+ - which environment variables to set
51
+
52
+
53
+ - should we add admin? ensureSchema:false etc...
54
+ - should we read existing database?
55
+ - knex issue with next
56
+
57
+
58
+ */
20
59
  //p1 - add aggregate to query
21
60
  //p1 - add parameter all to deleteMany, and updateMany
22
61
  //p1 filter.apply ApiPreFilter
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "remult",
3
- "version": "0.27.15",
3
+ "version": "0.27.17",
4
4
  "description": "A CRUD framework for full-stack TypeScript",
5
5
  "homepage": "https://remult.dev",
6
6
  "repository": {
@@ -378,6 +378,9 @@ var RemultServerImplementation = /** @class */ (function () {
378
378
  r.route(this.options.rootPath + '/admin/').get(admin);
379
379
  r.route(this.options.rootPath + '/admin').get(admin);
380
380
  }
381
+ r.route(this.options.rootPath + '/me').get(this.process(function (remult, req, res) { return tslib_1.__awaiter(_this, void 0, void 0, function () { var _a; return tslib_1.__generator(this, function (_b) {
382
+ return [2 /*return*/, res.success((_a = remult.user) !== null && _a !== void 0 ? _a : null)];
383
+ }); }); }));
381
384
  if (this.options.subscriptionServer instanceof SseSubscriptionServer_js_1.SseSubscriptionServer) {
382
385
  var streamPath = this.options.rootPath + '/' + SubscriptionChannel_js_1.streamUrl;
383
386
  r.route(streamPath).get(this.process(function (remult, req, res, origReq, origRes) { return tslib_1.__awaiter(_this, void 0, void 0, function () {
@@ -629,9 +632,7 @@ var RemultServerImplementation = /** @class */ (function () {
629
632
  case 7:
630
633
  _a.sent();
631
634
  return [3 /*break*/, 9];
632
- case 8:
633
- remult_static_js_1.remultStatic.asyncContext.setInInitRequest(false);
634
- return [7 /*endfinally*/];
635
+ case 8: return [7 /*endfinally*/];
635
636
  case 9: return [2 /*return*/];
636
637
  }
637
638
  });
@@ -120,7 +120,7 @@ function toPromise(p) {
120
120
  (x.status == 200 || x.status == 201) &&
121
121
  x.headers &&
122
122
  x.request &&
123
- x.data)
123
+ x.data !== undefined)
124
124
  //for axios
125
125
  return x.data;
126
126
  return x;
package/src/context.d.ts CHANGED
@@ -37,6 +37,13 @@ export declare class Remult {
37
37
  repo: <T>(entity: ClassType<T>, dataProvider?: DataProvider) => Repository<T>;
38
38
  /** Returns the current user's info */
39
39
  user?: UserInfo;
40
+ /**
41
+ * Fetches user information from the backend and updates the `remult.user` object.
42
+ * Typically used during application initialization and user authentication.
43
+ *
44
+ * @returns {Promise<UserInfo | undefined>} A promise that resolves to the user's information or `undefined` if unavailable.
45
+ */
46
+ initUser(): Promise<UserInfo | undefined>;
40
47
  /** Checks if a user was authenticated */
41
48
  authenticated(): boolean;
42
49
  /** checks if the user has any of the roles specified in the parameters
package/src/context.js CHANGED
@@ -26,7 +26,7 @@ var RemultAsyncLocalStorage = /** @class */ (function () {
26
26
  if (r)
27
27
  return r.remult;
28
28
  else
29
- throw new Error('remult object was requested outside of a valid context, try running it within initApi or a remult request cycle');
29
+ throw new Error('remult object was requested outside of a valid request cycle.valid context, try running `withRemult` or run within initApi or a remult request cycle');
30
30
  };
31
31
  };
32
32
  RemultAsyncLocalStorage.disable = function () {
@@ -132,6 +132,28 @@ var Remult = /** @class */ (function () {
132
132
  this.apiClient.wrapMessageHandling = apiClient.wrapMessageHandling;
133
133
  }
134
134
  }
135
+ /**
136
+ * Fetches user information from the backend and updates the `remult.user` object.
137
+ * Typically used during application initialization and user authentication.
138
+ *
139
+ * @returns {Promise<UserInfo | undefined>} A promise that resolves to the user's information or `undefined` if unavailable.
140
+ */
141
+ Remult.prototype.initUser = function () {
142
+ return tslib_1.__awaiter(this, void 0, void 0, function () {
143
+ var dp, data;
144
+ return tslib_1.__generator(this, function (_a) {
145
+ switch (_a.label) {
146
+ case 0:
147
+ dp = (0, buildRestDataProvider_js_1.buildRestDataProvider)(this.apiClient.httpClient);
148
+ return [4 /*yield*/, dp.get((0, rest_data_provider_js_1.buildFullUrl)(this.apiClient.url, 'me'))];
149
+ case 1:
150
+ data = _a.sent();
151
+ this.user = data !== null && data !== void 0 ? data : undefined;
152
+ return [2 /*return*/, this.user];
153
+ }
154
+ });
155
+ });
156
+ };
135
157
  /** Checks if a user was authenticated */
136
158
  Remult.prototype.authenticated = function () {
137
159
  var _a;
@@ -10,6 +10,7 @@ export declare class RestDataProvider implements DataProvider {
10
10
  transaction(action: (dataProvider: DataProvider) => Promise<void>): Promise<void>;
11
11
  isProxy: boolean;
12
12
  }
13
+ export declare function buildFullUrl(httpClientUrl: string | undefined, entityKey: string): string;
13
14
  export declare class RestEntityDataProvider implements EntityDataProvider, ProxyEntityDataProvider {
14
15
  private url;
15
16
  private http;
@@ -1,6 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.liveQueryAction = exports.RestDataProviderHttpProviderUsingFetch = exports.RestEntityDataProvider = exports.RestDataProvider = void 0;
4
+ exports.buildFullUrl = buildFullUrl;
4
5
  exports.findOptionsToJson = findOptionsToJson;
5
6
  exports.findOptionsFromJson = findOptionsFromJson;
6
7
  exports.addFilterToUrlAndReturnTrueIfSuccessful = addFilterToUrlAndReturnTrueIfSuccessful;
@@ -19,10 +20,7 @@ var RestDataProvider = /** @class */ (function () {
19
20
  var _this = this;
20
21
  return new RestEntityDataProvider(function () {
21
22
  var _a;
22
- var url = (_a = _this.apiProvider()) === null || _a === void 0 ? void 0 : _a.url;
23
- if (url === undefined || url === null)
24
- url = '/api';
25
- return url + '/' + entity.key;
23
+ return buildFullUrl((_a = _this.apiProvider()) === null || _a === void 0 ? void 0 : _a.url, entity.key);
26
24
  }, function () {
27
25
  return (0, buildRestDataProvider_js_1.buildRestDataProvider)(_this.apiProvider().httpClient);
28
26
  }, entity);
@@ -37,6 +35,11 @@ var RestDataProvider = /** @class */ (function () {
37
35
  return RestDataProvider;
38
36
  }());
39
37
  exports.RestDataProvider = RestDataProvider;
38
+ function buildFullUrl(httpClientUrl, entityKey) {
39
+ if (httpClientUrl === undefined || httpClientUrl === null)
40
+ httpClientUrl = '/api';
41
+ return httpClientUrl + '/' + entityKey;
42
+ }
40
43
  //@internal
41
44
  function findOptionsToJson(options, meta) {
42
45
  if (options.include) {
@@ -284,6 +284,9 @@ var RemultProxy = /** @class */ (function () {
284
284
  enumerable: false,
285
285
  configurable: true
286
286
  });
287
+ RemultProxy.prototype.initUser = function () {
288
+ return remult_static_js_1.remultStatic.remultFactory().initUser();
289
+ };
287
290
  RemultProxy.prototype.call = function (backendMethod, self) {
288
291
  var _a;
289
292
  var args = [];
@@ -35,14 +35,18 @@ function Entity(key) {
35
35
  options[_i - 1] = arguments[_i];
36
36
  }
37
37
  return function (target, info) {
38
- for (var rawFilterMember in target) {
39
- if (Object.prototype.hasOwnProperty.call(target, rawFilterMember)) {
40
- var element = target[rawFilterMember];
41
- if (element === null || element === void 0 ? void 0 : element.rawFilterInfo) {
42
- if (!element.rawFilterInfo.key)
43
- element.rawFilterInfo.key = rawFilterMember;
38
+ var theClass = target;
39
+ while (theClass != null) {
40
+ for (var rawFilterMember in theClass) {
41
+ if (Object.prototype.hasOwnProperty.call(theClass, rawFilterMember)) {
42
+ var element = target[rawFilterMember];
43
+ if (element === null || element === void 0 ? void 0 : element.rawFilterInfo) {
44
+ if (!element.rawFilterInfo.key)
45
+ element.rawFilterInfo.key = rawFilterMember;
46
+ }
44
47
  }
45
48
  }
49
+ theClass = Object.getPrototypeOf(theClass);
46
50
  }
47
51
  var factory = function (remult) {
48
52
  var e_1, _a;
@@ -20,6 +20,45 @@ var wnn = [
20
20
  exports.flags = {
21
21
  error500RetryCount: 4,
22
22
  };
23
+ /*p1 - create-remult discussion
24
+
25
+ p1 - should we add to remult some init code that populates remult based on a built in server route for current user.
26
+ - yes, `remult.initUser` - the url will be /api/me
27
+ - ask to add a todo example
28
+ - admin question
29
+ - ask to add a user table + password hash
30
+
31
+ - changeOrigin false to vite config
32
+ - test angular with auth
33
+ - check nextauth if the env variable should be called NEXTAUTH_SECRET or just AUTH_SECRET
34
+ /** @type {import('next').NextConfig}
35
+ const nextConfig = {
36
+ experimental: {
37
+ serverComponentsExternalPackages: ["knex"],
38
+ },
39
+ };
40
+
41
+ export default nextConfig;
42
+
43
+ p1 - Landing page:
44
+ - p2 include the selections (react,vite, postgres,auth)
45
+ - include server is alive test (remind to run dev-node)
46
+ - include the authenticated user with links to sign in & sign out
47
+ - include link to admin
48
+ - include todo
49
+
50
+ p1 - README:
51
+ - the selections
52
+ - how to run dev
53
+ - which environment variables to set
54
+
55
+
56
+ - should we add admin? ensureSchema:false etc...
57
+ - should we read existing database?
58
+ - knex issue with next
59
+
60
+
61
+ */
23
62
  //p1 - add aggregate to query
24
63
  //p1 - add parameter all to deleteMany, and updateMany
25
64
  //p1 filter.apply ApiPreFilter