mnfst 0.5.142 → 0.5.144

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.
@@ -5382,14 +5382,9 @@ function initializeTeamsConvenience() {
5382
5382
  const allRoles = this.allTeamRoles({ $id: teamId });
5383
5383
  const permissions = allRoles && allRoles[roleName] ? [...allRoles[roleName]] : [];
5384
5384
 
5385
- // Ensure allAvailablePermissions is populated (for dropdown)
5386
- if (!this.allAvailablePermissions || this.allAvailablePermissions.length === 0) {
5387
- if (this.getAllAvailablePermissions) {
5388
- await this.getAllAvailablePermissions(teamId);
5389
- }
5390
- }
5391
-
5392
- // Set editing state
5385
+ // Set editing state SYNCHRONOUSLY before the async dropdown fetch
5386
+ // below so a caller that mutates editingRole.permissions immediately
5387
+ // after this isn't racing (and getting overwritten by) that fetch.
5393
5388
  this.editingRole = {
5394
5389
  teamId: teamId,
5395
5390
  oldRoleName: roleName,
@@ -5397,10 +5392,46 @@ function initializeTeamsConvenience() {
5397
5392
  permissions: permissions
5398
5393
  };
5399
5394
 
5395
+ // Ensure allAvailablePermissions is populated (for dropdown)
5396
+ if (!this.allAvailablePermissions || this.allAvailablePermissions.length === 0) {
5397
+ if (this.getAllAvailablePermissions) {
5398
+ await this.getAllAvailablePermissions(teamId);
5399
+ }
5400
+ }
5401
+
5400
5402
  // Don't modify newRolePermissions when editing existing roles - that's only for new role creation
5401
5403
  // The UI will use editingRole.permissions or pendingPermissions for existing roles
5402
5404
  };
5403
5405
 
5406
+ // Reactive-safe role-permission write. Takes a plain array and persists
5407
+ // straight to team prefs via updateUserRole — WITHOUT going through the
5408
+ // reactive editingRole object. Use this for programmatic edits; mutating
5409
+ // $auth.editingRole.permissions directly is fragile under Alpine (the
5410
+ // $auth proxy wraps the already-reactive editingRole and can recurse on
5411
+ // get). updateUserRole refreshes the role cache, so allTeamRoles() re-reads.
5412
+ store.updateRolePermissions = async function (teamId, roleName, permissions) {
5413
+ if (!this.updateUserRole) {
5414
+ return { success: false, error: 'Roles module not ready' };
5415
+ }
5416
+ const plain = Array.isArray(permissions)
5417
+ ? permissions.filter(p => p && typeof p === 'string')
5418
+ : [];
5419
+ return await this.updateUserRole(teamId, roleName, plain);
5420
+ };
5421
+
5422
+ // Safely set the permissions on the in-progress edit (replaces editingRole
5423
+ // with a fresh object holding a plain array, rather than mutating the
5424
+ // reactive nested array). Pair with saveEditingRole().
5425
+ store.setEditingPermissions = function (permissions) {
5426
+ if (!this.editingRole) {
5427
+ return;
5428
+ }
5429
+ const plain = Array.isArray(permissions)
5430
+ ? permissions.filter(p => p && typeof p === 'string')
5431
+ : [];
5432
+ this.editingRole = { ...this.editingRole, permissions: plain };
5433
+ };
5434
+
5404
5435
  store.cancelEditingRole = function () {
5405
5436
  this.editingRole = null;
5406
5437
  this.newRolePermissions = [];
@@ -5494,29 +5525,43 @@ function initializeTeamsConvenience() {
5494
5525
  return userRoles.includes('owner');
5495
5526
  };
5496
5527
 
5497
- // Synchronous version for Alpine.js bindings (uses permission cache)
5528
+ // Synchronous version for Alpine.js bindings (x-show / :disabled).
5529
+ // Resolves from the cached role definitions (allTeamRoles) so it matches
5530
+ // the async hasTeamPermission() — including custom permission keys, not
5531
+ // just the six built-ins the permission cache pre-computes.
5498
5532
  store.hasTeamPermissionSync = function (permission) {
5499
5533
  if (!this.currentTeam || !this.currentTeamMemberships || !this.user) {
5500
5534
  return false;
5501
5535
  }
5502
5536
 
5503
- // Use cached permissions if available (updated by updatePermissionCache)
5504
- if (this._permissionCache && typeof this._permissionCache[permission] === 'boolean') {
5505
- return this._permissionCache[permission];
5537
+ const userRoles = this.getCurrentTeamRoles();
5538
+ if (!Array.isArray(userRoles)) {
5539
+ return false;
5540
+ }
5541
+
5542
+ // The merged config + user-generated role map for the current team
5543
+ // (same map the async path resolves against), available synchronously.
5544
+ const allRoles = (this.allTeamRoles && this.allTeamRoles(this.currentTeam)) || {};
5545
+
5546
+ // No custom roles defined → owner has every permission.
5547
+ if (!allRoles || Object.keys(allRoles).length === 0) {
5548
+ return userRoles.includes('owner');
5506
5549
  }
5507
5550
 
5508
- // Fallback: check if user has no custom roles (should have all permissions)
5509
- // This matches the logic in hasPermission: if customRoles.length === 0, return true
5510
- const userRoles = this.getCurrentTeamRoles();
5551
+ // User holds no custom role (only "owner" / empty) → all permissions.
5511
5552
  const customRoles = userRoles.filter(role => role !== 'owner');
5512
-
5513
- // If user has no custom roles (only "owner" or empty), grant all permissions
5514
- // This handles users with "No Role" who should have all owner permissions
5515
5553
  if (customRoles.length === 0) {
5516
5554
  return true;
5517
5555
  }
5518
5556
 
5519
- // If user has custom roles but cache is missing, return false (shouldn't happen if cache is working)
5557
+ // Granted if any of the user's custom roles includes this permission
5558
+ // (built-in or custom key).
5559
+ for (const roleName of customRoles) {
5560
+ const rolePermissions = allRoles[roleName];
5561
+ if (Array.isArray(rolePermissions) && rolePermissions.includes(permission)) {
5562
+ return true;
5563
+ }
5564
+ }
5520
5565
  return false;
5521
5566
  };
5522
5567
 
@@ -1,5 +1,5 @@
1
1
  {
2
- "manifest.appwrite.auth.js": "sha384-csLm/3JlkttPwGqBckmHytoiYWDSVheBwg/7G8dN2S8ebEhAHAG95W2qDPIGiHYO",
2
+ "manifest.appwrite.auth.js": "sha384-/IbcczrhhYWlsQFvFmHkulV1JPIBBFvMH513PwsnJo+D0F+YKhGJ1ig/UmJbGSe/",
3
3
  "manifest.appwrite.data.js": "sha384-00ulLT+GAIuPHA/rRT9p98vYlsyDzkyKXtg86BDQ6FGQa5vVVN+W6kuforniBAsz",
4
4
  "manifest.appwrite.presence.js": "sha384-uxRpx9/Jj0kGtklH5QmUlAzD3zdSvFRfK6bcJQqxl+Bsf5tOo4zgwqJTQgtZoHQP",
5
5
  "manifest.charts.js": "sha384-RuV7gWXt3s+JegxWgDieR/P5U99sbOYWiYHdJGe2uCJjDFU1cPp0mJ1QT55ec9uz",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mnfst",
3
- "version": "0.5.142",
3
+ "version": "0.5.144",
4
4
  "private": false,
5
5
  "workspaces": [
6
6
  "templates/starter",