initialize interfaces package
This commit is contained in:
+12
@@ -0,0 +1,12 @@
|
||||
.nogit/
|
||||
|
||||
# installs
|
||||
node_modules/
|
||||
|
||||
# builds
|
||||
dist/
|
||||
dist_*/
|
||||
|
||||
# caches
|
||||
.cache/
|
||||
.rpt2_cache
|
||||
@@ -0,0 +1,5 @@
|
||||
# Changelog
|
||||
|
||||
## 1.0.0
|
||||
|
||||
- Initial standalone extraction of idp.global shared interfaces.
|
||||
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2026 Task Venture Capital GmbH
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
@@ -0,0 +1,58 @@
|
||||
{
|
||||
"name": "@idp.global/interfaces",
|
||||
"version": "1.0.0",
|
||||
"private": false,
|
||||
"description": "Shared TypeScript interfaces and TypedRequest contracts for the idp.global ecosystem.",
|
||||
"exports": {
|
||||
".": "./dist_ts/index.js"
|
||||
},
|
||||
"type": "module",
|
||||
"author": "Task Venture Capital GmbH",
|
||||
"license": "MIT",
|
||||
"scripts": {
|
||||
"test": "tstest test/ --verbose --logfile --timeout 60",
|
||||
"build": "tsbuild tsfolders --allowimplicitany",
|
||||
"buildDocs": "tsdoc"
|
||||
},
|
||||
"dependencies": {
|
||||
"@api.global/typedrequest-interfaces": "^3.0.19",
|
||||
"@tsclass/tsclass": "^9.5.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@git.zone/tsbuild": "^4.4.0",
|
||||
"@git.zone/tsdoc": "^2.0.3",
|
||||
"@git.zone/tsrun": "^2.0.3",
|
||||
"@git.zone/tstest": "^3.6.3",
|
||||
"@types/node": "^25.6.0"
|
||||
},
|
||||
"files": [
|
||||
"ts/**/*",
|
||||
"dist/**/*",
|
||||
"dist_*/**/*",
|
||||
"dist_ts/**/*",
|
||||
"readme.md",
|
||||
"changelog.md",
|
||||
"license"
|
||||
],
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+ssh://git@code.foss.global:29419/idp.global/interfaces.git"
|
||||
},
|
||||
"bugs": {
|
||||
"url": "https://code.foss.global/idp.global/interfaces/issues"
|
||||
},
|
||||
"homepage": "https://code.foss.global/idp.global/interfaces#readme",
|
||||
"keywords": [
|
||||
"idp.global",
|
||||
"interfaces",
|
||||
"typedrequest",
|
||||
"contracts",
|
||||
"identity",
|
||||
"oidc",
|
||||
"typescript"
|
||||
],
|
||||
"browserslist": [
|
||||
"last 1 chrome versions"
|
||||
],
|
||||
"packageManager": "pnpm@10.7.0+sha512.6b865ad4b62a1d9842b61d674a393903b8712034030524f652b8842c2b553c72176b278f64c463e52d40fff8aba385c235c8c9ecf5cc7de4fd78b8bb6d49633ab6"
|
||||
}
|
||||
Generated
+8176
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,101 @@
|
||||
# @idp.global/interfaces
|
||||
|
||||
Shared TypeScript interfaces and TypedRequest contracts for the idp.global ecosystem.
|
||||
|
||||
This package contains only public data shapes, typed RPC request definitions, and shared tags used by the idp.global backend, browser client, CLI, web UI, and external integrations.
|
||||
|
||||
## Issue Reporting and Security
|
||||
|
||||
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
|
||||
pnpm add @idp.global/interfaces
|
||||
```
|
||||
|
||||
## Public API
|
||||
|
||||
```ts
|
||||
import { data, request, tags } from '@idp.global/interfaces';
|
||||
```
|
||||
|
||||
The root export exposes three namespaces:
|
||||
|
||||
```ts
|
||||
export {
|
||||
data,
|
||||
request,
|
||||
tags,
|
||||
};
|
||||
```
|
||||
|
||||
## Data Contracts
|
||||
|
||||
Use `data` for durable and transportable idp.global object shapes.
|
||||
|
||||
Common data contracts include users, JWTs, login sessions, registration sessions, organizations, roles, invitations, billing plans, apps, app connections, activity logs, alerts, alert rules, abuse windows, passport devices, passport challenges, passport nonces, and OIDC payloads.
|
||||
|
||||
```ts
|
||||
import { data } from '@idp.global/interfaces';
|
||||
|
||||
const organization: data.IOrganization = {
|
||||
id: 'org_1',
|
||||
data: {
|
||||
name: 'Acme',
|
||||
slug: 'acme',
|
||||
billingPlanId: 'plan_free',
|
||||
roleIds: [],
|
||||
},
|
||||
};
|
||||
```
|
||||
|
||||
## TypedRequest Contracts
|
||||
|
||||
Use `request` when registering handlers or creating typed clients with `@api.global/typedrequest` or `@api.global/typedsocket`.
|
||||
|
||||
```ts
|
||||
import { request } from '@idp.global/interfaces';
|
||||
|
||||
type LoginRequest = request.IReq_LoginWithEmailOrUsernameAndPassword;
|
||||
|
||||
const payload: LoginRequest['request'] = {
|
||||
username: 'user@example.com',
|
||||
password: 'secret',
|
||||
};
|
||||
```
|
||||
|
||||
Request groups cover login, registration, JWT refresh, user/session queries, organization membership, invitations, apps, billing, admin actions, alerts, passport device flows, password reset, device IDs, and OIDC authorization.
|
||||
|
||||
## Scope
|
||||
|
||||
This package is intentionally contract-only. It does not open sockets, store auth state, talk to MongoDB, send email, or implement authentication logic.
|
||||
|
||||
## Development
|
||||
|
||||
```bash
|
||||
pnpm install
|
||||
pnpm run build
|
||||
pnpm test
|
||||
```
|
||||
|
||||
## 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.
|
||||
|
||||
**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.
|
||||
|
||||
### Trademarks
|
||||
|
||||
This project is owned and maintained by Task Venture Capital GmbH. The names and logos associated with Task Venture Capital GmbH and any related products or services are trademarks of Task Venture Capital GmbH or third parties, and are not included within the scope of the MIT license granted herein.
|
||||
|
||||
Use of these trademarks must comply with Task Venture Capital GmbH's Trademark Guidelines or the guidelines of the respective third-party owners, and any usage must be approved in writing. Third-party trademarks used herein are the property of their respective owners and used only in a descriptive manner, e.g. for an implementation of an API or similar.
|
||||
|
||||
### Company Information
|
||||
|
||||
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.
|
||||
|
||||
By using this repository, you acknowledge that you have read this section, agree to comply with its terms, and understand that the licensing of the code does not imply endorsement by Task Venture Capital GmbH of any derivative works.
|
||||
@@ -0,0 +1,28 @@
|
||||
import { tap, expect } from '@git.zone/tstest/tapbundle';
|
||||
|
||||
import { data, request, tags } from '../ts/index.js';
|
||||
|
||||
tap.test('exports data contracts', async () => {
|
||||
const organization: data.IOrganization = {
|
||||
id: 'org-test',
|
||||
data: {
|
||||
name: 'Test Org',
|
||||
slug: 'test-org',
|
||||
billingPlanId: 'plan_free',
|
||||
roleIds: [],
|
||||
},
|
||||
};
|
||||
|
||||
expect(organization.data.slug).toEqual('test-org');
|
||||
});
|
||||
|
||||
tap.test('exports request contracts', async () => {
|
||||
const methodName: request.IReq_RefreshJwt['method'] = 'refreshJwt';
|
||||
expect(methodName).toEqual('refreshJwt');
|
||||
});
|
||||
|
||||
tap.test('exports tags namespace', async () => {
|
||||
expect(tags).toBeTruthy();
|
||||
});
|
||||
|
||||
export default tap.start();
|
||||
@@ -0,0 +1,8 @@
|
||||
/**
|
||||
* autocreated commitinfo by @push.rocks/commitinfo
|
||||
*/
|
||||
export const commitinfo = {
|
||||
name: '@idp.global/interfaces',
|
||||
version: '1.0.0',
|
||||
description: 'Shared TypeScript interfaces and TypedRequest contracts for idp.global.'
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
export interface IAbuseWindow {
|
||||
id: string;
|
||||
data: {
|
||||
action: string;
|
||||
identifierHash: string;
|
||||
attemptCount: number;
|
||||
windowStartedAt: number;
|
||||
blockedUntil: number;
|
||||
validUntil: number;
|
||||
createdAt: number;
|
||||
updatedAt: number;
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
export type TActivityAction =
|
||||
| 'login'
|
||||
| 'logout'
|
||||
| 'session_created'
|
||||
| 'session_revoked'
|
||||
| 'passport_device_enrolled'
|
||||
| 'passport_device_revoked'
|
||||
| 'passport_challenge_approved'
|
||||
| 'passport_challenge_rejected'
|
||||
| 'org_created'
|
||||
| 'org_updated'
|
||||
| 'org_deleted'
|
||||
| 'org_ownership_transferred'
|
||||
| 'org_joined'
|
||||
| 'org_left'
|
||||
| 'role_changed'
|
||||
| 'org_app_role_mappings_updated'
|
||||
| 'profile_updated'
|
||||
| 'app_connected'
|
||||
| 'app_disconnected';
|
||||
|
||||
export interface IActivityLog {
|
||||
id: string;
|
||||
data: {
|
||||
userId: string;
|
||||
action: TActivityAction;
|
||||
timestamp: number;
|
||||
metadata: {
|
||||
ip?: string;
|
||||
userAgent?: string;
|
||||
targetId?: string;
|
||||
targetType?: string;
|
||||
description: string;
|
||||
};
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
export type TAlertSeverity = 'low' | 'medium' | 'high' | 'critical';
|
||||
|
||||
export type TAlertStatus = 'pending' | 'seen' | 'dismissed';
|
||||
|
||||
export type TAlertCategory = 'security' | 'admin' | 'system';
|
||||
|
||||
export type TAlertNotificationStatus = 'pending' | 'sent' | 'failed' | 'seen';
|
||||
|
||||
export interface IAlert {
|
||||
id: string;
|
||||
data: {
|
||||
recipientUserId: string;
|
||||
organizationId?: string;
|
||||
category: TAlertCategory;
|
||||
eventType: string;
|
||||
severity: TAlertSeverity;
|
||||
title: string;
|
||||
body: string;
|
||||
actorUserId?: string;
|
||||
relatedEntityId?: string;
|
||||
relatedEntityType?: string;
|
||||
notification: {
|
||||
hintId: string;
|
||||
status: TAlertNotificationStatus;
|
||||
attemptCount: number;
|
||||
createdAt: number;
|
||||
deliveredAt?: number | null;
|
||||
seenAt?: number | null;
|
||||
lastError?: string | null;
|
||||
};
|
||||
createdAt: number;
|
||||
seenAt?: number | null;
|
||||
dismissedAt?: number | null;
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
import type { TAlertSeverity } from './alert.js';
|
||||
|
||||
export type TAlertRuleScope = 'global' | 'organization';
|
||||
|
||||
export type TAlertRuleRecipientMode = 'global_admins' | 'org_admins' | 'specific_users';
|
||||
|
||||
export interface IAlertRule {
|
||||
id: string;
|
||||
data: {
|
||||
scope: TAlertRuleScope;
|
||||
organizationId?: string;
|
||||
eventType: string;
|
||||
minimumSeverity: TAlertSeverity;
|
||||
recipientMode: TAlertRuleRecipientMode;
|
||||
recipientUserIds?: string[];
|
||||
push: boolean;
|
||||
enabled: boolean;
|
||||
createdByUserId: string;
|
||||
createdAt: number;
|
||||
updatedAt: number;
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,99 @@
|
||||
// App Types
|
||||
export type TAppType = 'global' | 'partner' | 'custom_oidc';
|
||||
export type TAppApprovalStatus = 'draft' | 'pending_review' | 'approved' | 'rejected' | 'suspended';
|
||||
|
||||
// OAuth Credentials
|
||||
export interface IOAuthCredentials {
|
||||
clientId: string;
|
||||
clientSecretHash: string;
|
||||
redirectUris: string[];
|
||||
allowedScopes: string[];
|
||||
grantTypes: ('authorization_code' | 'client_credentials' | 'refresh_token')[];
|
||||
}
|
||||
|
||||
// Base app data shared by all app types
|
||||
export interface IAppBaseData {
|
||||
name: string;
|
||||
description: string;
|
||||
logoUrl: string;
|
||||
appUrl: string;
|
||||
}
|
||||
|
||||
// Global App - First-party apps managed by platform (foss.global, task.vc, etc.)
|
||||
export interface IGlobalApp {
|
||||
id: string;
|
||||
type: 'global';
|
||||
data: IAppBaseData & {
|
||||
oauthCredentials: IOAuthCredentials;
|
||||
isActive: boolean;
|
||||
category: string;
|
||||
createdAt: number;
|
||||
createdByUserId: string;
|
||||
};
|
||||
}
|
||||
|
||||
// Partner App - Third-party apps submitted to AppStore
|
||||
export interface IPartnerApp {
|
||||
id: string;
|
||||
type: 'partner';
|
||||
data: IAppBaseData & {
|
||||
ownerOrganizationId: string;
|
||||
oauthCredentials: IOAuthCredentials;
|
||||
appStoreMetadata: {
|
||||
shortDescription: string;
|
||||
longDescription: string;
|
||||
screenshots: string[];
|
||||
category: string;
|
||||
tags: string[];
|
||||
pricing: { model: 'free' | 'paid' | 'freemium' };
|
||||
};
|
||||
approvalStatus: TAppApprovalStatus;
|
||||
isPublished: boolean;
|
||||
installCount: number;
|
||||
};
|
||||
}
|
||||
|
||||
// Custom OIDC App - Organization-created OAuth clients
|
||||
export interface ICustomOidcApp {
|
||||
id: string;
|
||||
type: 'custom_oidc';
|
||||
data: IAppBaseData & {
|
||||
ownerOrganizationId: string;
|
||||
oauthCredentials: IOAuthCredentials;
|
||||
oidcSettings: {
|
||||
accessTokenLifetime: number; // seconds
|
||||
refreshTokenLifetime: number; // seconds
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
// Union type for all app types
|
||||
export type IApp = IGlobalApp | IPartnerApp | ICustomOidcApp;
|
||||
|
||||
/**
|
||||
* Legacy interface for backwards compatibility with existing code
|
||||
* that expects a flat app structure (e.g., idpclient, transfermanager)
|
||||
*/
|
||||
export interface IAppLegacy {
|
||||
/**
|
||||
* must be unique
|
||||
*/
|
||||
id: string;
|
||||
/**
|
||||
* should be unique
|
||||
*/
|
||||
name: string;
|
||||
description: string;
|
||||
logoUrl: string;
|
||||
appUrl: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Storage interface for SmartData documents
|
||||
* Uses the discriminated union approach with a 'type' field
|
||||
*/
|
||||
export interface IAppDocument {
|
||||
id: string;
|
||||
type: TAppType;
|
||||
data: IGlobalApp['data'] | IPartnerApp['data'] | ICustomOidcApp['data'];
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
import type { TAppType } from './app.js';
|
||||
import type { IAppRoleMapping } from './role.js';
|
||||
|
||||
export type TAppConnectionStatus = 'active' | 'disconnected';
|
||||
|
||||
export interface IAppConnection {
|
||||
id: string;
|
||||
data: {
|
||||
organizationId: string;
|
||||
appId: string;
|
||||
appType: TAppType;
|
||||
status: TAppConnectionStatus;
|
||||
connectedAt: number;
|
||||
connectedByUserId: string;
|
||||
grantedScopes: string[];
|
||||
roleMappings?: IAppRoleMapping[];
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
import * as plugins from '../plugins.js';
|
||||
|
||||
export type TSupportedCurrency = 'EUR';
|
||||
|
||||
export interface IBillableItem {
|
||||
name: string;
|
||||
monthlyPrice: number;
|
||||
currency: TSupportedCurrency;
|
||||
from: number;
|
||||
to: number;
|
||||
factoredOn30DayMonth: number;
|
||||
quantity: number;
|
||||
}
|
||||
|
||||
export interface IBillingPlan {
|
||||
id: string;
|
||||
data: {
|
||||
type: 'Paddle' | 'AppSumo' | 'FairUsageFree' | 'Enterprise' | 'Internal' | 'Testing';
|
||||
proEnabled: boolean;
|
||||
organizationId: string;
|
||||
lastProcessed: number;
|
||||
seats: number;
|
||||
status: 'active' | 'activeOverdue' | 'pausedOverdue' | 'inactive' | 'suspended';
|
||||
paddleData?: {
|
||||
checkoutId: string;
|
||||
};
|
||||
alternativePaymentData?: {
|
||||
enterprise: boolean;
|
||||
appSumoCode: string;
|
||||
};
|
||||
nextBilling: {
|
||||
items: Array<IBillableItem>;
|
||||
method: 'paddle';
|
||||
ontrack: boolean;
|
||||
errorText?: string;
|
||||
selectedBillingDate: number;
|
||||
};
|
||||
billingEvents: Array<{
|
||||
timestamp: number;
|
||||
amount: number;
|
||||
currency: TSupportedCurrency;
|
||||
billedItems: Array<IBillableItem>;
|
||||
checkoutLink?: string;
|
||||
}>;
|
||||
communications: Array<any>;
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
import * as plugins from '../plugins.js';
|
||||
|
||||
export interface IDevice extends plugins.tsclass.network.IDevice {}
|
||||
@@ -0,0 +1,12 @@
|
||||
export type TEmailActionTokenAction = 'emailLogin' | 'passwordReset';
|
||||
|
||||
export interface IEmailActionToken {
|
||||
id: string;
|
||||
data: {
|
||||
email: string;
|
||||
action: TEmailActionTokenAction;
|
||||
tokenHash: string;
|
||||
validUntil: number;
|
||||
createdAt: number;
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
export * from './abusewindow.js';
|
||||
export * from './activity.js';
|
||||
export * from './alert.js';
|
||||
export * from './alertrule.js';
|
||||
export * from './app.js';
|
||||
export * from './emailactiontoken.js';
|
||||
export * from './oidc.js';
|
||||
export * from './appconnection.js';
|
||||
export * from './billingplan.js';
|
||||
export * from './device.js';
|
||||
export * from './jwt.js';
|
||||
export * from './loginsession.js';
|
||||
export * from './organization.js';
|
||||
export * from './paddlecheckoutdata.js';
|
||||
export * from './passportchallenge.js';
|
||||
export * from './passportdevice.js';
|
||||
export * from './passportnonce.js';
|
||||
export * from './registrationsession.js';
|
||||
export * from './role.js';
|
||||
export * from './user.js';
|
||||
export * from './userinvitation.js';
|
||||
@@ -0,0 +1,43 @@
|
||||
export type TLoginStatus = 'loggedIn' | 'loggedOut' | 'invalidated' | 'not found' | 'transfer';
|
||||
export type TLoginAction = 'login' | 'logout' | 'manage';
|
||||
|
||||
export interface IJwt {
|
||||
id: string;
|
||||
blocked: boolean;
|
||||
data: {
|
||||
/**
|
||||
* the user id of the jwt
|
||||
*/
|
||||
userId: string;
|
||||
|
||||
/**
|
||||
* the login session backing this jwt
|
||||
*/
|
||||
sessionId?: string;
|
||||
|
||||
/**
|
||||
* the latest point of
|
||||
*/
|
||||
validUntil: number;
|
||||
/**
|
||||
* hold off from refreshing before
|
||||
*/
|
||||
refreshFrom: number;
|
||||
/**
|
||||
* an interval in millis to recheck token invalidation
|
||||
*/
|
||||
refreshEvery: number;
|
||||
|
||||
/**
|
||||
* legacy field kept for compatibility with already-issued jwt documents
|
||||
*/
|
||||
refreshToken?: string;
|
||||
|
||||
/**
|
||||
* just for looks/debugging
|
||||
*/
|
||||
justForLooks: {
|
||||
validUntilIsoString: string;
|
||||
};
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
export interface ILoginSession {
|
||||
id: string;
|
||||
data: {
|
||||
userId: string | null;
|
||||
validUntil: number;
|
||||
invalidated: boolean;
|
||||
/**
|
||||
* legacy plaintext refresh token field kept so existing sessions can migrate on first use
|
||||
*/
|
||||
refreshToken?: string | null;
|
||||
refreshTokenHash?: string | null;
|
||||
rotatedRefreshTokenHashes?: string[];
|
||||
transferTokenHash?: string | null;
|
||||
transferTokenExpiresAt?: number | null;
|
||||
/**
|
||||
* a device id that can be used to share the login session
|
||||
* in different contexts on the same device
|
||||
*/
|
||||
deviceId?: string | null;
|
||||
/**
|
||||
* Device metadata for session display
|
||||
*/
|
||||
deviceInfo?: {
|
||||
deviceName: string;
|
||||
browser: string;
|
||||
os: string;
|
||||
ip: string;
|
||||
} | null;
|
||||
/**
|
||||
* When this session was created
|
||||
*/
|
||||
createdAt?: number;
|
||||
/**
|
||||
* Last time this session was active (e.g., refreshed)
|
||||
*/
|
||||
lastActive?: number;
|
||||
};
|
||||
}
|
||||
+281
@@ -0,0 +1,281 @@
|
||||
/**
|
||||
* OIDC (OpenID Connect) data interfaces for third-party client support
|
||||
*/
|
||||
|
||||
/**
|
||||
* Supported OIDC scopes
|
||||
*/
|
||||
export type TOidcScope = 'openid' | 'profile' | 'email' | 'organizations' | 'roles';
|
||||
|
||||
/**
|
||||
* Authorization code for OAuth 2.0 authorization code flow
|
||||
*/
|
||||
export interface IAuthorizationCode {
|
||||
id: string;
|
||||
data: {
|
||||
/** Hashed authorization code string */
|
||||
codeHash: string;
|
||||
/** OAuth client ID */
|
||||
clientId: string;
|
||||
/** User ID who authorized */
|
||||
userId: string;
|
||||
/** Scopes granted */
|
||||
scopes: TOidcScope[];
|
||||
/** Redirect URI used in authorization request */
|
||||
redirectUri: string;
|
||||
/** PKCE code challenge (S256 hashed) */
|
||||
codeChallenge?: string;
|
||||
/** PKCE code challenge method */
|
||||
codeChallengeMethod?: 'S256';
|
||||
/** Nonce from authorization request (for ID token) */
|
||||
nonce?: string;
|
||||
/** Expiration timestamp (10 minutes from creation) */
|
||||
expiresAt: number;
|
||||
/** Creation timestamp */
|
||||
issuedAt: number;
|
||||
/** Whether the code has been used (single-use) */
|
||||
used: boolean;
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* OIDC Access Token (opaque or JWT)
|
||||
*/
|
||||
export interface IOidcAccessToken {
|
||||
id: string;
|
||||
data: {
|
||||
/** The access token string hash for storage */
|
||||
tokenHash: string;
|
||||
/** OAuth client ID */
|
||||
clientId: string;
|
||||
/** User ID */
|
||||
userId: string;
|
||||
/** Granted scopes */
|
||||
scopes: TOidcScope[];
|
||||
/** Expiration timestamp */
|
||||
expiresAt: number;
|
||||
/** Creation timestamp */
|
||||
issuedAt: number;
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* OIDC Refresh Token
|
||||
*/
|
||||
export interface IOidcRefreshToken {
|
||||
id: string;
|
||||
data: {
|
||||
/** The refresh token string hash for storage */
|
||||
tokenHash: string;
|
||||
/** OAuth client ID */
|
||||
clientId: string;
|
||||
/** User ID */
|
||||
userId: string;
|
||||
/** Granted scopes */
|
||||
scopes: TOidcScope[];
|
||||
/** Expiration timestamp */
|
||||
expiresAt: number;
|
||||
/** Creation timestamp */
|
||||
issuedAt: number;
|
||||
/** Whether the token has been revoked */
|
||||
revoked: boolean;
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* User consent record for an OAuth client
|
||||
*/
|
||||
export interface IUserConsent {
|
||||
id: string;
|
||||
data: {
|
||||
/** User who gave consent */
|
||||
userId: string;
|
||||
/** OAuth client ID */
|
||||
clientId: string;
|
||||
/** Scopes the user consented to */
|
||||
scopes: TOidcScope[];
|
||||
/** When consent was granted */
|
||||
grantedAt: number;
|
||||
/** When consent was last updated */
|
||||
updatedAt: number;
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* OIDC Discovery Document (OpenID Provider Configuration)
|
||||
*/
|
||||
export interface IOidcDiscoveryDocument {
|
||||
issuer: string;
|
||||
authorization_endpoint: string;
|
||||
token_endpoint: string;
|
||||
userinfo_endpoint: string;
|
||||
jwks_uri: string;
|
||||
revocation_endpoint: string;
|
||||
scopes_supported: TOidcScope[];
|
||||
response_types_supported: string[];
|
||||
grant_types_supported: string[];
|
||||
subject_types_supported: string[];
|
||||
id_token_signing_alg_values_supported: string[];
|
||||
token_endpoint_auth_methods_supported: string[];
|
||||
code_challenge_methods_supported: string[];
|
||||
claims_supported: string[];
|
||||
}
|
||||
|
||||
/**
|
||||
* JSON Web Key Set (JWKS) response
|
||||
*/
|
||||
export interface IJwks {
|
||||
keys: IJwk[];
|
||||
}
|
||||
|
||||
/**
|
||||
* JSON Web Key (RSA public key)
|
||||
*/
|
||||
export interface IJwk {
|
||||
kty: 'RSA';
|
||||
use: 'sig';
|
||||
alg: 'RS256';
|
||||
kid: string;
|
||||
n: string; // RSA modulus (base64url encoded)
|
||||
e: string; // RSA exponent (base64url encoded)
|
||||
}
|
||||
|
||||
/**
|
||||
* ID Token claims (JWT payload)
|
||||
*/
|
||||
export interface IIdTokenClaims {
|
||||
/** Issuer (idp.global URL) */
|
||||
iss: string;
|
||||
/** Subject (user ID) */
|
||||
sub: string;
|
||||
/** Audience (client ID) */
|
||||
aud: string;
|
||||
/** Expiration time (Unix timestamp) */
|
||||
exp: number;
|
||||
/** Issued at (Unix timestamp) */
|
||||
iat: number;
|
||||
/** Authentication time (Unix timestamp) */
|
||||
auth_time?: number;
|
||||
/** Nonce (if provided in authorization request) */
|
||||
nonce?: string;
|
||||
/** Access token hash (for hybrid flows) */
|
||||
at_hash?: string;
|
||||
|
||||
// Profile scope claims
|
||||
name?: string;
|
||||
preferred_username?: string;
|
||||
picture?: string;
|
||||
|
||||
// Email scope claims
|
||||
email?: string;
|
||||
email_verified?: boolean;
|
||||
|
||||
// Custom claims for organizations scope
|
||||
organizations?: IOrganizationClaim[];
|
||||
|
||||
// Custom claims for roles scope
|
||||
roles?: string[];
|
||||
app_roles?: string[];
|
||||
app_permissions?: string[];
|
||||
app_scopes?: string[];
|
||||
}
|
||||
|
||||
/**
|
||||
* Organization claim in ID token / userinfo
|
||||
*/
|
||||
export interface IOrganizationClaim {
|
||||
id: string;
|
||||
name: string;
|
||||
slug: string;
|
||||
roles: string[];
|
||||
}
|
||||
|
||||
/**
|
||||
* UserInfo endpoint response
|
||||
*/
|
||||
export interface IUserInfoResponse {
|
||||
/** Subject (user ID) - always included */
|
||||
sub: string;
|
||||
|
||||
// Profile scope
|
||||
name?: string;
|
||||
preferred_username?: string;
|
||||
picture?: string;
|
||||
|
||||
// Email scope
|
||||
email?: string;
|
||||
email_verified?: boolean;
|
||||
|
||||
// Organizations scope (custom)
|
||||
organizations?: IOrganizationClaim[];
|
||||
|
||||
// Roles scope (custom)
|
||||
roles?: string[];
|
||||
app_roles?: string[];
|
||||
app_permissions?: string[];
|
||||
app_scopes?: string[];
|
||||
}
|
||||
|
||||
/**
|
||||
* Token endpoint response
|
||||
*/
|
||||
export interface ITokenResponse {
|
||||
access_token: string;
|
||||
token_type: 'Bearer';
|
||||
expires_in: number;
|
||||
refresh_token?: string;
|
||||
id_token?: string;
|
||||
scope: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Token endpoint error response
|
||||
*/
|
||||
export interface ITokenErrorResponse {
|
||||
error: 'invalid_request' | 'invalid_client' | 'invalid_grant' | 'unauthorized_client' | 'unsupported_grant_type' | 'invalid_scope';
|
||||
error_description?: string;
|
||||
error_uri?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Authorization request parameters
|
||||
*/
|
||||
export interface IAuthorizationRequest {
|
||||
client_id: string;
|
||||
redirect_uri: string;
|
||||
response_type: 'code';
|
||||
scope: string;
|
||||
state: string;
|
||||
code_challenge?: string;
|
||||
code_challenge_method?: 'S256';
|
||||
nonce?: string;
|
||||
prompt?: 'none' | 'login' | 'consent';
|
||||
}
|
||||
|
||||
/**
|
||||
* Token request for authorization_code grant
|
||||
*/
|
||||
export interface ITokenRequestAuthCode {
|
||||
grant_type: 'authorization_code';
|
||||
code: string;
|
||||
redirect_uri: string;
|
||||
client_id: string;
|
||||
client_secret?: string;
|
||||
code_verifier?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Token request for refresh_token grant
|
||||
*/
|
||||
export interface ITokenRequestRefresh {
|
||||
grant_type: 'refresh_token';
|
||||
refresh_token: string;
|
||||
client_id: string;
|
||||
client_secret?: string;
|
||||
scope?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Union type for token requests
|
||||
*/
|
||||
export type ITokenRequest = ITokenRequestAuthCode | ITokenRequestRefresh;
|
||||
@@ -0,0 +1,14 @@
|
||||
import * as plugins from '../plugins.js';
|
||||
import { type IBillingPlan } from './billingplan.js';
|
||||
import { type IOrgRoleDefinition, type IRole } from './role.js';
|
||||
|
||||
export interface IOrganization {
|
||||
id: string;
|
||||
data: {
|
||||
name: string;
|
||||
slug: string;
|
||||
billingPlanId: string;
|
||||
roleIds: string[];
|
||||
roleDefinitions?: IOrgRoleDefinition[];
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,316 @@
|
||||
export interface IPaddleCheckoutData<TPassthrough = null> {
|
||||
checkout: {
|
||||
created_at: string;
|
||||
completed: boolean;
|
||||
id: string;
|
||||
coupon: {
|
||||
coupon_code?: string;
|
||||
};
|
||||
passthrough?: TPassthrough;
|
||||
prices: {
|
||||
customer: {
|
||||
currency: string;
|
||||
unit: string;
|
||||
unit_tax: string;
|
||||
total: string;
|
||||
total_tax: string;
|
||||
items: Array<{
|
||||
checkout_product_id: number;
|
||||
product_id: number;
|
||||
name: string;
|
||||
custom_message: string;
|
||||
quantity: number;
|
||||
allow_quantity: false;
|
||||
icon_url: string;
|
||||
min_quantity: number;
|
||||
max_quantity: number;
|
||||
currency: string;
|
||||
unit_price: {
|
||||
net: number;
|
||||
gross: number;
|
||||
net_discount: number;
|
||||
gross_discount: number;
|
||||
net_after_discount: number;
|
||||
gross_after_discount: number;
|
||||
tax: number;
|
||||
tax_after_discount: number;
|
||||
};
|
||||
line_price: {
|
||||
net: number;
|
||||
gross: number;
|
||||
net_discount: number;
|
||||
gross_discount: number;
|
||||
net_after_discount: number;
|
||||
gross_after_discount: number;
|
||||
tax: number;
|
||||
tax_after_discount: number;
|
||||
};
|
||||
discounts: [];
|
||||
/**
|
||||
* factorised, not percentage, so looks like 0.19 for Germany.
|
||||
*/
|
||||
tax_rate: number;
|
||||
recurring: {
|
||||
period: string;
|
||||
interval: number;
|
||||
trial_days: number;
|
||||
currency: string;
|
||||
unit_price: {
|
||||
net: number;
|
||||
gross: number;
|
||||
net_discount: number;
|
||||
gross_discount: number;
|
||||
net_after_discount: number;
|
||||
gross_after_discount: number;
|
||||
tax: number;
|
||||
tax_after_discount: number;
|
||||
};
|
||||
line_price: {
|
||||
net: number;
|
||||
gross: number;
|
||||
net_discount: number;
|
||||
gross_discount: number;
|
||||
net_after_discount: number;
|
||||
gross_after_discount: number;
|
||||
tax: number;
|
||||
tax_after_discount: number;
|
||||
};
|
||||
discounts: [];
|
||||
tax_rate: number;
|
||||
};
|
||||
}>;
|
||||
};
|
||||
vendor: {
|
||||
currency: string;
|
||||
unit: string;
|
||||
unit_tax: string;
|
||||
total: string;
|
||||
total_tax: string;
|
||||
items: [
|
||||
{
|
||||
checkout_product_id: number;
|
||||
product_id: number;
|
||||
name: string;
|
||||
custom_message: string;
|
||||
quantity: number;
|
||||
allow_quantity: false;
|
||||
icon_url: string;
|
||||
min_quantity: number;
|
||||
max_quantity: number;
|
||||
currency: string;
|
||||
unit_price: {
|
||||
net: number;
|
||||
gross: number;
|
||||
net_discount: number;
|
||||
gross_discount: number;
|
||||
net_after_discount: number;
|
||||
gross_after_discount: number;
|
||||
tax: number;
|
||||
tax_after_discount: number;
|
||||
};
|
||||
line_price: {
|
||||
net: number;
|
||||
gross: number;
|
||||
net_discount: number;
|
||||
gross_discount: number;
|
||||
net_after_discount: number;
|
||||
gross_after_discount: number;
|
||||
tax: number;
|
||||
tax_after_discount: number;
|
||||
};
|
||||
discounts: [];
|
||||
tax_rate: number;
|
||||
recurring: {
|
||||
period: string;
|
||||
interval: number;
|
||||
trial_days: number;
|
||||
currency: string;
|
||||
unit_price: {
|
||||
net: number;
|
||||
gross: number;
|
||||
net_discount: number;
|
||||
gross_discount: number;
|
||||
net_after_discount: number;
|
||||
gross_after_discount: number;
|
||||
tax: number;
|
||||
tax_after_discount: number;
|
||||
};
|
||||
line_price: {
|
||||
net: number;
|
||||
gross: number;
|
||||
net_discount: number;
|
||||
gross_discount: number;
|
||||
net_after_discount: number;
|
||||
gross_after_discount: number;
|
||||
tax: number;
|
||||
tax_after_discount: number;
|
||||
};
|
||||
discounts: [];
|
||||
tax_rate: number;
|
||||
};
|
||||
}
|
||||
];
|
||||
};
|
||||
};
|
||||
redirect_url: null;
|
||||
test_variant: 'newCheckout';
|
||||
recurring_prices: {
|
||||
customer: {
|
||||
currency: string;
|
||||
unit: string;
|
||||
unit_tax: string;
|
||||
total: string;
|
||||
total_tax: string;
|
||||
items: [
|
||||
{
|
||||
checkout_product_id: number;
|
||||
product_id: number;
|
||||
name: string;
|
||||
custom_message: string;
|
||||
quantity: number;
|
||||
allow_quantity: false;
|
||||
icon_url: string;
|
||||
min_quantity: number;
|
||||
max_quantity: number;
|
||||
currency: string;
|
||||
unit_price: {
|
||||
net: number;
|
||||
gross: number;
|
||||
net_discount: number;
|
||||
gross_discount: number;
|
||||
net_after_discount: number;
|
||||
gross_after_discount: number;
|
||||
tax: number;
|
||||
tax_after_discount: number;
|
||||
};
|
||||
line_price: {
|
||||
net: number;
|
||||
gross: number;
|
||||
net_discount: number;
|
||||
gross_discount: number;
|
||||
net_after_discount: number;
|
||||
gross_after_discount: number;
|
||||
tax: number;
|
||||
tax_after_discount: number;
|
||||
};
|
||||
discounts: [];
|
||||
tax_rate: number;
|
||||
recurring: {
|
||||
period: string;
|
||||
interval: number;
|
||||
trial_days: number;
|
||||
currency: string;
|
||||
unit_price: {
|
||||
net: number;
|
||||
gross: number;
|
||||
net_discount: number;
|
||||
gross_discount: number;
|
||||
net_after_discount: number;
|
||||
gross_after_discount: number;
|
||||
tax: number;
|
||||
tax_after_discount: number;
|
||||
};
|
||||
line_price: {
|
||||
net: number;
|
||||
gross: number;
|
||||
net_discount: number;
|
||||
gross_discount: number;
|
||||
net_after_discount: number;
|
||||
gross_after_discount: number;
|
||||
tax: number;
|
||||
tax_after_discount: number;
|
||||
};
|
||||
discounts: [];
|
||||
tax_rate: number;
|
||||
};
|
||||
}
|
||||
];
|
||||
};
|
||||
interval: {
|
||||
length: number;
|
||||
type: string;
|
||||
};
|
||||
vendor: {
|
||||
currency: string;
|
||||
unit: string;
|
||||
unit_tax: string;
|
||||
total: string;
|
||||
total_tax: string;
|
||||
items: [
|
||||
{
|
||||
checkout_product_id: number;
|
||||
product_id: number;
|
||||
name: string;
|
||||
custom_message: string;
|
||||
quantity: number;
|
||||
allow_quantity: false;
|
||||
icon_url: string;
|
||||
min_quantity: number;
|
||||
max_quantity: number;
|
||||
currency: string;
|
||||
unit_price: {
|
||||
net: number;
|
||||
gross: number;
|
||||
net_discount: number;
|
||||
gross_discount: number;
|
||||
net_after_discount: number;
|
||||
gross_after_discount: number;
|
||||
tax: number;
|
||||
tax_after_discount: number;
|
||||
};
|
||||
line_price: {
|
||||
net: number;
|
||||
gross: number;
|
||||
net_discount: number;
|
||||
gross_discount: number;
|
||||
net_after_discount: number;
|
||||
gross_after_discount: number;
|
||||
tax: number;
|
||||
tax_after_discount: number;
|
||||
};
|
||||
discounts: [];
|
||||
tax_rate: number;
|
||||
recurring: {
|
||||
period: string;
|
||||
interval: number;
|
||||
trial_days: number;
|
||||
currency: string;
|
||||
unit_price: {
|
||||
net: number;
|
||||
gross: number;
|
||||
net_discount: number;
|
||||
gross_discount: number;
|
||||
net_after_discount: number;
|
||||
gross_after_discount: number;
|
||||
tax: number;
|
||||
tax_after_discount: number;
|
||||
};
|
||||
line_price: {
|
||||
net: number;
|
||||
gross: number;
|
||||
net_discount: number;
|
||||
gross_discount: number;
|
||||
net_after_discount: number;
|
||||
gross_after_discount: number;
|
||||
tax: number;
|
||||
tax_after_discount: number;
|
||||
};
|
||||
discounts: [];
|
||||
tax_rate: number;
|
||||
};
|
||||
}
|
||||
];
|
||||
};
|
||||
};
|
||||
};
|
||||
product: {
|
||||
quantity: number;
|
||||
id: number;
|
||||
name: string;
|
||||
};
|
||||
user: {
|
||||
id: string;
|
||||
email: string;
|
||||
country: string;
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
import type { IPassportCapabilities } from './passportdevice.js';
|
||||
|
||||
export type TPassportChallengeType =
|
||||
| 'device_enrollment'
|
||||
| 'authentication'
|
||||
| 'step_up'
|
||||
| 'physical_access';
|
||||
|
||||
export type TPassportChallengeStatus = 'pending' | 'approved' | 'expired' | 'rejected';
|
||||
|
||||
export type TPassportChallengeDeliveryStatus = 'pending' | 'sent' | 'failed' | 'seen';
|
||||
|
||||
export type TPassportSignatureFormat = 'raw' | 'der';
|
||||
|
||||
export interface IPassportLocationEvidence {
|
||||
latitude: number;
|
||||
longitude: number;
|
||||
accuracyMeters: number;
|
||||
capturedAt: number;
|
||||
}
|
||||
|
||||
export interface IPassportNfcEvidence {
|
||||
tagId?: string;
|
||||
readerId?: string;
|
||||
}
|
||||
|
||||
export interface IPassportLocationPolicy {
|
||||
mode: 'geofence';
|
||||
label?: string;
|
||||
latitude: number;
|
||||
longitude: number;
|
||||
radiusMeters: number;
|
||||
maxAccuracyMeters?: number;
|
||||
}
|
||||
|
||||
export interface IPassportChallenge {
|
||||
id: string;
|
||||
data: {
|
||||
userId: string;
|
||||
deviceId?: string | null;
|
||||
type: TPassportChallengeType;
|
||||
status: TPassportChallengeStatus;
|
||||
tokenHash?: string | null;
|
||||
challenge: string;
|
||||
metadata: {
|
||||
originHost?: string;
|
||||
audience?: string;
|
||||
notificationTitle?: string;
|
||||
deviceLabel?: string;
|
||||
requireLocation: boolean;
|
||||
requireNfc: boolean;
|
||||
locationPolicy?: IPassportLocationPolicy;
|
||||
requestedCapabilities?: Partial<IPassportCapabilities>;
|
||||
};
|
||||
evidence?: {
|
||||
signatureFormat?: TPassportSignatureFormat;
|
||||
location?: IPassportLocationEvidence;
|
||||
locationEvaluation?: {
|
||||
matched: boolean;
|
||||
distanceMeters?: number;
|
||||
accuracyAccepted?: boolean;
|
||||
evaluatedAt: number;
|
||||
reason?: string;
|
||||
};
|
||||
nfc?: IPassportNfcEvidence;
|
||||
};
|
||||
notification?: {
|
||||
hintId: string;
|
||||
status: TPassportChallengeDeliveryStatus;
|
||||
attemptCount: number;
|
||||
createdAt: number;
|
||||
deliveredAt?: number | null;
|
||||
seenAt?: number | null;
|
||||
lastError?: string | null;
|
||||
};
|
||||
createdAt: number;
|
||||
expiresAt: number;
|
||||
completedAt?: number | null;
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
export type TPassportDevicePlatform =
|
||||
| 'ios'
|
||||
| 'ipados'
|
||||
| 'macos'
|
||||
| 'watchos'
|
||||
| 'android'
|
||||
| 'web'
|
||||
| 'unknown';
|
||||
|
||||
export type TPassportDeviceStatus = 'active' | 'revoked';
|
||||
|
||||
export type TPassportPushProvider = 'apns';
|
||||
|
||||
export type TPassportPushEnvironment = 'development' | 'production';
|
||||
|
||||
export interface IPassportCapabilities {
|
||||
gps: boolean;
|
||||
nfc: boolean;
|
||||
push: boolean;
|
||||
}
|
||||
|
||||
export interface IPassportDevice {
|
||||
id: string;
|
||||
data: {
|
||||
userId: string;
|
||||
label: string;
|
||||
platform: TPassportDevicePlatform;
|
||||
status: TPassportDeviceStatus;
|
||||
publicKeyAlgorithm: 'p256';
|
||||
publicKeyX963Base64: string;
|
||||
capabilities: IPassportCapabilities;
|
||||
pushRegistration?: {
|
||||
provider: TPassportPushProvider;
|
||||
token: string;
|
||||
topic: string;
|
||||
environment: TPassportPushEnvironment;
|
||||
registeredAt: number;
|
||||
lastDeliveredAt?: number;
|
||||
lastError?: string;
|
||||
};
|
||||
appVersion?: string;
|
||||
createdAt: number;
|
||||
lastSeenAt?: number;
|
||||
lastChallengeAt?: number;
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
export interface IPassportNonce {
|
||||
id: string;
|
||||
data: {
|
||||
deviceId: string;
|
||||
nonceHash: string;
|
||||
createdAt: number;
|
||||
expiresAt: number;
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
import * as plugins from '../plugins.js';
|
||||
import { type IRole } from './role.js';
|
||||
|
||||
export interface ISubOrgProperty {
|
||||
name: string;
|
||||
domain: string;
|
||||
roles: IRole[];
|
||||
/**
|
||||
* contains the ids of all the apps that show the property
|
||||
*/
|
||||
attributedAppIds: string[];
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
export type TRegistrationSessionStatus =
|
||||
| 'announced'
|
||||
| 'emailValidated'
|
||||
| 'mobileVerified'
|
||||
| 'registered'
|
||||
| 'failed';
|
||||
|
||||
export interface IRegistrationSession {
|
||||
id: string;
|
||||
data: {
|
||||
emailAddress: string;
|
||||
hashedEmailToken: string;
|
||||
smsCodeHash?: string | null;
|
||||
smsvalidationCounter: number;
|
||||
status: TRegistrationSessionStatus;
|
||||
validUntil: number;
|
||||
createdAt: number;
|
||||
collectedData: {
|
||||
userData: {
|
||||
username?: string | null;
|
||||
connectedOrgs: string[];
|
||||
email?: string | null;
|
||||
name?: string | null;
|
||||
status?: 'new' | 'active' | 'deleted' | 'suspended' | null;
|
||||
mobileNumber?: string | null;
|
||||
password?: string | null;
|
||||
passwordHash?: string | null;
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
import * as plugins from '../plugins.js';
|
||||
|
||||
/** Standard role types available in all organizations */
|
||||
export type TStandardRole = 'owner' | 'admin' | 'editor' | 'guest' | 'viewer' | 'outlaw';
|
||||
|
||||
export interface IOrgRoleDefinition {
|
||||
key: string;
|
||||
name: string;
|
||||
description?: string;
|
||||
createdAt: number;
|
||||
updatedAt: number;
|
||||
}
|
||||
|
||||
export interface IAppRoleMapping {
|
||||
orgRoleKey: string;
|
||||
appRoles: string[];
|
||||
permissions: string[];
|
||||
scopes: string[];
|
||||
}
|
||||
|
||||
/**
|
||||
* A role describes a user's permissions within an organization.
|
||||
* Users can have multiple roles (e.g., ['owner', 'billing-admin']).
|
||||
*/
|
||||
export interface IRole {
|
||||
id: string;
|
||||
data: {
|
||||
userId: string;
|
||||
organizationId: string;
|
||||
/** Array of roles - supports standard roles and custom role names */
|
||||
roles: string[];
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
import * as plugins from '../plugins.js';
|
||||
import { type IRole } from './role.js';
|
||||
|
||||
export interface IUser {
|
||||
id: string;
|
||||
data: {
|
||||
name: string;
|
||||
username: string;
|
||||
email: string;
|
||||
|
||||
/**
|
||||
* mobile number used for verification
|
||||
*/
|
||||
mobileNumber?: string;
|
||||
/**
|
||||
* only used during initial password setting
|
||||
*/
|
||||
password?: string;
|
||||
/**
|
||||
* used for validation of passwords
|
||||
*/
|
||||
passwordHash?: string;
|
||||
status: 'new' | 'active' | 'deleted' | 'suspended';
|
||||
/**
|
||||
* a quick ref for which organizations might have roles for this user
|
||||
* speeds up lookup
|
||||
*/
|
||||
connectedOrgs: string[];
|
||||
/**
|
||||
* Platform-level admin flag
|
||||
* Users with this flag can access the global admin panel
|
||||
* to manage global apps, view platform stats, etc.
|
||||
*/
|
||||
isGlobalAdmin?: boolean;
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
import * as plugins from '../plugins.js';
|
||||
|
||||
/**
|
||||
* A UserInvitation represents an invitation to join an organization.
|
||||
* Key characteristics:
|
||||
* - Unique by email (multiple orgs can share the same invitation)
|
||||
* - Converts to real User on registration or folds into existing user
|
||||
* - Auto-expires after 90 days
|
||||
*/
|
||||
export interface IUserInvitation {
|
||||
id: string;
|
||||
data: {
|
||||
/** The invited email address - unique key for sharing across orgs */
|
||||
email: string;
|
||||
|
||||
/** Secure token for invitation link validation */
|
||||
token: string;
|
||||
|
||||
/** Current status of the invitation */
|
||||
status: 'pending' | 'accepted' | 'expired' | 'cancelled';
|
||||
|
||||
/** When the invitation was first created */
|
||||
createdAt: number;
|
||||
|
||||
/** When the invitation expires (createdAt + 90 days) */
|
||||
expiresAt: number;
|
||||
|
||||
/**
|
||||
* Organizations that have invited this email.
|
||||
* Multiple orgs can link to the same invitation.
|
||||
*/
|
||||
organizationRefs: IOrganizationInvitationRef[];
|
||||
|
||||
/** When the invitation was accepted (user registered/folded) */
|
||||
acceptedAt?: number;
|
||||
|
||||
/** The User ID after conversion (when accepted) */
|
||||
convertedToUserId?: string;
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents one organization's invitation to the user.
|
||||
* Stored as part of IUserInvitation.organizationRefs array.
|
||||
*/
|
||||
export interface IOrganizationInvitationRef {
|
||||
/** The organization that sent this invitation */
|
||||
organizationId: string;
|
||||
|
||||
/** The user who sent the invitation */
|
||||
invitedByUserId: string;
|
||||
|
||||
/** When this org invited the user */
|
||||
invitedAt: number;
|
||||
|
||||
/** Roles to assign when the invitation is accepted */
|
||||
roles: string[];
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
// requests
|
||||
import * as request from './request/index.js';
|
||||
import * as data from './data/index.js';
|
||||
import * as tags from './tags/index.js';
|
||||
|
||||
export { request, data, tags };
|
||||
@@ -0,0 +1,9 @@
|
||||
// @apiglobal scope
|
||||
import * as typedRequestInterfaces from '@api.global/typedrequest-interfaces';
|
||||
|
||||
export { typedRequestInterfaces };
|
||||
|
||||
// @tsclass scope
|
||||
import * as tsclass from '@tsclass/tsclass';
|
||||
|
||||
export { tsclass };
|
||||
+133
@@ -0,0 +1,133 @@
|
||||
# @idp.global/interfaces
|
||||
|
||||
Shared TypeScript contracts for the `idp.global` backend, browser client, CLI, and frontend.
|
||||
|
||||
Use this package when you want typed request/response payloads and shared data models for users, sessions, organizations, apps, billing, passport devices, alerts, and OIDC.
|
||||
|
||||
## Issue Reporting and Security
|
||||
|
||||
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
|
||||
pnpm add @idp.global/interfaces
|
||||
```
|
||||
|
||||
## Quick Start
|
||||
|
||||
```ts
|
||||
import { data, request, tags } from '@idp.global/interfaces';
|
||||
|
||||
const loginRequest: request.IReq_LoginWithEmailOrUsernameAndPassword['request'] = {
|
||||
username: 'user@example.com',
|
||||
password: 'secret',
|
||||
};
|
||||
|
||||
const organization: data.IOrganization = {
|
||||
id: 'org_1',
|
||||
data: {
|
||||
name: 'Acme',
|
||||
slug: 'acme',
|
||||
billingPlanId: 'plan_free',
|
||||
roleIds: [],
|
||||
},
|
||||
};
|
||||
```
|
||||
|
||||
## Exports
|
||||
|
||||
### `data`
|
||||
|
||||
The `data` export includes types for:
|
||||
|
||||
- users
|
||||
- organizations
|
||||
- roles
|
||||
- JWT payloads
|
||||
- login sessions
|
||||
- devices
|
||||
- activity logs
|
||||
- alerts and alert rules
|
||||
- apps and app connections
|
||||
- billing plans and Paddle checkout data
|
||||
- passport devices, challenges, and nonces
|
||||
- abuse windows
|
||||
- OIDC data structures
|
||||
- invitations
|
||||
|
||||
### `request`
|
||||
|
||||
The `request` export includes typed request contracts for:
|
||||
|
||||
- login, logout, refresh, password reset, and device attachment
|
||||
- registration flow requests
|
||||
- user and session queries
|
||||
- organization CRUD-style requests
|
||||
- invitations and membership changes
|
||||
- app and admin actions
|
||||
- billing and JWT validation support
|
||||
- alert and passport approval flows
|
||||
- OIDC authorization preparation and completion
|
||||
|
||||
### `tags`
|
||||
|
||||
Shared tag exports live under `tags/`.
|
||||
|
||||
## Layout
|
||||
|
||||
| Path | Purpose |
|
||||
| --- | --- |
|
||||
| `data/index.ts` | Re-exports all shared data interfaces |
|
||||
| `request/index.ts` | Re-exports all typed request contracts |
|
||||
| `tags/index.ts` | Re-exports shared tags |
|
||||
|
||||
## Examples
|
||||
|
||||
### Login Contract
|
||||
|
||||
```ts
|
||||
type TLogin = request.IReq_LoginWithEmailOrUsernameAndPassword;
|
||||
|
||||
const payload: TLogin['request'] = {
|
||||
username: 'user@example.com',
|
||||
password: 'secret',
|
||||
};
|
||||
```
|
||||
|
||||
### Session Contract
|
||||
|
||||
```ts
|
||||
type TSessions = request.IReq_GetUserSessions['response']['sessions'];
|
||||
```
|
||||
|
||||
### OIDC Contract
|
||||
|
||||
```ts
|
||||
type TUserInfo = data.IUserInfoResponse;
|
||||
```
|
||||
|
||||
## Scope
|
||||
|
||||
This package is intentionally contract-only. It does not open sockets, store auth state, or perform HTTP/websocket communication by itself.
|
||||
|
||||
## 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.
|
||||
|
||||
**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.
|
||||
|
||||
### Trademarks
|
||||
|
||||
This project is owned and maintained by Task Venture Capital GmbH. The names and logos associated with Task Venture Capital GmbH and any related products or services are trademarks of Task Venture Capital GmbH or third parties, and are not included within the scope of the MIT license granted herein.
|
||||
|
||||
Use of these trademarks must comply with Task Venture Capital GmbH's Trademark Guidelines or the guidelines of the respective third-party owners, and any usage must be approved in writing. Third-party trademarks used herein are the property of their respective owners and used only in a descriptive manner, e.g. for an implementation of an API or similar.
|
||||
|
||||
### Company Information
|
||||
|
||||
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.
|
||||
|
||||
By using this repository, you acknowledge that you have read this section, agree to comply with its terms, and understand that the licensing of the code does not imply endorsement by Task Venture Capital GmbH of any derivative works.
|
||||
@@ -0,0 +1,130 @@
|
||||
import * as plugins from '../plugins.js';
|
||||
import * as data from '../data/index.js';
|
||||
|
||||
/**
|
||||
* Check if the current user is a global admin
|
||||
*/
|
||||
export interface IReq_CheckGlobalAdmin
|
||||
extends plugins.typedRequestInterfaces.implementsTR<
|
||||
plugins.typedRequestInterfaces.ITypedRequest,
|
||||
IReq_CheckGlobalAdmin
|
||||
> {
|
||||
method: 'checkGlobalAdmin';
|
||||
request: {
|
||||
jwt: string;
|
||||
};
|
||||
response: {
|
||||
isGlobalAdmin: boolean;
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all global apps with statistics (admin only)
|
||||
*/
|
||||
export interface IReq_GetGlobalAppStats
|
||||
extends plugins.typedRequestInterfaces.implementsTR<
|
||||
plugins.typedRequestInterfaces.ITypedRequest,
|
||||
IReq_GetGlobalAppStats
|
||||
> {
|
||||
method: 'getGlobalAppStats';
|
||||
request: {
|
||||
jwt: string;
|
||||
};
|
||||
response: {
|
||||
apps: Array<{
|
||||
app: data.IGlobalApp;
|
||||
connectionCount: number;
|
||||
}>;
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new global app (admin only)
|
||||
*/
|
||||
export interface IReq_CreateGlobalApp
|
||||
extends plugins.typedRequestInterfaces.implementsTR<
|
||||
plugins.typedRequestInterfaces.ITypedRequest,
|
||||
IReq_CreateGlobalApp
|
||||
> {
|
||||
method: 'createGlobalApp';
|
||||
request: {
|
||||
jwt: string;
|
||||
name: string;
|
||||
description: string;
|
||||
logoUrl: string;
|
||||
appUrl: string;
|
||||
category: string;
|
||||
redirectUris: string[];
|
||||
allowedScopes: string[];
|
||||
};
|
||||
response: {
|
||||
app: data.IGlobalApp;
|
||||
clientSecret: string; // Only shown once on creation
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Update an existing global app (admin only)
|
||||
*/
|
||||
export interface IReq_UpdateGlobalApp
|
||||
extends plugins.typedRequestInterfaces.implementsTR<
|
||||
plugins.typedRequestInterfaces.ITypedRequest,
|
||||
IReq_UpdateGlobalApp
|
||||
> {
|
||||
method: 'updateGlobalApp';
|
||||
request: {
|
||||
jwt: string;
|
||||
appId: string;
|
||||
updates: {
|
||||
name?: string;
|
||||
description?: string;
|
||||
logoUrl?: string;
|
||||
appUrl?: string;
|
||||
category?: string;
|
||||
isActive?: boolean;
|
||||
redirectUris?: string[];
|
||||
allowedScopes?: string[];
|
||||
};
|
||||
};
|
||||
response: {
|
||||
app: data.IGlobalApp;
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete a global app (admin only)
|
||||
*/
|
||||
export interface IReq_DeleteGlobalApp
|
||||
extends plugins.typedRequestInterfaces.implementsTR<
|
||||
plugins.typedRequestInterfaces.ITypedRequest,
|
||||
IReq_DeleteGlobalApp
|
||||
> {
|
||||
method: 'deleteGlobalApp';
|
||||
request: {
|
||||
jwt: string;
|
||||
appId: string;
|
||||
};
|
||||
response: {
|
||||
success: boolean;
|
||||
disconnectedOrganizations: number;
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Regenerate OAuth credentials for a global app (admin only)
|
||||
*/
|
||||
export interface IReq_RegenerateAppCredentials
|
||||
extends plugins.typedRequestInterfaces.implementsTR<
|
||||
plugins.typedRequestInterfaces.ITypedRequest,
|
||||
IReq_RegenerateAppCredentials
|
||||
> {
|
||||
method: 'regenerateAppCredentials';
|
||||
request: {
|
||||
jwt: string;
|
||||
appId: string;
|
||||
};
|
||||
response: {
|
||||
clientId: string;
|
||||
clientSecret: string; // Only shown once
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,113 @@
|
||||
import * as plugins from '../plugins.js';
|
||||
import * as data from '../data/index.js';
|
||||
import type { IPassportDeviceSignedRequest } from './passport.js';
|
||||
|
||||
export interface IReq_ListPassportAlerts
|
||||
extends plugins.typedRequestInterfaces.implementsTR<
|
||||
plugins.typedRequestInterfaces.ITypedRequest,
|
||||
IReq_ListPassportAlerts
|
||||
> {
|
||||
method: 'listPassportAlerts';
|
||||
request: IPassportDeviceSignedRequest & {
|
||||
includeDismissed?: boolean;
|
||||
};
|
||||
response: {
|
||||
alerts: data.IAlert[];
|
||||
};
|
||||
}
|
||||
|
||||
export interface IReq_GetPassportAlertByHint
|
||||
extends plugins.typedRequestInterfaces.implementsTR<
|
||||
plugins.typedRequestInterfaces.ITypedRequest,
|
||||
IReq_GetPassportAlertByHint
|
||||
> {
|
||||
method: 'getPassportAlertByHint';
|
||||
request: IPassportDeviceSignedRequest & {
|
||||
hintId: string;
|
||||
};
|
||||
response: {
|
||||
alert?: data.IAlert;
|
||||
};
|
||||
}
|
||||
|
||||
export interface IReq_MarkPassportAlertSeen
|
||||
extends plugins.typedRequestInterfaces.implementsTR<
|
||||
plugins.typedRequestInterfaces.ITypedRequest,
|
||||
IReq_MarkPassportAlertSeen
|
||||
> {
|
||||
method: 'markPassportAlertSeen';
|
||||
request: IPassportDeviceSignedRequest & {
|
||||
hintId: string;
|
||||
};
|
||||
response: {
|
||||
success: boolean;
|
||||
};
|
||||
}
|
||||
|
||||
export interface IReq_DismissPassportAlert
|
||||
extends plugins.typedRequestInterfaces.implementsTR<
|
||||
plugins.typedRequestInterfaces.ITypedRequest,
|
||||
IReq_DismissPassportAlert
|
||||
> {
|
||||
method: 'dismissPassportAlert';
|
||||
request: IPassportDeviceSignedRequest & {
|
||||
hintId: string;
|
||||
};
|
||||
response: {
|
||||
success: boolean;
|
||||
};
|
||||
}
|
||||
|
||||
export interface IReq_UpsertAlertRule
|
||||
extends plugins.typedRequestInterfaces.implementsTR<
|
||||
plugins.typedRequestInterfaces.ITypedRequest,
|
||||
IReq_UpsertAlertRule
|
||||
> {
|
||||
method: 'upsertAlertRule';
|
||||
request: {
|
||||
jwt: string;
|
||||
ruleId?: string;
|
||||
scope: data.TAlertRuleScope;
|
||||
organizationId?: string;
|
||||
eventType: string;
|
||||
minimumSeverity: data.TAlertSeverity;
|
||||
recipientMode: data.TAlertRuleRecipientMode;
|
||||
recipientUserIds?: string[];
|
||||
push: boolean;
|
||||
enabled: boolean;
|
||||
};
|
||||
response: {
|
||||
rule: data.IAlertRule;
|
||||
};
|
||||
}
|
||||
|
||||
export interface IReq_GetAlertRules
|
||||
extends plugins.typedRequestInterfaces.implementsTR<
|
||||
plugins.typedRequestInterfaces.ITypedRequest,
|
||||
IReq_GetAlertRules
|
||||
> {
|
||||
method: 'getAlertRules';
|
||||
request: {
|
||||
jwt: string;
|
||||
scope?: data.TAlertRuleScope;
|
||||
organizationId?: string;
|
||||
};
|
||||
response: {
|
||||
rules: data.IAlertRule[];
|
||||
};
|
||||
}
|
||||
|
||||
export interface IReq_DeleteAlertRule
|
||||
extends plugins.typedRequestInterfaces.implementsTR<
|
||||
plugins.typedRequestInterfaces.ITypedRequest,
|
||||
IReq_DeleteAlertRule
|
||||
> {
|
||||
method: 'deleteAlertRule';
|
||||
request: {
|
||||
jwt: string;
|
||||
ruleId: string;
|
||||
};
|
||||
response: {
|
||||
success: boolean;
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
export {};
|
||||
@@ -0,0 +1,71 @@
|
||||
import * as data from '../data/index.js';
|
||||
import * as plugins from '../plugins.js';
|
||||
|
||||
// Get all global apps
|
||||
export interface IReq_GetGlobalApps
|
||||
extends plugins.typedRequestInterfaces.implementsTR<
|
||||
plugins.typedRequestInterfaces.ITypedRequest,
|
||||
IReq_GetGlobalApps
|
||||
> {
|
||||
method: 'getGlobalApps';
|
||||
request: {
|
||||
jwt: string;
|
||||
};
|
||||
response: {
|
||||
apps: data.IGlobalApp[];
|
||||
};
|
||||
}
|
||||
|
||||
// Get app connections for an organization
|
||||
export interface IReq_GetAppConnections
|
||||
extends plugins.typedRequestInterfaces.implementsTR<
|
||||
plugins.typedRequestInterfaces.ITypedRequest,
|
||||
IReq_GetAppConnections
|
||||
> {
|
||||
method: 'getAppConnections';
|
||||
request: {
|
||||
jwt: string;
|
||||
organizationId: string;
|
||||
};
|
||||
response: {
|
||||
connections: data.IAppConnection[];
|
||||
};
|
||||
}
|
||||
|
||||
// Connect/disconnect an app for an organization
|
||||
export interface IReq_ToggleAppConnection
|
||||
extends plugins.typedRequestInterfaces.implementsTR<
|
||||
plugins.typedRequestInterfaces.ITypedRequest,
|
||||
IReq_ToggleAppConnection
|
||||
> {
|
||||
method: 'toggleAppConnection';
|
||||
request: {
|
||||
jwt: string;
|
||||
organizationId: string;
|
||||
appId: string;
|
||||
action: 'connect' | 'disconnect';
|
||||
};
|
||||
response: {
|
||||
success: boolean;
|
||||
connection?: data.IAppConnection;
|
||||
};
|
||||
}
|
||||
|
||||
export interface IReq_UpdateAppRoleMappings
|
||||
extends plugins.typedRequestInterfaces.implementsTR<
|
||||
plugins.typedRequestInterfaces.ITypedRequest,
|
||||
IReq_UpdateAppRoleMappings
|
||||
> {
|
||||
method: 'updateAppRoleMappings';
|
||||
request: {
|
||||
jwt: string;
|
||||
organizationId: string;
|
||||
appId: string;
|
||||
roleMappings: data.IAppRoleMapping[];
|
||||
};
|
||||
response: {
|
||||
success: boolean;
|
||||
connection: data.IAppConnection;
|
||||
message?: string;
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
import * as plugins from '../plugins.js';
|
||||
import { type IUser, type IRole } from '../data/index.js';
|
||||
import { type TOidcScope } from '../data/index.js';
|
||||
|
||||
export interface IReq_InternalAuthorization
|
||||
extends plugins.typedRequestInterfaces.implementsTR<
|
||||
plugins.typedRequestInterfaces.ITypedRequest,
|
||||
IReq_InternalAuthorization
|
||||
> {
|
||||
method: '';
|
||||
request: {
|
||||
accountData: IUser;
|
||||
jwt: string;
|
||||
};
|
||||
response: {
|
||||
accountData: IUser;
|
||||
jwt: string;
|
||||
relevantRoles: IRole[];
|
||||
};
|
||||
}
|
||||
|
||||
export interface IReq_CompleteOidcAuthorization
|
||||
extends plugins.typedRequestInterfaces.implementsTR<
|
||||
plugins.typedRequestInterfaces.ITypedRequest,
|
||||
IReq_CompleteOidcAuthorization
|
||||
> {
|
||||
method: 'completeOidcAuthorization';
|
||||
request: {
|
||||
jwt: string;
|
||||
clientId: string;
|
||||
redirectUri: string;
|
||||
scope: string;
|
||||
state: string;
|
||||
prompt?: 'none' | 'login' | 'consent';
|
||||
codeChallenge?: string;
|
||||
codeChallengeMethod?: 'S256';
|
||||
nonce?: string;
|
||||
consentApproved?: boolean;
|
||||
};
|
||||
response: {
|
||||
code: string;
|
||||
redirectUrl: string;
|
||||
};
|
||||
}
|
||||
|
||||
export interface IReq_PrepareOidcAuthorization
|
||||
extends plugins.typedRequestInterfaces.implementsTR<
|
||||
plugins.typedRequestInterfaces.ITypedRequest,
|
||||
IReq_PrepareOidcAuthorization
|
||||
> {
|
||||
method: 'prepareOidcAuthorization';
|
||||
request: {
|
||||
jwt: string;
|
||||
clientId: string;
|
||||
redirectUri: string;
|
||||
scope: string;
|
||||
state: string;
|
||||
prompt?: 'none' | 'login' | 'consent';
|
||||
codeChallenge?: string;
|
||||
codeChallengeMethod?: 'S256';
|
||||
nonce?: string;
|
||||
};
|
||||
response: {
|
||||
status: 'ready' | 'consent_required';
|
||||
clientId: string;
|
||||
appName: string;
|
||||
appUrl: string;
|
||||
logoUrl?: string;
|
||||
requestedScopes: TOidcScope[];
|
||||
grantedScopes: TOidcScope[];
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
import * as plugins from '../plugins.js';
|
||||
import * as data from '../data/index.js';
|
||||
|
||||
export interface IReq_UpdatePaymentMethod
|
||||
extends plugins.typedRequestInterfaces.implementsTR<
|
||||
plugins.typedRequestInterfaces.ITypedRequest,
|
||||
IReq_UpdatePaymentMethod
|
||||
> {
|
||||
method: 'updatePaymentMethod';
|
||||
request: {
|
||||
jwtString: string;
|
||||
orgId: string;
|
||||
paddle?: {
|
||||
checkoutId: string;
|
||||
};
|
||||
};
|
||||
response: {
|
||||
billingPlan: plugins.tsclass.typeFest.PartialDeep<data.IBillingPlan>;
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* allows getting the billing plan for a user
|
||||
*/
|
||||
export interface IReq_GetBillingPlan
|
||||
extends plugins.typedRequestInterfaces.implementsTR<
|
||||
plugins.typedRequestInterfaces.ITypedRequest,
|
||||
IReq_GetBillingPlan
|
||||
> {
|
||||
method: 'getBillingPlan';
|
||||
request: {
|
||||
jwtString: string;
|
||||
orgId: string;
|
||||
billingPlanId: string;
|
||||
};
|
||||
response: {
|
||||
billingPlan: data.IBillingPlan;
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns Paddle configuration from environment variables
|
||||
*/
|
||||
export interface IReq_GetPaddleConfig
|
||||
extends plugins.typedRequestInterfaces.implementsTR<
|
||||
plugins.typedRequestInterfaces.ITypedRequest,
|
||||
IReq_GetPaddleConfig
|
||||
> {
|
||||
method: 'getPaddleConfig';
|
||||
request: {};
|
||||
response: {
|
||||
paddleToken: string;
|
||||
paddlePriceId: string;
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
export * from './admin.js';
|
||||
export * from './apitoken.js';
|
||||
export * from './alert.js';
|
||||
export * from './app.js';
|
||||
export * from './authorization.js';
|
||||
export * from './billingplan.js';
|
||||
export * from './jwt.js';
|
||||
export * from './login.js';
|
||||
export * from './organization.js';
|
||||
export * from './passport.js';
|
||||
export * from './plan.js';
|
||||
export * from './registration.js';
|
||||
export * from './user.js';
|
||||
export * from './userinvitation.js';
|
||||
@@ -0,0 +1,79 @@
|
||||
import * as data from '../data/index.js';
|
||||
import * as plugins from '../plugins.js';
|
||||
|
||||
/**
|
||||
* Request to get the public key for JWT validation.
|
||||
*
|
||||
* **Direction:** Client → idp.global
|
||||
* **Requester:** Backend services that need to verify JWTs
|
||||
* **Handler:** idp.global
|
||||
*
|
||||
* Use this to fetch the current public key for verifying JWT signatures.
|
||||
* The backend token authenticates the requesting service.
|
||||
*/
|
||||
export interface IReq_GetPublicKeyForValidation
|
||||
extends plugins.typedRequestInterfaces.implementsTR<
|
||||
plugins.typedRequestInterfaces.ITypedRequest,
|
||||
IReq_GetPublicKeyForValidation
|
||||
> {
|
||||
method: 'getPublicKeyForValidation';
|
||||
request: {
|
||||
backendToken: string;
|
||||
};
|
||||
response: {
|
||||
publicKeyPem: string;
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Push public key to connected backend services for JWT validation.
|
||||
*
|
||||
* **Direction:** idp.global → Client
|
||||
* **Requester:** idp.global (pushes when the JWT signing key rotates)
|
||||
* **Handler:** Backend services - must register a TypedHandler for this method
|
||||
*
|
||||
* Backend services should register a handler using `IdpClient.onPublicKeyPush()`
|
||||
* to receive key rotation updates and update their local key cache.
|
||||
*/
|
||||
export interface IReq_PushPublicKeyForValidation
|
||||
extends plugins.typedRequestInterfaces.implementsTR<
|
||||
plugins.typedRequestInterfaces.ITypedRequest,
|
||||
IReq_PushPublicKeyForValidation
|
||||
> {
|
||||
method: 'pushPublicKeyForValidation';
|
||||
request: {
|
||||
publicKeyPem: string;
|
||||
};
|
||||
response: {};
|
||||
}
|
||||
|
||||
/**
|
||||
* Push or get JWT ID blocklist for revoked tokens.
|
||||
*
|
||||
* **Bidirectional:**
|
||||
* - **GET direction:** Client → idp.global - Client requests current blocklist
|
||||
* - **PUSH direction:** idp.global → Client - Server pushes new blocklisted IDs
|
||||
*
|
||||
* **For GET (client fires):**
|
||||
* - Fire with empty/undefined `blockedJwtIds` to request the full blocklist
|
||||
* - Response contains the complete list of blocked JWT IDs
|
||||
* - Use `IdpClient.requests.getJwtIdBlocklist` for this direction
|
||||
*
|
||||
* **For PUSH (idp.global fires):**
|
||||
* - idp.global sends newly blocklisted JWT IDs to connected clients
|
||||
* - Clients must register a handler using `IdpClient.onBlocklistPush()`
|
||||
* - Store received IDs locally to reject revoked tokens
|
||||
*/
|
||||
export interface IReq_PushOrGetJwtIdBlocklist
|
||||
extends plugins.typedRequestInterfaces.implementsTR<
|
||||
plugins.typedRequestInterfaces.ITypedRequest,
|
||||
IReq_PushOrGetJwtIdBlocklist
|
||||
> {
|
||||
method: 'pushOrGetJwtIdBlocklist';
|
||||
request: {
|
||||
blockedJwtIds?: string[];
|
||||
};
|
||||
response: {
|
||||
blockedJwtIds?: string[];
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,181 @@
|
||||
import * as plugins from '../plugins.js';
|
||||
import * as data from '../data/index.js';
|
||||
|
||||
export interface IReq_LoginWithEmailOrUsernameAndPassword
|
||||
extends plugins.typedRequestInterfaces.implementsTR<
|
||||
plugins.typedRequestInterfaces.ITypedRequest,
|
||||
IReq_LoginWithEmailOrUsernameAndPassword
|
||||
> {
|
||||
method: 'loginWithEmailOrUsernameAndPassword';
|
||||
request: {
|
||||
username: string;
|
||||
password: string;
|
||||
};
|
||||
response: {
|
||||
refreshToken?: string;
|
||||
twoFaNeeded: boolean;
|
||||
};
|
||||
}
|
||||
|
||||
export interface IReq_LoginWithEmail
|
||||
extends plugins.typedRequestInterfaces.implementsTR<
|
||||
plugins.typedRequestInterfaces.ITypedRequest,
|
||||
IReq_LoginWithEmailOrUsernameAndPassword
|
||||
> {
|
||||
method: 'loginWithEmail';
|
||||
request: {
|
||||
email: string;
|
||||
};
|
||||
response: {
|
||||
status: 'ok' | 'not ok';
|
||||
testOnlyToken?: string;
|
||||
};
|
||||
}
|
||||
|
||||
export interface IReq_LoginWithEmailAfterEmailTokenAquired
|
||||
extends plugins.typedRequestInterfaces.implementsTR<
|
||||
plugins.typedRequestInterfaces.ITypedRequest,
|
||||
IReq_LoginWithEmailOrUsernameAndPassword
|
||||
> {
|
||||
method: 'loginWithEmailAfterEmailTokenAquired';
|
||||
request: {
|
||||
email: string;
|
||||
token: string;
|
||||
};
|
||||
response: {
|
||||
refreshToken: string;
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* in case you authenticate with a long lived api token
|
||||
*/
|
||||
export interface IReq_LoginWithApiToken
|
||||
extends plugins.typedRequestInterfaces.implementsTR<
|
||||
plugins.typedRequestInterfaces.ITypedRequest,
|
||||
IReq_LoginWithApiToken
|
||||
> {
|
||||
method: 'loginWithApiToken';
|
||||
request: {
|
||||
apiToken: string;
|
||||
};
|
||||
response: {
|
||||
jwt?: string;
|
||||
};
|
||||
}
|
||||
|
||||
export interface ILogoutRequest
|
||||
extends plugins.typedRequestInterfaces.implementsTR<
|
||||
plugins.typedRequestInterfaces.ITypedRequest,
|
||||
ILogoutRequest
|
||||
> {
|
||||
method: 'logout';
|
||||
request: {
|
||||
refreshToken: string;
|
||||
};
|
||||
response: {};
|
||||
}
|
||||
|
||||
export interface IReq_RefreshJwt
|
||||
extends plugins.typedRequestInterfaces.implementsTR<
|
||||
plugins.typedRequestInterfaces.ITypedRequest,
|
||||
IReq_RefreshJwt
|
||||
> {
|
||||
method: 'refreshJwt';
|
||||
request: {
|
||||
refreshToken: string;
|
||||
};
|
||||
response: {
|
||||
status: data.TLoginStatus;
|
||||
jwt?: string;
|
||||
refreshToken?: string;
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* allows the exchange between refreshToken and transferTokens
|
||||
*/
|
||||
export interface IReq_ExchangeRefreshTokenAndTransferToken
|
||||
extends plugins.typedRequestInterfaces.implementsTR<
|
||||
plugins.typedRequestInterfaces.ITypedRequest,
|
||||
IReq_ExchangeRefreshTokenAndTransferToken
|
||||
> {
|
||||
method: 'exchangeRefreshTokenAndTransferToken';
|
||||
request: {
|
||||
transferToken?: string;
|
||||
refreshToken?: string;
|
||||
appData: data.IAppLegacy;
|
||||
};
|
||||
response: {
|
||||
refreshToken?: string;
|
||||
transferToken?: string;
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* in case you authenticate with a long lived api token
|
||||
*/
|
||||
export interface IReq_ResetPassword
|
||||
extends plugins.typedRequestInterfaces.implementsTR<
|
||||
plugins.typedRequestInterfaces.ITypedRequest,
|
||||
IReq_ResetPassword
|
||||
> {
|
||||
method: 'resetPassword';
|
||||
request: {
|
||||
email: string;
|
||||
};
|
||||
response: {
|
||||
status: 'ok' | 'not ok';
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* in cse you authenticate with a long lived api token
|
||||
*/
|
||||
export interface IReq_SetNewPassword
|
||||
extends plugins.typedRequestInterfaces.implementsTR<
|
||||
plugins.typedRequestInterfaces.ITypedRequest,
|
||||
IReq_SetNewPassword
|
||||
> {
|
||||
method: 'setNewPassword';
|
||||
request: {
|
||||
email: string;
|
||||
oldPassword?: string;
|
||||
tokenArg?: string;
|
||||
newPassword: string;
|
||||
};
|
||||
response: {
|
||||
status: 'ok' | 'not ok';
|
||||
};
|
||||
}
|
||||
|
||||
export interface IReq_ObtainDeviceId
|
||||
extends plugins.typedRequestInterfaces.implementsTR<
|
||||
plugins.typedRequestInterfaces.ITypedRequest,
|
||||
IReq_ObtainDeviceId
|
||||
> {
|
||||
method: 'obtainDeviceId';
|
||||
request: {};
|
||||
response: {
|
||||
deviceId: data.IDevice;
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* allows attaching a device id to a login session
|
||||
* to share a login session across contexts
|
||||
*/
|
||||
export interface IReq_AttachDeviceId
|
||||
extends plugins.typedRequestInterfaces.implementsTR<
|
||||
plugins.typedRequestInterfaces.ITypedRequest,
|
||||
IReq_AttachDeviceId
|
||||
> {
|
||||
method: 'attachDeviceId';
|
||||
request: {
|
||||
jwt: string;
|
||||
deviceId: string;
|
||||
};
|
||||
response: {
|
||||
ok: boolean;
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,131 @@
|
||||
import * as data from '../data/index.js';
|
||||
import * as plugins from '../plugins.js';
|
||||
|
||||
export interface IReq_GetOrganizationById
|
||||
extends plugins.typedRequestInterfaces.implementsTR<
|
||||
plugins.typedRequestInterfaces.ITypedRequest,
|
||||
IReq_GetOrganizationById
|
||||
> {
|
||||
method: 'getOrganizationById';
|
||||
request: {
|
||||
jwt: string;
|
||||
id: string;
|
||||
};
|
||||
response: {
|
||||
organization: data.IOrganization;
|
||||
};
|
||||
}
|
||||
|
||||
export interface IReq_CreateOrganization
|
||||
extends plugins.typedRequestInterfaces.implementsTR<
|
||||
plugins.typedRequestInterfaces.ITypedRequest,
|
||||
IReq_CreateOrganization
|
||||
> {
|
||||
method: 'createOrganization';
|
||||
request: {
|
||||
jwt: string;
|
||||
userId: string;
|
||||
organizationName: string;
|
||||
organizationSlug: string;
|
||||
action: 'checkAvailability' | 'manifest';
|
||||
};
|
||||
response: {
|
||||
nameAvailable: boolean;
|
||||
resultingOrganization?: data.IOrganization;
|
||||
role?: data.IRole;
|
||||
};
|
||||
}
|
||||
|
||||
export interface IReq_UpdateOrganization
|
||||
extends plugins.typedRequestInterfaces.implementsTR<
|
||||
plugins.typedRequestInterfaces.ITypedRequest,
|
||||
IReq_UpdateOrganization
|
||||
> {
|
||||
method: 'updateOrganization';
|
||||
request: {
|
||||
jwt: string;
|
||||
organizationId: string;
|
||||
name?: string;
|
||||
slug?: string;
|
||||
confirmationText: string;
|
||||
};
|
||||
response: {
|
||||
success: boolean;
|
||||
organization: data.IOrganization;
|
||||
message?: string;
|
||||
};
|
||||
}
|
||||
|
||||
export interface IReq_DeleteOrganization
|
||||
extends plugins.typedRequestInterfaces.implementsTR<
|
||||
plugins.typedRequestInterfaces.ITypedRequest,
|
||||
IReq_DeleteOrganization
|
||||
> {
|
||||
method: 'deleteOrganization';
|
||||
request: {
|
||||
jwt: string;
|
||||
organizationId: string;
|
||||
confirmationText: string;
|
||||
};
|
||||
response: {
|
||||
success: boolean;
|
||||
deletedOrganizationId: string;
|
||||
message?: string;
|
||||
};
|
||||
}
|
||||
|
||||
export interface IReq_GetOrgRoleDefinitions
|
||||
extends plugins.typedRequestInterfaces.implementsTR<
|
||||
plugins.typedRequestInterfaces.ITypedRequest,
|
||||
IReq_GetOrgRoleDefinitions
|
||||
> {
|
||||
method: 'getOrgRoleDefinitions';
|
||||
request: {
|
||||
jwt: string;
|
||||
organizationId: string;
|
||||
};
|
||||
response: {
|
||||
roleDefinitions: data.IOrgRoleDefinition[];
|
||||
};
|
||||
}
|
||||
|
||||
export interface IReq_UpsertOrgRoleDefinition
|
||||
extends plugins.typedRequestInterfaces.implementsTR<
|
||||
plugins.typedRequestInterfaces.ITypedRequest,
|
||||
IReq_UpsertOrgRoleDefinition
|
||||
> {
|
||||
method: 'upsertOrgRoleDefinition';
|
||||
request: {
|
||||
jwt: string;
|
||||
organizationId: string;
|
||||
roleDefinition: {
|
||||
key: string;
|
||||
name: string;
|
||||
description?: string;
|
||||
};
|
||||
};
|
||||
response: {
|
||||
success: boolean;
|
||||
roleDefinitions: data.IOrgRoleDefinition[];
|
||||
message?: string;
|
||||
};
|
||||
}
|
||||
|
||||
export interface IReq_DeleteOrgRoleDefinition
|
||||
extends plugins.typedRequestInterfaces.implementsTR<
|
||||
plugins.typedRequestInterfaces.ITypedRequest,
|
||||
IReq_DeleteOrgRoleDefinition
|
||||
> {
|
||||
method: 'deleteOrgRoleDefinition';
|
||||
request: {
|
||||
jwt: string;
|
||||
organizationId: string;
|
||||
roleKey: string;
|
||||
confirmationText: string;
|
||||
};
|
||||
response: {
|
||||
success: boolean;
|
||||
roleDefinitions: data.IOrgRoleDefinition[];
|
||||
message?: string;
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,227 @@
|
||||
import * as plugins from '../plugins.js';
|
||||
import * as data from '../data/index.js';
|
||||
|
||||
export interface IPassportDeviceSignedRequest {
|
||||
deviceId: string;
|
||||
timestamp: number;
|
||||
nonce: string;
|
||||
signatureBase64: string;
|
||||
signatureFormat?: data.TPassportSignatureFormat;
|
||||
}
|
||||
|
||||
export interface IReq_CreatePassportEnrollmentChallenge
|
||||
extends plugins.typedRequestInterfaces.implementsTR<
|
||||
plugins.typedRequestInterfaces.ITypedRequest,
|
||||
IReq_CreatePassportEnrollmentChallenge
|
||||
> {
|
||||
method: 'createPassportEnrollmentChallenge';
|
||||
request: {
|
||||
jwt: string;
|
||||
deviceLabel: string;
|
||||
platform: data.TPassportDevicePlatform;
|
||||
appVersion?: string;
|
||||
capabilities?: Partial<data.IPassportCapabilities>;
|
||||
};
|
||||
response: {
|
||||
challengeId: string;
|
||||
pairingToken: string;
|
||||
pairingPayload: string;
|
||||
signingPayload: string;
|
||||
expiresAt: number;
|
||||
};
|
||||
}
|
||||
|
||||
export interface IReq_CompletePassportEnrollment
|
||||
extends plugins.typedRequestInterfaces.implementsTR<
|
||||
plugins.typedRequestInterfaces.ITypedRequest,
|
||||
IReq_CompletePassportEnrollment
|
||||
> {
|
||||
method: 'completePassportEnrollment';
|
||||
request: {
|
||||
pairingToken: string;
|
||||
deviceLabel: string;
|
||||
platform: data.TPassportDevicePlatform;
|
||||
publicKeyX963Base64: string;
|
||||
signatureBase64: string;
|
||||
signatureFormat?: data.TPassportSignatureFormat;
|
||||
appVersion?: string;
|
||||
capabilities?: Partial<data.IPassportCapabilities>;
|
||||
};
|
||||
response: {
|
||||
device: data.IPassportDevice;
|
||||
};
|
||||
}
|
||||
|
||||
export interface IReq_GetPassportDevices
|
||||
extends plugins.typedRequestInterfaces.implementsTR<
|
||||
plugins.typedRequestInterfaces.ITypedRequest,
|
||||
IReq_GetPassportDevices
|
||||
> {
|
||||
method: 'getPassportDevices';
|
||||
request: {
|
||||
jwt: string;
|
||||
};
|
||||
response: {
|
||||
devices: data.IPassportDevice[];
|
||||
};
|
||||
}
|
||||
|
||||
export interface IReq_RevokePassportDevice
|
||||
extends plugins.typedRequestInterfaces.implementsTR<
|
||||
plugins.typedRequestInterfaces.ITypedRequest,
|
||||
IReq_RevokePassportDevice
|
||||
> {
|
||||
method: 'revokePassportDevice';
|
||||
request: {
|
||||
jwt: string;
|
||||
deviceId: string;
|
||||
};
|
||||
response: {
|
||||
success: boolean;
|
||||
};
|
||||
}
|
||||
|
||||
export interface IReq_CreatePassportChallenge
|
||||
extends plugins.typedRequestInterfaces.implementsTR<
|
||||
plugins.typedRequestInterfaces.ITypedRequest,
|
||||
IReq_CreatePassportChallenge
|
||||
> {
|
||||
method: 'createPassportChallenge';
|
||||
request: {
|
||||
jwt: string;
|
||||
type?: Exclude<data.TPassportChallengeType, 'device_enrollment'>;
|
||||
preferredDeviceId?: string;
|
||||
audience?: string;
|
||||
notificationTitle?: string;
|
||||
requireLocation?: boolean;
|
||||
requireNfc?: boolean;
|
||||
locationPolicy?: data.IPassportLocationPolicy;
|
||||
};
|
||||
response: {
|
||||
challengeId: string;
|
||||
challenge: string;
|
||||
signingPayload: string;
|
||||
deviceId: string;
|
||||
expiresAt: number;
|
||||
};
|
||||
}
|
||||
|
||||
export interface IReq_ApprovePassportChallenge
|
||||
extends plugins.typedRequestInterfaces.implementsTR<
|
||||
plugins.typedRequestInterfaces.ITypedRequest,
|
||||
IReq_ApprovePassportChallenge
|
||||
> {
|
||||
method: 'approvePassportChallenge';
|
||||
request: {
|
||||
challengeId: string;
|
||||
deviceId: string;
|
||||
signatureBase64: string;
|
||||
signatureFormat?: data.TPassportSignatureFormat;
|
||||
location?: data.IPassportLocationEvidence;
|
||||
nfc?: data.IPassportNfcEvidence;
|
||||
};
|
||||
response: {
|
||||
success: boolean;
|
||||
challenge: data.IPassportChallenge;
|
||||
};
|
||||
}
|
||||
|
||||
export interface IReq_RejectPassportChallenge
|
||||
extends plugins.typedRequestInterfaces.implementsTR<
|
||||
plugins.typedRequestInterfaces.ITypedRequest,
|
||||
IReq_RejectPassportChallenge
|
||||
> {
|
||||
method: 'rejectPassportChallenge';
|
||||
request: IPassportDeviceSignedRequest & {
|
||||
challengeId: string;
|
||||
};
|
||||
response: {
|
||||
success: boolean;
|
||||
challenge: data.IPassportChallenge;
|
||||
};
|
||||
}
|
||||
|
||||
export interface IReq_RegisterPassportPushToken
|
||||
extends plugins.typedRequestInterfaces.implementsTR<
|
||||
plugins.typedRequestInterfaces.ITypedRequest,
|
||||
IReq_RegisterPassportPushToken
|
||||
> {
|
||||
method: 'registerPassportPushToken';
|
||||
request: IPassportDeviceSignedRequest & {
|
||||
provider: data.TPassportPushProvider;
|
||||
token: string;
|
||||
topic: string;
|
||||
environment: data.TPassportPushEnvironment;
|
||||
};
|
||||
response: {
|
||||
success: boolean;
|
||||
};
|
||||
}
|
||||
|
||||
export interface IReq_ListPendingPassportChallenges
|
||||
extends plugins.typedRequestInterfaces.implementsTR<
|
||||
plugins.typedRequestInterfaces.ITypedRequest,
|
||||
IReq_ListPendingPassportChallenges
|
||||
> {
|
||||
method: 'listPendingPassportChallenges';
|
||||
request: IPassportDeviceSignedRequest;
|
||||
response: {
|
||||
challenges: data.IPassportChallenge[];
|
||||
};
|
||||
}
|
||||
|
||||
export interface IReq_GetPassportChallengeByHint
|
||||
extends plugins.typedRequestInterfaces.implementsTR<
|
||||
plugins.typedRequestInterfaces.ITypedRequest,
|
||||
IReq_GetPassportChallengeByHint
|
||||
> {
|
||||
method: 'getPassportChallengeByHint';
|
||||
request: IPassportDeviceSignedRequest & {
|
||||
hintId: string;
|
||||
};
|
||||
response: {
|
||||
challenge?: {
|
||||
challenge: data.IPassportChallenge;
|
||||
signingPayload: string;
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export interface IReq_MarkPassportChallengeSeen
|
||||
extends plugins.typedRequestInterfaces.implementsTR<
|
||||
plugins.typedRequestInterfaces.ITypedRequest,
|
||||
IReq_MarkPassportChallengeSeen
|
||||
> {
|
||||
method: 'markPassportChallengeSeen';
|
||||
request: IPassportDeviceSignedRequest & {
|
||||
hintId: string;
|
||||
};
|
||||
response: {
|
||||
success: boolean;
|
||||
};
|
||||
}
|
||||
|
||||
export interface IReq_GetPassportDashboard
|
||||
extends plugins.typedRequestInterfaces.implementsTR<
|
||||
plugins.typedRequestInterfaces.ITypedRequest,
|
||||
IReq_GetPassportDashboard
|
||||
> {
|
||||
method: 'getPassportDashboard';
|
||||
request: IPassportDeviceSignedRequest;
|
||||
response: {
|
||||
profile: {
|
||||
userId: string;
|
||||
name: string;
|
||||
handle: string;
|
||||
organizations: Array<{ id: string; name: string }>;
|
||||
deviceCount: number;
|
||||
recoverySummary: string;
|
||||
};
|
||||
devices: data.IPassportDevice[];
|
||||
challenges: Array<{
|
||||
challenge: data.IPassportChallenge;
|
||||
signingPayload: string;
|
||||
}>;
|
||||
alerts: data.IAlert[];
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
import * as data from '../data/index.js';
|
||||
import * as plugins from '../plugins.js';
|
||||
|
||||
export interface IReq_GetPlansForOrganizationId
|
||||
extends plugins.typedRequestInterfaces.implementsTR<
|
||||
plugins.typedRequestInterfaces.ITypedRequest,
|
||||
IReq_GetPlansForOrganizationId
|
||||
> {
|
||||
method: 'getBillingPlansForOrganizationId';
|
||||
request: {
|
||||
jwt: string;
|
||||
organizationId: string;
|
||||
};
|
||||
response: {
|
||||
billingPlans: data.IBillingPlan[];
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
import * as plugins from '../plugins.js';
|
||||
import { type IUser } from '../data/index.js';
|
||||
|
||||
export interface IReq_FirstRegistration
|
||||
extends plugins.typedRequestInterfaces.implementsTR<
|
||||
plugins.typedRequestInterfaces.ITypedRequest,
|
||||
IReq_FirstRegistration
|
||||
> {
|
||||
method: 'firstRegistrationRequest';
|
||||
request: {
|
||||
email: string;
|
||||
productSlugOfInterest: string;
|
||||
};
|
||||
response: {
|
||||
status: 'ok' | 'not ok';
|
||||
testOnlyToken?: string;
|
||||
};
|
||||
}
|
||||
|
||||
export interface IReq_AfterRegistrationEmailClicked
|
||||
extends plugins.typedRequestInterfaces.implementsTR<
|
||||
plugins.typedRequestInterfaces.ITypedRequest,
|
||||
IReq_AfterRegistrationEmailClicked
|
||||
> {
|
||||
method: 'afterRegistrationEmailClicked';
|
||||
request: {
|
||||
/**
|
||||
* the token that has been sent with the registation email to verify access
|
||||
*/
|
||||
token: string;
|
||||
};
|
||||
response: {
|
||||
status: 'ok' | 'not ok';
|
||||
/**
|
||||
* the email thats associated with the given request token
|
||||
*/
|
||||
email: string;
|
||||
};
|
||||
}
|
||||
|
||||
export interface IReq_SetDataForRegistration
|
||||
extends plugins.typedRequestInterfaces.implementsTR<
|
||||
plugins.typedRequestInterfaces.ITypedRequest,
|
||||
IReq_SetDataForRegistration
|
||||
> {
|
||||
method: 'setDataForRegistration';
|
||||
request: {
|
||||
token: string;
|
||||
userData: IUser['data'];
|
||||
};
|
||||
response: {
|
||||
status: 'ok' | 'not ok';
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Should be used to verify a mobile number for an verifcation
|
||||
*/
|
||||
export interface IReq_MobileVerificationForRegistration
|
||||
extends plugins.typedRequestInterfaces.implementsTR<
|
||||
plugins.typedRequestInterfaces.ITypedRequest,
|
||||
IReq_MobileVerificationForRegistration
|
||||
> {
|
||||
method: 'mobileVerificationForRegistration';
|
||||
request: {
|
||||
token: string;
|
||||
mobileNumber?: string;
|
||||
verificationCode?: string;
|
||||
};
|
||||
response: {
|
||||
messageSent?: boolean;
|
||||
verficationCodeOk?: boolean;
|
||||
testOnlySmsCode?: string;
|
||||
};
|
||||
}
|
||||
|
||||
export interface IReq_FinishRegistration
|
||||
extends plugins.typedRequestInterfaces.implementsTR<
|
||||
plugins.typedRequestInterfaces.ITypedRequest,
|
||||
IReq_FinishRegistration
|
||||
> {
|
||||
method: 'finishRegistration';
|
||||
request: {
|
||||
token: string;
|
||||
};
|
||||
response: {
|
||||
status: 'ok' | 'not ok';
|
||||
userData?: IUser['data'];
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,142 @@
|
||||
import * as data from '../data/index.js';
|
||||
import * as plugins from '../plugins.js';
|
||||
|
||||
export interface IReq_GetUserData
|
||||
extends plugins.typedRequestInterfaces.implementsTR<
|
||||
plugins.typedRequestInterfaces.ITypedRequest,
|
||||
IReq_GetUserData
|
||||
> {
|
||||
method: 'getUserData';
|
||||
request: {
|
||||
refreshToken: string;
|
||||
};
|
||||
response: {
|
||||
jwt: string;
|
||||
};
|
||||
}
|
||||
|
||||
export interface IReq_SetUserData
|
||||
extends plugins.typedRequestInterfaces.implementsTR<
|
||||
plugins.typedRequestInterfaces.ITypedRequest,
|
||||
IReq_SetUserData
|
||||
> {
|
||||
method: 'setUserData';
|
||||
request: {
|
||||
refreshToken: string;
|
||||
};
|
||||
response: {
|
||||
oneTimeTransferCode: string;
|
||||
};
|
||||
}
|
||||
|
||||
export interface IReq_SuspendUser
|
||||
extends plugins.typedRequestInterfaces.implementsTR<
|
||||
plugins.typedRequestInterfaces.ITypedRequest,
|
||||
IReq_SuspendUser
|
||||
> {
|
||||
method: 'suspendUser';
|
||||
request: {
|
||||
jwt: string;
|
||||
userId: string;
|
||||
};
|
||||
response: {
|
||||
publicKeyPem: string;
|
||||
};
|
||||
}
|
||||
|
||||
export interface IDeleteSuspendedUser
|
||||
extends plugins.typedRequestInterfaces.implementsTR<
|
||||
plugins.typedRequestInterfaces.ITypedRequest,
|
||||
IDeleteSuspendedUser
|
||||
> {
|
||||
method: 'deleteSuspendedUser';
|
||||
request: {
|
||||
backendToken: string;
|
||||
};
|
||||
response: {
|
||||
ok: boolean;
|
||||
errorText?: string;
|
||||
};
|
||||
}
|
||||
|
||||
export interface IReq_GetRolesAndOrganizationsForUserId
|
||||
extends plugins.typedRequestInterfaces.implementsTR<
|
||||
plugins.typedRequestInterfaces.ITypedRequest,
|
||||
IReq_GetRolesAndOrganizationsForUserId
|
||||
> {
|
||||
method: 'getRolesAndOrganizationsForUserId';
|
||||
request: {
|
||||
jwt: string;
|
||||
userId: string;
|
||||
};
|
||||
response: {
|
||||
roles: data.IRole[];
|
||||
organizations: data.IOrganization[];
|
||||
};
|
||||
}
|
||||
|
||||
export interface IReq_WhoIs {
|
||||
method: 'whoIs';
|
||||
request: {
|
||||
jwt: string;
|
||||
};
|
||||
response: {
|
||||
user: data.IUser;
|
||||
};
|
||||
}
|
||||
|
||||
export interface IReq_GetUserSessions
|
||||
extends plugins.typedRequestInterfaces.implementsTR<
|
||||
plugins.typedRequestInterfaces.ITypedRequest,
|
||||
IReq_GetUserSessions
|
||||
> {
|
||||
method: 'getUserSessions';
|
||||
request: {
|
||||
jwt: string;
|
||||
};
|
||||
response: {
|
||||
sessions: Array<{
|
||||
id: string;
|
||||
deviceId: string;
|
||||
deviceName: string;
|
||||
browser: string;
|
||||
os: string;
|
||||
ip: string;
|
||||
lastActive: number;
|
||||
createdAt: number;
|
||||
isCurrent: boolean;
|
||||
}>;
|
||||
};
|
||||
}
|
||||
|
||||
export interface IReq_RevokeSession
|
||||
extends plugins.typedRequestInterfaces.implementsTR<
|
||||
plugins.typedRequestInterfaces.ITypedRequest,
|
||||
IReq_RevokeSession
|
||||
> {
|
||||
method: 'revokeSession';
|
||||
request: {
|
||||
jwt: string;
|
||||
sessionId: string;
|
||||
};
|
||||
response: {
|
||||
success: boolean;
|
||||
};
|
||||
}
|
||||
|
||||
export interface IReq_GetUserActivity
|
||||
extends plugins.typedRequestInterfaces.implementsTR<
|
||||
plugins.typedRequestInterfaces.ITypedRequest,
|
||||
IReq_GetUserActivity
|
||||
> {
|
||||
method: 'getUserActivity';
|
||||
request: {
|
||||
jwt: string;
|
||||
limit?: number;
|
||||
offset?: number;
|
||||
};
|
||||
response: {
|
||||
activities: data.IActivityLog[];
|
||||
total: number;
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,248 @@
|
||||
import * as data from '../data/index.js';
|
||||
import * as plugins from '../plugins.js';
|
||||
|
||||
/**
|
||||
* Create an invitation to join an organization
|
||||
*/
|
||||
export interface IReq_CreateInvitation
|
||||
extends plugins.typedRequestInterfaces.implementsTR<
|
||||
plugins.typedRequestInterfaces.ITypedRequest,
|
||||
IReq_CreateInvitation
|
||||
> {
|
||||
method: 'createInvitation';
|
||||
request: {
|
||||
jwt: string;
|
||||
organizationId: string;
|
||||
email: string;
|
||||
roles: string[];
|
||||
};
|
||||
response: {
|
||||
success: boolean;
|
||||
invitation?: data.IUserInvitation;
|
||||
message?: string;
|
||||
/** True if a new invitation was created, false if email was added to existing */
|
||||
isNew: boolean;
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Get pending invitations for an organization
|
||||
*/
|
||||
export interface IReq_GetOrgInvitations
|
||||
extends plugins.typedRequestInterfaces.implementsTR<
|
||||
plugins.typedRequestInterfaces.ITypedRequest,
|
||||
IReq_GetOrgInvitations
|
||||
> {
|
||||
method: 'getOrgInvitations';
|
||||
request: {
|
||||
jwt: string;
|
||||
organizationId: string;
|
||||
};
|
||||
response: {
|
||||
invitations: data.IUserInvitation[];
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Get members of an organization (users with roles)
|
||||
*/
|
||||
export interface IReq_GetOrgMembers
|
||||
extends plugins.typedRequestInterfaces.implementsTR<
|
||||
plugins.typedRequestInterfaces.ITypedRequest,
|
||||
IReq_GetOrgMembers
|
||||
> {
|
||||
method: 'getOrgMembers';
|
||||
request: {
|
||||
jwt: string;
|
||||
organizationId: string;
|
||||
};
|
||||
response: {
|
||||
members: Array<{
|
||||
user: data.IUser;
|
||||
role: data.IRole;
|
||||
}>;
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Cancel a pending invitation
|
||||
*/
|
||||
export interface IReq_CancelInvitation
|
||||
extends plugins.typedRequestInterfaces.implementsTR<
|
||||
plugins.typedRequestInterfaces.ITypedRequest,
|
||||
IReq_CancelInvitation
|
||||
> {
|
||||
method: 'cancelInvitation';
|
||||
request: {
|
||||
jwt: string;
|
||||
organizationId: string;
|
||||
invitationId: string;
|
||||
};
|
||||
response: {
|
||||
success: boolean;
|
||||
message?: string;
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Resend invitation email
|
||||
*/
|
||||
export interface IReq_ResendInvitation
|
||||
extends plugins.typedRequestInterfaces.implementsTR<
|
||||
plugins.typedRequestInterfaces.ITypedRequest,
|
||||
IReq_ResendInvitation
|
||||
> {
|
||||
method: 'resendInvitation';
|
||||
request: {
|
||||
jwt: string;
|
||||
organizationId: string;
|
||||
invitationId: string;
|
||||
};
|
||||
response: {
|
||||
success: boolean;
|
||||
message?: string;
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove a member from an organization
|
||||
*/
|
||||
export interface IReq_RemoveMember
|
||||
extends plugins.typedRequestInterfaces.implementsTR<
|
||||
plugins.typedRequestInterfaces.ITypedRequest,
|
||||
IReq_RemoveMember
|
||||
> {
|
||||
method: 'removeMember';
|
||||
request: {
|
||||
jwt: string;
|
||||
organizationId: string;
|
||||
userId: string;
|
||||
};
|
||||
response: {
|
||||
success: boolean;
|
||||
message?: string;
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Update a member's roles
|
||||
*/
|
||||
export interface IReq_UpdateMemberRoles
|
||||
extends plugins.typedRequestInterfaces.implementsTR<
|
||||
plugins.typedRequestInterfaces.ITypedRequest,
|
||||
IReq_UpdateMemberRoles
|
||||
> {
|
||||
method: 'updateMemberRoles';
|
||||
request: {
|
||||
jwt: string;
|
||||
organizationId: string;
|
||||
userId: string;
|
||||
roles: string[];
|
||||
};
|
||||
response: {
|
||||
success: boolean;
|
||||
role?: data.IRole;
|
||||
message?: string;
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Transfer organization ownership to another member
|
||||
*/
|
||||
export interface IReq_TransferOwnership
|
||||
extends plugins.typedRequestInterfaces.implementsTR<
|
||||
plugins.typedRequestInterfaces.ITypedRequest,
|
||||
IReq_TransferOwnership
|
||||
> {
|
||||
method: 'transferOwnership';
|
||||
request: {
|
||||
jwt: string;
|
||||
organizationId: string;
|
||||
newOwnerId: string;
|
||||
confirmationText: string;
|
||||
};
|
||||
response: {
|
||||
success: boolean;
|
||||
message?: string;
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Accept an invitation (called during registration or email verification)
|
||||
*/
|
||||
export interface IReq_AcceptInvitation
|
||||
extends plugins.typedRequestInterfaces.implementsTR<
|
||||
plugins.typedRequestInterfaces.ITypedRequest,
|
||||
IReq_AcceptInvitation
|
||||
> {
|
||||
method: 'acceptInvitation';
|
||||
request: {
|
||||
token: string;
|
||||
userId: string;
|
||||
};
|
||||
response: {
|
||||
success: boolean;
|
||||
organizations?: data.IOrganization[];
|
||||
roles?: data.IRole[];
|
||||
message?: string;
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Get invitation by token (for invitation landing page)
|
||||
*/
|
||||
export interface IReq_GetInvitationByToken
|
||||
extends plugins.typedRequestInterfaces.implementsTR<
|
||||
plugins.typedRequestInterfaces.ITypedRequest,
|
||||
IReq_GetInvitationByToken
|
||||
> {
|
||||
method: 'getInvitationByToken';
|
||||
request: {
|
||||
token: string;
|
||||
};
|
||||
response: {
|
||||
invitation?: data.IUserInvitation;
|
||||
organizations?: Array<{
|
||||
id: string;
|
||||
name: string;
|
||||
}>;
|
||||
isExpired: boolean;
|
||||
requiresRegistration: boolean;
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Bulk create invitations from a list (typically from CSV import)
|
||||
*/
|
||||
export interface IReq_BulkCreateInvitations
|
||||
extends plugins.typedRequestInterfaces.implementsTR<
|
||||
plugins.typedRequestInterfaces.ITypedRequest,
|
||||
IReq_BulkCreateInvitations
|
||||
> {
|
||||
method: 'bulkCreateInvitations';
|
||||
request: {
|
||||
jwt: string;
|
||||
organizationId: string;
|
||||
invitations: Array<{
|
||||
email: string;
|
||||
roles?: string[];
|
||||
}>;
|
||||
defaultRoles: string[];
|
||||
};
|
||||
response: {
|
||||
success: boolean;
|
||||
results: Array<{
|
||||
email: string;
|
||||
success: boolean;
|
||||
status: 'invited' | 'already_member' | 'invalid_email' | 'error';
|
||||
message?: string;
|
||||
}>;
|
||||
summary: {
|
||||
total: number;
|
||||
invited: number;
|
||||
alreadyMembers: number;
|
||||
invalid: number;
|
||||
errors: number;
|
||||
};
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
import * as plugins from '../plugins.js';
|
||||
|
||||
export interface ITag_LolePubapi
|
||||
extends plugins.typedRequestInterfaces.implementsTag<
|
||||
plugins.typedRequestInterfaces.ITag,
|
||||
ITag_LolePubapi
|
||||
> {
|
||||
name: 'lole-reception';
|
||||
payload: {
|
||||
backendToken: string;
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "ES2022",
|
||||
"module": "NodeNext",
|
||||
"moduleResolution": "NodeNext",
|
||||
"esModuleInterop": true,
|
||||
"verbatimModuleSyntax": true,
|
||||
"types": ["node"]
|
||||
},
|
||||
"exclude": [
|
||||
"dist_*/**/*.d.ts"
|
||||
]
|
||||
}
|
||||
Reference in New Issue
Block a user