@proteinjs/user-server 1.18.0 → 1.20.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 (55) hide show
  1. package/CHANGELOG.md +22 -0
  2. package/dist/generated/index.d.ts.map +1 -1
  3. package/dist/generated/index.js +3 -1
  4. package/dist/generated/index.js.map +1 -1
  5. package/dist/src/authorization/UserActivityStamp.d.ts +17 -15
  6. package/dist/src/authorization/UserActivityStamp.d.ts.map +1 -1
  7. package/dist/src/authorization/UserActivityStamp.js +21 -19
  8. package/dist/src/authorization/UserActivityStamp.js.map +1 -1
  9. package/dist/src/authorization/userCache.d.ts +9 -0
  10. package/dist/src/authorization/userCache.d.ts.map +1 -1
  11. package/dist/src/authorization/userCache.js +9 -9
  12. package/dist/src/authorization/userCache.js.map +1 -1
  13. package/dist/src/routes/DevBootstrapRoles.d.ts +21 -0
  14. package/dist/src/routes/DevBootstrapRoles.d.ts.map +1 -0
  15. package/dist/src/routes/DevBootstrapRoles.js +64 -0
  16. package/dist/src/routes/DevBootstrapRoles.js.map +1 -0
  17. package/dist/src/routes/devLogin.d.ts +11 -0
  18. package/dist/src/routes/devLogin.d.ts.map +1 -1
  19. package/dist/src/routes/devLogin.js +23 -3
  20. package/dist/src/routes/devLogin.js.map +1 -1
  21. package/dist/src/services/Roles.d.ts +29 -1
  22. package/dist/src/services/Roles.d.ts.map +1 -1
  23. package/dist/src/services/Roles.js +88 -14
  24. package/dist/src/services/Roles.js.map +1 -1
  25. package/dist/src/services/UserPresence.d.ts +16 -0
  26. package/dist/src/services/UserPresence.d.ts.map +1 -0
  27. package/dist/src/services/UserPresence.js +75 -0
  28. package/dist/src/services/UserPresence.js.map +1 -0
  29. package/dist/test/DevLogin.test.js +5 -2
  30. package/dist/test/DevLogin.test.js.map +1 -1
  31. package/dist/test/DevLoginBootstrapAdmin.test.js +2 -0
  32. package/dist/test/DevLoginBootstrapAdmin.test.js.map +1 -1
  33. package/dist/test/DevLoginBootstrapRoles.test.d.ts +2 -0
  34. package/dist/test/DevLoginBootstrapRoles.test.d.ts.map +1 -0
  35. package/dist/test/DevLoginBootstrapRoles.test.js +491 -0
  36. package/dist/test/DevLoginBootstrapRoles.test.js.map +1 -0
  37. package/dist/test/UserActivityStamp.integration.test.js +57 -90
  38. package/dist/test/UserActivityStamp.integration.test.js.map +1 -1
  39. package/dist/test/UserCacheDoesNotStampPresence.integration.test.d.ts +2 -0
  40. package/dist/test/UserCacheDoesNotStampPresence.integration.test.d.ts.map +1 -0
  41. package/dist/test/UserCacheDoesNotStampPresence.integration.test.js +117 -0
  42. package/dist/test/UserCacheDoesNotStampPresence.integration.test.js.map +1 -0
  43. package/generated/index.ts +3 -1
  44. package/package.json +3 -3
  45. package/src/authorization/UserActivityStamp.ts +22 -20
  46. package/src/authorization/userCache.ts +9 -9
  47. package/src/routes/DevBootstrapRoles.ts +50 -0
  48. package/src/routes/devLogin.ts +18 -0
  49. package/src/services/Roles.ts +61 -1
  50. package/src/services/UserPresence.ts +26 -0
  51. package/test/DevLogin.test.ts +5 -2
  52. package/test/DevLoginBootstrapAdmin.test.ts +2 -0
  53. package/test/DevLoginBootstrapRoles.test.ts +248 -0
  54. package/test/UserActivityStamp.integration.test.ts +38 -50
  55. package/test/UserCacheDoesNotStampPresence.integration.test.ts +44 -0
@@ -46,33 +46,35 @@ var logger_1 = require("@proteinjs/logger");
46
46
  var user_1 = require("@proteinjs/user");
47
47
  /**
48
48
  * Writes the LAST-ACTIVITY presence stamp (`user_activity`, one row per user — see
49
- * UserActivityTable's contract): "this human made an interactive request just now".
49
+ * UserActivityTable's contract): "this person gave a page input just now".
50
50
  *
51
- * The TRANSPORT keying lives at the call site — userCache.create runs once per session-cookie
52
- * request (wrapRoute's session-cache build) and only there, so seeded/background contexts
53
- * (runInUserScope sets session data directly) structurally never reach this class. What this
54
- * class owns is the ACCOUNT predicate: machine accounts (`isLoadedFromSource`) are refused —
55
- * their requests do arrive over real sessions (e.g. the error bridge's polling), but a machine
56
- * logging in is not a person being present.
51
+ * The INPUT keying lives at the call site — the UserPresence service is the only caller, and
52
+ * the page reports through it only from a real pointer / key / touch / wheel event. The
53
+ * per-request session build (userCache.create) does NOT call this: it runs for every request
54
+ * over a session cookie, and that transport is what an idle tab produces all day (polls, socket
55
+ * re-joins on reconnect, the reload a deploy pushes) — presence keyed on it read every user as
56
+ * "active today" (founder finding 2026-09-12). What this class owns is the ACCOUNT predicate:
57
+ * the guest identity and machine accounts (`machine` — the one owner of "is this a machine",
58
+ * founder ruling 2026-09-02) are refused, whatever door they arrive through.
57
59
  *
58
60
  * Write behavior mirrors DbSessionStore's touch: throttled per user (a presence fact consumed at
59
- * day grain needs no finer cadence, and an unthrottled stamp would put a write on EVERY request),
60
- * fail-open (a lost stamp is a few minutes of staleness, never a failed request — the returned
61
- * promise NEVER rejects), and race-tolerant (concurrent first stamps contend on the scope-unique
62
- * index; the loser's error is swallowed as debug).
61
+ * day grain needs no finer cadence, and the page already throttles its reports — this is the
62
+ * belt), fail-open (a lost stamp is a few minutes of staleness, never a failed call — the
63
+ * returned promise NEVER rejects), and race-tolerant (concurrent first stamps contend on the
64
+ * scope-unique index; the loser's error is swallowed as debug).
63
65
  */
