feat(apps): Add Apps subsystem: App and AppConnection models, managers, typed request handlers, web UI routes and documentation
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
export * from './loint-reception.app.js';
|
||||
export * from './loint-reception.appconnection.js';
|
||||
export * from './loint-reception.billingplan.js';
|
||||
export * from './loint-reception.device.js';
|
||||
export * from './loint-reception.jwt.js';
|
||||
|
||||
@@ -1,4 +1,78 @@
|
||||
export interface IApp {
|
||||
// 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;
|
||||
};
|
||||
}
|
||||
|
||||
// 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
|
||||
*/
|
||||
@@ -11,3 +85,13 @@ export interface IApp {
|
||||
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,16 @@
|
||||
import type { TAppType } from './loint-reception.app.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[];
|
||||
};
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
export * from './loint-reception.apitoken.js';
|
||||
export * from './loint-reception.app.js';
|
||||
export * from './loint-reception.authorization.js';
|
||||
export * from './loint-reception.billingplan.js';
|
||||
export * from './loint-reception.jwt.js';
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
import * as data from '../data/index.js';
|
||||
import * as plugins from '../loint-reception.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;
|
||||
};
|
||||
}
|
||||
@@ -103,7 +103,7 @@ export interface IReq_ExchangeRefreshTokenAndTransferToken
|
||||
request: {
|
||||
transferToken?: string;
|
||||
refreshToken?: string;
|
||||
appData: data.IApp;
|
||||
appData: data.IAppLegacy;
|
||||
};
|
||||
response: {
|
||||
refreshToken?: string;
|
||||
|
||||
Reference in New Issue
Block a user