proto.io 0.0.227 → 0.0.229

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.
Files changed (65) hide show
  1. package/README.md +1017 -0
  2. package/dist/adapters/file/aliyun-oss.d.mts +26 -0
  3. package/dist/adapters/file/aliyun-oss.d.mts.map +1 -0
  4. package/dist/adapters/file/aliyun-oss.d.ts +3 -3
  5. package/dist/adapters/file/database.d.mts +23 -0
  6. package/dist/adapters/file/database.d.mts.map +1 -0
  7. package/dist/adapters/file/database.d.ts +2 -2
  8. package/dist/adapters/file/database.js +1 -1
  9. package/dist/adapters/file/database.mjs +1 -1
  10. package/dist/adapters/file/filesystem.d.mts +25 -0
  11. package/dist/adapters/file/filesystem.d.mts.map +1 -0
  12. package/dist/adapters/file/filesystem.d.ts +3 -3
  13. package/dist/adapters/file/google-cloud-storage.d.mts +29 -0
  14. package/dist/adapters/file/google-cloud-storage.d.mts.map +1 -0
  15. package/dist/adapters/file/google-cloud-storage.d.ts +3 -3
  16. package/dist/adapters/storage/postgres.d.mts +299 -0
  17. package/dist/adapters/storage/postgres.d.mts.map +1 -0
  18. package/dist/adapters/storage/postgres.d.ts +5 -1
  19. package/dist/adapters/storage/postgres.d.ts.map +1 -1
  20. package/dist/adapters/storage/postgres.js +182 -74
  21. package/dist/adapters/storage/postgres.js.map +1 -1
  22. package/dist/adapters/storage/postgres.mjs +182 -74
  23. package/dist/adapters/storage/postgres.mjs.map +1 -1
  24. package/dist/client.d.mts +16 -0
  25. package/dist/client.d.mts.map +1 -0
  26. package/dist/client.d.ts +3 -3
  27. package/dist/client.js +1 -1
  28. package/dist/client.mjs +2 -2
  29. package/dist/index.d.mts +151 -0
  30. package/dist/index.d.mts.map +1 -0
  31. package/dist/index.d.ts +3 -3
  32. package/dist/index.js +68 -25
  33. package/dist/index.js.map +1 -1
  34. package/dist/index.mjs +69 -26
  35. package/dist/index.mjs.map +1 -1
  36. package/dist/internals/{base-DSo02iAX.d.ts → base-Bhrj5Pq1.d.ts} +2 -2
  37. package/dist/internals/{base-DSo02iAX.d.ts.map → base-Bhrj5Pq1.d.ts.map} +1 -1
  38. package/dist/internals/base-CiZHXD0o.d.mts +27 -0
  39. package/dist/internals/base-CiZHXD0o.d.mts.map +1 -0
  40. package/dist/internals/chunk-Cp2QN7ug.d.mts +17 -0
  41. package/dist/internals/chunk-Cp2QN7ug.d.mts.map +1 -0
  42. package/dist/internals/{chunk-BhwfdCdq.d.ts → chunk-o7lWIP-f.d.ts} +3 -3
  43. package/dist/internals/{chunk-BhwfdCdq.d.ts.map → chunk-o7lWIP-f.d.ts.map} +1 -1
  44. package/dist/internals/{index-vOFh8pVc.js → index-B0TO6h9r.js} +8 -1
  45. package/dist/internals/index-B0TO6h9r.js.map +1 -0
  46. package/dist/internals/{index-Cj45GkKv.d.ts → index-B710pfTH.d.ts} +2 -2
  47. package/dist/internals/{index-Cj45GkKv.d.ts.map → index-B710pfTH.d.ts.map} +1 -1
  48. package/dist/internals/{index-BWZIV3_T.mjs → index-DG2-4tQ1.mjs} +8 -1
  49. package/dist/internals/index-DG2-4tQ1.mjs.map +1 -0
  50. package/dist/internals/index-DwjvuRyl.d.mts +92 -0
  51. package/dist/internals/index-DwjvuRyl.d.mts.map +1 -0
  52. package/dist/internals/index-OwgXw07h.d.mts +2107 -0
  53. package/dist/internals/index-OwgXw07h.d.mts.map +1 -0
  54. package/dist/internals/{index-1ZK5N4yb.d.ts → index-OwgXw07h.d.ts} +49 -7
  55. package/dist/internals/index-OwgXw07h.d.ts.map +1 -0
  56. package/dist/internals/{validator-Bc1jRJfA.js → validator-CFlx3oyq.js} +33 -1
  57. package/dist/internals/validator-CFlx3oyq.js.map +1 -0
  58. package/dist/internals/{validator-Boj1PUjM.mjs → validator-DubDY921.mjs} +32 -2
  59. package/dist/internals/validator-DubDY921.mjs.map +1 -0
  60. package/package.json +7 -19
  61. package/dist/internals/index-1ZK5N4yb.d.ts.map +0 -1
  62. package/dist/internals/index-BWZIV3_T.mjs.map +0 -1
  63. package/dist/internals/index-vOFh8pVc.js.map +0 -1
  64. package/dist/internals/validator-Bc1jRJfA.js.map +0 -1
  65. package/dist/internals/validator-Boj1PUjM.mjs.map +0 -1
