profileShare

rasmusjy / profileshare

Read-only snapshot

No repository description.

main default branch 54 files Expires Sep 13, 2026, 9:06 AM
README.md 6,401 bytes

profileShare

profileShare creates time-limited, read-only snapshots of selected GitHub repositories. Anyone with a valid link can search the snapshot, switch frozen branches and tags, browse repositories and files, preview Markdown and raster images, open line-linked source, review file history, inspect commit diffs, read issues and pull request reviews, and inspect releases without a GitHub account.

Requirements

  • Node.js 24 or later
  • A GitHub account that can create a GitHub App

Check your Node.js version:

node --version

Local setup

  1. Install dependencies:

    npm install
    
  2. Create a GitHub App at GitHub Settings > Developer settings > GitHub Apps > New GitHub App. Use these settings:

    Setting Local value
    GitHub App name Any unique name
    Homepage URL http://localhost:3000
    Callback URL http://localhost:3000/auth/github/callback
    Setup URL http://localhost:3000/github/installed
    Webhook Clear Active
    Repository permissions: Contents Read-only
    Repository permissions: Issues Read-only
    Repository permissions: Metadata Read-only
    Repository permissions: Pull requests Read-only
    Where can this GitHub App be installed? Only on this account

    No webhook secret, private key, or user permission is needed. Keep Request user authorization (OAuth) during installation cleared because profileShare authorizes the owner before starting installation.

  3. Open the new GitHub App's settings page and create a client secret. Copy the Client ID, generated client secret, and app slug. The slug is the final part of the app's public URL, such as my-profile-share in https://github.com/apps/my-profile-share.

  4. Copy the example environment file:

    PowerShell:

    Copy-Item .env.example .env
    

    macOS or Linux:

    cp .env.example .env
    
  5. Fill in .env. Generate a stable session secret with:

    node -e "console.log(require('node:crypto').randomBytes(32).toString('hex'))"
    

    Keep this secret unchanged while using the same database. It is used to encrypt stored GitHub access tokens. Changing it makes existing owner records unreadable.

  6. Start the app:

    npm start
    
  7. Open http://localhost:3000, connect GitHub, and choose Only select repositories during GitHub App installation. Back in profileShare, select repositories, choose an expiry from 1 to 365 days, and create the link.

For automatic restart while editing:

npm run dev

Configuration

Variable Required Default Purpose
NODE_ENV No None Set to production for deployment safety checks
GITHUB_CLIENT_ID Yes None GitHub App client ID
GITHUB_CLIENT_SECRET Yes None GitHub App client secret
GITHUB_APP_SLUG Yes None GitHub App URL slug
SESSION_SECRET Yes Development fallback Token-encryption secret
BASE_URL No http://localhost:3000 Public origin used for OAuth callbacks and generated share links
PORT No 3000 HTTP port
DATABASE_PATH No data/profileshare.db SQLite database path

For a deployed instance, set NODE_ENV=production, set BASE_URL to its HTTPS origin, and update the GitHub App callback and setup URLs to the same origin. Generated links use BASE_URL, so it must be reachable by viewers.

Snapshots are stored in the SQLite database. The owner workspace lists created links and lets the signed-in owner copy, open, or revoke active links. Revoking a link removes its stored repository content. When an expired link is opened, its stored snapshot content is removed and the expired message is shown.

Verify

Run the complete test suite:

npm test

Run an individual spec check:

npm test -- auth
npm test -- snapshot
npm test -- e2e

Manual acceptance check:

  1. Create a link with a known set of repositories.
  2. Open it in a private browser window and confirm no viewer login is requested.
  3. Confirm only the selected repositories appear.
  4. Search for a file or code phrase across the snapshot.
  5. Switch between a repository's branches and tags, and confirm each ref shows its frozen files and commits.
  6. Open the Issues and Pull requests tabs, then inspect a conversation and a changed-file diff.
  7. Open Releases, inspect the release notes and asset metadata, and browse its tag.
  8. Confirm the repository overview shows topics, license, languages, stars, forks, branches, and tags.
  9. Browse a nested folder, preview a Markdown file and a raster image, switch Markdown to source, follow a line link, and open file history.
  10. Open a commit diff and confirm the full commit list appears for each selected repository.
  11. Filter the profile's repository tab by name and language.
  12. Change a source repository and confirm the existing link remains unchanged.
  13. Return to the owner workspace, revoke the link, and confirm the public URL no longer exposes repository content.

Troubleshooting

  • GitHub is not configured: Confirm all three GITHUB_* values are present in .env, then restart the server.
  • Callback error or sign-in verification error: Make sure BASE_URL and the GitHub App callback URL use the same origin, port, and protocol. Start sign-in again from the home page.
  • No repositories appear: Open the GitHub App installation settings and grant it access to the intended repositories. The app lists only repositories selected for that installation.
  • Issues or pull requests do not appear: Grant the GitHub App read-only Issues and Pull requests permissions, approve the updated installation permissions, then create a new snapshot.
  • Repository snapshot fails: Confirm the GitHub App has read-only Contents and Metadata repository permissions and that the owner still has access.
  • Stored token errors after changing SESSION_SECRET: Restore the previous secret, or move the local database aside and sign in again. Do not delete a database that contains snapshots you need.
  • The generated link points to localhost: Set BASE_URL to the viewer-reachable HTTPS origin before creating the link.
  • Port conflict: Set PORT and use the same port in BASE_URL, the callback URL, and the setup URL.