@proteinjs/user-server 1.5.4 → 1.7.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.
Files changed (67) hide show
  1. package/CHANGELOG.md +33 -0
  2. package/dist/generated/index.d.ts +1 -4
  3. package/dist/generated/index.d.ts.map +1 -1
  4. package/dist/generated/index.js +4 -5
  5. package/dist/generated/index.js.map +1 -1
  6. package/dist/src/authorization/userCache.d.ts.map +1 -1
  7. package/dist/src/authorization/userCache.js +18 -3
  8. package/dist/src/authorization/userCache.js.map +1 -1
  9. package/dist/src/routes/avatar.d.ts +19 -0
  10. package/dist/src/routes/avatar.d.ts.map +1 -0
  11. package/dist/src/routes/avatar.js +108 -0
  12. package/dist/src/routes/avatar.js.map +1 -0
  13. package/dist/src/routes/devLogin.d.ts +15 -5
  14. package/dist/src/routes/devLogin.d.ts.map +1 -1
  15. package/dist/src/routes/devLogin.js +61 -13
  16. package/dist/src/routes/devLogin.js.map +1 -1
  17. package/dist/src/services/Signup.d.ts +16 -1
  18. package/dist/src/services/Signup.d.ts.map +1 -1
  19. package/dist/src/services/Signup.js +49 -15
  20. package/dist/src/services/Signup.js.map +1 -1
  21. package/dist/src/services/UpdateUserInfo.d.ts +40 -2
  22. package/dist/src/services/UpdateUserInfo.d.ts.map +1 -1
  23. package/dist/src/services/UpdateUserInfo.js +183 -12
  24. package/dist/src/services/UpdateUserInfo.js.map +1 -1
  25. package/dist/test/DevLogin.test.d.ts +2 -0
  26. package/dist/test/DevLogin.test.d.ts.map +1 -0
  27. package/dist/test/DevLogin.test.js +261 -0
  28. package/dist/test/DevLogin.test.js.map +1 -0
  29. package/dist/test/UpdateUserInfoAvatar.test.d.ts +2 -0
  30. package/dist/test/UpdateUserInfoAvatar.test.d.ts.map +1 -0
  31. package/dist/test/UpdateUserInfoAvatar.test.js +337 -0
  32. package/dist/test/UpdateUserInfoAvatar.test.js.map +1 -0
  33. package/dist/test/UpdateUserInfoSessionRefresh.test.d.ts +2 -0
  34. package/dist/test/UpdateUserInfoSessionRefresh.test.d.ts.map +1 -0
  35. package/dist/test/UpdateUserInfoSessionRefresh.test.js +94 -0
  36. package/dist/test/UpdateUserInfoSessionRefresh.test.js.map +1 -0
  37. package/dist/test/UserCacheMissingAccount.test.d.ts +2 -0
  38. package/dist/test/UserCacheMissingAccount.test.d.ts.map +1 -0
  39. package/dist/test/UserCacheMissingAccount.test.js +104 -0
  40. package/dist/test/UserCacheMissingAccount.test.js.map +1 -0
  41. package/dist/test/UserServerTestEnvironment.d.ts +26 -0
  42. package/dist/test/UserServerTestEnvironment.d.ts.map +1 -0
  43. package/dist/test/UserServerTestEnvironment.js +202 -0
  44. package/dist/test/UserServerTestEnvironment.js.map +1 -0
  45. package/dist/test/avatarRoute.test.d.ts +2 -0
  46. package/dist/test/avatarRoute.test.d.ts.map +1 -0
  47. package/dist/test/avatarRoute.test.js +222 -0
  48. package/dist/test/avatarRoute.test.js.map +1 -0
  49. package/generated/index.ts +4 -5
  50. package/jest.config.js +4 -1
  51. package/package.json +8 -5
  52. package/src/authorization/userCache.ts +17 -2
  53. package/src/heic-decode.d.ts +13 -0
  54. package/src/routes/avatar.ts +57 -0
  55. package/src/routes/devLogin.ts +50 -7
  56. package/src/services/Signup.ts +42 -11
  57. package/src/services/UpdateUserInfo.ts +124 -13
  58. package/test/DevLogin.test.ts +159 -0
  59. package/test/UpdateUserInfoAvatar.test.ts +174 -0
  60. package/test/UpdateUserInfoSessionRefresh.test.ts +37 -0
  61. package/test/UserCacheMissingAccount.test.ts +42 -0
  62. package/test/UserServerTestEnvironment.ts +97 -0
  63. package/test/avatarRoute.test.ts +111 -0
  64. package/test/emulatorLock.globalSetup.js +11 -0
  65. package/test/emulatorLock.globalTeardown.js +8 -0
  66. package/test/emulatorLock.js +124 -0
  67. package/test/fixtures/fixture.heic +0 -0