package/dist/index.mjs CHANGED
@@ -1,10 +1,10 @@
1
1
  import _ from 'lodash';
2
2
  import { Server } from '@o2ter/server-js';
3
- import { Q as QueryValidator, a as QueryExpression, r as resolveColumn, b as resolveDataType, c as QuerySelector } from './internals/validator-Boj1PUjM.mjs';
3
+ import { Q as QueryValidator, a as QueryExpression, b as QueryAccumulator, r as resolveColumn, c as resolveDataType, d as QuerySelector } from './internals/validator-DubDY921.mjs';
4
4
  import { P as PVK } from './internals/private-CNw40LZ7.mjs';
5
5
  import { prototypes, asyncStream, isBinaryData, base64ToBuffer } from '@o2ter/utils-js';
6
- import { L as LiveQuerySubscription, T as TQuery, d as deserialize, s as serialize, a as TUser, P as ProtoType, _ as _logLevels } from './internals/index-BWZIV3_T.mjs';
7
- export { b as ProtoClient, c as classExtends } from './internals/index-BWZIV3_T.mjs';
6
+ import { L as LiveQuerySubscription, T as TQuery, d as deserialize, s as serialize, a as TUser, P as ProtoType, _ as _logLevels } from './internals/index-DG2-4tQ1.mjs';
7
+ export { b as ProtoClient, c as classExtends } from './internals/index-DG2-4tQ1.mjs';
8
8
  import { i as isPointer, a as isRelation, T as TObject, d as defaultObjectKeyTypes, b as isShape, c as isPrimitive } from './internals/index-CSOoWRr1.mjs';
9
9
  import jwt from 'jsonwebtoken';
10
10
  import { Blob } from 'node:buffer';
@@ -113,6 +113,16 @@ const dispatcher = (proto, options) => {
113
113
  throw Error('No permission');
114
114
  return proto.storage.find(decoded);
115
115
  },
116
+ async groupFind(query, accumulators) {
117
+ QueryValidator.recursiveCheck(query);
118
+ const _validator = await validator();
119
+ const decoded = _validator.decodeQuery(normalize(query), 'read');
120
+ const isGet = _validator.isGetMethod(decoded.filter);
121
+ if (!_validator.validateCLPs(query.className, isGet ? 'get' : 'find'))
122
+ throw Error('No permission');
123
+ const acc = _.mapValues(accumulators, x => QueryAccumulator.decode(x).simplify());
124
+ return proto.storage.groupFind(decoded, acc);
125
+ },
116
126
  async nonrefs(query) {
117
127
  QueryValidator.recursiveCheck(query);
118
128
  const _validator = await validator();
@@ -309,6 +319,9 @@ class _ProtoQuery extends TQuery {
309
319
  yield self._objectMethods(object);
310
320
  });
311
321
  }
