Skip to content

Find a component

Loading the directory…

↑ ↓ to select · Enter to open · Esc to closeBrowse all →
Contributor login

Convex Invite-links

Membership and invite management for Convex — shareable invite links with expiration, email locking, and group access control.

Upstream source
git clone https://github.com/TimpiaAI/convex-invite-links.git
cd convex-invite-links

This upstream package has not been adapted or qualified for Bijection. Read the original documentation before adopting it.

Description

Membership and invite management for Convex — shareable invite links with expiration, email locking, and group access control.

Explore the package README for API concepts, configuration, and examples. Check the Bijection source for adaptation-specific setup.

Available to evaluate

Review the source and its dependencies before adopting this package. Source availability does not establish npm publication or runtime qualification.

Getting started

  1. Get the source at the revision above and read its package documentation.
  2. Check the required Bijection SDK version, dependencies, and external service credentials.
  3. Follow the package setup instructions and the guide to using components.
  4. Exercise the component in your deployment according to your project’s verification rules.

Open source

Maintained source: TimpiaAI/convex-invite-links. License: See repository. Consult the repository for license terms, notices, and contributor attribution.

From the upstream publisher

Convex component for membership and invite management — create shareable invite links with expiration, email locking, group/resource access control, and full lifecycle tracking

Explore the demo ↗

Upstream overview

From the upstream package documentation.

A Convex component that provides membership tracking and invite-based access control through shareable links. It handles group-level and resource-level permissions, invite lifecycle management with expiration and email locking, and includes HTTP endpoints for social preview generation. The component offers both direct membership management and invite-flow onboarding with comprehensive validation and cleanup utilities.

Use cases

From the upstream package documentation.

  • Team onboarding workflows where you need invite links that grant group membership with role-based access and email validation
  • Document or resource sharing that requires time-limited access control with revocation capabilities
  • Multi-tenant applications managing user permissions across different groups or organizations with invite tracking
  • Collaborative platforms needing automated membership management with social preview links for better user experience
  • Applications with approval flows where administrators create invites for specific users with predefined access levels

How it works

From the upstream package documentation.

The component registers with your Convex app and exposes membership APIs like isMember(), hasAccess(), and getAllGroups() for querying permissions, plus mutation functions like addMember() and grantAccess() for direct access management. Invite creation happens through makeInvite() which generates tokens with optional email locks, expiration dates, and metadata, while claimInvite() validates and applies the invite to grant appropriate access.

HTTP integration is handled by handleInviteWebhook() which processes GET requests to invite URLs and returns HTML with Open Graph metadata for social previews. The component includes utility functions like makeInviteUrl() for generating shareable links and inviteFromUrl() for parsing tokens from requests.

Invite management includes revokeInvite() for immediate invalidation, listInvites() with filtering options, and deleteOldInvites() for scheduled cleanup through Convex cron jobs. The system tracks invite status (pending, claimed, expired, revoked) and provides detailed validation results during the claiming process.

Upstream package FAQ

Can I restrict invites to specific email addresses?

Yes, convex-invite-links supports email-locked invites. When creating an invite with makeInvite(), pass an email parameter to restrict claiming to that specific email address. The claimInvite() function will validate the email match before granting access.

How do I check if a user has access to a resource?

Use the hasAccess() query function from convex-invite-links to check resource-level permissions, or isMember() to verify group membership. Both functions take a userId and return boolean results for authorization checks in your Convex queries and mutations.

Does this component handle invite URL generation automatically?

The convex-invite-links component provides makeInviteUrl() to generate shareable URLs from invite tokens, and inviteFromUrl() to parse tokens from incoming requests. You configure the base URL during initialization and the component handles token generation and parsing.

Can I add users to groups without sending invites?

Yes, convex-invite-links includes direct membership management with addMember() and grantAccess() functions. These bypass the invite process and immediately add users to groups or grant resource access, useful for admin actions or programmatic membership changes.

How do I clean up old expired invites?

Use the deleteOldInvites() mutation from convex-invite-links in a scheduled Convex cron job. Pass an olderThanMs parameter to specify the age threshold, and the component will remove expired, claimed, and revoked invites older than the specified time period.

