proto.io 0.0.171 → 0.0.173

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 (32) hide show
  1. package/dist/adapters/file/database.d.ts +2 -2
  2. package/dist/adapters/file/filesystem.d.ts +2 -2
  3. package/dist/adapters/file/google-cloud-storage.d.ts +2 -2
  4. package/dist/adapters/storage/progres.d.ts +8 -1
  5. package/dist/adapters/storage/progres.js +66 -9
  6. package/dist/adapters/storage/progres.js.map +1 -1
  7. package/dist/adapters/storage/progres.mjs +66 -9
  8. package/dist/adapters/storage/progres.mjs.map +1 -1
  9. package/dist/client.d.ts +3 -3
  10. package/dist/client.js +1 -1
  11. package/dist/client.mjs +2 -2
  12. package/dist/index.d.ts +3 -3
  13. package/dist/index.js +137 -25
  14. package/dist/index.js.map +1 -1
  15. package/dist/index.mjs +138 -26
  16. package/dist/index.mjs.map +1 -1
  17. package/dist/internals/{index-B5u7VXjz.d.ts → index-BJnQhKf3.d.ts} +2 -2
  18. package/dist/internals/index-BJnQhKf3.d.ts.map +1 -0
  19. package/dist/internals/{index-D0hHgn2P.mjs → index-BZNPlw1L.mjs} +20 -1
  20. package/dist/internals/index-BZNPlw1L.mjs.map +1 -0
  21. package/dist/internals/{index-BJP46VGq.js → index-CIecB6mS.js} +20 -1
  22. package/dist/internals/index-CIecB6mS.js.map +1 -0
  23. package/dist/internals/{index-D_GYwO8X.d.ts → index-Cpv1DoEI.d.ts} +2 -2
  24. package/dist/internals/index-Cpv1DoEI.d.ts.map +1 -0
  25. package/dist/internals/{index-BB2vDnq0.d.ts → index-lX-M76Tn.d.ts} +16 -3
  26. package/dist/internals/index-lX-M76Tn.d.ts.map +1 -0
  27. package/package.json +1 -1
  28. package/dist/internals/index-B5u7VXjz.d.ts.map +0 -1
  29. package/dist/internals/index-BB2vDnq0.d.ts.map +0 -1
  30. package/dist/internals/index-BJP46VGq.js.map +0 -1
  31. package/dist/internals/index-D0hHgn2P.mjs.map +0 -1
  32. package/dist/internals/index-D_GYwO8X.d.ts.map +0 -1
package/dist/index.mjs CHANGED
@@ -3,8 +3,8 @@ import { Server } from '@o2ter/server-js';
3
3
  import { Q as QueryValidator, r as resolveColumn, a as resolveDataType, g as generateId } from './internals/random-BCpwYpyw.mjs';
4
4
  import { P as PVK } from './internals/private-BUpLAMZi.mjs';
5
5
  import { prototypes, asyncStream, asyncIterableToArray, isBinaryData, base64ToBuffer } from '@o2ter/utils-js';
6
- import { T as TQuery, M as MASTER_USER_HEADER_NAME, a as MASTER_PASS_HEADER_NAME, A as AUTH_COOKIE_KEY, b as TUser, P as ProtoType, s as serialize, d as deserialize, U as UPLOAD_TOKEN_HEADER_NAME } from './internals/index-D0hHgn2P.mjs';
7
- export { c as ProtoClient, e as classExtends, j as isFile, f as isObject, i as isQuery, h as isRole, g as isUser } from './internals/index-D0hHgn2P.mjs';
6
+ import { T as TQuery, M as MASTER_USER_HEADER_NAME, a as MASTER_PASS_HEADER_NAME, A as AUTH_COOKIE_KEY, b as TUser, P as ProtoType, s as serialize, d as deserialize, U as UPLOAD_TOKEN_HEADER_NAME } from './internals/index-BZNPlw1L.mjs';
7
+ export { c as ProtoClient, e as classExtends, j as isFile, f as isObject, i as isQuery, h as isRole, g as isUser } from './internals/index-BZNPlw1L.mjs';
8
8
  import { i as isPointer, a as isRelation, d as decodeUpdateOp, T as TObject, b as isShape, c as defaultObjectKeyTypes, e as isPrimitive } from './internals/index-BYbMU-Ao.mjs';
9
9
  import jwt from 'jsonwebtoken';
10
10
  import { Blob } from 'node:buffer';