322
+ groupFind(accumulators, options) {
323
+ return this._dispatcher(options).groupFind(this._queryOptions, accumulators);
324
+ }
312
325
  nonrefs(options) {
313
326
  const self = this;
314
327
  return asyncStream(async function* () {
@@ -523,6 +536,8 @@ const defaultSchema = {
523
536
  'User': {
524
537
  fields: {
525
538
  password: 'object',
539
+ password_history: 'array',
540
+ password_changed_at: 'date',
526
541
  },
527
542
  classLevelPermissions: {
528
543
  find: [],
@@ -532,7 +547,7 @@ const defaultSchema = {
532
547
  fieldLevelPermissions: {
533
548
  _expired_at: { create: [], update: [] },
534
549
  },
535
- secureFields: ['password'],
550
+ secureFields: ['password', 'password_history', 'password_changed_at'],
536
551
  },
537
552
  'Role': {
538
553
  fields: {
@@ -701,7 +716,7 @@ const passwordHash = async (alg, password, options) => {
701
716
  ...options
702
717
  };
703
718
  };
704
- const varifyPassword = async (alg, password, options) => {
719
+ const verifyPassword = async (alg, password, options) => {
705
720
  if (!_.isString(options.salt))
706
721
  return false;
707
722
  if (!_.isString(options.derivedKey))
@@ -898,7 +913,7 @@ class ProtoInternal {
898
913
  }
899
914
  return callback(proxy(payload ?? proto));
900
915
  }
901
- async varifyPassword(proto, user, password, options) {
916
+ async verifyPassword(proto, user, password, options) {
902
917
  if (!user.id)
903
918
  throw Error('Invalid user object');
904
919
  const _user = await proto.InsecureQuery('User')
@@ -906,20 +921,46 @@ class ProtoInternal {
906
921
  .includes('_id', 'password')
907
922
  .first(options);
908
923
  const { alg, ...opts } = _user?.get('password') ?? {};
909
- return varifyPassword(alg, password, opts);
924
+ return verifyPassword(alg, password, opts);
910
925
  }
911
926
  async setPassword(proto, user, password, options) {
912
927
  if (!user.id)
913
928
  throw Error('Invalid user object');
914
929
  if (_.isEmpty(password))
915
930
  throw Error('Invalid password');
931
+ const { maxPasswordHistory, validatorCallback, } = this.options.passwordPolicy || {};
932
+ if (validatorCallback) {
933
+ const isValid = await validatorCallback(password, user);
934
+ if (!isValid)
935
+ throw Error('Password does not meet the policy requirements');
936
+ }
916
937
  const { alg, ...opts } = this.options.passwordHashOptions;
917
938
  const hashed = await passwordHash(alg, password, opts);
939
+ let history = [];
940
+ if (maxPasswordHistory && maxPasswordHistory > 0) {
941
+ const _user = await proto.InsecureQuery('User')
942
+ .equalTo('_id', user.id)
943
+ .includes('_id', 'password_history')
944
+ .first(options);
945
+ history = _.slice(_user?.get('password_history') ?? [], 0, maxPasswordHistory);
946
+ for (const entry of history) {
947
+ const { alg, ...opts } = entry;
948
+ if (await verifyPassword(alg, password, opts)) {
949
+ throw Error('Cannot reuse previous passwords');
950
+ }
951
+ }
952
+ }
918
953
  await proto.InsecureQuery('User')
919
954
  .equalTo('_id', user.id)
920
955
  .includes('_id')
921
956
  .updateOne({
922
957
  password: { $set: hashed },
958
+ password_history: {
959
+ $set: maxPasswordHistory && maxPasswordHistory > 0
960
+ ? _.slice([{ ...hashed, password }, ...history], 0, maxPasswordHistory)
961
+ : [],
962
+ },
963
+ password_changed_at: { $set: new Date() },
923
964
  }, options);
924
965
  }
925
966
  async unsetPassword(proto, user, options) {
@@ -930,6 +971,7 @@ class ProtoInternal {
930
971
  .includes('_id')
931
972
  .updateOne({
932
973
  password: { $set: {} },
974
+ password_changed_at: { $set: new Date() },
933
975
  }, options);
934
976
  }
935
977
  async updateFile(proto, object, options) {
@@ -947,8 +989,8 @@ class ProtoInternal {
947
989
  }
948
990
  return object;
949
991
  }
950
- varifyUploadToken(proto, token, isMaster) {
951
- const { nonce, attributes, maxUploadSize, } = (_.isString(token) ? this.jwtVarify(token, 'upload') ?? {} : {});
992
+ verifyUploadToken(proto, token, isMaster) {
993
+ const { nonce, attributes, maxUploadSize, } = (_.isString(token) ? this.jwtVerify(token, 'upload') ?? {} : {});
952
994
  if (!isMaster && !nonce)
953
995
  throw Error('Upload token is required');
954
996
  return {
@@ -961,7 +1003,7 @@ class ProtoInternal {
961
1003
  const data = object[PVK].extra.data;
962
1004
  if (_.isNil(data))
963
1005
  throw Error('Invalid file object');
964
- const { nonce, attributes = {}, maxUploadSize = this.options.maxUploadSize, } = options?.uploadToken ? this.varifyUploadToken(proto, options.uploadToken, options.master) : {};
1006
+ const { nonce, attributes = {}, maxUploadSize = this.options.maxUploadSize, } = options?.uploadToken ? this.verifyUploadToken(proto, options.uploadToken, options.master) : {};
965
1007
  if (nonce) {
966
1008
  const found = await proto.Query('File').equalTo('nonce', nonce).first({ master: true });
967
1009
  if (found)
@@ -1068,7 +1110,7 @@ class ProtoInternal {
1068
1110
  })();
1069
1111
  return jwt.sign(payload, this.options.jwtToken, opts);
1070
1112
  }
1071
- jwtVarify(token, options = {}) {
1113
+ jwtVerify(token, options = {}) {
1072
1114
  try {
1073
1115
  const opts = (() => {
1074
1116
  switch (options) {
@@ -1204,7 +1246,7 @@ class ProtoInternal {
1204
1246
  obj.set('data', params);
1205
1247
  obj.set('user', user);
1206
1248
  await obj.save({ master: true });
1207
- this.jobRunner.excuteJob(proto);
1249
+ this.jobRunner.executeJob(proto);
1208
1250
  return obj;
1209
1251
  }
1210
1252
  }
@@ -1266,7 +1308,7 @@ class JobRunner {
1266
1308
  job.set('completedAt', new Date());
1267
1309
  await job.save({ master: true });
1268
1310
  }
1269
- async excuteJob(proto) {
1311
+ async executeJob(proto) {
1270
1312
  if (this._running || this._stopped)
1271
1313
  return;
1272
1314
  this._running = true;
@@ -1296,7 +1338,7 @@ class JobRunner {
1296
1338
  finally {
1297
1339
  clearInterval(timer);
1298
1340
  }
1299
- this.excuteJob(proto);
1341
+ this.executeJob(proto);
1300
1342
  })();
1301
1343
  }
1302
1344
  this._running = false;
@@ -1330,7 +1372,7 @@ class JobRunner {
1330
1372
  const _sessionWithToken = async (proto, token) => {
1331
1373
  if (_.isEmpty(token))
1332
1374
  return;
1333
- const payload = proto[PVK].jwtVarify(token, 'login') ?? {};
1375
+ const payload = proto[PVK].jwtVerify(token, 'login') ?? {};
1334
1376
  if (!_.isString(payload.sessionId) || _.isEmpty(payload.sessionId))
1335
1377
  return;
1336
1378
  const session = await proto.Query('_Session')
@@ -1489,8 +1531,8 @@ const scheduleOp = {
1489
1531
  expireDocument: async (proto) => {
1490
1532
  await proto.gc();
1491
1533
  },
1492
- excuteJob: async (proto) => {
1493
- proto[PVK].jobRunner.excuteJob(proto);
1534
+ executeJob: async (proto) => {
1535
+ proto[PVK].jobRunner.executeJob(proto);
1494
1536
  },
1495
1537
  };
1496
1538
  const schedule = (proto) => {
@@ -1699,8 +1741,8 @@ class ProtoService extends ProtoType {
1699
1741
  if (req.res)
1700
1742
  await signUser(this, req.res, undefined, options);
1701
1743
  }
1702
- varifyPassword(user, password, options) {
1703
- return this[PVK].varifyPassword(this, user, password, options);
1744
+ verifyPassword(user, password, options) {
1745
+ return this[PVK].verifyPassword(this, user, password, options);
1704
1746
  }
1705
1747
  setPassword(user, password, options) {
1706
1748
  return this[PVK].setPassword(this, user, password, options);
@@ -1787,8 +1829,8 @@ class ProtoService extends ProtoType {
1787
1829
  jwtSign(payload, options) {
1788
1830
  return this[PVK].jwtSign(payload, options);
1789
1831
  }
1790
- jwtVarify(token, options = {}) {
1791
- return this[PVK].jwtVarify(token, options);
1832
+ jwtVerify(token, options = {}) {
1833
+ return this[PVK].jwtVerify(token, options);
1792
1834
  }
1793
1835
  notify(data) {
1794
1836
  return this[PVK].notify(this, data);
@@ -1974,7 +2016,7 @@ const verifyRelatedBy = (relatedBy) => {
1974
2016
  var classesRoute = (router, proto) => {
1975
2017
  const defaultHandler = async (req) => {
1976
2018
  const { name } = req.params;
1977
- const { operation, random, attributes, update, setOnInsert, relatedBy, silent, ...options } = deserialize(req.body);
2019
+ const { operation, accumulators, random, attributes, update, setOnInsert, relatedBy, silent, ...options } = deserialize(req.body);
1978
2020
  verifyRelatedBy(relatedBy);
1979
2021
  const payload = proto.connect(req);
1980
2022
  const query = relatedBy ? payload.Relation(payload.Object(relatedBy.className, relatedBy.id), relatedBy.key) : payload.Query(name);
@@ -1995,15 +2037,16 @@ var classesRoute = (router, proto) => {
1995
2037
  query[PVK].options.limit = query[PVK].options.limit ?? maxFetchLimit;
1996
2038
  if (query[PVK].options.limit > maxFetchLimit)
1997
2039
  throw Error('Query over limit');
1998
- return await query.find(opts);
2040
+ return query.find(opts);
1999
2041
  }
2042
+ case 'groupFind': return query.groupFind(accumulators, opts);
2000
2043
  case 'random':
2001
2044
  {
2002
2045
  const maxFetchLimit = payload[PVK].options.maxFetchLimit;
2003
2046
  query[PVK].options.limit = query[PVK].options.limit ?? maxFetchLimit;
2004
2047
  if (query[PVK].options.limit > maxFetchLimit)
2005
2048
  throw Error('Query over limit');
2006
- return await query.random(random, opts);
2049
+ return query.random(random, opts);
2007
2050
  }
2008
2051
  case 'nonrefs':
2009
2052
  {
@@ -2011,7 +2054,7 @@ var classesRoute = (router, proto) => {
2011
2054
  query[PVK].options.limit = query[PVK].options.limit ?? maxFetchLimit;
2012
2055
  if (query[PVK].options.limit > maxFetchLimit)
2013
2056
  throw Error('Query over limit');
2014
- return await query.nonrefs(opts);
2057
+ return query.nonrefs(opts);
2015
2058
  }
2016
2059
  case 'insert': return query.insert(attributes, opts);
2017
2060
  case 'insertMany': return query.insertMany(attributes, opts);
@@ -2281,7 +2324,7 @@ var filesRoute = (router, proto) => {
2281
2324
  await response(res, async () => {
2282
2325
  const payload = proto.connect(req);
2283
2326
  const uploadToken = req.header(UPLOAD_TOKEN_HEADER_NAME);
2284
- const { maxUploadSize } = payload[PVK].varifyUploadToken(payload, uploadToken, payload.isMaster);
2327
+ const { maxUploadSize } = payload[PVK].verifyUploadToken(payload, uploadToken, payload.isMaster);
2285
2328
  const { attributes, file } = await decodeFormStream(req, (file, info) => proto.fileStorage.create(proto, file, info, maxUploadSize));
2286
2329
  try {
2287
2330
  const obj = payload.Object('File');