Use with agents and CLI

Give your coding agent the component’s source identity and setup guidance.

agent-prompt.md
Help me integrate Convex Invite-links with Bijection.

Read: https://bijection.com/components/convex-invite-links/SKILL.md

Check SDK compatibility and dependency availability.
Follow this project's execution and verification rules.

Upstream README.md

View repository ↗

Documentation from TimpiaAI/convex-invite-links, recorded October 23, 2026. APIs and setup may differ in the Bijection adaptation.

convex-invite-links

A Convex component for membership and invite management — create shareable invite links with expiration, email locking, group/resource access control, and full lifecycle tracking.

Built for apps that need invite-based onboarding, team management, resource sharing, and access control.

Convex Components Challenge — Invite Links: Membership Tracking, Invite Creation, Claiming, and HTTP Integration

Features

  • Membership Tracking — isMember(), hasAccess(), getAllGroups(), getAllMembers(), addMember(), grantAccess()
  • Generic Access Control — Group-level and resource-level access, configurable per invite
  • Invite Creation — makeInvite() with optional email/phone lock, expiration, destination URL, and metadata
  • Configurable Defaults — Set default expiration at component initialization
  • Invite Revocation — revokeInvite() to immediately invalidate by ID or token
  • Invite Listing — listInvites() with filters for group, resource, user, and status
  • Invite Cleanup — deleteOldInvites() for scheduled garbage collection
  • Invite Claiming — claimInvite() validates token, checks recipient lock, auto-grants access
  • Pending Invite Check — hasInvite() to check for unclaimed invites
  • HTTP Integration — handleInviteWebhook for direct invite URL visits with social previews
  • URL Helpers — makeInviteUrl() and inviteFromUrl() for link generation and parsing
  • Social Previews — og:title, og:description metadata on invite pages
  • TypeScript — Fully typed with exported interfaces for all result types

Installation

npm install convex-invite-links

Setup

1. Register the component

// convex/convex.config.ts
import { defineApp } from "convex/server";
import inviteLinks from "convex-invite-links/convex.config";

const app = defineApp();
app.use(inviteLinks);

export default app;

2. Initialize the client

// convex/invites.ts
import { InviteLinks } from "convex-invite-links";
import { components } from "./_generated/api.js";

const invites = new InviteLinks(components.inviteLinks, {
  defaultExpiryMs: 7 * 24 * 60 * 60 * 1000, // 7 days
  baseUrl: "https://myapp.com/invite",
});

Usage

Create an invite

import { mutation } from "./_generated/server.js";
import { v } from "convex/values";

export const createInvite = mutation({
  args: { email: v.optional(v.string()), groupId: v.string() },
  handler: async (ctx, args) => {
    const userId = await getAuthUserId(ctx);

    const result = await invites.makeInvite(ctx, {
      email: args.email,
      groupId: args.groupId,
      createdBy: userId,
      destinationUrl: "https://myapp.com/dashboard",
      metadata: { role: "member" },
      ogTitle: "Join My Team",
      ogDescription: "You've been invited to collaborate!",
    });

    // Generate a shareable URL
    const url = invites.makeInviteUrl(result.token);
    return { ...result, url };
  },
});

Claim an invite

export const acceptInvite = mutation({
  args: { token: v.string() },
  handler: async (ctx, args) => {
    const userId = await getAuthUserId(ctx);
    const userEmail = await getUserEmail(ctx);

    const result = await invites.claimInvite(ctx, {
      token: args.token,
      userId,
      email: userEmail,
    });

    if (!result.ok) {
      throw new Error(`Invite invalid: ${result.reason}`);
      // reason: "invalid" | "expired" | "revoked" | "already_claimed"
      //         | "email_mismatch" | "phone_mismatch"
    }

    return {
      destinationUrl: result.destinationUrl,
      groupId: result.groupId,
    };
  },
});

Check membership

export const checkAccess = query({
  args: { groupId: v.string() },
  handler: async (ctx, args) => {
    const userId = await getAuthUserId(ctx);

    const isMember = await invites.isMember(ctx, {
      userId,
      groupId: args.groupId,
    });

    return { isMember };
  },
});

