@nextsparkjs/core 0.1.0-beta.154 → 0.1.0-beta.156

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.
@@ -1 +1 @@
1
- {"version":3,"file":"generic-handler.d.ts","sourceRoot":"","sources":["../../../../src/lib/api/entity/generic-handler.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,aAAa,CAAA;AAyhBvD;;GAEG;AACH,wBAAsB,iBAAiB,CAAC,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,YAAY,CAAC,CA+fnF;AAED;;GAEG;AACH,wBAAsB,mBAAmB,CAAC,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,YAAY,CAAC,CAyXrF;AAED;;GAEG;AACH,wBAAsB,iBAAiB,CAAC,OAAO,EAAE,WAAW,EAAE,EAAE,MAAM,EAAE,EAAE;IAAE,MAAM,EAAE,OAAO,CAAC;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,EAAE,EAAE,MAAM,CAAA;KAAE,CAAC,CAAA;CAAE,GAAG,OAAO,CAAC,YAAY,CAAC,CAmMpJ;AAED;;GAEG;AACH,wBAAsB,mBAAmB,CAAC,OAAO,EAAE,WAAW,EAAE,EAAE,MAAM,EAAE,EAAE;IAAE,MAAM,EAAE,OAAO,CAAC;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,EAAE,EAAE,MAAM,CAAA;KAAE,CAAC,CAAA;CAAE,GAAG,OAAO,CAAC,YAAY,CAAC,CAyXtJ;AAED;;GAEG;AACH,wBAAsB,mBAAmB,CAAC,OAAO,EAAE,WAAW,EAAE,EAAE,MAAM,EAAE,EAAE;IAAE,MAAM,EAAE,OAAO,CAAC;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,EAAE,EAAE,MAAM,CAAA;KAAE,CAAC,CAAA;CAAE,GAAG,OAAO,CAAC,YAAY,CAAC,CAoJtJ;AAED;;GAEG;AACH,wBAAsB,oBAAoB,CAAC,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,YAAY,CAAC,CAEtF"}
1
+ {"version":3,"file":"generic-handler.d.ts","sourceRoot":"","sources":["../../../../src/lib/api/entity/generic-handler.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,aAAa,CAAA;AAyhBvD;;GAEG;AACH,wBAAsB,iBAAiB,CAAC,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,YAAY,CAAC,CA+fnF;AAED;;GAEG;AACH,wBAAsB,mBAAmB,CAAC,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,YAAY,CAAC,CAmZrF;AAED;;GAEG;AACH,wBAAsB,iBAAiB,CAAC,OAAO,EAAE,WAAW,EAAE,EAAE,MAAM,EAAE,EAAE;IAAE,MAAM,EAAE,OAAO,CAAC;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,EAAE,EAAE,MAAM,CAAA;KAAE,CAAC,CAAA;CAAE,GAAG,OAAO,CAAC,YAAY,CAAC,CAmMpJ;AAED;;GAEG;AACH,wBAAsB,mBAAmB,CAAC,OAAO,EAAE,WAAW,EAAE,EAAE,MAAM,EAAE,EAAE;IAAE,MAAM,EAAE,OAAO,CAAC;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,EAAE,EAAE,MAAM,CAAA;KAAE,CAAC,CAAA;CAAE,GAAG,OAAO,CAAC,YAAY,CAAC,CAyXtJ;AAED;;GAEG;AACH,wBAAsB,mBAAmB,CAAC,OAAO,EAAE,WAAW,EAAE,EAAE,MAAM,EAAE,EAAE;IAAE,MAAM,EAAE,OAAO,CAAC;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,EAAE,EAAE,MAAM,CAAA;KAAE,CAAC,CAAA;CAAE,GAAG,OAAO,CAAC,YAAY,CAAC,CAoJtJ;AAED;;GAEG;AACH,wBAAsB,oBAAoB,CAAC,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,YAAY,CAAC,CAEtF"}
@@ -681,7 +681,14 @@ async function handleGenericCreate(request) {
681
681
  let values;
682
682
  let paramCount;
683
683
  const isSharedEntity = ((_b = entityConfig.access) == null ? void 0 : _b.shared) === true;
684
- const userIdToUse = isSharedEntity && rawUserId ? rawUserId : authResult.user.id;
684
+ let userIdToUse = authResult.user.id;
685
+ if (isSharedEntity && Object.prototype.hasOwnProperty.call(entityData, "userId")) {
686
+ if (rawUserId === null) {
687
+ userIdToUse = null;
688
+ } else if (typeof rawUserId === "string" && rawUserId.trim() !== "") {
689
+ userIdToUse = rawUserId;
690
+ }
691
+ }
685
692
  const teamValidation = await validateTeamContextWithBypass(request, authResult, authResult.user.id);
686
693
  if (!teamValidation.valid) {
687
694
  return teamValidation.error;
@@ -35,7 +35,7 @@ class UserService {
35
35
  "emailVerified",
36
36
  "createdAt",
37
37
  "updatedAt"
38
- FROM "user"
38
+ FROM "users"
39
39
  WHERE id = $1 OR email = $1`,
40
40
  [identifier],
41
41
  currentUserId
@@ -81,7 +81,7 @@ class UserService {
81
81
  "emailVerified",
82
82
  "createdAt",
83
83
  "updatedAt"
84
- FROM "user"
84
+ FROM "users"
85
85
  WHERE email = $1`,
86
86
  [email],
87
87
  currentUserId
@@ -127,7 +127,7 @@ class UserService {
127
127
  "emailVerified",
128
128
  "createdAt",
129
129
  "updatedAt"
130
- FROM "user"
130
+ FROM "users"
131
131
  WHERE id = $1`,
132
132
  [userId],
133
133
  currentUserId
@@ -174,7 +174,7 @@ class UserService {
174
174
  "emailVerified",
175
175
  "createdAt",
176
176
  "updatedAt"
177
- FROM "user"
177
+ FROM "users"
178
178
  WHERE id IN (${placeholders})`,
179
179
  userIds,
180
180
  currentUserId
@@ -238,7 +238,7 @@ class UserService {
238
238
  updateFields.push(`"updatedAt" = CURRENT_TIMESTAMP`);
239
239
  values.push(userId);
240
240
  const query = `
241
- UPDATE "user"
241
+ UPDATE "users"
242
242
  SET ${updateFields.join(", ")}
243
243
  WHERE id = $${paramCount}
244
244
  RETURNING
@@ -89,6 +89,24 @@ export declare function isSuperadmin(userRole: UserRole): boolean;
89
89
  * @returns True if action is allowed, false otherwise
90
90
  */
91
91
  export declare function canManageRole(actorRole: string, targetRole: string): boolean;
92
+ /**
93
+ * Check if a role can invite another role to the team
94
+ *
95
+ * Reads hierarchy from the merged permissions registry, so any roles added
96
+ * by consumers via additional config are supported automatically.
97
+ *
98
+ * Semantics: invitation is allowed when the actor's hierarchy level is
99
+ * greater than or equal to the target's hierarchy level. Peers can invite
100
+ * peers (e.g. admin → admin); a lower-ranked actor cannot invite a
101
+ * higher-ranked target.
102
+ *
103
+ * Missing hierarchy entries are treated as 0, mirroring canManageRole.
104
+ *
105
+ * @param actorRole - The role of the user issuing the invitation
106
+ * @param targetRole - The role the invitee would receive
107
+ * @returns True if the invitation is allowed, false otherwise
108
+ */
109
+ export declare function canInviteToRole(actorRole: string, targetRole: string): boolean;
92
110
  /**
93
111
  * Get human-readable role description
94
112
  *
@@ -1 +1 @@
1
- {"version":3,"file":"permissions.d.ts","sourceRoot":"","sources":["../../../src/lib/teams/permissions.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAUH;;GAEG;AACH,MAAM,MAAM,QAAQ,GAAG,QAAQ,GAAG,YAAY,CAAA;AAE9C;;GAEG;AACH,MAAM,MAAM,cAAc,GACtB,WAAW,GACX,WAAW,GACX,aAAa,GACb,mBAAmB,GACnB,qBAAqB,GACrB,qBAAqB,GACrB,0BAA0B,GAC1B,oBAAoB,GACpB,oBAAoB,GACpB,mBAAmB,GACnB,qBAAqB,CAAA;AAEzB;;;GAGG;AACH,eAAO,MAAM,oBAAoB,EAAE,cAAc,EAYhD,CAAA;AAuCD;;;;;;;GAOG;AACH,eAAO,MAAM,eAAe,EAAE,MAAM,CAAC,MAAM,EAAE,cAAc,EAAE,CAAgC,CAAA;AAM7F;;;;;;;GAOG;AACH,wBAAgB,aAAa,CAC3B,IAAI,EAAE,MAAM,EACZ,UAAU,EAAE,cAAc,EAC1B,aAAa,GAAE,OAAe,GAC7B,OAAO,CAWT;AAED;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CAChC,IAAI,EAAE,MAAM,EACZ,aAAa,GAAE,OAAe,GAC7B,cAAc,EAAE,CAQlB;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,mBAAmB,CACjC,QAAQ,EAAE,QAAQ,EAClB,QAAQ,EAAE,MAAM,GAAG,IAAI,EACvB,UAAU,EAAE,cAAc,GACzB,OAAO,CAcT;AAED;;;;;GAKG;AACH,wBAAgB,YAAY,CAAC,QAAQ,EAAE,QAAQ,GAAG,OAAO,CAExD;AAMD;;;;;;;;;GASG;AACH,wBAAgB,aAAa,CAC3B,SAAS,EAAE,MAAM,EACjB,UAAU,EAAE,MAAM,GACjB,OAAO,CAKT;AAED;;;;;;;GAOG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAGvD;AAMD;;;;;;GAMG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAGrD;AAED;;;;;GAKG;AACH,wBAAgB,iBAAiB,IAAI,MAAM,EAAE,CAI5C;AAMD;;;;;;;;GAQG;AACH,wBAAgB,sBAAsB,CACpC,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,MAAM,EACd,SAAS,EAAE,MAAM,GAChB;IAAE,OAAO,EAAE,OAAO,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAA;CAAE,CA0BvC"}
1
+ {"version":3,"file":"permissions.d.ts","sourceRoot":"","sources":["../../../src/lib/teams/permissions.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAUH;;GAEG;AACH,MAAM,MAAM,QAAQ,GAAG,QAAQ,GAAG,YAAY,CAAA;AAE9C;;GAEG;AACH,MAAM,MAAM,cAAc,GACtB,WAAW,GACX,WAAW,GACX,aAAa,GACb,mBAAmB,GACnB,qBAAqB,GACrB,qBAAqB,GACrB,0BAA0B,GAC1B,oBAAoB,GACpB,oBAAoB,GACpB,mBAAmB,GACnB,qBAAqB,CAAA;AAEzB;;;GAGG;AACH,eAAO,MAAM,oBAAoB,EAAE,cAAc,EAYhD,CAAA;AAuCD;;;;;;;GAOG;AACH,eAAO,MAAM,eAAe,EAAE,MAAM,CAAC,MAAM,EAAE,cAAc,EAAE,CAAgC,CAAA;AAM7F;;;;;;;GAOG;AACH,wBAAgB,aAAa,CAC3B,IAAI,EAAE,MAAM,EACZ,UAAU,EAAE,cAAc,EAC1B,aAAa,GAAE,OAAe,GAC7B,OAAO,CAWT;AAED;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CAChC,IAAI,EAAE,MAAM,EACZ,aAAa,GAAE,OAAe,GAC7B,cAAc,EAAE,CAQlB;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,mBAAmB,CACjC,QAAQ,EAAE,QAAQ,EAClB,QAAQ,EAAE,MAAM,GAAG,IAAI,EACvB,UAAU,EAAE,cAAc,GACzB,OAAO,CAcT;AAED;;;;;GAKG;AACH,wBAAgB,YAAY,CAAC,QAAQ,EAAE,QAAQ,GAAG,OAAO,CAExD;AAMD;;;;;;;;;GASG;AACH,wBAAgB,aAAa,CAC3B,SAAS,EAAE,MAAM,EACjB,UAAU,EAAE,MAAM,GACjB,OAAO,CAKT;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,eAAe,CAC7B,SAAS,EAAE,MAAM,EACjB,UAAU,EAAE,MAAM,GACjB,OAAO,CAIT;AAED;;;;;;;GAOG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAGvD;AAMD;;;;;;GAMG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAGrD;AAED;;;;;GAKG;AACH,wBAAgB,iBAAiB,IAAI,MAAM,EAAE,CAI5C;AAMD;;;;;;;;GAQG;AACH,wBAAgB,sBAAsB,CACpC,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,MAAM,EACd,SAAS,EAAE,MAAM,GAChB;IAAE,OAAO,EAAE,OAAO,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAA;CAAE,CA0BvC"}
@@ -63,6 +63,10 @@ function canManageRole(actorRole, targetRole) {
63
63
  const hierarchy = getHierarchyFromRegistry();
64
64
  return (hierarchy[actorRole] ?? 0) > (hierarchy[targetRole] ?? 0);
65
65
  }
66
+ function canInviteToRole(actorRole, targetRole) {
67
+ const hierarchy = getHierarchyFromRegistry();
68
+ return (hierarchy[actorRole] ?? 0) >= (hierarchy[targetRole] ?? 0);
69
+ }
66
70
  function getRoleDescription(role) {
67
71
  const descriptions = getDescriptionsFromRegistry();
68
72
  return descriptions[role] ?? "No description available";
@@ -97,6 +101,7 @@ function validateRoleTransition(fromRole, toRole, actorRole) {
97
101
  }
98
102
  export {
99
103
  ALL_TEAM_PERMISSIONS,
104
+ canInviteToRole,
100
105
  canManageRole,
101
106
  checkTeamPermission,
102
107
  getInvitableRoles,
@@ -1,5 +1,5 @@
1
1
  {
2
- "generated": "2026-05-27T00:35:24.358Z",
2
+ "generated": "2026-05-31T22:59:50.588Z",
3
3
  "totalClasses": 1080,
4
4
  "classes": [
5
5
  "!text-2xl",
@@ -14,24 +14,12 @@ import { checkRateLimit, withRateLimitTier } from '@nextsparkjs/core/lib/api/rat
14
14
  import { RATE_LIMITS } from '@nextsparkjs/core/lib/api/keys'
15
15
  import { inviteMemberSchema, memberListQuerySchema } from '@nextsparkjs/core/lib/teams/schema'
16
16
  import { TeamMemberService, MembershipService } from '@nextsparkjs/core/lib/services'
17
+ import { canInviteToRole } from '@nextsparkjs/core/lib/teams/permissions'
17
18
  import type { TeamMember, TeamInvitation, TeamRole, Team } from '@nextsparkjs/core/lib/teams/types'
18
19
  import { EmailFactory } from '@nextsparkjs/core/lib/email/factory'
19
20
  import { sendTeamInvitationEmail } from '@nextsparkjs/core/lib/email/send'
20
21
  import { I18N_CONFIG } from '@nextsparkjs/core/lib/config'
21
22
 
22
- // Role hierarchy for invite validation (higher number = more power)
23
- const ROLE_HIERARCHY: Record<TeamRole, number> = {
24
- owner: 4,
25
- admin: 3,
26
- member: 2,
27
- viewer: 1,
28
- }
29
-
30
- // Check if a user can invite to a specific role (same level or below)
31
- function canInviteToRole(actorRole: TeamRole, targetRole: TeamRole): boolean {
32
- return ROLE_HIERARCHY[actorRole] >= ROLE_HIERARCHY[targetRole]
33
- }
34
-
35
23
  // Handle CORS preflight
36
24
  export async function OPTIONS() {
37
25
  return handleCorsPreflightRequest()
@@ -226,7 +214,8 @@ export const POST = withRateLimitTier(withApiLogging(
226
214
  const body = await req.json()
227
215
  const validatedData = inviteMemberSchema.parse(body)
228
216
 
229
- // Check role hierarchy - users can only invite to same role or below
217
+ // Check role hierarchy via the merged permissions registry users can
218
+ // only invite to roles at the same level or below their own
230
219
  if (!canInviteToRole(userRole, validatedData.role)) {
231
220
  const response = createApiError(
232
221
  `You cannot invite members to a role higher than your own. Your role: ${userRole}, requested role: ${validatedData.role}`,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nextsparkjs/core",
3
- "version": "0.1.0-beta.154",
3
+ "version": "0.1.0-beta.156",
4
4
  "description": "NextSpark - The complete SaaS framework for Next.js",
5
5
  "license": "MIT",
6
6
  "author": "NextSpark <hello@nextspark.dev>",
@@ -467,7 +467,7 @@
467
467
  "tailwind-merge": "^3.3.1",
468
468
  "uuid": "^13.0.0",
469
469
  "zod": "^4.1.5",
470
- "@nextsparkjs/testing": "0.1.0-beta.154"
470
+ "@nextsparkjs/testing": "0.1.0-beta.156"
471
471
  },
472
472
  "scripts": {
473
473
  "postinstall": "node scripts/postinstall.mjs || true",
@@ -14,24 +14,12 @@ import { checkRateLimit, withRateLimitTier } from '@nextsparkjs/core/lib/api/rat
14
14
  import { RATE_LIMITS } from '@nextsparkjs/core/lib/api/keys'
15
15
  import { inviteMemberSchema, memberListQuerySchema } from '@nextsparkjs/core/lib/teams/schema'
16
16
  import { TeamMemberService, MembershipService } from '@nextsparkjs/core/lib/services'
17
+ import { canInviteToRole } from '@nextsparkjs/core/lib/teams/permissions'
17
18
  import type { TeamMember, TeamInvitation, TeamRole, Team } from '@nextsparkjs/core/lib/teams/types'
18
19
  import { EmailFactory } from '@nextsparkjs/core/lib/email/factory'
19
20
  import { sendTeamInvitationEmail } from '@nextsparkjs/core/lib/email/send'
20
21
  import { I18N_CONFIG } from '@nextsparkjs/core/lib/config'
21
22
 
22
- // Role hierarchy for invite validation (higher number = more power)
23
- const ROLE_HIERARCHY: Record<TeamRole, number> = {
24
- owner: 4,
25
- admin: 3,
26
- member: 2,
27
- viewer: 1,
28
- }
29
-
30
- // Check if a user can invite to a specific role (same level or below)
31
- function canInviteToRole(actorRole: TeamRole, targetRole: TeamRole): boolean {
32
- return ROLE_HIERARCHY[actorRole] >= ROLE_HIERARCHY[targetRole]
33
- }
34
-
35
23
  // Handle CORS preflight
36
24
  export async function OPTIONS() {
37
25
  return handleCorsPreflightRequest()
@@ -226,7 +214,8 @@ export const POST = withRateLimitTier(withApiLogging(
226
214
  const body = await req.json()
227
215
  const validatedData = inviteMemberSchema.parse(body)
228
216
 
229
- // Check role hierarchy - users can only invite to same role or below
217
+ // Check role hierarchy via the merged permissions registry users can
218
+ // only invite to roles at the same level or below their own
230
219
  if (!canInviteToRole(userRole, validatedData.role)) {
231
220
  const response = createApiError(
232
221
  `You cannot invite members to a role higher than your own. Your role: ${userRole}, requested role: ${validatedData.role}`,