@@ -183,6 +183,13 @@ const dispatcher = (proto, options, disableSecurity) => {
183
183
  throw Error('No permission');
184
184
  return proto.storage.atomic((storage) => storage.updateOne(_validator.decodeQuery(normalize(query), 'update'), normalize(_validator.validateFields(query.className, update, 'update', QueryValidator.patterns.path))));
185
185
  },
186
+ async updateMany(query, update) {
187
+ QueryValidator.recursiveCheck(query, update);
188
+ const _validator = await validator();
189
+ if (!_validator.validateCLPs(query.className, 'update'))
190
+ throw Error('No permission');
191
+ return proto.storage.atomic((storage) => storage.updateMany(_validator.decodeQuery(normalize(query), 'update'), normalize(_validator.validateFields(query.className, update, 'update', QueryValidator.patterns.path))));
192
+ },
186
193
  async upsertOne(query, update, setOnInsert) {
187
194
  QueryValidator.recursiveCheck(query, update, setOnInsert);
188
195
  const _validator = await validator();
@@ -202,6 +209,25 @@ const dispatcher = (proto, options, disableSecurity) => {
202
209
  }
203
210
  }
204
211
  },
212
+ async upsertMany(query, update, setOnInsert) {
213
+ QueryValidator.recursiveCheck(query, update, setOnInsert);
214
+ const _validator = await validator();
215
+ if (!_validator.validateCLPs(query.className, 'create', 'update'))
216
+ throw Error('No permission');
217
+ const _query = _validator.decodeQuery(normalize(query), 'update');
218
+ const _update = normalize(_validator.validateFields(query.className, update, 'update', QueryValidator.patterns.path));
219
+ const _setOnInsert = normalize(_validator.validateFields(query.className, setOnInsert, 'create', QueryValidator.patterns.name));
220
+ while (true) {
221
+ try {
222
+ return await proto.storage.atomic((storage) => storage.upsertMany(_query, _update, _setOnInsert), { lockTable: query.className, retry: true });
223
+ }
224
+ catch (e) {
225
+ if (proto.storage.isDuplicateIdError(e))
226
+ continue;
227
+ throw e;
228
+ }
229
+ }
230
+ },
205
231
  async deleteOne(query) {
206
232
  QueryValidator.recursiveCheck(query);
207
233
  const _validator = await validator();
@@ -440,6 +466,33 @@ class _ProtoQuery extends TQuery {
440
466
  }
441
467
  return result;
442
468
  }
469
+ async updateMany(update, options) {
470
+ const context = options?.context ?? {};
471
+ const silent = _.castArray(options?.silent ?? []);
472
+ const beforeSave = _.includes(silent, 'beforeSave') ? null : this._proto[PVK].triggers?.beforeSave?.[this.className];
473
+ const afterSave = _.includes(silent, 'afterSave') ? null : this._proto[PVK].triggers?.afterSave?.[this.className];
474
+ if (_.isFunction(beforeSave) || _.isFunction(afterSave)) {
475
+ const objects = this._objectMethods(await asyncIterableToArray(this._dispatcher(options).find(this._queryOptions)));
476
+ if (_.isEmpty(objects))
477
+ return 0;
478
+ if (_.isFunction(beforeSave)) {
479
+ await Promise.all(_.map(objects, object => beforeSave(proxy(Object.setPrototypeOf({ object, context }, options?.session ?? this._proto)))));
480
+ }
481
+ if (!_.isFunction(afterSave)) {
482
+ return this._dispatcher(options).updateMany({
483
+ ...this._queryOptions,
484
+ filter: { _id: { $in: _.map(objects, x => x.objectId) } },
485
+ }, update);
486
+ }
487
+ const updated = await Promise.all(_.map(objects, x => this._dispatcher(options).updateOne({
488
+ ...this._queryOptions,
489
+ filter: { _id: { $eq: x.objectId } },
490
+ }, update)));
491
+ await Promise.all(_.map(updated, object => afterSave(proxy(Object.setPrototypeOf({ object, context }, options?.session ?? this._proto)))));
492
+ return updated.length;
493
+ }
494
+ return this._dispatcher(options).updateMany(this._queryOptions, update);
495
+ }
443
496
  async upsertOne(update, setOnInsert, options) {
444
497
  const context = options?.context ?? {};
445
498
  const silent = _.castArray(options?.silent ?? []);
@@ -478,6 +531,47 @@ class _ProtoQuery extends TQuery {
478
531
  }
479
532
  return result;
480
533
  }
