spine-framework 0.3.57 → 0.3.59

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.
@@ -213,7 +213,8 @@ export const validateToken = createHandler(async (_ctx, _body) => {
213
213
  * (invite path is handled entirely in the DB trigger)
214
214
  */
215
215
  export const completeRegistration = createHandler(async (ctx, body) => {
216
- const { path, account_name, email } = body
216
+ const { path, account_name, email, role_slug } = body
217
+ console.log('completeRegistration called with:', { path, account_name, email, role_slug })
217
218
 
218
219
  if (!path || !email) {
219
220
  throw new Error('path and email are required')
@@ -238,15 +239,50 @@ export const completeRegistration = createHandler(async (ctx, body) => {
238
239
  .eq('slug', 'account')
239
240
  .single()
240
241
 
241
- // Resolve member_admin role (fall back to member if not seeded yet)
242
- const { data: roles } = await adminDb
242
+ // Resolve role from role_slug param, or fall back to member_admin/member lookup
243
+ const targetRoleSlug = role_slug || 'member'
244
+ console.log('Looking for role:', targetRoleSlug)
245
+
246
+ let { data: roles } = await adminDb
243
247
  .from('roles')
244
- .select('id')
245
- .in('slug', ['member_admin', 'member'])
246
- .order('slug') // member_admin sorts before member
248
+ .select('id, slug')
249
+ .eq('slug', targetRoleSlug)
247
250
  .limit(1)
248
251
 
249
- const role = roles?.[0]
252
+ let role = roles?.[0]
253
+ console.log('Found role:', role)
254
+
255
+ // If specific role not found, try member_admin or member as fallback
256
+ if (!role) {
257
+ console.log('Role not found, trying fallbacks...')
258
+ const { data: fallbackRoles } = await adminDb
259
+ .from('roles')
260
+ .select('id, slug')
261
+ .in('slug', ['member_admin', 'member'])
262
+ .order('slug')
263
+ .limit(1)
264
+ role = fallbackRoles?.[0]
265
+ console.log('Fallback role:', role)
266
+ }
267
+
268
+ // If no roles exist yet (apps not installed), create a default member role
269
+ if (!role) {
270
+ const { data: newRole, error: roleErr } = await adminDb
271
+ .from('roles')
272
+ .insert({
273
+ slug: 'member',
274
+ name: 'Member',
275
+ description: 'Default member role with basic permissions',
276
+ permissions: { items: ['read', 'create'], accounts: ['read'] },
277
+ is_active: true,
278
+ })
279
+ .select('id')
280
+ .single()
281
+
282
+ if (!roleErr && newRole) {
283
+ role = newRole
284
+ }
285
+ }
250
286
 
251
287
  // Create account
252
288
  const slug = generateAccountSlug(account_name)
@@ -282,17 +318,28 @@ export const completeRegistration = createHandler(async (ctx, body) => {
282
318
  }
283
319
 
284
320
  if (path === 'join_request') {
285
- const { target_account_id } = body
321
+ const { target_account_id, role_slug } = body
286
322
  if (!target_account_id) throw new Error('target_account_id is required for join_request')
287
323
 
288
- // Resolve member role
289
- const { data: roles } = await adminDb
324
+ // Resolve role from role_slug param, or fall back to member
325
+ const targetRoleSlug = role_slug || 'member'
326
+ let { data: roles } = await adminDb
290
327
  .from('roles')
291
328
  .select('id')
292
- .eq('slug', 'member')
329
+ .eq('slug', targetRoleSlug)
293
330
  .limit(1)
294
331
 
295
- const role = roles?.[0]
332
+ let role = roles?.[0]
333
+
334
+ // Fallback to member if specific role not found
335
+ if (!role) {
336
+ const { data: fallbackRoles } = await adminDb
337
+ .from('roles')
338
+ .select('id')
339
+ .eq('slug', 'member')
340
+ .limit(1)
341
+ role = fallbackRoles?.[0]
342
+ }
296
343
 
297
344
  // Resolve type_id
298
345
  const { data: personType } = await adminDb
@@ -234,11 +234,17 @@ export function RegisterPage() {
234
234
  // 4. Walk-up paths — call complete-registration
235
235
  const resolvedEmail = email
236
236
 
237
+ // Determine role from URL params or config
238
+ const urlRole = searchParams.get('role')
239
+ const urlApp = searchParams.get('app')
240
+ const effectiveRole = urlRole || (urlApp && regConfig?.apps[urlApp]?.role) || regConfig?.default_role || 'member'
241
+
237
242
  if (domainMatchChoice === 'join') {
238
243
  // Join existing account as access_request
239
244
  const joinResult = await callInvitesApi('complete-registration', {
240
245
  path: 'join_request',
241
246
  email: resolvedEmail,
247
+ role_slug: effectiveRole,
242
248
  }, 'POST')
243
249
 
244
250
  if (joinResult.error) {
@@ -255,6 +261,7 @@ export function RegisterPage() {
255
261
  path: 'new_account',
256
262
  email: resolvedEmail,
257
263
  account_name: accountName,
264
+ role_slug: effectiveRole,
258
265
  }, 'POST')
259
266
 
260
267
  if (newResult.error) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "spine-framework",
3
- "version": "0.3.57",
3
+ "version": "0.3.59",
4
4
  "description": "Multi-tenant, modular application platform for modern SaaS systems",
5
5
  "type": "module",
6
6
  "bin": {