@happyvertical/smrt-users 0.53.1 → 0.53.2

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 (28) hide show
  1. package/README.md +40 -0
  2. package/agents/permissions.md +7 -0
  3. package/dist/chunks/{TerminalAuthService-DKDfXpDG.js → TerminalAuthService-DG8HwPgq.js} +49 -26
  4. package/dist/chunks/TerminalAuthService-DG8HwPgq.js.map +1 -0
  5. package/dist/collections/RoleCollection.d.ts.map +1 -1
  6. package/dist/index.d.ts +1 -0
  7. package/dist/index.d.ts.map +1 -1
  8. package/dist/index.js +40 -5
  9. package/dist/index.js.map +1 -1
  10. package/dist/manifest.json +26 -18
  11. package/dist/migrations/deduplicateRolePermissions.d.ts +23 -0
  12. package/dist/migrations/deduplicateRolePermissions.d.ts.map +1 -0
  13. package/dist/models/RolePermission.d.ts.map +1 -1
  14. package/dist/smrt-knowledge.json +9 -5
  15. package/dist/sveltekit.js +1 -1
  16. package/package.json +11 -11
  17. package/dist/__tests__/helpers/oidc-test-server.d.ts +0 -45
  18. package/dist/__tests__/helpers/oidc-test-server.d.ts.map +0 -1
  19. package/dist/__tests__/helpers/postgres-rls-reset.d.ts +0 -15
  20. package/dist/__tests__/helpers/postgres-rls-reset.d.ts.map +0 -1
  21. package/dist/chunks/TerminalAuthService-DKDfXpDG.js.map +0 -1
  22. package/dist/svelte/components/__tests__/InviteUserModal.test.js +0 -65
  23. package/dist/svelte/components/__tests__/UserAvatar.test.js +0 -31
  24. package/dist/svelte/components/__tests__/UserCard.test.js +0 -39
  25. package/dist/svelte/components/__tests__/UserForm.test.js +0 -50
  26. package/dist/svelte/components/__tests__/UserList.test.js +0 -48
  27. package/dist/svelte/components/__tests__/UserMenu.test.js +0 -83
  28. package/dist/svelte/components/__tests__/UserStatus.test.js +0 -36
package/README.md CHANGED
@@ -920,3 +920,43 @@ for authentication, deduplication, and status semantics.
920
920
  ## License
921
921
 
922
922
  MIT
923
+
924
+ ### Upgrade duplicate role grants (#3329)
925
+
926
+ `RolePermission` now has a unique natural key `(role_id, permission_id)`.
927
+ Concurrent seeders converge through core's conflict-tolerant writes, preserving
928
+ one grant ID per pair. Permissions already use `(slug, context)` and system
929
+ roles use the tenant-aware natural key. System-role bootstrap holds a
930
+ PostgreSQL transaction advisory lock across its read/create sequence so two
931
+ seeders also return the same global (`tenant_id = NULL`) role IDs. The concurrent cold-seed test
932
+ checks all three catalogs. Seeding still uses bounded batches and is additive
933
+ unless `prune: true`; concurrent passes must use the same catalog/matrix.
934
+
935
+ Existing deployments need a maintenance window **before ordinary schema
936
+ migration**: adding the new unique index directly fails if duplicates exist.
937
+ Back up the database, stop every application writer and bootstrap/seed process,
938
+ and run the following once with the new package from an operator process:
939
+
940
+ ```typescript
941
+ import { getDatabase } from '@happyvertical/sql';
942
+ import { deduplicateRolePermissions } from '@happyvertical/smrt-users';
943
+
944
+ const db = await getDatabase(databaseConfig);
945
+ console.log(await deduplicateRolePermissions(db, { dryRun: true }));
946
+ console.log(await deduplicateRolePermissions(db, {
947
+ maintenanceConfirmed: true,
948
+ }));
949
+ ```
950
+
951
+ The migration keeps the earliest `created_at` per pair (lowest `id` breaks ties;
952
+ null timestamps sort last), deletes only extra grants, and creates
953
+ `role_permissions_role_id_permission_id_idx` in the same transaction. Other
954
+ pairs and surviving grant data remain intact. Failure rolls the transaction
955
+ back; after resolving its cause, rerun the migration. Dry runs change nothing.
956
+ The helper requires transaction support and supports SQLite, DuckDB and
957
+ PostgreSQL; PostgreSQL locks the grant table while repairing it. Writer shutdown
958
+ is still required because older application versions cannot seed safely
959
+ against the new constraint. Apply the remaining application schema migrations,
960
+ run `smrt doctor --db` / `db:status --parity`, deploy the new version to every
961
+ writer, then resume traffic. Do not roll back application writers without also
962
+ restoring the pre-upgrade schema/database backup.
@@ -188,3 +188,10 @@ access once principal context is set. Child-tenant sessions receive resolved
188
188
  inherited permissions automatically, but RLS row filtering remains bound to the
189
189
  session tenant: a root session's app-level guard authorization does not itself
190
190
  permit child rows through RLS. Preserve this distinction.
191
+
192
+ RolePermission's natural key is `(role_id, permission_id)` (#3329); repeated or
193
+ concurrent inserts converge without changing the grant ID. Existing deployments
194
+ must run `deduplicateRolePermissions()` with stopped writers before ordinary
195
+ schema migration; see README's "Upgrade duplicate role grants". It keeps the
196
+ oldest row and installs uniqueness atomically. Runtime seeding never performs
197
+ this schema repair.