Direct membership management

// Add a user to a group directly (without invite)
await invites.addMember(ctx, {
  userId: targetUserId,
  groupId: "team_123",
  addedBy: adminUserId,
});

// Grant resource access directly
await invites.grantAccess(ctx, {
  userId: targetUserId,
  resourceId: "doc_456",
  grantedBy: adminUserId,
});

// Remove membership or access
await invites.removeMember(ctx, { userId, groupId: "team_123" });
await invites.revokeAccess(ctx, { userId, resourceId: "doc_456" });

Revoke and manage invites

// Revoke by ID
await invites.revokeInvite(ctx, { inviteId: "invite_id_here" });

// Revoke by token
await invites.revokeInviteByToken(ctx, { token: "inv_abc123..." });

// List pending invites for a group
const pending = await invites.listInvites(ctx, {
  groupId: "team_123",
});

// List all invites including claimed/expired
const all = await invites.listInvites(ctx, {
  groupId: "team_123",
  includeClaimed: true,
  includeRevoked: true,
  includeExpired: true,
});

Schedule automatic cleanup

// In a cron job (convex/crons.ts)
import { cronJobs } from "convex/server";
import { internal } from "./_generated/api.js";

const crons = cronJobs();
crons.daily("cleanup invites", { hourUTC: 3, minuteUTC: 0 }, internal.invites.cleanupOld);
export default crons;

// In your invites file
export const cleanupOld = internalMutation({
  handler: async (ctx) => {
    const deleted = await invites.deleteOldInvites(ctx, {
      olderThanMs: 30 * 24 * 60 * 60 * 1000,
    });
    console.log(`Cleaned up ${deleted} old invites`);
  },
});

HTTP integration with social previews

import { handleInviteWebhook } from "convex-invite-links";
import { httpRouter } from "convex/server";

const http = httpRouter();

const inviteHandler = handleInviteWebhook(components.inviteLinks, {
  appName: "My App",
  redirectUrl: "https://myapp.com/accept-invite",
});

http.route({
  path: "/invite",
  method: "GET",
  handler: httpAction(async (ctx, request) => {
    return await inviteHandler(ctx, request);
  }),
});

export default http;

Parse invite tokens from URLs

// In an HTTP action or server function
const token = invites.inviteFromUrl(request);
if (token) {
  const invite = await invites.getInviteByToken(ctx, { token });
  if (invite?.isValid) {
    // Show invite acceptance page
  }
}

API Reference

Membership

MethodContextDescription
isMember(ctx, args)queryCheck if user is in a group
hasAccess(ctx, args)queryCheck if user has resource access
getAllGroups(ctx, args)queryList groups for a user
getAllMembers(ctx, args)queryList members of a group
addMember(ctx, args)mutationAdd user to group
removeMember(ctx, args)mutationRemove user from group
grantAccess(ctx, args)mutationGrant resource access
revokeAccess(ctx, args)mutationRevoke resource access

Invite Management

MethodContextDescription
makeInvite(ctx, args)mutationCreate invite with optional locks
revokeInvite(ctx, args)mutationRevoke invite by ID
revokeInviteByToken(ctx, args)mutationRevoke invite by token
listInvites(ctx, args?)queryList invites with filters
deleteOldInvites(ctx, args?)mutationCleanup old invites

Invite Claiming

MethodContextDescription
claimInvite(ctx, args)mutationValidate and apply invite
hasInvite(ctx, args)queryCheck for pending invites
getInviteByToken(ctx, args)queryGet invite details by token

HTTP Integration

FunctionDescription
handleInviteWebhook(component, options)HTTP handler with social preview metadata
invites.makeInviteUrl(token)Generate shareable invite URL
invites.inviteFromUrl(request)Parse token from URL/Request

Group Management

MethodContextDescription
upsertGroup(ctx, args)mutationCreate or update group
getGroup(ctx, args)queryGet group details

Live Demo

Check out the live demo for a working example.

Author

Built and maintained by TimpiaAI.

License

MIT

Keywords