64
66
  var UserActivityStamp = /** @class */ (function () {
65
67
  function UserActivityStamp() {
66
68
  this.logger = new logger_1.Logger({ name: this.constructor.name });
67
69
  }
68
70
  /**
69
- * Record that `user` is present on an interactive request. Fire-and-forget safe: errors are
70
- * handled (and logged) here, so callers may `void` the returned promise.
71
+ * Record that `user` gave a page human input. Fire-and-forget safe: errors are handled (and
72
+ * logged) here, so callers may `void` the returned promise.
71
73
  */
72
- UserActivityStamp.prototype.recordInteractiveRequest = function (user) {
74
+ UserActivityStamp.prototype.recordHumanInput = function (user) {
73
75
  var _this = this;
74
76
  var _a;
75
- if (!user.id || user.isLoadedFromSource === true) {
77
+ if (!user.id || user.id === user_1.guestUser.id || user.machine === true) {
76
78
  return Promise.resolve();
77
79
  }
78
80
  var last = (_a = UserActivityStamp.lastStampMs.get(user.id)) !== null && _a !== void 0 ? _a : 0;
@@ -85,9 +87,9 @@ var UserActivityStamp = /** @class */ (function () {
85
87
  UserActivityStamp.lastStampMs.clear(); // bounded memory; worst case is one extra stamp per user
86
88
  }
87
89
  return this.upsert(user.id).catch(function (error) {
88
- // Contention (a concurrent request stamped first, racing the scope-unique index) and real
89
- // failures land here alike; both are harmless to the request. Un-throttle so the next
90
- // request retries instead of waiting out a full interval on a stamp that never landed.
90
+ // Contention (a concurrent report stamped first, racing the scope-unique index) and real
91
+ // failures land here alike; both are harmless to the caller. Un-throttle so the next
92
+ // report retries instead of waiting out a full interval on a stamp that never landed.
91
93
  UserActivityStamp.lastStampMs.delete(user.id);
92
94
  _this.logger.error({ message: 'Failed to write user activity stamp', error: error });
93
95
  });
@@ -118,7 +120,7 @@ var UserActivityStamp = /** @class */ (function () {
118
120
  };
119
121
  /** Stamp at most this often per user — same cadence class as DbSessionStore.TOUCH_INTERVAL. */
120
122
  UserActivityStamp.STAMP_INTERVAL_MS = 1000 * 60 * 5;
121
- /** Process-wide: userCache is a plain object, so throttle state can't live per-instance. */
123
+ /** Process-wide: the throttle outlives any one service instance. */
122
124
  UserActivityStamp.lastStampMs = new Map();
123
125
  return UserActivityStamp;
124
126
  }());
@@ -1 +1 @@
1
- {"version":3,"file":"UserActivityStamp.js","sourceRoot":"","sources":["../../../src/authorization/UserActivityStamp.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,kDAA4B;AAC5B,oCAA8C;AAC9C,4CAA2C;AAC3C,wCAAuE;AAEvE;;;;;;;;;;;;;;;;GAgBG;AACH;IAAA;QAMU,WAAM,GAAG,IAAI,eAAM,CAAC,EAAE,IAAI,EAAE,IAAI,CAAC,WAAW,CAAC,IAAI,EAAE,CAAC,CAAC;IAqC/D,CAAC;IAnCC;;;OAGG;IACH,oDAAwB,GAAxB,UAAyB,IAAU;QAAnC,iBAoBC;;QAnBC,IAAI,CAAC,IAAI,CAAC,EAAE,IAAI,IAAI,CAAC,kBAAkB,KAAK,IAAI,EAAE;YAChD,OAAO,OAAO,CAAC,OAAO,EAAE,CAAC;SAC1B;QACD,IAAM,IAAI,GAAG,MAAA,iBAAiB,CAAC,WAAW,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,mCAAI,CAAC,CAAC;QAC7D,IAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QACvB,IAAI,GAAG,GAAG,IAAI,GAAG,iBAAiB,CAAC,iBAAiB,EAAE;YACpD,OAAO,OAAO,CAAC,OAAO,EAAE,CAAC;SAC1B;QACD,iBAAiB,CAAC,WAAW,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,EAAE,GAAG,CAAC,CAAC;QAChD,IAAI,iBAAiB,CAAC,WAAW,CAAC,IAAI,GAAG,KAAK,EAAE;YAC9C,iBAAiB,CAAC,WAAW,CAAC,KAAK,EAAE,CAAC,CAAC,yDAAyD;SACjG;QACD,OAAO,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,UAAC,KAAK;YACtC,0FAA0F;YAC1F,sFAAsF;YACtF,uFAAuF;YACvF,iBAAiB,CAAC,WAAW,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;YAC9C,KAAI,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,OAAO,EAAE,qCAAqC,EAAE,KAAK,OAAA,EAAE,CAAC,CAAC;QAC/E,CAAC,CAAC,CAAC;IACL,CAAC;IAEa,kCAAM,GAApB,UAAqB,MAAc;;;;;;wBAC3B,EAAE,GAAG,IAAA,kBAAa,GAAE,CAAC;wBACV,qBAAM,EAAE,CAAC,GAAG,CAAC,aAAM,CAAC,YAAY,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC,EAAA;;wBAA/D,QAAQ,GAAG,SAAoD;6BACjE,QAAQ,EAAR,wBAAQ;wBACV,qBAAM,EAAE,CAAC,MAAM,CAAC,aAAM,CAAC,YAAY,EAAE,EAAE,EAAE,EAAE,QAAQ,CAAC,EAAE,EAAE,YAAY,EAAE,IAAA,gBAAM,GAAE,EAAkB,CAAC,EAAA;;wBAAjG,SAAiG,CAAC;;4BAElG,qBAAM,EAAE,CAAC,MAAM,CAAC,aAAM,CAAC,YAAY,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,YAAY,EAAE,IAAA,gBAAM,GAAE,EAAkB,CAAC,EAAA;;wBAA/F,SAA+F,CAAC;;;;;;KAEnG;IAzCD,+FAA+F;IACvE,mCAAiB,GAAG,IAAI,GAAG,EAAE,GAAG,CAAC,AAAhB,CAAiB;IAC1D,4FAA4F;IAC7E,6BAAW,GAAG,IAAI,GAAG,EAAkB,AAA5B,CAA6B;IAuCzD,wBAAC;CAAA,AA3CD,IA2CC;AA3CY,8CAAiB"}
1
+ {"version":3,"file":"UserActivityStamp.js","sourceRoot":"","sources":["../../../src/authorization/UserActivityStamp.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,kDAA4B;AAC5B,oCAA8C;AAC9C,4CAA2C;AAC3C,wCAAkF;AAElF;;;;;;;;;;;;;;;;;;GAkBG;AACH;IAAA;QAMU,WAAM,GAAG,IAAI,eAAM,CAAC,EAAE,IAAI,EAAE,IAAI,CAAC,WAAW,CAAC,IAAI,EAAE,CAAC,CAAC;IAqC/D,CAAC;IAnCC;;;OAGG;IACH,4CAAgB,GAAhB,UAAiB,IAAkC;QAAnD,iBAoBC;;QAnBC,IAAI,CAAC,IAAI,CAAC,EAAE,IAAI,IAAI,CAAC,EAAE,KAAK,gBAAS,CAAC,EAAE,IAAI,IAAI,CAAC,OAAO,KAAK,IAAI,EAAE;YACjE,OAAO,OAAO,CAAC,OAAO,EAAE,CAAC;SAC1B;QACD,IAAM,IAAI,GAAG,MAAA,iBAAiB,CAAC,WAAW,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,mCAAI,CAAC,CAAC;QAC7D,IAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QACvB,IAAI,GAAG,GAAG,IAAI,GAAG,iBAAiB,CAAC,iBAAiB,EAAE;YACpD,OAAO,OAAO,CAAC,OAAO,EAAE,CAAC;SAC1B;QACD,iBAAiB,CAAC,WAAW,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,EAAE,GAAG,CAAC,CAAC;QAChD,IAAI,iBAAiB,CAAC,WAAW,CAAC,IAAI,GAAG,KAAK,EAAE;YAC9C,iBAAiB,CAAC,WAAW,CAAC,KAAK,EAAE,CAAC,CAAC,yDAAyD;SACjG;QACD,OAAO,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,UAAC,KAAK;YACtC,yFAAyF;YACzF,qFAAqF;YACrF,sFAAsF;YACtF,iBAAiB,CAAC,WAAW,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;YAC9C,KAAI,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,OAAO,EAAE,qCAAqC,EAAE,KAAK,OAAA,EAAE,CAAC,CAAC;QAC/E,CAAC,CAAC,CAAC;IACL,CAAC;IAEa,kCAAM,GAApB,UAAqB,MAAc;;;;;;wBAC3B,EAAE,GAAG,IAAA,kBAAa,GAAE,CAAC;wBACV,qBAAM,EAAE,CAAC,GAAG,CAAC,aAAM,CAAC,YAAY,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC,EAAA;;wBAA/D,QAAQ,GAAG,SAAoD;6BACjE,QAAQ,EAAR,wBAAQ;wBACV,qBAAM,EAAE,CAAC,MAAM,CAAC,aAAM,CAAC,YAAY,EAAE,EAAE,EAAE,EAAE,QAAQ,CAAC,EAAE,EAAE,YAAY,EAAE,IAAA,gBAAM,GAAE,EAAkB,CAAC,EAAA;;wBAAjG,SAAiG,CAAC;;4BAElG,qBAAM,EAAE,CAAC,MAAM,CAAC,aAAM,CAAC,YAAY,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,YAAY,EAAE,IAAA,gBAAM,GAAE,EAAkB,CAAC,EAAA;;wBAA/F,SAA+F,CAAC;;;;;;KAEnG;IAzCD,+FAA+F;IACvE,mCAAiB,GAAG,IAAI,GAAG,EAAE,GAAG,CAAC,AAAhB,CAAiB;IAC1D,oEAAoE;IACrD,6BAAW,GAAG,IAAI,GAAG,EAAkB,AAA5B,CAA6B;IAuCzD,wBAAC;CAAA,AA3CD,IA2CC;AA3CY,8CAAiB"}
@@ -1,4 +1,13 @@
1
1
  import { SessionDataCache } from '@proteinjs/server-api';
2
2
  import { User } from '@proteinjs/user';
3
+ /**
4
+ * The per-request session-cache build: resolves the session's email to the account row every
5
+ * request that rides a session cookie (wrapRoute), and every socket event (util-server's
6
+ * SocketSessionContext). It resolves IDENTITY only — it does not write the presence stamp
7
+ * (`user_activity`, UserActivityTable's contract): this build runs for an idle tab's polls, a
8
+ * socket's room re-joins on every reconnect, the reload a deploy pushes onto every open tab —
9
+ * transport, not a person. Presence is written from the page's human-input report alone
10
+ * (UserPresence.recordPresence).
11
+ */
3
12
  export declare const userCache: SessionDataCache<User>;
4
13
  //# sourceMappingURL=userCache.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"userCache.d.ts","sourceRoot":"","sources":["../../../src/authorization/userCache.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AAGzD,OAAO,EAAE,IAAI,EAA6C,MAAM,iBAAiB,CAAC;AAOlF,eAAO,MAAM,SAAS,EAAE,gBAAgB,CAAC,IAAI,CAqD5C,CAAC"}
1
+ {"version":3,"file":"userCache.d.ts","sourceRoot":"","sources":["../../../src/authorization/userCache.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AAGzD,OAAO,EAAE,IAAI,EAA6C,MAAM,iBAAiB,CAAC;AAKlF;;;;;;;;GAQG;AACH,eAAO,MAAM,SAAS,EAAE,gBAAgB,CAAC,IAAI,CA8C5C,CAAC"}
@@ -45,9 +45,16 @@ var db_1 = require("@proteinjs/db");
45
45
  var logger_1 = require("@proteinjs/logger");
46
46
  var user_1 = require("@proteinjs/user");
47
47
  var DefaultAdminCredentials_1 = require("../authentication/DefaultAdminCredentials");
48
- var UserActivityStamp_1 = require("./UserActivityStamp");
49
48
  var logger = new logger_1.Logger({ name: 'userCache' });
50
- var userActivityStamp = new UserActivityStamp_1.UserActivityStamp();
49
+ /**
50
+ * The per-request session-cache build: resolves the session's email to the account row every
51
+ * request that rides a session cookie (wrapRoute), and every socket event (util-server's
52
+ * SocketSessionContext). It resolves IDENTITY only — it does not write the presence stamp
53
+ * (`user_activity`, UserActivityTable's contract): this build runs for an idle tab's polls, a
54
+ * socket's room re-joins on every reconnect, the reload a deploy pushes onto every open tab —
55
+ * transport, not a person. Presence is written from the page's human-input report alone
56
+ * (UserPresence.recordPresence).
57
+ */
51
58
  exports.userCache = {
52
59
  key: user_1.USER_SESSION_CACHE_KEY,
53
60
  create: function (sessionId, userEmail) { return __awaiter(void 0, void 0, void 0, function () {
@@ -86,13 +93,6 @@ exports.userCache = {
86
93
  else if (accountUser) {
87
94
  delete accountUser['password'];
88
95
  user = accountUser;
89
- // LAST ACTIVITY (human presence — UserActivityTable's contract): stamped HERE because
90
- // this cache build runs exactly once per session-cookie request (wrapRoute), i.e. only
91
- // for interactive transport. Background/seeded contexts (runInUserScope) set session
92
- // data directly and never pass through, so machinery acting as the user structurally
93
- // cannot stamp; the stamp itself refuses machine accounts. Fire-and-forget: the
94
- // returned promise never rejects, and a request never waits on its own stamp.
95
- void userActivityStamp.recordInteractiveRequest(user);
96
96
  }
97
97
  else {
98
98
  // A session can outlive its account (row deleted, or a dev auto-login for a never-created
@@ -1 +1 @@
1
- {"version":3,"file":"userCache.js","sourceRoot":"","sources":["../../../src/authorization/userCache.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,kDAA4B;AAE5B,oCAA8C;AAC9C,4CAA2C;AAC3C,wCAAkF;AAClF,qFAAoF;AACpF,yDAAwD;AAExD,IAAM,MAAM,GAAG,IAAI,eAAM,CAAC,EAAE,IAAI,EAAE,WAAW,EAAE,CAAC,CAAC;AACjD,IAAM,iBAAiB,GAAG,IAAI,qCAAiB,EAAE,CAAC;AAErC,QAAA,SAAS,GAA2B;IAC/C,GAAG,EAAE,6BAAsB;IAC3B,MAAM,EAAE,UAAO,SAAiB,EAAE,SAAiB;;;;;oBAC7C,IAAI,GAAG,gBAAS,CAAC;yBACjB,SAAS,EAAT,wBAAS;oBACL,gBAAgB,GAAG,iDAAuB,CAAC,cAAc,EAAE,CAAC;yBAC9D,CAAA,gBAAgB,IAAI,SAAS,IAAI,gBAAgB,CAAC,QAAQ,CAAA,EAA1D,wBAA0D;oBACtD,SAAS,GAAS;wBACtB,IAAI,EAAE,OAAO;wBACb,KAAK,EAAE,gBAAgB,CAAC,QAAQ;wBAChC,QAAQ,EAAE,gBAAgB,CAAC,QAAQ;wBACnC,aAAa,EAAE,IAAI;wBACnB,KAAK,EAAE,CAAC,OAAO,CAAC;wBAChB,OAAO,EAAE,IAAA,gBAAM,GAAE;wBACjB,OAAO,EAAE,IAAA,gBAAM,GAAE;wBACjB,EAAE,EAAE,OAAO;qBACZ,CAAC;oBACF,IAAI,GAAG,SAAS,CAAC;;wBAEG,qBAAM,IAAA,kBAAa,GAAE,CAAC,GAAG,CAAC,aAAM,CAAC,IAAI,EAAE,EAAE,KAAK,EAAE,SAAS,CAAC,WAAW,EAAE,EAAE,CAAC,EAAA;;oBAAxF,WAAW,GAAG,SAA0E;oBAC9F,IAAI,WAAW,IAAI,WAAW,CAAC,MAAM,KAAK,aAAa,EAAE;wBACvD,sFAAsF;wBACtF,iFAAiF;wBACjF,4EAA4E;wBAC5E,MAAM,CAAC,IAAI,CAAC;4BACV,OAAO,EAAE,wEAAwE;4BACjF,GAAG,EAAE,EAAE,SAAS,WAAA,EAAE,SAAS,WAAA,EAAE;yBAC9B,CAAC,CAAC;qBACJ;yBAAM,IAAI,WAAW,EAAE;wBACtB,OAAQ,WAAmB,CAAC,UAAU,CAAC,CAAC;wBACxC,IAAI,GAAG,WAAW,CAAC;wBACnB,sFAAsF;wBACtF,uFAAuF;wBACvF,qFAAqF;wBACrF,qFAAqF;wBACrF,gFAAgF;wBAChF,8EAA8E;wBAC9E,KAAK,iBAAiB,CAAC,wBAAwB,CAAC,IAAI,CAAC,CAAC;qBACvD;yBAAM;wBACL,0FAA0F;wBAC1F,+EAA+E;wBAC/E,sFAAsF;wBACtF,yDAAyD;wBACzD,MAAM,CAAC,IAAI,CAAC;4BACV,OAAO,EAAE,iFAAiF;4BAC1F,GAAG,EAAE,EAAE,SAAS,WAAA,EAAE,SAAS,WAAA,EAAE;yBAC9B,CAAC,CAAC;qBACJ;;wBAIL,sBAAO,IAAI,EAAC;;;SACb;CACF,CAAC"}
1
+ {"version":3,"file":"userCache.js","sourceRoot":"","sources":["../../../src/authorization/userCache.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,kDAA4B;AAE5B,oCAA8C;AAC9C,4CAA2C;AAC3C,wCAAkF;AAClF,qFAAoF;AAEpF,IAAM,MAAM,GAAG,IAAI,eAAM,CAAC,EAAE,IAAI,EAAE,WAAW,EAAE,CAAC,CAAC;AAEjD;;;;;;;;GAQG;AACU,QAAA,SAAS,GAA2B;IAC/C,GAAG,EAAE,6BAAsB;IAC3B,MAAM,EAAE,UAAO,SAAiB,EAAE,SAAiB;;;;;oBAC7C,IAAI,GAAG,gBAAS,CAAC;yBACjB,SAAS,EAAT,wBAAS;oBACL,gBAAgB,GAAG,iDAAuB,CAAC,cAAc,EAAE,CAAC;yBAC9D,CAAA,gBAAgB,IAAI,SAAS,IAAI,gBAAgB,CAAC,QAAQ,CAAA,EAA1D,wBAA0D;oBACtD,SAAS,GAAS;wBACtB,IAAI,EAAE,OAAO;wBACb,KAAK,EAAE,gBAAgB,CAAC,QAAQ;wBAChC,QAAQ,EAAE,gBAAgB,CAAC,QAAQ;wBACnC,aAAa,EAAE,IAAI;wBACnB,KAAK,EAAE,CAAC,OAAO,CAAC;wBAChB,OAAO,EAAE,IAAA,gBAAM,GAAE;wBACjB,OAAO,EAAE,IAAA,gBAAM,GAAE;wBACjB,EAAE,EAAE,OAAO;qBACZ,CAAC;oBACF,IAAI,GAAG,SAAS,CAAC;;wBAEG,qBAAM,IAAA,kBAAa,GAAE,CAAC,GAAG,CAAC,aAAM,CAAC,IAAI,EAAE,EAAE,KAAK,EAAE,SAAS,CAAC,WAAW,EAAE,EAAE,CAAC,EAAA;;oBAAxF,WAAW,GAAG,SAA0E;oBAC9F,IAAI,WAAW,IAAI,WAAW,CAAC,MAAM,KAAK,aAAa,EAAE;wBACvD,sFAAsF;wBACtF,iFAAiF;wBACjF,4EAA4E;wBAC5E,MAAM,CAAC,IAAI,CAAC;4BACV,OAAO,EAAE,wEAAwE;4BACjF,GAAG,EAAE,EAAE,SAAS,WAAA,EAAE,SAAS,WAAA,EAAE;yBAC9B,CAAC,CAAC;qBACJ;yBAAM,IAAI,WAAW,EAAE;wBACtB,OAAQ,WAAmB,CAAC,UAAU,CAAC,CAAC;wBACxC,IAAI,GAAG,WAAW,CAAC;qBACpB;yBAAM;wBACL,0FAA0F;wBAC1F,+EAA+E;wBAC/E,sFAAsF;wBACtF,yDAAyD;wBACzD,MAAM,CAAC,IAAI,CAAC;4BACV,OAAO,EAAE,iFAAiF;4BAC1F,GAAG,EAAE,EAAE,SAAS,WAAA,EAAE,SAAS,WAAA,EAAE;yBAC9B,CAAC,CAAC;qBACJ;;wBAIL,sBAAO,IAAI,EAAC;;;SACb;CACF,CAAC"}
@@ -0,0 +1,21 @@
1
+ import type { BootstrapRolesOutcome } from '../services/Roles';
2
+ /**
3
+ * The `DEV_BOOTSTRAP_ROLES` contract of the dev role-bootstrap door (routes/devLogin.ts):
4
+ *
5
+ * DEV_BOOTSTRAP_ROLES='email:role[,role];email:role…'
6
+ *
7
+ * Addresses and roles are trimmed; addresses are lowercased (the normalization every account
8
+ * email gets); a repeated address unions its roles; an entry with no `:`, no address or no role
9
+ * is ignored (malformed input is skipped, never fatal). The door grants the listed roles the
10
+ * account does not hold and logs ONE marker line per hit for a listed address —
11
+ * `[dev-bootstrap] <email>: granted a, b; held c; refused d (why)` — which tooling that provisions
12
+ * a development database can read back from the server log as proof of the grant.
13
+ */
14
+ export declare class DevBootstrapRoles {
15
+ /** The roles listed for `email` in the process env (empty when the variable is unset or the address is not listed). */
16
+ static rolesFor(email: string): string[];
17
+ static parse(value: string | undefined): Map<string, string[]>;
18
+ /** The one marker line per hit — a log contract its readers parse; change the shape only together with them. */
19
+ static markerLine(email: string, outcome: BootstrapRolesOutcome): string;
20
+ }
21
+ //# sourceMappingURL=DevBootstrapRoles.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"DevBootstrapRoles.d.ts","sourceRoot":"","sources":["../../../src/routes/DevBootstrapRoles.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,mBAAmB,CAAC;AAE/D;;;;;;;;;;;GAWG;AACH,qBAAa,iBAAiB;IAC5B,uHAAuH;IACvH,MAAM,CAAC,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE;IAIxC,MAAM,CAAC,KAAK,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,GAAG,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC;IAqB9D,gHAAgH;IAChH,MAAM,CAAC,UAAU,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,qBAAqB,GAAG,MAAM;CAOzE"}
@@ -0,0 +1,64 @@
1
+ "use strict";
2
+ var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) {
3
+ if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {
4
+ if (ar || !(i in from)) {
5
+ if (!ar) ar = Array.prototype.slice.call(from, 0, i);
6
+ ar[i] = from[i];
7
+ }
8
+ }
9
+ return to.concat(ar || Array.prototype.slice.call(from));
10
+ };
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.DevBootstrapRoles = void 0;
13
+ /**
14
+ * The `DEV_BOOTSTRAP_ROLES` contract of the dev role-bootstrap door (routes/devLogin.ts):
15
+ *
16
+ * DEV_BOOTSTRAP_ROLES='email:role[,role];email:role…'
17
+ *
18
+ * Addresses and roles are trimmed; addresses are lowercased (the normalization every account
19
+ * email gets); a repeated address unions its roles; an entry with no `:`, no address or no role
20
+ * is ignored (malformed input is skipped, never fatal). The door grants the listed roles the
21
+ * account does not hold and logs ONE marker line per hit for a listed address —
22
+ * `[dev-bootstrap] <email>: granted a, b; held c; refused d (why)` — which tooling that provisions
23
+ * a development database can read back from the server log as proof of the grant.
24
+ */
25
+ var DevBootstrapRoles = /** @class */ (function () {
26
+ function DevBootstrapRoles() {
27
+ }
28
+ /** The roles listed for `email` in the process env (empty when the variable is unset or the address is not listed). */
29
+ DevBootstrapRoles.rolesFor = function (email) {
30
+ var _a;
31
+ return (_a = DevBootstrapRoles.parse(process.env.DEV_BOOTSTRAP_ROLES).get(email.trim().toLowerCase())) !== null && _a !== void 0 ? _a : [];
32
+ };
33
+ DevBootstrapRoles.parse = function (value) {
34
+ var _a;
35
+ var entries = new Map();
36
+ for (var _i = 0, _b = (value !== null && value !== void 0 ? value : '').split(';'); _i < _b.length; _i++) {
37
+ var entry = _b[_i];
38
+ var colon = entry.indexOf(':');
39
+ if (colon < 0) {
40
+ continue;
41
+ }
42
+ var email = entry.slice(0, colon).trim().toLowerCase();
43
+ var roles = entry
44
+ .slice(colon + 1)
45
+ .split(',')
46
+ .map(function (role) { return role.trim(); })
47
+ .filter(Boolean);
48
+ if (!email || roles.length === 0) {
49
+ continue;
50
+ }
51
+ entries.set(email, Array.from(new Set(__spreadArray(__spreadArray([], ((_a = entries.get(email)) !== null && _a !== void 0 ? _a : []), true), roles, true))));
52
+ }
53
+ return entries;
54
+ };
55
+ /** The one marker line per hit — a log contract its readers parse; change the shape only together with them. */
56
+ DevBootstrapRoles.markerLine = function (email, outcome) {
57
+ var list = function (items) { return (items.length ? items.join(', ') : '(none)'); };
58
+ return ("[dev-bootstrap] ".concat(email, ": granted ").concat(list(outcome.granted), "; held ").concat(list(outcome.held), "; ") +
59
+ "refused ".concat(list(outcome.refused.map(function (refusal) { return "".concat(refusal.role, " (").concat(refusal.why, ")"); }))));
60
+ };
61
+ return DevBootstrapRoles;
62
+ }());
63
+ exports.DevBootstrapRoles = DevBootstrapRoles;
64
+ //# sourceMappingURL=DevBootstrapRoles.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"DevBootstrapRoles.js","sourceRoot":"","sources":["../../../src/routes/DevBootstrapRoles.ts"],"names":[],"mappings":";;;;;;;;;;;;AAEA;;;;;;;;;;;GAWG;AACH;IAAA;IAmCA,CAAC;IAlCC,uHAAuH;IAChH,0BAAQ,GAAf,UAAgB,KAAa;;QAC3B,OAAO,MAAA,iBAAiB,CAAC,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,mBAAmB,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC,mCAAI,EAAE,CAAC;IACxG,CAAC;IAEM,uBAAK,GAAZ,UAAa,KAAyB;;QACpC,IAAM,OAAO,GAAG,IAAI,GAAG,EAAoB,CAAC;QAC5C,KAAoB,UAAwB,EAAxB,KAAA,CAAC,KAAK,aAAL,KAAK,cAAL,KAAK,GAAI,EAAE,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,EAAxB,cAAwB,EAAxB,IAAwB,EAAE;YAAzC,IAAM,KAAK,SAAA;YACd,IAAM,KAAK,GAAG,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;YACjC,IAAI,KAAK,GAAG,CAAC,EAAE;gBACb,SAAS;aACV;YACD,IAAM,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;YACzD,IAAM,KAAK,GAAG,KAAK;iBAChB,KAAK,CAAC,KAAK,GAAG,CAAC,CAAC;iBAChB,KAAK,CAAC,GAAG,CAAC;iBACV,GAAG,CAAC,UAAC,IAAI,IAAK,OAAA,IAAI,CAAC,IAAI,EAAE,EAAX,CAAW,CAAC;iBAC1B,MAAM,CAAC,OAAO,CAAC,CAAC;YACnB,IAAI,CAAC,KAAK,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE;gBAChC,SAAS;aACV;YACD,OAAO,CAAC,GAAG,CAAC,KAAK,EAAE,KAAK,CAAC,IAAI,CAAC,IAAI,GAAG,iCAAK,CAAC,MAAA,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,mCAAI,EAAE,CAAC,SAAK,KAAK,QAAE,CAAC,CAAC,CAAC;SACpF;QACD,OAAO,OAAO,CAAC;IACjB,CAAC;IAED,gHAAgH;IACzG,4BAAU,GAAjB,UAAkB,KAAa,EAAE,OAA8B;QAC7D,IAAM,IAAI,GAAG,UAAC,KAAe,IAAK,OAAA,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,EAA5C,CAA4C,CAAC;QAC/E,OAAO,CACL,0BAAmB,KAAK,uBAAa,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,oBAAU,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,OAAI;YAC1F,kBAAW,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,UAAC,OAAO,IAAK,OAAA,UAAG,OAAO,CAAC,IAAI,eAAK,OAAO,CAAC,GAAG,MAAG,EAAlC,CAAkC,CAAC,CAAC,CAAE,CACxF,CAAC;IACJ,CAAC;IACH,wBAAC;AAAD,CAAC,AAnCD,IAmCC;AAnCY,8CAAiB"}
@@ -33,6 +33,17 @@ import { Route } from '@proteinjs/server-api';
33
33
  * Test and prod never set it — the omission is the safety, the same idiom as the gates. The
34
34
  * outcome is logged as ONE marker line, `Dev bootstrap admin door: <granted|admin-exists>`,
35
35
  * which the n3xa compose-estate boot proof reads from the server log to PROVE the grant landed.
36
+ *
37
+ * Role-bootstrap door (`DEV_BOOTSTRAP_ROLES='email:role[,role];email:role…'`, the grammar in
38
+ * DevBootstrapRoles.ts): the first-admin door leaves every OTHER account role-less, and a
39
+ * consumer's admin-grant-only roles then need an admin's act on every fresh development database.
40
+ * Behind the same two gates, when the resolved address is listed, the listed roles the account
41
+ * does not hold are granted through `Roles.bootstrapRoles` — once each, audited, never revoking,
42
+ * never break-glass (refused and named, like a role the catalog does not know); the grant precedes
43
+ * the session so the first page load carries the roles. ONE marker line per hit for a listed
44
+ * address, `[dev-bootstrap] <email>: granted …; held …; refused …`, is what provisioning tooling
45
+ * reads back as proof. The variable absent = nothing changes; the gates closed = 404 regardless; a
46
+ * deployment outside development never sets it.
36
47
  */
37
48
  export declare const devLogin: Route;
38
49
  //# sourceMappingURL=devLogin.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"devLogin.d.ts","sourceRoot":"","sources":["../../../src/routes/devLogin.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,uBAAuB,CAAC;AAa9C;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AACH,eAAO,MAAM,QAAQ,EAAE,KAsDtB,CAAC"}
1
+ {"version":3,"file":"devLogin.d.ts","sourceRoot":"","sources":["../../../src/routes/devLogin.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,uBAAuB,CAAC;AAc9C;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6CG;AACH,eAAO,MAAM,QAAQ,EAAE,KA4DtB,CAAC"}
@@ -42,6 +42,7 @@ var util_1 = require("@proteinjs/util");
42
42
  var establishSession_1 = require("../authentication/establishSession");
43
43
  var Roles_1 = require("../services/Roles");
44
44
  var Signup_1 = require("../services/Signup");
45
+ var DevBootstrapRoles_1 = require("./DevBootstrapRoles");
45
46
  var logger = new logger_1.Logger({ name: 'devLogin' });
46
47
  /** Lowercased domain of an email address (the whole string when there is no `@`, which can never
47
48
  * equal a real env domain — so malformed params fall out at the domain rail). */
@@ -80,12 +81,23 @@ var emailDomain = function (address) { return address.slice(address.lastIndexOf(
80
81
  * Test and prod never set it — the omission is the safety, the same idiom as the gates. The
81
82
  * outcome is logged as ONE marker line, `Dev bootstrap admin door: <granted|admin-exists>`,
82
83
  * which the n3xa compose-estate boot proof reads from the server log to PROVE the grant landed.
84
+ *
85
+ * Role-bootstrap door (`DEV_BOOTSTRAP_ROLES='email:role[,role];email:role…'`, the grammar in
86
+ * DevBootstrapRoles.ts): the first-admin door leaves every OTHER account role-less, and a
87
+ * consumer's admin-grant-only roles then need an admin's act on every fresh development database.
88
+ * Behind the same two gates, when the resolved address is listed, the listed roles the account
89
+ * does not hold are granted through `Roles.bootstrapRoles` — once each, audited, never revoking,
90
+ * never break-glass (refused and named, like a role the catalog does not know); the grant precedes
91
+ * the session so the first page load carries the roles. ONE marker line per hit for a listed
92
+ * address, `[dev-bootstrap] <email>: granted …; held …; refused …`, is what provisioning tooling
93
+ * reads back as proof. The variable absent = nothing changes; the gates closed = 404 regardless; a
94
+ * deployment outside development never sets it.
83
95
  */
84
96
  exports.devLogin = {
85
97
  path: '/dev/login',
86
98
  method: 'get',
87
99
  onRequest: function (request, response) { return __awaiter(void 0, void 0, void 0, function () {
88
- var envEmail, email, emailParam, requested, creation, bootstrapEmail, outcome;
100
+ var envEmail, email, emailParam, requested, creation, bootstrapEmail, outcome, bootstrapRoles, outcome;
89
101
  var _a, _b, _c;
90
102
  return __generator(this, function (_d) {
91
103
  switch (_d.label) {
@@ -132,11 +144,19 @@ exports.devLogin = {
132
144
  outcome = _d.sent();
133
145
  logger.info({ message: "Dev bootstrap admin door: ".concat(outcome), obj: { email: email } });
134
146
  _d.label = 3;
135
- case 3:
147
+ case 3:
148
+ bootstrapRoles = DevBootstrapRoles_1.DevBootstrapRoles.rolesFor(email);
149
+ if (!(bootstrapRoles.length > 0)) return [3 /*break*/, 5];
150
+ return [4 /*yield*/, new Roles_1.Roles().bootstrapRoles(email, bootstrapRoles)];
151
+ case 4:
152
+ outcome = _d.sent();
153
+ logger.info({ message: DevBootstrapRoles_1.DevBootstrapRoles.markerLine(email, outcome) });
154
+ _d.label = 5;
155
+ case 5:
136
156
  // establishSession commits the session row before the redirect — the redirected GET / must
137
157
  // never read the store ahead of the write (observed: first /dev/login load landed on /login).
138
158
  return [4 /*yield*/, (0, establishSession_1.establishSession)(request, email)];
139
- case 4:
159
+ case 6:
140
160
  // establishSession commits the session row before the redirect — the redirected GET / must
141
161
  // never read the store ahead of the write (observed: first /dev/login load landed on /login).
142
162
  _d.sent();
@@ -1 +1 @@
1
- {"version":3,"file":"devLogin.js","sourceRoot":"","sources":["../../../src/routes/devLogin.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"devLogin.js","sourceRoot":"","sources":["../../../src/routes/devLogin.ts"],"names":[],"mappings":"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"}
@@ -8,12 +8,22 @@ import { Service } from '@proteinjs/service';
8
8
  *
9
9
  * Break-glass roles are never granted through the service door — see `changeRole`; revoking one
10
10
  * stays allowed. The ONE break-glass grant in code is `bootstrapAdmin`, the dev first-admin door
11
- * (server-internal; reachable only through `/dev/login`'s gates, never over RPC).
11
+ * (server-internal; reachable only through `/dev/login`'s gates, never over RPC). Its sibling
12
+ * `bootstrapRoles` is the dev role-bootstrap door's grant — never break-glass, catalog-checked.
12
13
  *
13
14
  * Nobody edits their OWN roles: separating 'roles' from 'users' means nothing if the holder can
14
15
  * simply grant themselves more, and a self-revoke is the mirror hazard (the last holder locking
15
16
  * themselves out). Both directions are refused — see `changeRole`; ask another user manager.
16
17
  */
18
+ /** What one `bootstrapRoles` call did, per role: written now, already on the row, or refused with the reason. */
19
+ export type BootstrapRolesOutcome = {
20
+ granted: string[];
21
+ held: string[];
22
+ refused: {
23
+ role: string;
24
+ why: string;
25
+ }[];
26
+ };
17
27
  export declare class Roles implements RolesService {
18
28
  serviceMetadata: Service['serviceMetadata'];
19
29
  grantRole(userId: string, role: string): Promise<void>;
@@ -33,6 +43,24 @@ export declare class Roles implements RolesService {
33
43
  * in, and test/prod never set the variable.
34
44
  */
35
45
  bootstrapAdmin(email: string): Promise<'granted' | 'admin-exists' | 'no-account'>;
46
+ /**
47
+ * The dev role-bootstrap door's grant — `/dev/login` honoring `DEV_BOOTSTRAP_ROLES`
48
+ * (routes/devLogin.ts, the grammar in routes/DevBootstrapRoles.ts). A fresh development
49
+ * database has one admin at most (the first-admin door) and every other account role-less, and
50
+ * a consumer's `adminGrantOnly` roles can be handed out by an admin only — a manual act on
51
+ * every fresh database. So this grants `roles` to `email`'s account, each
52
+ * once: a role the account holds is `held` (no write, no audit row — idempotent); nothing is
53
+ * ever revoked; a role the catalog does not know or a break-glass role is `refused` and named
54
+ * (`bootstrapAdmin` is the ONE break-glass path, with its own rail). Admin-grant-only roles ARE
55
+ * granted here — that is the door's point. Every grant is audited like any grant, actor = the
56
+ * account itself (the door acts for nobody else), the role update and its rows in one
57
+ * transaction.
58
+ *
59
+ * Server-internal, like `bootstrapAdmin`: absent from `RolesService`, never RPC-reachable; the
60
+ * caller's two gates (DEVELOPMENT + DEV_AUTO_LOGIN_EMAIL) are the only way in, and a deployment
61
+ * outside development never sets the variable.
62
+ */
63
+ bootstrapRoles(email: string, roles: string[]): Promise<BootstrapRolesOutcome>;
36
64
  private changeRole;
37
65
  /** Whether any account carries the break-glass role — `UserAuth.hasRole`'s membership test, over every row. */
38
66
  private adminExists;
@@ -1 +1 @@
1
- {"version":3,"file":"Roles.d.ts","sourceRoot":"","sources":["../../../src/services/Roles.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,YAAY,EAA8D,MAAM,iBAAiB,CAAC;AAE3G,OAAO,EAAE,OAAO,EAAE,MAAM,oBAAoB,CAAC;AAE7C;;;;;;;;;;;;;GAaG;AACH,qBAAa,KAAM,YAAW,YAAY;IACjC,eAAe,EAAE,OAAO,CAAC,iBAAiB,CAAC,CAIhD;IAEI,SAAS,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAItD,UAAU,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAI7D;;;;;;;;;;;;;OAaG;IACG,cAAc,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,GAAG,cAAc,GAAG,YAAY,CAAC;YAqBzE,UAAU;IA8ExB,+GAA+G;YACjG,WAAW;CAK1B"}
1
+ {"version":3,"file":"Roles.d.ts","sourceRoot":"","sources":["../../../src/services/Roles.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,YAAY,EAA8D,MAAM,iBAAiB,CAAC;AAE3G,OAAO,EAAE,OAAO,EAAE,MAAM,oBAAoB,CAAC;AAE7C;;;;;;;;;;;;;;GAcG;AACH,iHAAiH;AACjH,MAAM,MAAM,qBAAqB,GAAG;IAAE,OAAO,EAAE,MAAM,EAAE,CAAC;IAAC,IAAI,EAAE,MAAM,EAAE,CAAC;IAAC,OAAO,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,CAAA;KAAE,EAAE,CAAA;CAAE,CAAC;AAEpH,qBAAa,KAAM,YAAW,YAAY;IACjC,eAAe,EAAE,OAAO,CAAC,iBAAiB,CAAC,CAIhD;IAEI,SAAS,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAItD,UAAU,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAI7D;;;;;;;;;;;;;OAaG;IACG,cAAc,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,GAAG,cAAc,GAAG,YAAY,CAAC;IAqBvF;;;;;;;;;;;;;;;;OAgBG;IACG,cAAc,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,qBAAqB,CAAC;YAuCtE,UAAU;IA8ExB,+GAA+G;YACjG,WAAW;CAK1B"}
@@ -49,20 +49,6 @@ exports.Roles = void 0;
49
49
  var db_1 = require("@proteinjs/db");
50
50
  var user_1 = require("@proteinjs/user");
51
51
  var logger_1 = require("@proteinjs/logger");
52
- /**
53
- * The ONE write path for user roles (the `user.roles` column is service-protected — generic
54
- * record writes cannot touch it). Grants and revokes are validated against the roles catalog and
55
- * audited: the role update and its `role_grant_event` row (actor, target, role, action; `created`
56
- * is the timestamp) commit in one transaction, so the trail cannot diverge from the grants.
57
- *
58
- * Break-glass roles are never granted through the service door — see `changeRole`; revoking one
59
- * stays allowed. The ONE break-glass grant in code is `bootstrapAdmin`, the dev first-admin door
60
- * (server-internal; reachable only through `/dev/login`'s gates, never over RPC).
61
- *
62
- * Nobody edits their OWN roles: separating 'roles' from 'users' means nothing if the holder can
63
- * simply grant themselves more, and a self-revoke is the mirror hazard (the last holder locking
64
- * themselves out). Both directions are refused — see `changeRole`; ask another user manager.
65
- */
66
52
  var Roles = /** @class */ (function () {
67
53
  function Roles() {
68
54
  this.serviceMetadata = {
@@ -152,6 +138,94 @@ var Roles = /** @class */ (function () {
152
138
  });
153
139
  });
154
140
  };
141
+ /**
142
+ * The dev role-bootstrap door's grant — `/dev/login` honoring `DEV_BOOTSTRAP_ROLES`
143
+ * (routes/devLogin.ts, the grammar in routes/DevBootstrapRoles.ts). A fresh development
144
+ * database has one admin at most (the first-admin door) and every other account role-less, and
145
+ * a consumer's `adminGrantOnly` roles can be handed out by an admin only — a manual act on
146
+ * every fresh database. So this grants `roles` to `email`'s account, each
147
+ * once: a role the account holds is `held` (no write, no audit row — idempotent); nothing is
148
+ * ever revoked; a role the catalog does not know or a break-glass role is `refused` and named
149
+ * (`bootstrapAdmin` is the ONE break-glass path, with its own rail). Admin-grant-only roles ARE
150
+ * granted here — that is the door's point. Every grant is audited like any grant, actor = the
151
+ * account itself (the door acts for nobody else), the role update and its rows in one
152
+ * transaction.
153
+ *
154
+ * Server-internal, like `bootstrapAdmin`: absent from `RolesService`, never RPC-reachable; the
155
+ * caller's two gates (DEVELOPMENT + DEV_AUTO_LOGIN_EMAIL) are the only way in, and a deployment
156
+ * outside development never sets the variable.
157
+ */
158
+ Roles.prototype.bootstrapRoles = function (email, roles) {
159
+ var _a;
160
+ return __awaiter(this, void 0, void 0, function () {
161
+ var logger, db, user, held, outcome, _i, _b, role, entry;
162
+ var _this = this;
163
+ return __generator(this, function (_c) {
164
+ switch (_c.label) {
165
+ case 0:
166
+ logger = new logger_1.Logger({ name: 'Roles.bootstrapRoles' });
167
+ db = (0, db_1.getDbAsSystem)();
168
+ return [4 /*yield*/, db.get(user_1.tables.User, { email: email.toLowerCase() })];
169
+ case 1:
170
+ user = _c.sent();
171
+ if (!user) {
172
+ throw new Error("bootstrapRoles: no account for ".concat(email, " \u2014 the door creates the account before it grants"));
173
+ }
174
+ held = (_a = user.roles) !== null && _a !== void 0 ? _a : [];
175
+ outcome = { granted: [], held: [], refused: [] };
176
+ for (_i = 0, _b = Array.from(new Set(roles)); _i < _b.length; _i++) {
177
+ role = _b[_i];
178
+ entry = user_1.RolesCatalog.getEntry(role);
179
+ if (!entry) {
180
+ outcome.refused.push({ role: role, why: 'unknown role' });
181
+ }
182
+ else if (entry.breakGlass) {
183
+ outcome.refused.push({ role: role, why: 'break-glass' });
184
+ }
185
+ else if (held.includes(role)) {
186
+ outcome.held.push(role);
187
+ }
188
+ else {
189
+ outcome.granted.push(role);
190
+ }
191
+ }
192
+ if (outcome.granted.length === 0) {
193
+ return [2 /*return*/, outcome];
194
+ }
195
+ return [4 /*yield*/, db.runTransaction(function () { return __awaiter(_this, void 0, void 0, function () {
196
+ var _i, _a, role;
197
+ return __generator(this, function (_b) {
198
+ switch (_b.label) {
199
+ case 0: return [4 /*yield*/, db.update(user_1.tables.User, { id: user.id, roles: __spreadArray(__spreadArray([], held, true), outcome.granted, true) })];
200
+ case 1:
201
+ _b.sent();
202
+ _i = 0, _a = outcome.granted;
203
+ _b.label = 2;
204
+ case 2:
205
+ if (!(_i < _a.length)) return [3 /*break*/, 5];
206
+ role = _a[_i];
207
+ return [4 /*yield*/, db.insert(user_1.tables.RoleGrantEvent, { actor: user.id, target: user.id, role: role, action: 'grant' })];
208
+ case 3:
209
+ _b.sent();
210
+ _b.label = 4;
211
+ case 4:
212
+ _i++;
213
+ return [3 /*break*/, 2];
214
+ case 5: return [2 /*return*/];
215
+ }
216
+ });
217
+ }); })];
218
+ case 2:
219
+ _c.sent();
220
+ logger.info({
221
+ message: 'Roles granted by the dev role-bootstrap door',
222
+ obj: { target: user.id, email: email, granted: outcome.granted },
223
+ });
224
+ return [2 /*return*/, outcome];
225
+ }
226
+ });
227
+ });
228
+ };
155
229
  Roles.prototype.changeRole = function (userId, role, action) {
156
230
  var _a;
157
231
  return __awaiter(this, void 0, void 0, function () {
@@ -1 +1 @@
1
- {"version":3,"file":"Roles.js","sourceRoot":"","sources":["../../../src/services/Roles.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,oCAAmE;AACnE,wCAA2G;AAC3G,4CAA2C;AAG3C;;;;;;;;;;;;;GAaG;AACH;IAAA;QACS,oBAAe,GAA+B;YACnD,IAAI,EAAE;gBACJ,UAAU,EAAE,uBAAgB,CAAC,KAAK;aACnC;SACF,CAAC;IAiIJ,CAAC;IA/HO,yBAAS,GAAf,UAAgB,MAAc,EAAE,IAAY;;;;4BAC1C,qBAAM,IAAI,CAAC,UAAU,CAAC,MAAM,EAAE,IAAI,EAAE,OAAO,CAAC,EAAA;;wBAA5C,SAA4C,CAAC;;;;;KAC9C;IAEK,0BAAU,GAAhB,UAAiB,MAAc,EAAE,IAAY;;;;4BAC3C,qBAAM,IAAI,CAAC,UAAU,CAAC,MAAM,EAAE,IAAI,EAAE,QAAQ,CAAC,EAAA;;wBAA7C,SAA6C,CAAC;;;;;KAC/C;IAED;;;;;;;;;;;;;OAaG;IACG,8BAAc,GAApB,UAAqB,KAAa;;;;;;;;wBAC1B,MAAM,GAAG,IAAI,eAAM,CAAC,EAAE,IAAI,EAAE,sBAAsB,EAAE,CAAC,CAAC;wBACtD,EAAE,GAAG,IAAA,kBAAa,GAAE,CAAC;wBACvB,qBAAM,IAAI,CAAC,WAAW,EAAE,EAAA;;wBAA5B,IAAI,SAAwB,EAAE;4BAC5B,sBAAO,cAAc,EAAC;yBACvB;wBAEY,qBAAM,EAAE,CAAC,GAAG,CAAC,aAAM,CAAC,IAAI,EAAE,EAAE,KAAK,EAAE,KAAK,CAAC,WAAW,EAAE,EAAE,CAAC,EAAA;;wBAAhE,IAAI,GAAG,SAAyD;wBACtE,IAAI,CAAC,IAAI,EAAE;4BACT,sBAAO,YAAY,EAAC;yBACrB;wBAEK,KAAK,GAAG,MAAA,IAAI,CAAC,KAAK,mCAAI,EAAE,CAAC;wBAC/B,qBAAM,EAAE,CAAC,cAAc,CAAC;;;gDACtB,qBAAM,EAAE,CAAC,MAAM,CAAC,aAAM,CAAC,IAAI,EAAE,EAAE,EAAE,EAAE,IAAI,CAAC,EAAE,EAAE,KAAK,kCAAM,KAAK,UAAE,OAAO,SAAC,EAAE,CAAC,EAAA;;4CAAzE,SAAyE,CAAC;4CAC1E,qBAAM,EAAE,CAAC,MAAM,CAAC,aAAM,CAAC,cAAc,EAAE,EAAE,KAAK,EAAE,IAAI,CAAC,EAAE,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC,EAAA;;4CAA3G,SAA2G,CAAC;;;;iCAC7G,CAAC,EAAA;;wBAHF,SAGE,CAAC;wBACH,MAAM,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,uDAAuD,EAAE,GAAG,EAAE,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,EAAE,KAAK,OAAA,EAAE,EAAE,CAAC,CAAC;wBACnH,sBAAO,SAAS,EAAC;;;;KAClB;IAEa,0BAAU,GAAxB,UAAyB,MAAc,EAAE,IAAY,EAAE,MAA0B;;;;;;;;wBACzE,MAAM,GAAG,IAAI,eAAM,CAAC,EAAE,IAAI,EAAE,gBAAS,MAAM,SAAM,EAAE,CAAC,CAAC;wBACrD,KAAK,GAAG,mBAAY,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;wBAC1C,IAAI,CAAC,KAAK,EAAE;4BACV,MAAM,IAAI,KAAK,CAAC,WAAI,IAAI,4DAAyD,CAAC,CAAC;yBACpF;wBAED,sFAAsF;wBACtF,yFAAyF;wBACzF,6FAA6F;wBAC7F,yFAAyF;wBACzF,6DAA6D;wBAC7D,IAAI,KAAK,CAAC,UAAU,IAAI,MAAM,KAAK,OAAO,EAAE;4BAC1C,MAAM,IAAI,KAAK,CACb,WAAI,IAAI,uFAA+E;gCACrF,sFAAsF;gCACtF,iBAAiB,CACpB,CAAC;yBACH;wBAED,2FAA2F;wBAC3F,6FAA6F;wBAC7F,yFAAyF;wBACzF,2FAA2F;wBAC3F,IAAI,KAAK,CAAC,cAAc,IAAI,MAAM,KAAK,OAAO,IAAI,CAAC,eAAQ,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE;4BAC5E,MAAM,IAAI,KAAK,CACb,WAAI,IAAI,mFAA2E;gCACjF,mCAAmC,CACtC,CAAC;yBACH;wBAEK,EAAE,GAAG,IAAA,kBAAa,GAAE,CAAC;wBACd,qBAAM,EAAE,CAAC,GAAG,CAAC,aAAM,CAAC,IAAI,EAAE,EAAE,EAAE,EAAE,MAAM,EAAE,CAAC,EAAA;;wBAAhD,IAAI,GAAG,SAAyC;wBACtD,IAAI,CAAC,IAAI,EAAE;4BACT,MAAM,IAAI,KAAK,CAAC,gCAAyB,MAAM,CAAE,CAAC,CAAC;yBACpD;wBAED,4FAA4F;wBAC5F,4FAA4F;wBAC5F,iFAAiF;wBACjF,IAAI,IAAI,CAAC,kBAAkB,KAAK,IAAI,EAAE;4BACpC,MAAM,IAAI,KAAK,CACb,WAAI,IAAI,CAAC,KAAK,gFAA6E;gCACzF,6FAA6F,CAChG,CAAC;yBACH;wBAEK,KAAK,GAAG,IAAI,eAAQ,EAAE,CAAC,OAAO,EAAE,CAAC;wBACvC,wFAAwF;wBACxF,0FAA0F;wBAC1F,2EAA2E;wBAC3E,IAAI,MAAM,KAAK,KAAK,CAAC,EAAE,EAAE;4BACvB,MAAM,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,qCAAqC,EAAE,GAAG,EAAE,EAAE,KAAK,EAAE,KAAK,CAAC,EAAE,EAAE,IAAI,MAAA,EAAE,MAAM,QAAA,EAAE,EAAE,CAAC,CAAC;4BACxG,MAAM,IAAI,KAAK,CAAC,oBAAa,MAAM,qDAA6C,CAAC,CAAC;yBACnF;wBAEK,KAAK,GAAG,MAAA,IAAI,CAAC,KAAK,mCAAI,EAAE,CAAC;wBAC/B,IAAI,MAAM,KAAK,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE;4BACrE,mFAAmF;4BACnF,sBAAO;yBACR;wBAEK,QAAQ,GAAG,MAAM,KAAK,OAAO,CAAC,CAAC,iCAAK,KAAK,UAAE,IAAI,UAAE,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,UAAC,QAAQ,IAAK,OAAA,QAAQ,KAAK,IAAI,EAAjB,CAAiB,CAAC,CAAC;wBACvG,qBAAM,EAAE,CAAC,cAAc,CAAC;;;gDACtB,qBAAM,EAAE,CAAC,MAAM,CAAC,aAAM,CAAC,IAAI,EAAE,EAAE,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,QAAQ,EAAE,CAAC,EAAA;;4CAA7D,SAA6D,CAAC;4CAC9D,qBAAM,EAAE,CAAC,MAAM,CAAC,aAAM,CAAC,cAAc,EAAE;oDACrC,KAAK,EAAE,KAAK,CAAC,EAAE;oDACf,MAAM,EAAE,MAAM;oDACd,IAAI,MAAA;oDACJ,MAAM,QAAA;iDACP,CAAC,EAAA;;4CALF,SAKE,CAAC;;;;iCACJ,CAAC,EAAA;;wBARF,SAQE,CAAC;wBACH,MAAM,CAAC,IAAI,CAAC;4BACV,OAAO,EAAE,eAAQ,MAAM,KAAK,OAAO,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,SAAS,CAAE;4BAC7D,GAAG,EAAE,EAAE,KAAK,EAAE,KAAK,CAAC,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,MAAA,EAAE;yBAC/C,CAAC,CAAC;;;;;KACJ;IAED,+GAA+G;IACjG,2BAAW,GAAzB;;;;;;wBACQ,EAAE,GAAG,IAAI,wBAAmB,EAAE,CAAC,eAAe,CAAC,aAAM,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC,IAAI,EAAE,OAAO,CAAC,EAAE,CAAC,CAAC;wBACxF,qBAAM,IAAA,kBAAa,GAAE,CAAC,KAAK,CAAC,aAAM,CAAC,IAAI,EAAE,EAAE,CAAC,EAAA;;wBAApD,KAAK,GAAG,SAA4C;wBAC1D,sBAAO,KAAK,CAAC,IAAI,CAAC,UAAC,IAAI,YAAK,OAAA,CAAC,MAAA,IAAI,CAAC,KAAK,mCAAI,EAAE,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAA,EAAA,CAAC,EAAC;;;;KACnE;IACH,YAAC;AAAD,CAAC,AAtID,IAsIC;AAtIY,sBAAK"}
1
+ {"version":3,"file":"Roles.js","sourceRoot":"","sources":["../../../src/services/Roles.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,16 @@
1
+ import { Service } from '@proteinjs/service';
2
+ import { UserPresenceService } from '@proteinjs/user';
3
+ /**
4
+ * The server end of the human-input presence door (UserActivityTable's contract): the page
5
+ * reports "a person interacted just now" and this writes the `user_activity` stamp for the
6
+ * CALLING user — the one write path onto presence. Any signed-in user may report their own
7
+ * presence and nobody else's (the user is the session's, never an argument); the guest identity
8
+ * and machine accounts are refused inside the stamp. `doNotAwait`: the page never waits on its
9
+ * own stamp, and a lost stamp is minutes of staleness at day grain, never a failed call.
10
+ */
11
+ export declare class UserPresence implements UserPresenceService {
12
+ serviceMetadata: Service['serviceMetadata'];
13
+ private stamp;
14
+ recordPresence(): Promise<void>;
15
+ }
16
+ //# sourceMappingURL=UserPresence.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"UserPresence.d.ts","sourceRoot":"","sources":["../../../src/services/UserPresence.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,oBAAoB,CAAC;AAC7C,OAAO,EAAE,mBAAmB,EAAuB,MAAM,iBAAiB,CAAC;AAG3E;;;;;;;GAOG;AACH,qBAAa,YAAa,YAAW,mBAAmB;IAC/C,eAAe,EAAE,OAAO,CAAC,iBAAiB,CAAC,CAKhD;IAEF,OAAO,CAAC,KAAK,CAA2B;IAElC,cAAc,IAAI,OAAO,CAAC,IAAI,CAAC;CAGtC"}