@absolutejs/auth 0.85.0 → 0.86.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/index.d.ts CHANGED
@@ -3045,6 +3045,7 @@ export declare const createAuthApplications: <UserType>(configuration: AuthConfi
3045
3045
  property?: string;
3046
3046
  expected?: string;
3047
3047
  };
3048
+ 502: "Invitation delivery failed; create a new invitation to retry";
3048
3049
  };
3049
3050
  error: never;
3050
3051
  };
package/dist/index.js CHANGED
@@ -10243,29 +10243,17 @@ init_crypto();
10243
10243
  var acceptInvitation = async ({
10244
10244
  organizationStore,
10245
10245
  token,
10246
- userId
10246
+ userId,
10247
+ verifiedEmail
10247
10248
  }) => {
10248
- const invitation = await organizationStore.getInvitationByTokenHash(await hashToken(token));
10249
- if (!invitation || invitation.state !== "pending")
10250
- return;
10251
- if (invitation.expiresAt < Date.now())
10249
+ if (!verifiedEmail?.trim() || !organizationStore.acceptInvitation)
10252
10250
  return;
10253
- const now = Date.now();
10254
- await organizationStore.saveInvitation({
10255
- ...invitation,
10256
- acceptedAt: now,
10257
- state: "accepted"
10251
+ return organizationStore.acceptInvitation({
10252
+ now: Date.now(),
10253
+ tokenHash: await hashToken(token),
10254
+ userId,
10255
+ verifiedEmail: verifiedEmail.trim().toLowerCase()
10258
10256
  });
10259
- const membership = {
10260
- createdAt: now,
10261
- organizationId: invitation.organizationId,
10262
- roles: invitation.roles,
10263
- status: "active",
10264
- updatedAt: now,
10265
- userId
10266
- };
10267
- await organizationStore.saveMembership(membership);
10268
- return membership;
10269
10257
  };
10270
10258
  var createOrganization = async ({
10271
10259
  metadata,
@@ -10336,6 +10324,7 @@ var organizationRoutes = ({
10336
10324
  canManageMembers,
10337
10325
  emit,
10338
10326
  getUserId,
10327
+ getVerifiedEmail,
10339
10328
  invitationDurationMs,
10340
10329
  onMembershipAdded,
10341
10330
  onMembershipRemoved,
@@ -10442,13 +10431,21 @@ var organizationRoutes = ({
10442
10431
  organizationStore,
10443
10432
  roles: roles ?? []
10444
10433
  });
10445
- await onSendInvitation?.({
10446
- email: invitation.email,
10447
- expiresAt: invitation.expiresAt,
10448
- inviterUserId: invitation.inviterUserId,
10449
- organizationId,
10450
- token
10451
- });
10434
+ try {
10435
+ await onSendInvitation?.({
10436
+ email: invitation.email,
10437
+ expiresAt: invitation.expiresAt,
10438
+ inviterUserId: invitation.inviterUserId,
10439
+ organizationId,
10440
+ token
10441
+ });
10442
+ } catch {
10443
+ await organizationStore.saveInvitation({
10444
+ ...invitation,
10445
+ state: "revoked"
10446
+ });
10447
+ return status("Bad Gateway", "Invitation delivery failed; create a new invitation to retry");
10448
+ }
10452
10449
  await emit?.({
10453
10450
  at: Date.now(),
10454
10451
  metadata: { email: invitation.email },
@@ -10524,7 +10521,8 @@ var organizationRoutes = ({
10524
10521
  const membership = await acceptInvitation({
10525
10522
  organizationStore,
10526
10523
  token,
10527
- userId: getUserId(user)
10524
+ userId: getUserId(user),
10525
+ verifiedEmail: await getVerifiedEmail?.(user)
10528
10526
  });
10529
10527
  if (!membership) {
10530
10528
  return status("Bad Request", "Invalid or expired invitation");
@@ -10555,7 +10553,7 @@ var organizationRoutes = ({
10555
10553
  return status("Unauthorized", "Authentication required");
10556
10554
  }
10557
10555
  const membership = await organizationStore.getMembership(organizationId, getUserId(user));
10558
- if (membership?.status !== "active") {
10556
+ if (membership?.status !== "active" && !await mayManage(user, organizationId)) {
10559
10557
  return status("Forbidden", "Not a member");
10560
10558
  }
10561
10559
  const members = await organizationStore.listMembershipsByOrganization(organizationId);
@@ -39421,6 +39419,27 @@ var toInvitation = (row) => ({
39421
39419
  });
39422
39420
  var createNeonOrganizationStore = (databaseUrl) => createPostgresOrganizationStore(createNeonDatabase(databaseUrl));
39423
39421
  var createPostgresOrganizationStore = (db) => ({
39422
+ acceptInvitation: async ({ now, tokenHash, userId, verifiedEmail }) => {
39423
+ const claimed = db.$with("claimed").as(db.update(organizationInvitationsTable).set({ accepted_at_ms: now, state: "accepted" }).where(and(eq(organizationInvitationsTable.token_hash, tokenHash), eq(organizationInvitationsTable.state, "pending"), gt(organizationInvitationsTable.expires_at_ms, now), sql`lower(trim(${organizationInvitationsTable.email})) = ${verifiedEmail}`, exists(db.select().from(organizationsTable).where(eq(organizationsTable.organization_id, organizationInvitationsTable.organization_id))), notExists(db.select().from(organizationMembershipsTable).where(and(eq(organizationMembershipsTable.organization_id, organizationInvitationsTable.organization_id), eq(organizationMembershipsTable.user_id, userId), eq(organizationMembershipsTable.status, "suspended")))))).returning({
39424
+ organizationId: organizationInvitationsTable.organization_id,
39425
+ roles: organizationInvitationsTable.roles
39426
+ }));
39427
+ const [row] = await db.with(claimed).insert(organizationMembershipsTable).select(db.select({
39428
+ created_at_ms: sql`${now}`.as("created_at_ms"),
39429
+ organization_id: claimed.organizationId,
39430
+ roles: claimed.roles,
39431
+ status: sql`'active'`.as("status"),
39432
+ updated_at_ms: sql`${now}`.as("updated_at_ms"),
39433
+ user_id: sql`${userId}`.as("user_id")
39434
+ }).from(claimed)).onConflictDoUpdate({
39435
+ set: { user_id: userId },
39436
+ target: [
39437
+ organizationMembershipsTable.organization_id,
39438
+ organizationMembershipsTable.user_id
39439
+ ]
39440
+ }).returning();
39441
+ return row && row.status === "active" ? toMembership(row) : undefined;
39442
+ },
39424
39443
  deleteOrganization: async (organizationId) => {
39425
39444
  await db.delete(organizationsTable).where(eq(organizationsTable.organization_id, organizationId));
39426
39445
  },
@@ -40471,6 +40490,30 @@ var createInMemoryOrganizationStore = () => {
40471
40490
  const memberships = new Map;
40472
40491
  const invitations = new Map;
40473
40492
  return {
40493
+ acceptInvitation: async ({ tokenHash, userId, verifiedEmail, now }) => {
40494
+ const invitation = [...invitations.values()].find((value) => value.tokenHash === tokenHash);
40495
+ if (!invitation || invitation.state !== "pending" || invitation.expiresAt <= now || invitation.email.trim().toLowerCase() !== verifiedEmail || !organizations.has(invitation.organizationId))
40496
+ return;
40497
+ const key = membershipKey(invitation.organizationId, userId);
40498
+ const existing = memberships.get(key);
40499
+ if (existing?.status === "suspended")
40500
+ return;
40501
+ const membership = existing ?? {
40502
+ createdAt: now,
40503
+ organizationId: invitation.organizationId,
40504
+ roles: [...invitation.roles],
40505
+ status: "active",
40506
+ updatedAt: now,
40507
+ userId
40508
+ };
40509
+ invitations.set(invitation.invitationId, {
40510
+ ...invitation,
40511
+ acceptedAt: now,
40512
+ state: "accepted"
40513
+ });
40514
+ memberships.set(key, membership);
40515
+ return cloneMembership(membership);
40516
+ },
40474
40517
  deleteOrganization: async (organizationId) => {
40475
40518
  organizations.delete(organizationId);
40476
40519
  },
@@ -41573,5 +41616,5 @@ export {
41573
41616
  writeWarrant
41574
41617
  };
41575
41618
 
41576
- //# debugId=B0A4E820C09B981564756E2164756E21
41619
+ //# debugId=DC508F314D7A052E64756E2164756E21
41577
41620
  //# sourceMappingURL=index.js.map