fix(docs): refresh module readmes and add repository license file

This commit is contained in:
2026-04-20 08:15:42 +00:00
parent 2d1e6ea6e1
commit 76efcb835f
10 changed files with 511 additions and 1286 deletions
+78 -311
View File
@@ -1,71 +1,61 @@
# @idp.global/idpclient
# @idp.global/client
A TypeScript client library for integrating with the idp.global Identity Provider. Works in both browser and Node.js environments.
Browser-facing TypeScript client for talking to an `idp.global` server over `typedrequest` and `typedsocket`.
## Overview
It handles login state, refresh tokens, JWT housekeeping, cross-app transfer tokens, and direct access to the typed request surface.
The IdpClient provides a complete API for authentication, session management, and organization operations. It uses WebSocket connections via TypedSocket for real-time, type-safe communication with the IdP server.
## Issue Reporting and Security
## Installation
For reporting bugs, issues, or security vulnerabilities, please visit [community.foss.global/](https://community.foss.global/). This is the central community hub for all issue reporting. Developers who sign and comply with our contribution agreement and go through identification can also get a [code.foss.global/](https://code.foss.global/) account to submit Pull Requests directly.
## Install
```bash
npm install @idp.global/idpclient
# or
pnpm add @idp.global/idpclient
pnpm add @idp.global/client
```
## Quick Start
```typescript
import { IdpClient } from '@idp.global/idpclient';
```ts
import { IdpClient } from '@idp.global/client';
// Initialize the client
const idpClient = new IdpClient('https://idp.global');
// Enable WebSocket connection
await idpClient.enableTypedSocket();
// Check login status
const isLoggedIn = await idpClient.determineLoginStatus();
const loggedIn = await idpClient.determineLoginStatus();
if (isLoggedIn) {
const userInfo = await idpClient.whoIs();
console.log('Logged in as:', userInfo.user.data.name);
if (!loggedIn) {
const loginResult = await idpClient.requests.loginWithUserNameAndPassword.fire({
username: 'user@example.com',
password: 'secret',
});
if (loginResult.refreshToken) {
await idpClient.refreshJwt(loginResult.refreshToken);
}
}
const whoIs = await idpClient.whoIs();
console.log(whoIs.user.data.email);
```
## Core Features
## What The Client Handles
### Authentication
- Normalizes the base URL to the server's `/typedrequest` endpoint.
- Stores JWT and refresh token state in a browser `WebStore`.
- Refreshes expiring JWTs via `performJwtHousekeeping()`.
- Redirects to `/login` when `determineLoginStatus(true)` is used.
- Exchanges refresh tokens for cross-app transfer tokens.
- Exposes the low-level typed requests through `idpClient.requests`.
#### Password Login
## Common Flows
```typescript
const response = await idpClient.requests.loginWithUserNameAndPassword.fire({
### Password Login
```ts
const result = await idpClient.requests.loginWithUserNameAndPassword.fire({
username: 'user@example.com',
password: 'securepassword',
});
if (response.refreshToken) {
await idpClient.refreshJwt(response.refreshToken);
console.log('Login successful!');
} else if (response.twoFaNeeded) {
console.log('2FA verification required');
}
```
#### Magic Link Login
```typescript
// Request magic link
await idpClient.requests.loginWithEmail.fire({
email: 'user@example.com',
});
// After clicking the email link
const result = await idpClient.requests.loginWithEmailAfterToken.fire({
email: 'user@example.com',
token: 'token-from-email-link',
password: 'secret',
});
if (result.refreshToken) {
@@ -73,303 +63,80 @@ if (result.refreshToken) {
}
```
#### API Token Login
### Magic Link Login
```typescript
const result = await idpClient.requests.loginWithApiToken.fire({
apiToken: 'your-api-token',
```ts
await idpClient.requests.loginWithEmail.fire({
email: 'user@example.com',
});
if (result.jwt) {
await idpClient.setJwt(result.jwt);
}
const result = await idpClient.requests.loginWithEmailAfterToken.fire({
email: 'user@example.com',
token: 'token-from-email',
});
await idpClient.refreshJwt(result.refreshToken);
```
### Session Management
### Session and Identity
```typescript
// Get current JWT
const jwt = await idpClient.getJwt();
// Get parsed JWT data
const jwtData = await idpClient.getJwtData();
console.log('User ID:', jwtData.id);
// Refresh JWT (automatic housekeeping)
```ts
await idpClient.performJwtHousekeeping();
// Manual refresh
await idpClient.refreshJwt();
const jwt = await idpClient.getJwt();
const jwtData = await idpClient.getJwtData();
const whoIs = await idpClient.whoIs();
// Logout
await idpClient.logout();
console.log(jwtData.id, whoIs.user.data.username);
```
### User Information
### Organizations
```typescript
// Get current user details
const whoIsResponse = await idpClient.whoIs();
console.log('Name:', whoIsResponse.user.data.name);
console.log('Email:', whoIsResponse.user.data.email);
```ts
const rolesAndOrganizations = await idpClient.getRolesAndOrganizations();
// Get user data
const userData = await idpClient.requests.getUserData.fire({
jwt: await idpClient.getJwt(),
userId: jwtData.id,
});
// Update user data
await idpClient.requests.setUserData.fire({
jwt: await idpClient.getJwt(),
userId: jwtData.id,
name: 'New Name',
});
```
### Organization Management
```typescript
// Get user's organizations and roles
const orgsAndRoles = await idpClient.getRolesAndOrganizations();
console.log('Organizations:', orgsAndRoles.organizations);
console.log('Roles:', orgsAndRoles.roles);
// Create a new organization
const result = await idpClient.createOrganization(
'My Company', // name
'my-company', // slug
'manifest' // mode: 'checkAvailability' or 'manifest'
const created = await idpClient.createOrganization(
'Acme',
'acme',
'manifest'
);
if (result.resultingOrganization) {
console.log('Created:', result.resultingOrganization.id);
}
// Get organization details
const orgDetails = await idpClient.requests.getOrganizationById.fire({
jwt: await idpClient.getJwt(),
organizationId: 'org-id',
});
```
### Member & Invitation Management
```typescript
// Get organization members
const members = await idpClient.requests.getOrgMembers.fire({
jwt: await idpClient.getJwt(),
organizationId: 'org-id',
});
// Invite a new member
await idpClient.requests.createInvitation.fire({
jwt: await idpClient.getJwt(),
organizationId: 'org-id',
email: 'newmember@example.com',
roles: ['member'],
});
// Bulk invite members
await idpClient.requests.bulkCreateInvitations.fire({
jwt: await idpClient.getJwt(),
organizationId: 'org-id',
invitations: [
{ email: 'user1@example.com', roles: ['member'] },
{ email: 'user2@example.com', roles: ['admin'] },
],
});
// Accept an invitation
await idpClient.requests.acceptInvitation.fire({
jwt: await idpClient.getJwt(),
invitationToken: 'token-from-invite-email',
});
// Remove a member
await idpClient.requests.removeMember.fire({
jwt: await idpClient.getJwt(),
organizationId: 'org-id',
userId: 'user-id',
});
// Transfer ownership
await idpClient.requests.transferOwnership.fire({
jwt: await idpClient.getJwt(),
organizationId: 'org-id',
newOwnerId: 'new-owner-user-id',
organizationId: created.resultingOrganization.id,
});
```
### Password Management
### Cross-App Transfer
```typescript
// Request password reset
await idpClient.requests.resetPassword.fire({
email: 'user@example.com',
});
// Set new password (with token from email)
await idpClient.requests.setNewPassword.fire({
email: 'user@example.com',
tokenArg: 'reset-token',
newPassword: 'newsecurepassword',
});
// Change password (when logged in)
await idpClient.requests.setNewPassword.fire({
email: 'user@example.com',
oldPassword: 'currentpassword',
newPassword: 'newsecurepassword',
});
```
### Session & Device Management
```typescript
// Get active sessions
const sessions = await idpClient.requests.getUserSessions.fire({
jwt: await idpClient.getJwt(),
userId: jwtData.id,
});
// Revoke a session
await idpClient.requests.revokeSession.fire({
jwt: await idpClient.getJwt(),
sessionId: 'session-id',
});
// Get device ID
const deviceInfo = await idpClient.requests.obtainDeviceId.fire({});
// Attach device to session
await idpClient.requests.attachDeviceId.fire({
jwt: await idpClient.getJwt(),
deviceId: deviceInfo.deviceId.id,
});
```
### Cross-Domain Authentication
```typescript
// Get transfer token for SSO between apps
```ts
const transferToken = await idpClient.getTransferToken();
// Switch to another app with authentication
await idpClient.getTransferTokenAndSwitchToLocation('https://app.example.com/');
// Process incoming transfer token (in target app)
const success = await idpClient.processTransferToken();
if (success) {
console.log('Cross-domain login successful');
}
```
### Billing Integration
## Typed Request Surface
```typescript
// Get billing plan for an organization
const billingPlan = await idpClient.requests.getBillingPlan.fire({
jwt: await idpClient.getJwt(),
organizationId: 'org-id',
});
`IdpRequests` exposes typed request getters for:
// Get Paddle configuration
const paddleConfig = await idpClient.requests.getPaddleConfig.fire({
jwt: await idpClient.getJwt(),
});
- authentication
- registration
- user/session queries
- org and invitation management
- billing requests
- JWT validation key requests
- admin requests
// Update payment method
await idpClient.updatePaddleCheckoutId('org-id', 'checkout-id');
```
Use these when you want full control instead of the higher-level helper methods on `IdpClient`.
### Admin Operations (Global Admins Only)
## Important Runtime Notes
```typescript
// Check if user is global admin
const isAdmin = await idpClient.requests.checkGlobalAdmin.fire({
jwt: await idpClient.getJwt(),
});
// Get platform statistics
const stats = await idpClient.requests.getGlobalAppStats.fire({
jwt: await idpClient.getJwt(),
});
// Create a global app
await idpClient.requests.createGlobalApp.fire({
jwt: await idpClient.getJwt(),
name: 'My App',
description: 'App description',
});
// Suspend a user
await idpClient.requests.suspendUser.fire({
jwt: await idpClient.getJwt(),
userId: 'user-id',
});
```
## Reactive Subscriptions
The client provides RxJS subjects for reactive updates:
```typescript
// Subscribe to login status changes
idpClient.statusObservable.subscribe((status) => {
console.log('Login status changed:', status);
});
// Subscribe to roles updates
idpClient.rolesReplaySubject.subscribe((roles) => {
console.log('Roles updated:', roles);
});
// Subscribe to organizations updates
idpClient.organizationsReplaySubject.subscribe((orgs) => {
console.log('Organizations updated:', orgs);
});
```
## API Reference
### IdpClient Class
| Method | Description |
|--------|-------------|
| `enableTypedSocket()` | Initialize WebSocket connection |
| `determineLoginStatus(requireLogin?)` | Check if user is logged in |
| `getJwt()` | Get stored JWT string |
| `getJwtData()` | Get parsed JWT data |
| `setJwt(jwt)` | Store JWT |
| `deleteJwt()` | Remove stored JWT |
| `refreshJwt(refreshToken?)` | Refresh the JWT |
| `performJwtHousekeeping()` | Auto-refresh JWT if needed |
| `logout()` | End session and redirect |
| `whoIs()` | Get current user info |
| `getRolesAndOrganizations()` | Get user's orgs and roles |
| `createOrganization(name, slug, mode)` | Create new organization |
| `getTransferToken(appData?)` | Get SSO transfer token |
| `processTransferToken()` | Process incoming transfer token |
| `stop()` | Close WebSocket connection |
### IdpRequests Class
Access via `idpClient.requests.*`:
**Authentication**: `loginWithUserNameAndPassword`, `loginWithEmail`, `loginWithEmailAfterToken`, `loginWithApiToken`, `resetPassword`, `setNewPassword`
**User**: `getUserData`, `setUserData`, `getUserSessions`, `revokeSession`, `getUserActivity`
**Organization**: `getOrganizationById`, `updateOrganization`, `createInvitation`, `bulkCreateInvitations`, `getOrgMembers`, `getOrgInvitations`, `acceptInvitation`, `cancelInvitation`, `resendInvitation`, `removeMember`, `updateMemberRoles`, `transferOwnership`
**Billing**: `getBillingPlan`, `getPaddleConfig`
**Admin**: `checkGlobalAdmin`, `getGlobalAppStats`, `createGlobalApp`, `updateGlobalApp`, `deleteGlobalApp`, `suspendUser`, `deleteSuspendedUser`
- The default fallback `appData` uses `window.location`, so this package is primarily browser-oriented.
- The client expects the backend `typedrequest` websocket surface to be reachable.
- Auth state is persisted in browser storage under the `idpglobalStore` store name.
## License and Legal Information
This repository contains open-source code licensed under the MIT License. A copy of the license can be found in the [LICENSE](../LICENSE) file.
This repository contains open-source code licensed under the MIT License. A copy of the license can be found in the [license](../license) file.
**Please note:** The MIT License does not grant permission to use the trade names, trademarks, service marks, or product names of the project, except as required for reasonable and customary use in describing the origin of the work and reproducing the content of the NOTICE file.
@@ -381,7 +148,7 @@ Use of these trademarks must comply with Task Venture Capital GmbH's Trademark G
### Company Information
Task Venture Capital GmbH
Task Venture Capital GmbH
Registered at District Court Bremen HRB 35230 HB, Germany
For any legal inquiries or further information, please contact us via email at hello@task.vc.