534
+ async upsertMany(update, setOnInsert, options) {
535
+ const context = options?.context ?? {};
536
+ const silent = _.castArray(options?.silent ?? []);
537
+ const beforeSave = _.includes(silent, 'beforeSave') ? null : this._proto[PVK].triggers?.beforeSave?.[this.className];
538
+ const afterSave = _.includes(silent, 'afterSave') ? null : this._proto[PVK].triggers?.afterSave?.[this.className];
539
+ if (_.isFunction(beforeSave) || _.isFunction(afterSave)) {
540
+ const objects = this._objectMethods(await asyncIterableToArray(this._dispatcher(options).find(this._queryOptions)));
541
+ if (!_.isEmpty(objects) && _.isFunction(beforeSave)) {
542
+ await Promise.all(_.map(objects, object => beforeSave(proxy(Object.setPrototypeOf({ object, context }, options?.session ?? this._proto)))));
543
+ }
544
+ if (_.isEmpty(objects)) {
545
+ const result = await this._dispatcher(options).insert({
546
+ className: this.className,
547
+ includes: this[PVK].options.includes,
548
+ matches: this[PVK].options.matches,
549
+ }, setOnInsert);
550
+ if (!result)
551
+ throw Error('Unable to insert document');
552
+ if (_.isFunction(afterSave)) {
553
+ await afterSave(proxy(Object.setPrototypeOf({ object: result, context }, options?.session ?? this._proto)));
554
+ }
555
+ return { updated: 0, inserted: 1 };
556
+ }
557
+ if (!_.isFunction(afterSave)) {
558
+ return {
559
+ inserted: 0,
560
+ updated: await this._dispatcher(options).updateMany({
561
+ ...this._queryOptions,
562
+ filter: { _id: { $in: _.map(objects, x => x.objectId) } },
563
+ }, update),
564
+ };
565
+ }
566
+ const updated = await Promise.all(_.map(objects, x => this._dispatcher(options).updateOne({
567
+ ...this._queryOptions,
568
+ filter: { _id: { $eq: x.objectId } },
569
+ }, update)));
570
+ await Promise.all(_.map(updated, object => afterSave(proxy(Object.setPrototypeOf({ object, context }, options?.session ?? this._proto)))));
571
+ return { updated: updated.length, inserted: 0 };
572
+ }
573
+ return this._dispatcher(options).upsertMany(this._queryOptions, update, setOnInsert);
574
+ }
481
575
  async deleteOne(options) {
482
576
  const context = options?.context ?? {};
483
577
  const silent = _.castArray(options?.silent ?? []);
@@ -848,7 +942,7 @@ class ProtoInternal {
848
942
  validateSchemaName(options.schema);
849
943
  const schema = mergeSchema(defaultSchema, options.fileStorage.schema, options.schema);
850
944
  validateSchema(schema);
851
- if (!_.every(options.roleInheritKeys, k => {
945
+ if (!_.every(options.roleResolver?.inheritKeys, k => {
852
946
  const type = resolveDataType(schema, 'Role', k);
853
947
  return type && isRelation(type) && _.includes(['User', 'Role'], type.target);
854
948
  })) {
@@ -1354,7 +1448,7 @@ class ProtoService extends ProtoType {
1354
1448
  constructor(options) {
1355
1449
  super();
1356
1450
  this[PVK] = new ProtoInternal({
1357
- roleInheritKeys: [],
1451
+ roleResolver: {},
1358
1452
  objectIdSize: 10,
1359
1453
  maxFetchLimit: 1000,
1360
1454
  maxUploadSize: 20 * 1024 * 1024,
@@ -1441,30 +1535,36 @@ class ProtoService extends ProtoType {
1441
1535
  return _.assign(payload, _.isFunction(attrs) ? attrs(payload) : attrs);
1442
1536
  }
1443
1537
  async userRoles(user) {
1444
- const roleInheritKeys = this[PVK].options.roleInheritKeys;
1445
- const schema = this.schema;
1446
- const userKeys = _.filter(roleInheritKeys, k => {
1447
- const type = resolveDataType(schema, 'Role', k);
1448
- return !!type && isRelation(type) && type.target === 'User';
1449
- });
1450
- const roleKeys = _.filter(roleInheritKeys, k => {
1451
- const type = resolveDataType(schema, 'Role', k);
1452
- return !!type && isRelation(type) && type.target === 'Role';
1453
- });
1454
- let queue = await this.Query('Role')
1455
- .or(_.map(_.uniq(['users', ...userKeys]), k => q => q.isIntersect(k, [user])))
1456
- .includes('name')
1457
- .find({ master: true });
1458
- let roles = queue;
1459
- while (!_.isEmpty(queue)) {
1460
- queue = await this.Query('Role')
1461
- .or(_.map(_.uniq(['roles', ...roleKeys]), k => q => q.isIntersect(k, queue)))
1462
- .notContainsIn('_id', _.compact(_.map(roles, x => x.objectId)))
1538
+ const self = this;
1539
+ const { inheritKeys, resolver } = self[PVK].options.roleResolver;
1540
+ const defaultResolver = async () => {
1541
+ const schema = self.schema;
1542
+ const userKeys = _.filter(inheritKeys, k => {
1543
+ const type = resolveDataType(schema, 'Role', k);
1544
+ return !!type && isRelation(type) && type.target === 'User';
1545
+ });
1546
+ const roleKeys = _.filter(inheritKeys, k => {
1547
+ const type = resolveDataType(schema, 'Role', k);
1548
+ return !!type && isRelation(type) && type.target === 'Role';
1549
+ });
1550
+ let queue = await self.Query('Role')
1551
+ .or(_.map(_.uniq(['users', ...userKeys]), k => q => q.isIntersect(k, [user])))
1463
1552
  .includes('name')
1464
1553
  .find({ master: true });
1465
- roles = _.uniqBy([...roles, ...queue], x => x.objectId);
1466
- }
1467
- return roles;
1554
+ let roles = queue;
1555
+ while (!_.isEmpty(queue)) {
1556
+ queue = await self.Query('Role')
1557
+ .or(_.map(_.uniq(['roles', ...roleKeys]), k => q => q.isIntersect(k, queue)))
1558
+ .notContainsIn('_id', _.compact(_.map(roles, x => x.objectId)))
1559
+ .includes('name')
1560
+ .find({ master: true });
1561
+ roles = _.uniqBy([...roles, ...queue], x => x.objectId);
1562
+ }
1563
+ return roles;
1564
+ };
1565
+ if (resolver)
1566
+ return resolver(user, defaultResolver);
1567
+ return defaultResolver();
1468
1568
  }
1469
1569
  async becomeUser(req, user, options) {
1470
1570
  if (!user.objectId)
@@ -1769,7 +1869,9 @@ var classesRoute = (router, proto) => {
1769
1869
  case 'insert': return query.insert(attributes, opts);
1770
1870
  case 'insertMany': return query.insertMany(attributes, opts);
1771
1871
  case 'updateOne': return query.updateOne(update, opts);
1872
+ case 'updateMany': return query.updateMany(update, opts);
1772
1873
  case 'upsertOne': return query.upsertOne(update, setOnInsert, opts);
1874
+ case 'upsertMany': return query.upsertMany(update, setOnInsert, opts);
1773
1875
  case 'deleteOne': return query.deleteOne(opts);
1774
1876
  case 'deleteMany': return query.deleteMany(opts);
1775
1877
  default: throw Error('Invalid operation');
@@ -1873,6 +1975,16 @@ var classesRoute = (router, proto) => {
1873
1975
  const payload = proto.connect(req);
1874
1976
  await response(res, async () => payload.refs(payload.Object(name, id), { master: payload.isMaster }));
1875
1977
  });
1978
+ router.patch('/classes/:name', Server.text({ type: '*/*' }), async (req, res) => {
1979
+ res.setHeader('Cache-Control', ['no-cache', 'no-store']);
1980
+ const { name } = req.params;
1981
+ const classes = proto.classes();
1982
+ if (!_.includes(classes, name))
1983
+ return void res.sendStatus(404);
1984
+ const payload = proto.connect(req);
1985
+ const update = _.mapValues(deserialize(req.body), v => ({ $set: v }));
1986
+ await response(res, () => createQuery(payload, req, false).updateMany(update, { master: payload.isMaster }));
1987
+ });
1876
1988
  router.patch('/classes/:name/:id', Server.text({ type: '*/*' }), async (req, res) => {
1877
1989
  res.setHeader('Cache-Control', ['no-cache', 'no-store']);
1878
1990
  const { name, id } = req.params;