@rovela-ai/sdk 0.2.1 → 0.3.1
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.
- package/dist/admin/api/accept-invite.d.ts +65 -0
- package/dist/admin/api/accept-invite.d.ts.map +1 -0
- package/dist/admin/api/accept-invite.js +115 -0
- package/dist/admin/api/accept-invite.js.map +1 -0
- package/dist/admin/api/categories.d.ts.map +1 -1
- package/dist/admin/api/categories.js +21 -28
- package/dist/admin/api/categories.js.map +1 -1
- package/dist/admin/api/customers.d.ts.map +1 -1
- package/dist/admin/api/customers.js +17 -25
- package/dist/admin/api/customers.js.map +1 -1
- package/dist/admin/api/forgot-password.d.ts +39 -0
- package/dist/admin/api/forgot-password.d.ts.map +1 -0
- package/dist/admin/api/forgot-password.js +66 -0
- package/dist/admin/api/forgot-password.js.map +1 -0
- package/dist/admin/api/index.d.ts +6 -0
- package/dist/admin/api/index.d.ts.map +1 -1
- package/dist/admin/api/index.js +9 -0
- package/dist/admin/api/index.js.map +1 -1
- package/dist/admin/api/me.d.ts +72 -0
- package/dist/admin/api/me.d.ts.map +1 -0
- package/dist/admin/api/me.js +177 -0
- package/dist/admin/api/me.js.map +1 -0
- package/dist/admin/api/orders.d.ts.map +1 -1
- package/dist/admin/api/orders.js +21 -28
- package/dist/admin/api/orders.js.map +1 -1
- package/dist/admin/api/products.d.ts.map +1 -1
- package/dist/admin/api/products.js +33 -37
- package/dist/admin/api/products.js.map +1 -1
- package/dist/admin/api/refund.d.ts.map +1 -1
- package/dist/admin/api/refund.js +5 -7
- package/dist/admin/api/refund.js.map +1 -1
- package/dist/admin/api/reset-password.d.ts +49 -0
- package/dist/admin/api/reset-password.d.ts.map +1 -0
- package/dist/admin/api/reset-password.js +99 -0
- package/dist/admin/api/reset-password.js.map +1 -0
- package/dist/admin/api/return.d.ts.map +1 -1
- package/dist/admin/api/return.js +9 -12
- package/dist/admin/api/return.js.map +1 -1
- package/dist/admin/api/settings.d.ts.map +1 -1
- package/dist/admin/api/settings.js +9 -12
- package/dist/admin/api/settings.js.map +1 -1
- package/dist/admin/api/shipping.d.ts.map +1 -1
- package/dist/admin/api/shipping.js +65 -61
- package/dist/admin/api/shipping.js.map +1 -1
- package/dist/admin/api/stats.d.ts.map +1 -1
- package/dist/admin/api/stats.js +5 -7
- package/dist/admin/api/stats.js.map +1 -1
- package/dist/admin/api/stripe-status.d.ts.map +1 -1
- package/dist/admin/api/stripe-status.js +5 -7
- package/dist/admin/api/stripe-status.js.map +1 -1
- package/dist/admin/api/tax-zones.d.ts.map +1 -1
- package/dist/admin/api/tax-zones.js +21 -28
- package/dist/admin/api/tax-zones.js.map +1 -1
- package/dist/admin/api/users.d.ts +142 -0
- package/dist/admin/api/users.d.ts.map +1 -0
- package/dist/admin/api/users.js +356 -0
- package/dist/admin/api/users.js.map +1 -0
- package/dist/admin/components/AdminAcceptInviteForm.d.ts +3 -0
- package/dist/admin/components/AdminAcceptInviteForm.d.ts.map +1 -0
- package/dist/admin/components/AdminAcceptInviteForm.js +137 -0
- package/dist/admin/components/AdminAcceptInviteForm.js.map +1 -0
- package/dist/admin/components/AdminAccountPage.d.ts +10 -0
- package/dist/admin/components/AdminAccountPage.d.ts.map +1 -0
- package/dist/admin/components/AdminAccountPage.js +123 -0
- package/dist/admin/components/AdminAccountPage.js.map +1 -0
- package/dist/admin/components/AdminForgotPasswordForm.d.ts +8 -0
- package/dist/admin/components/AdminForgotPasswordForm.d.ts.map +1 -0
- package/dist/admin/components/AdminForgotPasswordForm.js +59 -0
- package/dist/admin/components/AdminForgotPasswordForm.js.map +1 -0
- package/dist/admin/components/AdminNav.d.ts.map +1 -1
- package/dist/admin/components/AdminNav.js +32 -4
- package/dist/admin/components/AdminNav.js.map +1 -1
- package/dist/admin/components/AdminResetPasswordForm.d.ts +12 -0
- package/dist/admin/components/AdminResetPasswordForm.d.ts.map +1 -0
- package/dist/admin/components/AdminResetPasswordForm.js +134 -0
- package/dist/admin/components/AdminResetPasswordForm.js.map +1 -0
- package/dist/admin/components/AdminUserMenu.d.ts.map +1 -1
- package/dist/admin/components/AdminUserMenu.js +2 -2
- package/dist/admin/components/AdminUserMenu.js.map +1 -1
- package/dist/admin/components/InviteUserDialog.d.ts +3 -0
- package/dist/admin/components/InviteUserDialog.d.ts.map +1 -0
- package/dist/admin/components/InviteUserDialog.js +127 -0
- package/dist/admin/components/InviteUserDialog.js.map +1 -0
- package/dist/admin/components/UsersTable.d.ts +3 -0
- package/dist/admin/components/UsersTable.d.ts.map +1 -0
- package/dist/admin/components/UsersTable.js +399 -0
- package/dist/admin/components/UsersTable.js.map +1 -0
- package/dist/admin/components/index.d.ts +9 -0
- package/dist/admin/components/index.d.ts.map +1 -1
- package/dist/admin/components/index.js +9 -0
- package/dist/admin/components/index.js.map +1 -1
- package/dist/admin/config.d.ts +15 -10
- package/dist/admin/config.d.ts.map +1 -1
- package/dist/admin/config.js +38 -11
- package/dist/admin/config.js.map +1 -1
- package/dist/admin/hooks/index.d.ts +4 -0
- package/dist/admin/hooks/index.d.ts.map +1 -1
- package/dist/admin/hooks/index.js +3 -0
- package/dist/admin/hooks/index.js.map +1 -1
- package/dist/admin/hooks/useAdminMe.d.ts +31 -0
- package/dist/admin/hooks/useAdminMe.d.ts.map +1 -0
- package/dist/admin/hooks/useAdminMe.js +103 -0
- package/dist/admin/hooks/useAdminMe.js.map +1 -0
- package/dist/admin/hooks/useAdminPermissions.d.ts +3 -0
- package/dist/admin/hooks/useAdminPermissions.d.ts.map +1 -0
- package/dist/admin/hooks/useAdminPermissions.js +51 -0
- package/dist/admin/hooks/useAdminPermissions.js.map +1 -0
- package/dist/admin/hooks/useAdminUsers.d.ts +3 -0
- package/dist/admin/hooks/useAdminUsers.d.ts.map +1 -0
- package/dist/admin/hooks/useAdminUsers.js +240 -0
- package/dist/admin/hooks/useAdminUsers.js.map +1 -0
- package/dist/admin/index.d.ts +4 -4
- package/dist/admin/index.d.ts.map +1 -1
- package/dist/admin/index.js +20 -2
- package/dist/admin/index.js.map +1 -1
- package/dist/admin/permissions.d.ts +92 -0
- package/dist/admin/permissions.d.ts.map +1 -0
- package/dist/admin/permissions.js +201 -0
- package/dist/admin/permissions.js.map +1 -0
- package/dist/admin/server/admin-invite.d.ts +122 -0
- package/dist/admin/server/admin-invite.d.ts.map +1 -0
- package/dist/admin/server/admin-invite.js +235 -0
- package/dist/admin/server/admin-invite.js.map +1 -0
- package/dist/admin/server/admin-password-reset.d.ts +87 -0
- package/dist/admin/server/admin-password-reset.d.ts.map +1 -0
- package/dist/admin/server/admin-password-reset.js +220 -0
- package/dist/admin/server/admin-password-reset.js.map +1 -0
- package/dist/admin/server/admin-self-service.d.ts +86 -0
- package/dist/admin/server/admin-self-service.d.ts.map +1 -0
- package/dist/admin/server/admin-self-service.js +188 -0
- package/dist/admin/server/admin-self-service.js.map +1 -0
- package/dist/admin/server/admin-service.d.ts.map +1 -1
- package/dist/admin/server/admin-service.js +21 -2
- package/dist/admin/server/admin-service.js.map +1 -1
- package/dist/admin/server/admin-session.d.ts +137 -0
- package/dist/admin/server/admin-session.d.ts.map +1 -0
- package/dist/admin/server/admin-session.js +229 -0
- package/dist/admin/server/admin-session.js.map +1 -0
- package/dist/admin/server/index.d.ts +7 -0
- package/dist/admin/server/index.d.ts.map +1 -1
- package/dist/admin/server/index.js +20 -0
- package/dist/admin/server/index.js.map +1 -1
- package/dist/admin/server/user-management.d.ts +223 -0
- package/dist/admin/server/user-management.d.ts.map +1 -0
- package/dist/admin/server/user-management.js +846 -0
- package/dist/admin/server/user-management.js.map +1 -0
- package/dist/admin/types.d.ts +153 -2
- package/dist/admin/types.d.ts.map +1 -1
- package/dist/auth/config.d.ts.map +1 -1
- package/dist/auth/config.js +11 -2
- package/dist/auth/config.js.map +1 -1
- package/dist/core/db/queries.d.ts +19 -13
- package/dist/core/db/queries.d.ts.map +1 -1
- package/dist/core/db/schema.d.ts +327 -9
- package/dist/core/db/schema.d.ts.map +1 -1
- package/dist/core/db/schema.js +80 -3
- package/dist/core/db/schema.js.map +1 -1
- package/dist/core/types.d.ts +19 -3
- package/dist/core/types.d.ts.map +1 -1
- package/dist/emails/index.d.ts +2 -2
- package/dist/emails/index.d.ts.map +1 -1
- package/dist/emails/index.js +3 -1
- package/dist/emails/index.js.map +1 -1
- package/dist/emails/send/admin-auth.d.ts +94 -0
- package/dist/emails/send/admin-auth.d.ts.map +1 -0
- package/dist/emails/send/admin-auth.js +118 -0
- package/dist/emails/send/admin-auth.js.map +1 -0
- package/dist/emails/send/index.d.ts +2 -0
- package/dist/emails/send/index.d.ts.map +1 -1
- package/dist/emails/send/index.js +4 -0
- package/dist/emails/send/index.js.map +1 -1
- package/dist/emails/templates/admin-invite.d.ts +40 -0
- package/dist/emails/templates/admin-invite.d.ts.map +1 -0
- package/dist/emails/templates/admin-invite.js +62 -0
- package/dist/emails/templates/admin-invite.js.map +1 -0
- package/dist/emails/templates/index.d.ts +1 -0
- package/dist/emails/templates/index.d.ts.map +1 -1
- package/dist/emails/templates/index.js +4 -0
- package/dist/emails/templates/index.js.map +1 -1
- package/dist/emails/types.d.ts +22 -1
- package/dist/emails/types.d.ts.map +1 -1
- package/package.json +21 -1
|
@@ -5,4 +5,11 @@
|
|
|
5
5
|
* Re-exports from admin-service for cleaner imports.
|
|
6
6
|
*/
|
|
7
7
|
export { authenticateAdmin, createAdmin, findAdminForSession, findAdminByEmail, findAdminById, updateAdmin, updateAdminPassword, adminEmailExists, countAdmins, type CreateAdminResult, type AuthenticateAdminResult, type AuthenticateAdminError, } from './admin-service';
|
|
8
|
+
export { requestAdminPasswordReset, validateAdminResetToken, resetAdminPassword, deleteAdminPasswordResetTokens, cleanupExpiredAdminResetTokens, } from './admin-password-reset';
|
|
9
|
+
export { listAdmins, countActiveOwners, deactivateAdmin, reactivateAdmin, hardDeleteAdmin, statusCodeFor, inviteAdmin, resendAdminInvite, cancelAdminInvite, changeAdminRole, } from './user-management';
|
|
10
|
+
export type { Actor, AdminListOptions, UserManagementError, UserManagementResult, InviteAdminRequest, InviteAdminSuccess, InviteAdminResult, ResendInviteSuccess, ResendInviteResult, } from './user-management';
|
|
11
|
+
export { validateInviteToken, acceptAdminInvite, deleteAdminInviteTokens, cleanupExpiredInviteTokens, createInviteToken, INVITE_EXPIRY_HOURS, } from './admin-invite';
|
|
12
|
+
export type { AdminInviteSnapshot, ValidateInviteResult, AcceptInviteResult, } from './admin-invite';
|
|
13
|
+
export { changeOwnPassword, updateOwnProfile, } from './admin-self-service';
|
|
14
|
+
export type { SelfServiceError, ChangeOwnPasswordResult, UpdateOwnProfileResult, } from './admin-self-service';
|
|
8
15
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/admin/server/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAMH,OAAO,EAEL,iBAAiB,EAEjB,WAAW,EACX,mBAAmB,EACnB,gBAAgB,EAChB,aAAa,EACb,WAAW,EACX,mBAAmB,EACnB,gBAAgB,EAChB,WAAW,EAEX,KAAK,iBAAiB,EACtB,KAAK,uBAAuB,EAC5B,KAAK,sBAAsB,GAC5B,MAAM,iBAAiB,CAAA"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/admin/server/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAMH,OAAO,EAEL,iBAAiB,EAEjB,WAAW,EACX,mBAAmB,EACnB,gBAAgB,EAChB,aAAa,EACb,WAAW,EACX,mBAAmB,EACnB,gBAAgB,EAChB,WAAW,EAEX,KAAK,iBAAiB,EACtB,KAAK,uBAAuB,EAC5B,KAAK,sBAAsB,GAC5B,MAAM,iBAAiB,CAAA;AAMxB,OAAO,EACL,yBAAyB,EACzB,uBAAuB,EACvB,kBAAkB,EAClB,8BAA8B,EAC9B,8BAA8B,GAC/B,MAAM,wBAAwB,CAAA;AAM/B,OAAO,EAEL,UAAU,EACV,iBAAiB,EACjB,eAAe,EACf,eAAe,EACf,eAAe,EACf,aAAa,EAEb,WAAW,EACX,iBAAiB,EACjB,iBAAiB,EACjB,eAAe,GAChB,MAAM,mBAAmB,CAAA;AAE1B,YAAY,EACV,KAAK,EACL,gBAAgB,EAChB,mBAAmB,EACnB,oBAAoB,EAEpB,kBAAkB,EAClB,kBAAkB,EAClB,iBAAiB,EACjB,mBAAmB,EACnB,kBAAkB,GACnB,MAAM,mBAAmB,CAAA;AAM1B,OAAO,EACL,mBAAmB,EACnB,iBAAiB,EACjB,uBAAuB,EACvB,0BAA0B,EAC1B,iBAAiB,EACjB,mBAAmB,GACpB,MAAM,gBAAgB,CAAA;AAEvB,YAAY,EACV,mBAAmB,EACnB,oBAAoB,EACpB,kBAAkB,GACnB,MAAM,gBAAgB,CAAA;AAMvB,OAAO,EACL,iBAAiB,EACjB,gBAAgB,GACjB,MAAM,sBAAsB,CAAA;AAE7B,YAAY,EACV,gBAAgB,EAChB,uBAAuB,EACvB,sBAAsB,GACvB,MAAM,sBAAsB,CAAA"}
|
|
@@ -12,4 +12,24 @@ export {
|
|
|
12
12
|
authenticateAdmin,
|
|
13
13
|
// CRUD
|
|
14
14
|
createAdmin, findAdminForSession, findAdminByEmail, findAdminById, updateAdmin, updateAdminPassword, adminEmailExists, countAdmins, } from './admin-service';
|
|
15
|
+
// =============================================================================
|
|
16
|
+
// Admin Password Reset Service
|
|
17
|
+
// =============================================================================
|
|
18
|
+
export { requestAdminPasswordReset, validateAdminResetToken, resetAdminPassword, deleteAdminPasswordResetTokens, cleanupExpiredAdminResetTokens, } from './admin-password-reset';
|
|
19
|
+
// =============================================================================
|
|
20
|
+
// User Management (Phase 2 + Phase 3)
|
|
21
|
+
// =============================================================================
|
|
22
|
+
export {
|
|
23
|
+
// Phase 2
|
|
24
|
+
listAdmins, countActiveOwners, deactivateAdmin, reactivateAdmin, hardDeleteAdmin, statusCodeFor,
|
|
25
|
+
// Phase 3
|
|
26
|
+
inviteAdmin, resendAdminInvite, cancelAdminInvite, changeAdminRole, } from './user-management';
|
|
27
|
+
// =============================================================================
|
|
28
|
+
// Admin Invite Token Service (Phase 3)
|
|
29
|
+
// =============================================================================
|
|
30
|
+
export { validateInviteToken, acceptAdminInvite, deleteAdminInviteTokens, cleanupExpiredInviteTokens, createInviteToken, INVITE_EXPIRY_HOURS, } from './admin-invite';
|
|
31
|
+
// =============================================================================
|
|
32
|
+
// Self-Service (Phase 4)
|
|
33
|
+
// =============================================================================
|
|
34
|
+
export { changeOwnPassword, updateOwnProfile, } from './admin-self-service';
|
|
15
35
|
//# sourceMappingURL=index.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/admin/server/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,gFAAgF;AAChF,gBAAgB;AAChB,gFAAgF;AAEhF,OAAO;AACL,iBAAiB;AACjB,iBAAiB;AACjB,OAAO;AACP,WAAW,EACX,mBAAmB,EACnB,gBAAgB,EAChB,aAAa,EACb,WAAW,EACX,mBAAmB,EACnB,gBAAgB,EAChB,WAAW,GAKZ,MAAM,iBAAiB,CAAA"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/admin/server/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,gFAAgF;AAChF,gBAAgB;AAChB,gFAAgF;AAEhF,OAAO;AACL,iBAAiB;AACjB,iBAAiB;AACjB,OAAO;AACP,WAAW,EACX,mBAAmB,EACnB,gBAAgB,EAChB,aAAa,EACb,WAAW,EACX,mBAAmB,EACnB,gBAAgB,EAChB,WAAW,GAKZ,MAAM,iBAAiB,CAAA;AAExB,gFAAgF;AAChF,+BAA+B;AAC/B,gFAAgF;AAEhF,OAAO,EACL,yBAAyB,EACzB,uBAAuB,EACvB,kBAAkB,EAClB,8BAA8B,EAC9B,8BAA8B,GAC/B,MAAM,wBAAwB,CAAA;AAE/B,gFAAgF;AAChF,sCAAsC;AACtC,gFAAgF;AAEhF,OAAO;AACL,UAAU;AACV,UAAU,EACV,iBAAiB,EACjB,eAAe,EACf,eAAe,EACf,eAAe,EACf,aAAa;AACb,UAAU;AACV,WAAW,EACX,iBAAiB,EACjB,iBAAiB,EACjB,eAAe,GAChB,MAAM,mBAAmB,CAAA;AAe1B,gFAAgF;AAChF,uCAAuC;AACvC,gFAAgF;AAEhF,OAAO,EACL,mBAAmB,EACnB,iBAAiB,EACjB,uBAAuB,EACvB,0BAA0B,EAC1B,iBAAiB,EACjB,mBAAmB,GACpB,MAAM,gBAAgB,CAAA;AAQvB,gFAAgF;AAChF,yBAAyB;AACzB,gFAAgF;AAEhF,OAAO,EACL,iBAAiB,EACjB,gBAAgB,GACjB,MAAM,sBAAsB,CAAA"}
|
|
@@ -0,0 +1,223 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @rovela/sdk/admin/server/user-management
|
|
3
|
+
*
|
|
4
|
+
* User lifecycle management for store admins — list, deactivate, reactivate,
|
|
5
|
+
* and hard-delete operations, with all invariants enforced at the service
|
|
6
|
+
* layer so every future caller inherits them automatically.
|
|
7
|
+
*
|
|
8
|
+
* # Invariants (enforced in every mutation)
|
|
9
|
+
*
|
|
10
|
+
* 1. Self-protection: actor cannot act on themselves via these helpers.
|
|
11
|
+
* Self-service flows (password change, profile update) go through
|
|
12
|
+
* dedicated `/api/admin/me/*` endpoints (Phase 4).
|
|
13
|
+
*
|
|
14
|
+
* 2. Last-owner protection: there must ALWAYS be at least one admin with
|
|
15
|
+
* role='owner' AND status='active'. Deactivating, demoting, or deleting
|
|
16
|
+
* the last active owner is rejected. This is enforced via an atomic
|
|
17
|
+
* conditional UPDATE (or a pre-check for hard delete), not a
|
|
18
|
+
* check-then-act pattern — no TOCTOU race window.
|
|
19
|
+
*
|
|
20
|
+
* 3. Lateral-escalation protection: administrators can only touch managers
|
|
21
|
+
* and users. They cannot modify owners or other administrators.
|
|
22
|
+
* Enforced via `canManageUser(actor, target)` from `permissions.ts`.
|
|
23
|
+
*
|
|
24
|
+
* 4. Hard delete requires prior deactivation: you cannot DELETE an admin
|
|
25
|
+
* whose status is 'active' or 'invited'. Must call `deactivateAdmin`
|
|
26
|
+
* first. This creates a two-step safety rail for irreversible actions.
|
|
27
|
+
*
|
|
28
|
+
* 5. Audit trail on deactivate: `deactivated_at` and `deactivated_by` are
|
|
29
|
+
* populated from the service layer. Reactivate clears them.
|
|
30
|
+
*
|
|
31
|
+
* 6. Reactivate only applies to 'deactivated' admins, not 'invited'.
|
|
32
|
+
* Invited admins must accept their invite (Phase 3) to become active.
|
|
33
|
+
*
|
|
34
|
+
* # Session cache invalidation
|
|
35
|
+
*
|
|
36
|
+
* Every mutation ends with `invalidateAdminSession(targetId)` so the 30-second
|
|
37
|
+
* per-admin status cache in `requireAdmin()` sees the new state on the very
|
|
38
|
+
* next request. Without this call, a deactivated admin could continue making
|
|
39
|
+
* authenticated requests for up to 30 seconds.
|
|
40
|
+
*
|
|
41
|
+
* # This module never throws on invariant failures — it returns a typed
|
|
42
|
+
* discriminated union `{ ok: true }` or `{ ok: false, error: {...} }`.
|
|
43
|
+
* Unexpected runtime errors (DB connectivity, etc.) still throw and bubble
|
|
44
|
+
* up to the API route's try/catch.
|
|
45
|
+
*/
|
|
46
|
+
import type { AdminRole } from '../../core/types';
|
|
47
|
+
import type { StoreAdmin } from '../../core/db/schema';
|
|
48
|
+
export interface AdminListOptions {
|
|
49
|
+
/** Case-insensitive substring match against name OR email. */
|
|
50
|
+
search?: string;
|
|
51
|
+
/** Filter by status. 'all' (default) returns every admin regardless of status. */
|
|
52
|
+
status?: 'all' | 'active' | 'invited' | 'deactivated';
|
|
53
|
+
/** Filter by role. 'all' (default) returns every admin regardless of role. */
|
|
54
|
+
role?: 'all' | AdminRole;
|
|
55
|
+
/** Max rows to return. Clamped to 1..100 at the API layer. */
|
|
56
|
+
limit?: number;
|
|
57
|
+
/** Offset for pagination (0-indexed). */
|
|
58
|
+
offset?: number;
|
|
59
|
+
}
|
|
60
|
+
export interface UserManagementError {
|
|
61
|
+
code: 'NOT_FOUND' | 'FORBIDDEN' | 'SELF_ACTION_FORBIDDEN' | 'LAST_OWNER_PROTECTED' | 'MUST_DEACTIVATE_FIRST' | 'INVALID_STATE' | 'VALIDATION_ERROR' | 'EMAIL_ALREADY_EXISTS' | 'EMAIL_ALREADY_INVITED' | 'EMAIL_DEACTIVATED_EXISTS';
|
|
62
|
+
message: string;
|
|
63
|
+
}
|
|
64
|
+
export type UserManagementResult = {
|
|
65
|
+
ok: true;
|
|
66
|
+
} | {
|
|
67
|
+
ok: false;
|
|
68
|
+
error: UserManagementError;
|
|
69
|
+
};
|
|
70
|
+
export interface Actor {
|
|
71
|
+
id: string;
|
|
72
|
+
role: AdminRole;
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* List admins with filters and pagination.
|
|
76
|
+
*
|
|
77
|
+
* Returns the raw `StoreAdmin` rows — the caller is responsible for stripping
|
|
78
|
+
* sensitive fields (`passwordHash`) before serializing to JSON. The API
|
|
79
|
+
* handler does this mapping.
|
|
80
|
+
*/
|
|
81
|
+
export declare function listAdmins(opts?: AdminListOptions): Promise<{
|
|
82
|
+
admins: StoreAdmin[];
|
|
83
|
+
total: number;
|
|
84
|
+
}>;
|
|
85
|
+
/**
|
|
86
|
+
* Count admins with role='owner' and status='active'.
|
|
87
|
+
*
|
|
88
|
+
* The single source of truth for the last-owner invariant. Always queried
|
|
89
|
+
* fresh — it's a one-row COUNT, trivially fast, and caching would introduce
|
|
90
|
+
* staleness risk for a safety-critical check.
|
|
91
|
+
*/
|
|
92
|
+
export declare function countActiveOwners(): Promise<number>;
|
|
93
|
+
/**
|
|
94
|
+
* Soft-delete an admin: set status='deactivated' and stamp audit fields.
|
|
95
|
+
*
|
|
96
|
+
* Rejects on any invariant violation. Never throws on business errors;
|
|
97
|
+
* returns a typed result the caller can branch on.
|
|
98
|
+
*
|
|
99
|
+
* Uses an atomic conditional UPDATE to enforce the last-owner invariant —
|
|
100
|
+
* no check-then-act race window. If another request deactivates the second-
|
|
101
|
+
* to-last owner between our check and our update, our UPDATE's WHERE clause
|
|
102
|
+
* will match zero rows and we return LAST_OWNER_PROTECTED.
|
|
103
|
+
*/
|
|
104
|
+
export declare function deactivateAdmin(actor: Actor, targetId: string): Promise<UserManagementResult>;
|
|
105
|
+
/**
|
|
106
|
+
* Reactivate a previously-deactivated admin: set status='active', clear
|
|
107
|
+
* audit fields. Does NOT apply to 'invited' admins — they must accept
|
|
108
|
+
* their invite (Phase 3) to become active.
|
|
109
|
+
*/
|
|
110
|
+
export declare function reactivateAdmin(actor: Actor, targetId: string): Promise<UserManagementResult>;
|
|
111
|
+
/**
|
|
112
|
+
* Permanently delete an admin row. Cascades to `admin_password_reset_tokens`
|
|
113
|
+
* and `admin_invite_tokens` via the `ON DELETE CASCADE` foreign keys defined
|
|
114
|
+
* in the Phase 0 schema.
|
|
115
|
+
*
|
|
116
|
+
* Requires the target to already be 'deactivated' — this is a two-step
|
|
117
|
+
* irreversible action. The API route additionally gates on `users.delete`
|
|
118
|
+
* permission (owner-only), but we re-check here for defense-in-depth.
|
|
119
|
+
*
|
|
120
|
+
* Dangling `deactivated_by` / `created_by` references on other admin rows
|
|
121
|
+
* are intentionally left as dangling UUIDs. The UI renders them as
|
|
122
|
+
* "Unknown user". Phase 4 may revisit.
|
|
123
|
+
*/
|
|
124
|
+
export declare function hardDeleteAdmin(actor: Actor, targetId: string): Promise<UserManagementResult>;
|
|
125
|
+
/**
|
|
126
|
+
* Map a `UserManagementError.code` to the HTTP status the API handler
|
|
127
|
+
* should respond with. Exported so both the API handlers and any future
|
|
128
|
+
* caller use the same mapping.
|
|
129
|
+
*/
|
|
130
|
+
export declare function statusCodeFor(code: UserManagementError['code']): number;
|
|
131
|
+
export interface InviteAdminRequest {
|
|
132
|
+
email: string;
|
|
133
|
+
name: string;
|
|
134
|
+
role: AdminRole;
|
|
135
|
+
}
|
|
136
|
+
export interface InviteAdminSuccess {
|
|
137
|
+
ok: true;
|
|
138
|
+
adminId: string;
|
|
139
|
+
token: string;
|
|
140
|
+
inviteUrl: string;
|
|
141
|
+
}
|
|
142
|
+
export type InviteAdminResult = InviteAdminSuccess | {
|
|
143
|
+
ok: false;
|
|
144
|
+
error: UserManagementError;
|
|
145
|
+
};
|
|
146
|
+
/**
|
|
147
|
+
* Invite a new admin to manage the store.
|
|
148
|
+
*
|
|
149
|
+
* Creates a `store_admins` row in `invited` status with no password,
|
|
150
|
+
* issues an invite token (72h expiry), and sends the invite email. The
|
|
151
|
+
* caller receives both the token AND the fully-qualified invite URL — so
|
|
152
|
+
* if email delivery fails, the UI can show a "copy link manually"
|
|
153
|
+
* fallback instead of silently losing the invite.
|
|
154
|
+
*
|
|
155
|
+
* # Invariants (in order)
|
|
156
|
+
*
|
|
157
|
+
* 1. `canManageUser(actor, {role})` — actor can grant the requested role.
|
|
158
|
+
* Administrators cannot invite owners or other administrators.
|
|
159
|
+
* 2. Valid email format + name length ≥ 2.
|
|
160
|
+
* 3. Email uniqueness — rejects with a distinct error code depending on
|
|
161
|
+
* the existing row's status (active / invited / deactivated) so the
|
|
162
|
+
* UI can show actionable messages.
|
|
163
|
+
* 4. Legal role: must be one of 'owner' | 'administrator' | 'manager' | 'user'.
|
|
164
|
+
* The legacy 'admin' value is never chosen by the caller here — new
|
|
165
|
+
* invites always use the canonical names.
|
|
166
|
+
*
|
|
167
|
+
* Email send failures are logged but NOT propagated — the invite row +
|
|
168
|
+
* token are already persisted, the caller gets the URL, and the UI
|
|
169
|
+
* handles fallback display.
|
|
170
|
+
*/
|
|
171
|
+
export declare function inviteAdmin(actor: Actor, request: InviteAdminRequest): Promise<InviteAdminResult>;
|
|
172
|
+
export interface ResendInviteSuccess {
|
|
173
|
+
ok: true;
|
|
174
|
+
token: string;
|
|
175
|
+
inviteUrl: string;
|
|
176
|
+
}
|
|
177
|
+
export type ResendInviteResult = ResendInviteSuccess | {
|
|
178
|
+
ok: false;
|
|
179
|
+
error: UserManagementError;
|
|
180
|
+
};
|
|
181
|
+
/**
|
|
182
|
+
* Resend an invite to an admin who is still in `invited` status.
|
|
183
|
+
*
|
|
184
|
+
* Generates a fresh token (invalidating any previous ones) and resends
|
|
185
|
+
* the email. Preserves the single-active-token policy — older tokens
|
|
186
|
+
* are deleted before the new one is created.
|
|
187
|
+
*/
|
|
188
|
+
export declare function resendAdminInvite(actor: Actor, targetId: string): Promise<ResendInviteResult>;
|
|
189
|
+
/**
|
|
190
|
+
* Cancel a pending invite. Hard-deletes the `store_admins` row — which
|
|
191
|
+
* cascades via FK to delete all `admin_invite_tokens` rows for that
|
|
192
|
+
* admin. Only valid for `invited` status (not `active` / `deactivated`).
|
|
193
|
+
*
|
|
194
|
+
* Uses `users.write` permission (administrators + owners), unlike the
|
|
195
|
+
* DELETE endpoint which is owner-only. Canceling an invite for a manager
|
|
196
|
+
* or user is a normal administrator action, not a destructive one.
|
|
197
|
+
*/
|
|
198
|
+
export declare function cancelAdminInvite(actor: Actor, targetId: string): Promise<UserManagementResult>;
|
|
199
|
+
/**
|
|
200
|
+
* Change an admin's role.
|
|
201
|
+
*
|
|
202
|
+
* Invariants (in strict order):
|
|
203
|
+
*
|
|
204
|
+
* 1. Target exists (→ NOT_FOUND).
|
|
205
|
+
* 2. Self-protection — actor cannot change their own role (→
|
|
206
|
+
* SELF_ACTION_FORBIDDEN). A solo owner needing to demote themselves
|
|
207
|
+
* must either invite another owner first, or use a future Phase 4
|
|
208
|
+
* emergency-reset flow.
|
|
209
|
+
* 3. canManageUser at CURRENT role — actor must be allowed to manage
|
|
210
|
+
* the target at their current role (administrator cannot touch
|
|
211
|
+
* owners or other administrators).
|
|
212
|
+
* 4. canManageUser at NEW role — actor must be allowed to grant the
|
|
213
|
+
* new role (administrator cannot promote to administrator/owner).
|
|
214
|
+
* 5. No-op fast path — if newRole === current role, return success
|
|
215
|
+
* without touching the DB.
|
|
216
|
+
* 6. Last-owner protection — if target is currently 'owner' and the
|
|
217
|
+
* new role is not 'owner', require `countActiveOwners() > 1`.
|
|
218
|
+
* Enforced atomically via a conditional UPDATE so there's no
|
|
219
|
+
* check-then-act race window.
|
|
220
|
+
* 7. Update; invalidate session cache.
|
|
221
|
+
*/
|
|
222
|
+
export declare function changeAdminRole(actor: Actor, targetId: string, newRole: AdminRole): Promise<UserManagementResult>;
|
|
223
|
+
//# sourceMappingURL=user-management.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"user-management.d.ts","sourceRoot":"","sources":["../../../src/admin/server/user-management.ts"],"names":[],"mappings":"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"}
|