@@ -38,34 +38,82 @@ var __generator = (this && this.__generator) || function (thisArg, body) {
38
38
  Object.defineProperty(exports, "__esModule", { value: true });
39
39
  exports.devLogin = void 0;
40
40
  var logger_1 = require("@proteinjs/logger");
41
+ var Signup_1 = require("../services/Signup");
41
42
  var logger = new logger_1.Logger({ name: 'devLogin' });
43
+ /** Lowercased domain of an email address (the whole string when there is no `@`, which can never
44
+ * equal a real env domain — so malformed params fall out at the domain rail). */
45
+ var emailDomain = function (address) { return address.slice(address.lastIndexOf('@') + 1).toLowerCase(); };
42
46
  /**
43
- * DEV-ONLY session bootstrap: `GET /dev/login` establishes a session for the account named by
44
- * `DEV_AUTO_LOGIN_EMAIL` — no credentials involved — so automated dev-loop testing (agent-driven
45
- * browsers) can self-serve a session instead of stalling on the login form every time a cookie
46
- * is lost.
47
+ * DEV-ONLY session bootstrap: `GET /dev/login` establishes a session — no credentials involved —
48
+ * so automated dev-loop testing (agent-driven browsers) can self-serve a session instead of
49
+ * stalling on the login form. `?email=<addr>` selects the session's account so parallel
50
+ * verification can fan out over distinct users; absent, the `DEV_AUTO_LOGIN_EMAIL` account is
51
+ * used as before.
47
52
  *
48
53
  * Double-gated, acts only when BOTH hold; otherwise the path answers 404 as if unregistered:
49
54
  * 1. `process.env.DEVELOPMENT` — the dev-server switch, never set in prod images.
50
- * 2. `DEV_AUTO_LOGIN_EMAIL` — explicit per-launch opt-in naming exactly one account.
55
+ * 2. `DEV_AUTO_LOGIN_EMAIL` — explicit per-launch opt-in naming the default account.
56
+ *
57
+ * Domain rail: `?email` must share `DEV_AUTO_LOGIN_EMAIL`'s domain — even a dev server must not
58
+ * mint sessions (much less accounts) for arbitrary domains; anything else answers 400.
59
+ *
60
+ * A missing account is created through the normal signup creation path (`Signup.createAccount`)
61
+ * as a normal test user — password `test`, matching the seeded test-account convention, so
62
+ * interactive login works for the same identity. Composes with userCache's missing-account→guest
63
+ * seam: that covers sessions whose account was deleted AFTER minting; this ensures dev-minted
64
+ * sessions reference a real account from the start.
51
65
  */
52
66
  exports.devLogin = {
53
67
  path: '/dev/login',
54
68
  method: 'get',
55
69
  onRequest: function (request, response) { return __awaiter(void 0, void 0, void 0, function () {
56
- var email;
57
- var _a;
58
- return __generator(this, function (_b) {
59
- switch (_b.label) {
70
+ var envEmail, email, emailParam, requested, creation;
71
+ var _a, _b;
72
+ return __generator(this, function (_c) {
73
+ switch (_c.label) {
60
74
  case 0:
61
- email = ((_a = process.env.DEV_AUTO_LOGIN_EMAIL) !== null && _a !== void 0 ? _a : '').trim();
62
- if (!process.env.DEVELOPMENT || !email) {
75
+ envEmail = ((_a = process.env.DEV_AUTO_LOGIN_EMAIL) !== null && _a !== void 0 ? _a : '').trim();
76
+ if (!process.env.DEVELOPMENT || !envEmail) {
63
77
  response.status(404).send();
64
78
  return [2 /*return*/];
65
79
  }
66
- return [4 /*yield*/, new Promise(function (resolve) { return request.login(email, resolve); })];
80
+ email = envEmail;
81
+ emailParam = (_b = request.query) === null || _b === void 0 ? void 0 : _b.email;
82
+ if (emailParam !== undefined) {
83
+ requested = typeof emailParam === 'string' ? emailParam.trim() : '';
84
+ if (emailDomain(requested) !== emailDomain(envEmail)) {
85
+ response.status(400).send("/dev/login only accepts accounts on the @".concat(emailDomain(envEmail), " domain"));
86
+ return [2 /*return*/];
87
+ }
88
+ email = requested;
89
+ }
90
+ email = email.toLowerCase();
91
+ return [4 /*yield*/, new Signup_1.Signup().createAccount({
92
+ name: email.slice(0, email.indexOf('@')),
93
+ email: email,
94
+ password: 'test',
95
+ emailVerified: false,
96
+ invitedBy: null,
97
+ })];
67
98
  case 1:
68
- _b.sent();
99
+ creation = _c.sent();
100
+ if (creation === 'created') {
101
+ logger.info({ message: 'Dev auto-login created missing test account', obj: { email: email } });
102
+ }
103
+ return [4 /*yield*/, new Promise(function (resolve) { return request.login(email, resolve); })];
104
+ case 2:
105
+ _c.sent();
106
+ // Explicit save before redirecting: with a DB-backed session store, save-on-response-end
107
+ // races the redirected GET / — the follow-up request can read the session row before the
108
+ // write commits and render the login page (observed: first /dev/login load lands on /login,
109
+ // second succeeds). Awaiting the store write closes the race.
110
+ return [4 /*yield*/, new Promise(function (resolve) { return request.session.save(resolve); })];
111
+ case 3:
112
+ // Explicit save before redirecting: with a DB-backed session store, save-on-response-end
113
+ // races the redirected GET / — the follow-up request can read the session row before the
114
+ // write commits and render the login page (observed: first /dev/login load lands on /login,
115
+ // second succeeds). Awaiting the store write closes the race.
116
+ _c.sent();
69
117
  logger.info({ message: 'Dev auto-login session established', obj: { email: email } });
70
118
  response.redirect('/');
71
119
  return [2 /*return*/];
@@ -1 +1 @@
1
- {"version":3,"file":"devLogin.js","sourceRoot":"","sources":["../../../src/routes/devLogin.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AACA,4CAA2C;AAE3C,IAAM,MAAM,GAAG,IAAI,eAAM,CAAC,EAAE,IAAI,EAAE,UAAU,EAAE,CAAC,CAAC;AAEhD;;;;;;;;;GASG;AACU,QAAA,QAAQ,GAAU;IAC7B,IAAI,EAAE,YAAY;IAClB,MAAM,EAAE,KAAK;IACb,SAAS,EAAE,UAAO,OAAY,EAAE,QAAQ;;;;;;oBAChC,KAAK,GAAG,CAAC,MAAA,OAAO,CAAC,GAAG,CAAC,oBAAoB,mCAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;oBAC9D,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,WAAW,IAAI,CAAC,KAAK,EAAE;wBACtC,QAAQ,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC;wBAC5B,sBAAO;qBACR;oBAED,qBAAM,IAAI,OAAO,CAAC,UAAC,OAAO,IAAK,OAAA,OAAO,CAAC,KAAK,CAAC,KAAK,EAAE,OAAO,CAAC,EAA7B,CAA6B,CAAC,EAAA;;oBAA7D,SAA6D,CAAC;oBAC9D,MAAM,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,oCAAoC,EAAE,GAAG,EAAE,EAAE,KAAK,OAAA,EAAE,EAAE,CAAC,CAAC;oBAC/E,QAAQ,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC;;;;SACxB;CACF,CAAC"}
1
+ {"version":3,"file":"devLogin.js","sourceRoot":"","sources":["../../../src/routes/devLogin.ts"],"names":[],"mappings":"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"}
@@ -1,4 +1,4 @@
1
- import { SendInviteResponse, SignupService, InitializeSignupResponse, Invite, UserSignup } from '@proteinjs/user';
1
+ import { SendInviteResponse, SignupService, InitializeSignupResponse, Invite, User, UserSignup } from '@proteinjs/user';
2
2
  import { Loadable } from '@proteinjs/reflection';
3
3
  /**
4
4
  * How long an invite link stays usable. Deliberately generous: a legitimate invite that gets
@@ -39,6 +39,21 @@ export declare class Signup implements SignupService {
39
39
  * `DefaultInviteConfigFactory` defaults to invite optional.
40
40
  */
41
41
  initializeSignup(inviteToken: string | undefined): Promise<InitializeSignupResponse>;
42
+ /**
43
+ * Single owner of account-record creation: case-normalized existence check + sha256-hashed
44
+ * insert. Both doors into a user row go through here — the signup flow (`createUser`, which
45
+ * layers invite validation and confirmation emails on top) and the dev-login bootstrap
46
+ * (`devLogin`, which auto-creates missing same-domain test accounts). Not exposed as an RPC:
47
+ * the service surface is the `SignupService` INTERFACE (ServiceRouter walks its declared
48
+ * methods), so extra class methods stay server-internal.
49
+ */
50
+ createAccount(account: {
51
+ name: string;
52
+ email: string;
53
+ password: string;
54
+ emailVerified: boolean;
55
+ invitedBy: User['invitedBy'];
56
+ }): Promise<'created' | 'exists'>;
42
57
  /** Resolves an invite token, distinguishing "expired" from "never existed / already revoked". */
43
58
  private lookupInvite;
44
59
  }
@@ -1 +1 @@
1
- {"version":3,"file":"Signup.d.ts","sourceRoot":"","sources":["../../../src/services/Signup.ts"],"names":[],"mappings":"AACA,OAAO,EACL,kBAAkB,EAIlB,aAAa,EACb,wBAAwB,EAExB,MAAM,EACN,UAAU,EAEX,MAAM,iBAAiB,CAAC;AAUzB,OAAO,EAAE,QAAQ,EAAoB,MAAM,uBAAuB,CAAC;AAEnE;;;;GAIG;AACH,eAAO,MAAM,qBAAqB,KAAK,CAAC;AAExC,MAAM,WAAW,YAAY;IAC3B,YAAY,EAAE,OAAO,CAAC;CACvB;AAED;;;GAGG;AACH,MAAM,MAAM,YAAY,GAAG;IAAE,MAAM,EAAE,OAAO,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GAAG;IAAE,MAAM,EAAE,SAAS,CAAA;CAAE,GAAG;IAAE,MAAM,EAAE,UAAU,CAAA;CAAE,CAAC;AAEhH,MAAM,WAAW,0BAA2B,SAAQ,QAAQ;IAC1D,SAAS,IAAI,YAAY,CAAC;CAC3B;AAED,eAAO,MAAM,6BAA6B,QAAO,0BAShD,CAAC;AAEF,qBAAa,MAAO,YAAW,aAAa;IACnC,eAAe;;oCAEM,MAAM,QAAQ,GAAG,EAAE;;MAY7C;IAEI,UAAU,CAAC,IAAI,EAAE,UAAU,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IA6D3D,UAAU,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,kBAAkB,CAAC;IA0DtD,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAWhD;;;OAGG;IACG,gBAAgB,CAAC,WAAW,EAAE,MAAM,GAAG,SAAS,GAAG,OAAO,CAAC,wBAAwB,CAAC;IAoD1F,iGAAiG;YACnF,YAAY;CAc3B"}
1
+ {"version":3,"file":"Signup.d.ts","sourceRoot":"","sources":["../../../src/services/Signup.ts"],"names":[],"mappings":"AACA,OAAO,EACL,kBAAkB,EAIlB,aAAa,EACb,wBAAwB,EAExB,MAAM,EACN,IAAI,EACJ,UAAU,EAEX,MAAM,iBAAiB,CAAC;AAUzB,OAAO,EAAE,QAAQ,EAAoB,MAAM,uBAAuB,CAAC;AAEnE;;;;GAIG;AACH,eAAO,MAAM,qBAAqB,KAAK,CAAC;AAExC,MAAM,WAAW,YAAY;IAC3B,YAAY,EAAE,OAAO,CAAC;CACvB;AAED;;;GAGG;AACH,MAAM,MAAM,YAAY,GAAG;IAAE,MAAM,EAAE,OAAO,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GAAG;IAAE,MAAM,EAAE,SAAS,CAAA;CAAE,GAAG;IAAE,MAAM,EAAE,UAAU,CAAA;CAAE,CAAC;AAEhH,MAAM,WAAW,0BAA2B,SAAQ,QAAQ;IAC1D,SAAS,IAAI,YAAY,CAAC;CAC3B;AAED,eAAO,MAAM,6BAA6B,QAAO,0BAShD,CAAC;AAEF,qBAAa,MAAO,YAAW,aAAa;IACnC,eAAe;;oCAEM,MAAM,QAAQ,GAAG,EAAE;;MAY7C;IAEI,UAAU,CAAC,IAAI,EAAE,UAAU,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IA0D3D,UAAU,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,kBAAkB,CAAC;IA0DtD,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAWhD;;;OAGG;IACG,gBAAgB,CAAC,WAAW,EAAE,MAAM,GAAG,SAAS,GAAG,OAAO,CAAC,wBAAwB,CAAC;IAoD1F;;;;;;;OAOG;IACG,aAAa,CAAC,OAAO,EAAE;QAC3B,IAAI,EAAE,MAAM,CAAC;QACb,KAAK,EAAE,MAAM,CAAC;QACd,QAAQ,EAAE,MAAM,CAAC;QACjB,aAAa,EAAE,OAAO,CAAC;QACvB,SAAS,EAAE,IAAI,CAAC,WAAW,CAAC,CAAC;KAC9B,GAAG,OAAO,CAAC,SAAS,GAAG,QAAQ,CAAC;IAmBjC,iGAAiG;YACnF,YAAY;CAc3B"}
@@ -93,7 +93,7 @@ var Signup = /** @class */ (function () {
93
93
  Signup.prototype.createUser = function (user, token) {
94
94
  var _a, _b, _c, _d;
95
95
  return __awaiter(this, void 0, void 0, function () {
96
- var logger, db, initSignupResponse, invite, email, defaultEmailConfigFactory, config, emailSender, userRecord, _e, text_1, html_1, _f, text, html;
96
+ var logger, db, initSignupResponse, invite, email, defaultEmailConfigFactory, config, emailSender, creation, _e, text_1, html_1, _f, text, html;
97
97
  return __generator(this, function (_g) {
98
98
  switch (_g.label) {
99
99
  case 0:
@@ -119,10 +119,16 @@ var Signup = /** @class */ (function () {
119
119
  defaultEmailConfigFactory = (0, email_server_1.getDefaultSignupConfirmationEmailConfigFactory)();
120
120
  config = defaultEmailConfigFactory.getConfig();
121
121
  emailSender = new email_server_1.EmailSender();
122
- return [4 /*yield*/, db.get(user_1.tables.User, { email: email })];
122
+ return [4 /*yield*/, this.createAccount({
123
+ name: user.name,
124
+ email: email,
125
+ password: user.password,
126
+ emailVerified: invite ? true : false,
127
+ invitedBy: invite ? invite.invitedBy : null,
128
+ })];
123
129
  case 4:
124
- userRecord = _g.sent();
125
- if (!userRecord) return [3 /*break*/, 7];
130
+ creation = _g.sent();
131
+ if (!(creation === 'exists')) return [3 /*break*/, 7];
126
132
  logger.error({ message: "User with this email already exists", obj: { email: email } });
127
133
  if (!config.getExistingUserEmailContent) return [3 /*break*/, 6];
128
134
  _e = config.getExistingUserEmailContent(), text_1 = _e.text, html_1 = _e.html;
@@ -131,19 +137,10 @@ var Signup = /** @class */ (function () {
131
137
  _g.sent();
132
138
  _g.label = 6;
133
139
  case 6: return [2 /*return*/];
134
- case 7: return [4 /*yield*/, db.insert(user_1.tables.User, {
135
- name: user.name,
136
- email: email,
137
- password: (0, sha256_1.default)(user.password).toString(),
138
- emailVerified: invite ? true : false,
139
- roles: [],
140
- invitedBy: invite ? invite.invitedBy : null,
141
- })];
142
- case 8:
143
- _g.sent();
140
+ case 7:
144
141
  _f = config.getNewUserEmailContent(), text = _f.text, html = _f.html;
145
142
  return [4 /*yield*/, emailSender.sendEmail(__assign({ to: email, subject: config.newUserSubject || ((_d = config.options) === null || _d === void 0 ? void 0 : _d.subject) || 'Welcome!', text: text, html: html }, config.options))];
146
- case 9:
143
+ case 8:
147
144
  _g.sent();
148
145
  logger.info({ message: "Created user", obj: { email: email } });
149
146
  return [2 /*return*/];
@@ -293,6 +290,43 @@ var Signup = /** @class */ (function () {
293
290
  });
294
291
  });
295
292
  };
293
+ /**
294
+ * Single owner of account-record creation: case-normalized existence check + sha256-hashed
295
+ * insert. Both doors into a user row go through here — the signup flow (`createUser`, which
296
+ * layers invite validation and confirmation emails on top) and the dev-login bootstrap
297
+ * (`devLogin`, which auto-creates missing same-domain test accounts). Not exposed as an RPC:
298
+ * the service surface is the `SignupService` INTERFACE (ServiceRouter walks its declared
299
+ * methods), so extra class methods stay server-internal.
300
+ */
301
+ Signup.prototype.createAccount = function (account) {
302
+ return __awaiter(this, void 0, void 0, function () {
303
+ var db, email, existingUser;
304
+ return __generator(this, function (_a) {
305
+ switch (_a.label) {
306
+ case 0:
307
+ db = (0, db_1.getDbAsSystem)();
308
+ email = account.email.toLowerCase();
309
+ return [4 /*yield*/, db.get(user_1.tables.User, { email: email })];
310
+ case 1:
311
+ existingUser = _a.sent();
312
+ if (existingUser) {
313
+ return [2 /*return*/, 'exists'];
314
+ }
315
+ return [4 /*yield*/, db.insert(user_1.tables.User, {
316
+ name: account.name,
317
+ email: email,
318
+ password: (0, sha256_1.default)(account.password).toString(),
319
+ emailVerified: account.emailVerified,
320
+ roles: [],
321
+ invitedBy: account.invitedBy,
322
+ })];
323
+ case 2:
324
+ _a.sent();
325
+ return [2 /*return*/, 'created'];
326
+ }
327
+ });
328
+ });
329
+ };
296
330
  /** Resolves an invite token, distinguishing "expired" from "never existed / already revoked". */
297
331
  Signup.prototype.lookupInvite = function (token) {
298
332
  return __awaiter(this, void 0, void 0, function () {
@@ -1 +1 @@
1
- {"version":3,"file":"Signup.js","sourceRoot":"","sources":["../../../src/services/Signup.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"Signup.js","sourceRoot":"","sources":["../../../src/services/Signup.ts"],"names":[],"mappings":"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"}
@@ -1,11 +1,49 @@
1
- import { UpdatePasswordResponse, UpdateUserInfoService } from '@proteinjs/user';
1
+ import { UpdatePasswordResponse, UpdatedUser, UpdateUserInfoService } from '@proteinjs/user';
2
2
  export declare class UpdateUserInfo implements UpdateUserInfoService {
3
+ /** Stored avatar photos are exactly this: cover-cropped square JPEG. */
4
+ private static readonly AVATAR_SIZE;
5
+ private static readonly AVATAR_JPEG_QUALITY;
6
+ private static readonly MAX_AVATAR_PHOTO_BYTES;
7
+ private static readonly ACCEPTED_AVATAR_MIME_TYPES;
8
+ /** One emoji (possibly a ZWJ/flag/keycap sequence) — a handful of code units, never a sentence. */
9
+ private static readonly MAX_AVATAR_EMOJI_LENGTH;
10
+ /** Constructed (not a literal) because tsconfig targets es5; runs on Node, which supports `\p`. */
11
+ private static readonly EMOJI_PATTERN;
3
12
  serviceMetadata: {
4
13
  auth: {
5
14
  allUsers: boolean;
6
15
  };
7
16
  };
8
- updateName(name: string): Promise<void>;
17
+ updateName(name: string): Promise<UpdatedUser>;
9
18
  updatePassword(currentPassword: string, newPassword: string): Promise<UpdatePasswordResponse>;
19
+ updateAvatarPhoto(fileData: string, mimeType: string): Promise<UpdatedUser>;
20
+ updateAvatarEmoji(emoji: string): Promise<UpdatedUser>;
21
+ clearAvatar(): Promise<UpdatedUser>;
22
+ /**
23
+ * The single door to the avatar columns — every mutation assigns BOTH, which is what enforces
24
+ * the exactly-one-active invariant (photo OR emoji, never both). Also the previous photo's
25
+ * cleanup point: an avatar file the user row no longer points to is unreachable (the /avatar
26
+ * route serves only the id on the user row), so it is deleted here, after the row moves off it.
27
+ */
28
+ private setAvatar;
29
+ /**
30
+ * The one path every user-info mutation persists through: writes the changes AND refreshes the
31
+ * server session cache in the same stroke. userCache serializes the user into session data at
32
+ * request start; a bare DB write leaves every read through UserRepo in the same context — and
33
+ * long-lived contexts that keep their session data (sockets) — serving the STALE user until
34
+ * re-login (the rename wart). Fusing persist + refresh here means no future mutation can
35
+ * reintroduce that class of staleness.
36
+ */
37
+ private saveUserInfo;
38
+ /**
39
+ * Minimal avatar pipeline: decode, auto-orient from EXIF, cover-crop square, re-encode JPEG.
40
+ * sharp drops metadata (EXIF orientation/GPS) on re-encode by default — the stored avatar
41
+ * carries no camera metadata. HEIC/HEIF (default iPhone camera format) is decoded with WASM
42
+ * libheif (`heic-decode`) because sharp's prebuilt libvips has no HEVC decoder. NOTE: this
43
+ * duplicates the HEIC-normalization approach of chat-server's FileTransformer, which this
44
+ * package cannot import (layering) — future extraction target: a shared image-transform seam.
45
+ */
46
+ private toAvatarJpeg;
47
+ private decodeHeic;
10
48
  }
11
49
  //# sourceMappingURL=UpdateUserInfo.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"UpdateUserInfo.d.ts","sourceRoot":"","sources":["../../../src/services/UpdateUserInfo.ts"],"names":[],"mappings":"AACA,OAAO,EAAoB,sBAAsB,EAAE,qBAAqB,EAAE,MAAM,iBAAiB,CAAC;AAIlG,qBAAa,cAAe,YAAW,qBAAqB;IACnD,eAAe;;;;MAIpB;IAEI,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAMvC,cAAc,CAAC,eAAe,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,sBAAsB,CAAC;CAwDpG"}
1
+ {"version":3,"file":"UpdateUserInfo.d.ts","sourceRoot":"","sources":["../../../src/services/UpdateUserInfo.ts"],"names":[],"mappings":"AAKA,OAAO,EAA0B,sBAAsB,EAAE,WAAW,EAAE,qBAAqB,EAAE,MAAM,iBAAiB,CAAC;AAGrH,qBAAa,cAAe,YAAW,qBAAqB;IAC1D,wEAAwE;IACxE,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,WAAW,CAAO;IAC1C,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,mBAAmB,CAAM;IACjD,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,sBAAsB,CAAoB;IAClE,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,0BAA0B,CAMhD;IACF,mGAAmG;IACnG,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,uBAAuB,CAAM;IACrD,mGAAmG;IACnG,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,aAAa,CAAiF;IAE/G,eAAe;;;;MAIpB;IAEI,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC;IAI9C,cAAc,CAAC,eAAe,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,sBAAsB,CAAC;IAmD7F,iBAAiB,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC;IAoB3E,iBAAiB,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC;IActD,WAAW,IAAI,OAAO,CAAC,WAAW,CAAC;IAIzC;;;;;OAKG;YACW,SAAS;IAWvB;;;;;;;OAOG;YACW,YAAY;IAW1B;;;;;;;OAOG;YACW,YAAY;YAWZ,UAAU;CAMzB"}
@@ -51,10 +51,13 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
51
51
  };
52
52
  Object.defineProperty(exports, "__esModule", { value: true });
53
53
  exports.UpdateUserInfo = void 0;
54
+ var sharp_1 = __importDefault(require("sharp"));
55
+ var heic_decode_1 = __importDefault(require("heic-decode"));
56
+ var sha256_1 = __importDefault(require("crypto-js/sha256"));
54
57
  var db_1 = require("@proteinjs/db");
58
+ var db_file_1 = require("@proteinjs/db-file");
55
59
  var user_1 = require("@proteinjs/user");
56
60
  var email_server_1 = require("@proteinjs/email-server");
57
- var sha256_1 = __importDefault(require("crypto-js/sha256"));
58
61
  var UpdateUserInfo = /** @class */ (function () {
59
62
  function UpdateUserInfo() {
60
63
  this.serviceMetadata = {
@@ -65,16 +68,10 @@ var UpdateUserInfo = /** @class */ (function () {
65
68
  }
66
69
  UpdateUserInfo.prototype.updateName = function (name) {
67
70
  return __awaiter(this, void 0, void 0, function () {
68
- var db, user;
69
71
  return __generator(this, function (_a) {
70
72
  switch (_a.label) {
71
- case 0:
72
- db = (0, db_1.getDbAsSystem)();
73
- user = new user_1.UserRepo().getUser();
74
- return [4 /*yield*/, db.update(user_1.tables.User, { name: name }, { id: user.id })];
75
- case 1:
76
- _a.sent();
77
- return [2 /*return*/];
73
+ case 0: return [4 /*yield*/, this.saveUserInfo({ name: name })];
74
+ case 1: return [2 /*return*/, _a.sent()];
78
75
  }
79
76
  });
80
77
  });
@@ -119,9 +116,7 @@ var UpdateUserInfo = /** @class */ (function () {
119
116
  case 5:
120
117
  _b.trys.push([5, 7, , 8]);
121
118
  hashedNewPassword = (0, sha256_1.default)(newPassword).toString();
122
- return [4 /*yield*/, db.update(user_1.tables.User, {
123
- password: hashedNewPassword,
124
- }, { id: user.id })];
119
+ return [4 /*yield*/, this.saveUserInfo({ password: hashedNewPassword })];
125
120
  case 6:
126
121
  _b.sent();
127
122
  return [3 /*break*/, 8];
@@ -138,6 +133,182 @@ var UpdateUserInfo = /** @class */ (function () {
138
133
  });
139
134
  });
140
135
  };
136
+ UpdateUserInfo.prototype.updateAvatarPhoto = function (fileData, mimeType) {
137
+ return __awaiter(this, void 0, void 0, function () {
138
+ var imageBytes, jpeg, file;
139
+ return __generator(this, function (_a) {
140
+ switch (_a.label) {
141
+ case 0:
142
+ if (!UpdateUserInfo.ACCEPTED_AVATAR_MIME_TYPES.includes(mimeType)) {
143
+ throw new Error("Unsupported avatar image type '".concat(mimeType, "'. Accepted: ").concat(UpdateUserInfo.ACCEPTED_AVATAR_MIME_TYPES.join(', ')));
144
+ }
145
+ imageBytes = Buffer.from(fileData, 'base64');
146
+ if (imageBytes.length > UpdateUserInfo.MAX_AVATAR_PHOTO_BYTES) {
147
+ throw new Error("Avatar photo is too large (max 10MB)");
148
+ }
149
+ return [4 /*yield*/, this.toAvatarJpeg(imageBytes, mimeType)];
150
+ case 1:
151
+ jpeg = _a.sent();
152
+ return [4 /*yield*/, new db_file_1.FileStorage().createFile({ name: 'avatar.jpg', type: 'image/jpeg', size: jpeg.length }, jpeg.toString('base64'))];
153
+ case 2:
154
+ file = _a.sent();
155
+ return [4 /*yield*/, this.setAvatar({ avatarEmoji: null, avatarFileId: file.id })];
156
+ case 3: return [2 /*return*/, _a.sent()];
157
+ }
158
+ });
159
+ });
160
+ };
161
+ UpdateUserInfo.prototype.updateAvatarEmoji = function (emoji) {
162
+ return __awaiter(this, void 0, void 0, function () {
163
+ var trimmed;
164
+ return __generator(this, function (_a) {
165
+ switch (_a.label) {
166
+ case 0:
167
+ trimmed = emoji.trim();
168
+ if (!trimmed ||
169
+ trimmed.length > UpdateUserInfo.MAX_AVATAR_EMOJI_LENGTH ||
170
+ /\s/.test(trimmed) ||
171
+ !UpdateUserInfo.EMOJI_PATTERN.test(trimmed)) {
172
+ throw new Error("Avatar emoji must be a single short emoji");
173
+ }
174
+ return [4 /*yield*/, this.setAvatar({ avatarEmoji: trimmed, avatarFileId: null })];
175
+ case 1: return [2 /*return*/, _a.sent()];
176
+ }
177
+ });
178
+ });
179
+ };
180
+ UpdateUserInfo.prototype.clearAvatar = function () {
181
+ return __awaiter(this, void 0, void 0, function () {
182
+ return __generator(this, function (_a) {
183
+ switch (_a.label) {
184
+ case 0: return [4 /*yield*/, this.setAvatar({ avatarEmoji: null, avatarFileId: null })];
185
+ case 1: return [2 /*return*/, _a.sent()];
186
+ }
187
+ });
188
+ });
189
+ };
190
+ /**
191
+ * The single door to the avatar columns — every mutation assigns BOTH, which is what enforces
192
+ * the exactly-one-active invariant (photo OR emoji, never both). Also the previous photo's
193
+ * cleanup point: an avatar file the user row no longer points to is unreachable (the /avatar
194
+ * route serves only the id on the user row), so it is deleted here, after the row moves off it.
195
+ */
196
+ UpdateUserInfo.prototype.setAvatar = function (avatar) {
197
+ return __awaiter(this, void 0, void 0, function () {
198
+ var userId, previousAvatarFileId, updated;
199
+ return __generator(this, function (_a) {
200
+ switch (_a.label) {
201
+ case 0:
202
+ userId = new user_1.UserRepo().getUser().id;
203
+ return [4 /*yield*/, (0, db_1.getDbAsSystem)().get(user_1.tables.User, { id: userId })];
204
+ case 1:
205
+ previousAvatarFileId = (_a.sent()).avatarFileId;
206
+ return [4 /*yield*/, this.saveUserInfo(avatar)];
207
+ case 2:
208
+ updated = _a.sent();
209
+ if (!(previousAvatarFileId && previousAvatarFileId !== avatar.avatarFileId)) return [3 /*break*/, 4];
210
+ return [4 /*yield*/, new db_file_1.FileStorage().deleteFile(previousAvatarFileId)];
211
+ case 3:
212
+ _a.sent();
213
+ _a.label = 4;
214
+ case 4: return [2 /*return*/, updated];
215
+ }
216
+ });
217
+ });
218
+ };
219
+ /**
220
+ * The one path every user-info mutation persists through: writes the changes AND refreshes the
221
+ * server session cache in the same stroke. userCache serializes the user into session data at
222
+ * request start; a bare DB write leaves every read through UserRepo in the same context — and
223
+ * long-lived contexts that keep their session data (sockets) — serving the STALE user until
224
+ * re-login (the rename wart). Fusing persist + refresh here means no future mutation can
225
+ * reintroduce that class of staleness.
226
+ */
227
+ UpdateUserInfo.prototype.saveUserInfo = function (changes) {
228
+ return __awaiter(this, void 0, void 0, function () {
229
+ var userRepo, userId, db, updated;
230
+ return __generator(this, function (_a) {
231
+ switch (_a.label) {
232
+ case 0:
233
+ userRepo = new user_1.UserRepo();
234
+ userId = userRepo.getUser().id;
235
+ db = (0, db_1.getDbAsSystem)();
236
+ return [4 /*yield*/, db.update(user_1.tables.User, changes, { id: userId })];
237
+ case 1:
238
+ _a.sent();
239
+ return [4 /*yield*/, db.get(user_1.tables.User, { id: userId })];
240
+ case 2:
241
+ updated = _a.sent();
242
+ delete updated.password; // the same password-less shape userCache caches
243
+ userRepo.setUser(updated);
244
+ return [2 /*return*/, updated];
245
+ }
246
+ });
247
+ });
248
+ };
249
+ /**
250
+ * Minimal avatar pipeline: decode, auto-orient from EXIF, cover-crop square, re-encode JPEG.
251
+ * sharp drops metadata (EXIF orientation/GPS) on re-encode by default — the stored avatar
252
+ * carries no camera metadata. HEIC/HEIF (default iPhone camera format) is decoded with WASM
253
+ * libheif (`heic-decode`) because sharp's prebuilt libvips has no HEVC decoder. NOTE: this
254
+ * duplicates the HEIC-normalization approach of chat-server's FileTransformer, which this
255
+ * package cannot import (layering) — future extraction target: a shared image-transform seam.
256
+ */
257
+ UpdateUserInfo.prototype.toAvatarJpeg = function (imageBytes, mimeType) {
258
+ return __awaiter(this, void 0, void 0, function () {
259
+ var pipeline, _a;
260
+ return __generator(this, function (_b) {
261
+ switch (_b.label) {
262
+ case 0:
263
+ if (!(mimeType === 'image/heic' || mimeType === 'image/heif')) return [3 /*break*/, 2];
264
+ return [4 /*yield*/, this.decodeHeic(imageBytes)];
265
+ case 1:
266
+ _a = _b.sent();
267
+ return [3 /*break*/, 3];
268
+ case 2:
269
+ _a = (0, sharp_1.default)(imageBytes).rotate();
270
+ _b.label = 3;
271
+ case 3:
272
+ pipeline = _a;
273
+ return [4 /*yield*/, pipeline
274
+ .resize(UpdateUserInfo.AVATAR_SIZE, UpdateUserInfo.AVATAR_SIZE, { fit: 'cover' })
275
+ .jpeg({ quality: UpdateUserInfo.AVATAR_JPEG_QUALITY })
276
+ .toBuffer()];
277
+ case 4: return [2 /*return*/, _b.sent()];
278
+ }
279
+ });
280
+ });
281
+ };
282
+ UpdateUserInfo.prototype.decodeHeic = function (imageBytes) {
283
+ return __awaiter(this, void 0, void 0, function () {
284
+ var _a, width, height, data;
285
+ return __generator(this, function (_b) {
286
+ switch (_b.label) {
287
+ case 0: return [4 /*yield*/, (0, heic_decode_1.default)({ buffer: imageBytes })];
288
+ case 1:
289
+ _a = _b.sent(), width = _a.width, height = _a.height, data = _a.data;
290
+ return [2 /*return*/, (0, sharp_1.default)(Buffer.from(data.buffer, data.byteOffset, data.byteLength), {
291
+ raw: { width: width, height: height, channels: 4 },
292
+ })];
293
+ }
294
+ });
295
+ });
296
+ };
297
+ /** Stored avatar photos are exactly this: cover-cropped square JPEG. */
298
+ UpdateUserInfo.AVATAR_SIZE = 512;
299
+ UpdateUserInfo.AVATAR_JPEG_QUALITY = 85;
300
+ UpdateUserInfo.MAX_AVATAR_PHOTO_BYTES = 10 * 1024 * 1024;
301
+ UpdateUserInfo.ACCEPTED_AVATAR_MIME_TYPES = [
302
+ 'image/jpeg',
303
+ 'image/png',
304
+ 'image/webp',
305
+ 'image/heic',
306
+ 'image/heif',
307
+ ];
308
+ /** One emoji (possibly a ZWJ/flag/keycap sequence) — a handful of code units, never a sentence. */
309
+ UpdateUserInfo.MAX_AVATAR_EMOJI_LENGTH = 16;
310
+ /** Constructed (not a literal) because tsconfig targets es5; runs on Node, which supports `\p`. */
311
+ UpdateUserInfo.EMOJI_PATTERN = new RegExp('[\\p{Extended_Pictographic}\\p{Regional_Indicator}\\u20E3]', 'u');
141
312
  return UpdateUserInfo;
142
313
  }());
143
314
  exports.UpdateUserInfo = UpdateUserInfo;
@@ -1 +1 @@
1
- {"version":3,"file":"UpdateUserInfo.js","sourceRoot":"","sources":["../../../src/services/UpdateUserInfo.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,oCAA8C;AAC9C,wCAAkG;AAClG,wDAAmG;AACnG,4DAAsC;AAEtC;IAAA;QACS,oBAAe,GAAG;YACvB,IAAI,EAAE;gBACJ,QAAQ,EAAE,IAAI;aACf;SACF,CAAC;IAgEJ,CAAC;IA9DO,mCAAU,GAAhB,UAAiB,IAAY;;;;;;wBACrB,EAAE,GAAG,IAAA,kBAAa,GAAE,CAAC;wBACrB,IAAI,GAAG,IAAI,eAAQ,EAAE,CAAC,OAAO,EAAE,CAAC;wBACtC,qBAAM,EAAE,CAAC,MAAM,CAAC,aAAM,CAAC,IAAI,EAAE,EAAE,IAAI,MAAA,EAAE,EAAE,EAAE,EAAE,EAAE,IAAI,CAAC,EAAE,EAAE,CAAC,EAAA;;wBAAvD,SAAuD,CAAC;;;;;KACzD;IAEK,uCAAc,GAApB,UAAqB,eAAuB,EAAE,WAAmB;;;;;;;wBACzD,EAAE,GAAG,IAAA,kBAAa,GAAE,CAAC;wBACrB,MAAM,GAAG,IAAI,eAAQ,EAAE,CAAC,OAAO,EAAE,CAAC,EAAE,CAAC;wBAGrC,qBAAqB,GAAG,IAAA,gBAAM,EAAC,eAAe,CAAC,CAAC,QAAQ,EAAE,CAAC;wBACpD,qBAAM,EAAE,CAAC,GAAG,CAAC,aAAM,CAAC,IAAI,EAAE,EAAE,EAAE,EAAE,MAAM,EAAE,CAAC,EAAA;;wBAAhD,IAAI,GAAG,SAAyC;wBACtD,IAAI,qBAAqB,KAAK,IAAI,CAAC,QAAQ,EAAE;4BAC3C,sBAAO;oCACL,OAAO,EAAE,KAAK;oCACd,KAAK,EAAE,kBAAkB;iCAC1B,EAAC;yBACH;;;;wBAGO,WAAW,GAAG,IAAI,0BAAW,EAAE,CAAC;wBAChC,oBAAoB,GAAG,IAAA,0DAA2C,GAAE,CAAC;wBACrE,MAAM,GAAG,oBAAoB,CAAC,SAAS,EAAE,CAAC;wBAEhD,iDAAiD;wBACjD,qBAAM,WAAW,CAAC,SAAS,YACzB,EAAE,EAAE,IAAI,CAAC,KAAK,EACd,OAAO,EAAE,CAAA,MAAA,MAAM,CAAC,OAAO,0CAAE,OAAO,KAAI,gCAAgC,EACpE,IAAI,EAAE,MAAM,CAAC,IAAI,EACjB,IAAI,EAAE,MAAM,CAAC,IAAI,IACd,MAAM,CAAC,OAAO,EACjB,EAAA;;wBAPF,iDAAiD;wBACjD,SAME,CAAC;;;;wBAEH,sBAAO;gCACL,OAAO,EAAE,KAAK;gCACd,KAAK,EAAE,sBAAsB;6BAC9B,EAAC;;;wBAMI,iBAAiB,GAAG,IAAA,gBAAM,EAAC,WAAW,CAAC,CAAC,QAAQ,EAAE,CAAC;wBACzD,qBAAM,EAAE,CAAC,MAAM,CACb,aAAM,CAAC,IAAI,EACX;gCACE,QAAQ,EAAE,iBAAiB;6BAC5B,EACD,EAAE,EAAE,EAAE,IAAI,CAAC,EAAE,EAAE,CAChB,EAAA;;wBAND,SAMC,CAAC;;;;wBAEF,sBAAO;gCACL,OAAO,EAAE,KAAK;gCACd,KAAK,EAAE,2BAA2B;6BACnC,EAAC;4BAGJ,sBAAO;4BACL,OAAO,EAAE,IAAI;yBACd,EAAC;;;;KACH;IACH,qBAAC;AAAD,CAAC,AArED,IAqEC;AArEY,wCAAc"}
1
+ {"version":3,"file":"UpdateUserInfo.js","sourceRoot":"","sources":["../../../src/services/UpdateUserInfo.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=DevLogin.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"DevLogin.test.d.ts","sourceRoot":"","sources":["../../test/DevLogin.test.ts"],"names":[],"mappings":""}