feat: implement naming convention, deployment automation, and infrastructure updates
- Add comprehensive naming convention (provider-region-resource-env-purpose) - Implement Terraform locals for centralized naming - Update all Terraform resources to use new naming convention - Create deployment automation framework (18 phase scripts) - Add Azure setup scripts (provider registration, quota checks) - Update deployment scripts config with naming functions - Create complete deployment documentation (guide, steps, quick reference) - Add frontend portal implementations (public and internal) - Add UI component library (18 components) - Enhance Entra VerifiedID integration with file utilities - Add API client package for all services - Create comprehensive documentation (naming, deployment, next steps) Infrastructure: - Resource groups, storage accounts with new naming - Terraform configuration updates - Outputs with naming convention examples Deployment: - Automated deployment scripts for all 15 phases - State management and logging - Error handling and validation Documentation: - Naming convention guide and implementation summary - Complete deployment guide (296 steps) - Next steps and quick start guides - Azure prerequisites and setup completion docs Note: ESLint warnings present - will be addressed in follow-up commit
This commit is contained in:
23
packages/api-client/package.json
Normal file
23
packages/api-client/package.json
Normal file
@@ -0,0 +1,23 @@
|
||||
{
|
||||
"name": "@the-order/api-client",
|
||||
"version": "0.1.0",
|
||||
"private": true,
|
||||
"description": "API client library for The Order services",
|
||||
"main": "./src/index.ts",
|
||||
"types": "./src/index.ts",
|
||||
"scripts": {
|
||||
"build": "tsc",
|
||||
"dev": "tsc --watch",
|
||||
"lint": "eslint src --ext .ts",
|
||||
"type-check": "tsc --noEmit"
|
||||
},
|
||||
"dependencies": {
|
||||
"axios": "^1.6.2",
|
||||
"@the-order/schemas": "workspace:*"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "^20.10.6",
|
||||
"typescript": "^5.3.3"
|
||||
}
|
||||
}
|
||||
|
||||
53
packages/api-client/src/client.ts
Normal file
53
packages/api-client/src/client.ts
Normal file
@@ -0,0 +1,53 @@
|
||||
import { IdentityClient } from './identity';
|
||||
import { EResidencyClient } from './eresidency';
|
||||
import { IntakeClient } from './intake';
|
||||
import { FinanceClient } from './finance';
|
||||
import { DataroomClient } from './dataroom';
|
||||
|
||||
export class ApiClient {
|
||||
public readonly identity: IdentityClient;
|
||||
public readonly eresidency: EResidencyClient;
|
||||
public readonly intake: IntakeClient;
|
||||
public readonly finance: FinanceClient;
|
||||
public readonly dataroom: DataroomClient;
|
||||
|
||||
constructor(baseURL?: string) {
|
||||
// Initialize service clients - each manages its own axios instance
|
||||
this.identity = new IdentityClient();
|
||||
this.eresidency = new EResidencyClient();
|
||||
this.intake = new IntakeClient();
|
||||
this.finance = new FinanceClient();
|
||||
this.dataroom = new DataroomClient();
|
||||
}
|
||||
|
||||
setAuthToken(token: string): void {
|
||||
if (typeof window !== 'undefined') {
|
||||
localStorage.setItem('auth_token', token);
|
||||
}
|
||||
// Update all service clients
|
||||
this.identity.setAuthToken(token);
|
||||
this.eresidency.setAuthToken(token);
|
||||
this.intake.setAuthToken(token);
|
||||
this.finance.setAuthToken(token);
|
||||
this.dataroom.setAuthToken(token);
|
||||
}
|
||||
|
||||
clearAuth(): void {
|
||||
// Clear tokens in all service clients
|
||||
this.identity.clearAuthToken();
|
||||
this.eresidency.clearAuthToken();
|
||||
this.intake.clearAuthToken();
|
||||
this.finance.clearAuthToken();
|
||||
this.dataroom.clearAuthToken();
|
||||
}
|
||||
}
|
||||
|
||||
// Singleton instance
|
||||
let apiClientInstance: ApiClient | null = null;
|
||||
|
||||
export function getApiClient(): ApiClient {
|
||||
if (!apiClientInstance) {
|
||||
apiClientInstance = new ApiClient();
|
||||
}
|
||||
return apiClientInstance;
|
||||
}
|
||||
140
packages/api-client/src/dataroom.ts
Normal file
140
packages/api-client/src/dataroom.ts
Normal file
@@ -0,0 +1,140 @@
|
||||
import axios, { AxiosInstance } from 'axios';
|
||||
|
||||
export interface DealRoom {
|
||||
id: string;
|
||||
name: string;
|
||||
description?: string;
|
||||
status: 'active' | 'archived' | 'closed';
|
||||
createdAt: string;
|
||||
updatedAt: string;
|
||||
participants: string[];
|
||||
documents: string[];
|
||||
}
|
||||
|
||||
export interface Document {
|
||||
id: string;
|
||||
roomId: string;
|
||||
fileName: string;
|
||||
fileSize: number;
|
||||
uploadedBy: string;
|
||||
uploadedAt: string;
|
||||
category?: string;
|
||||
tags?: string[];
|
||||
}
|
||||
|
||||
export class DataroomClient {
|
||||
protected client: AxiosInstance;
|
||||
|
||||
constructor(baseURL?: string) {
|
||||
const apiBaseURL =
|
||||
baseURL ||
|
||||
(typeof window !== 'undefined'
|
||||
? process.env.NEXT_PUBLIC_DATAROOM_SERVICE_URL || 'http://localhost:4006'
|
||||
: 'http://localhost:4006');
|
||||
|
||||
this.client = axios.create({
|
||||
baseURL: apiBaseURL,
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
});
|
||||
|
||||
// Set up request interceptor for authentication
|
||||
this.client.interceptors.request.use(
|
||||
(config) => {
|
||||
const token = this.getAuthToken();
|
||||
if (token) {
|
||||
config.headers.Authorization = `Bearer ${token}`;
|
||||
}
|
||||
return config;
|
||||
},
|
||||
(error) => Promise.reject(error)
|
||||
);
|
||||
}
|
||||
|
||||
private getAuthToken(): string | null {
|
||||
if (typeof window === 'undefined') return null;
|
||||
return localStorage.getItem('auth_token');
|
||||
}
|
||||
|
||||
setAuthToken(token: string): void {
|
||||
if (typeof window !== 'undefined') {
|
||||
localStorage.setItem('auth_token', token);
|
||||
}
|
||||
}
|
||||
|
||||
clearAuthToken(): void {
|
||||
if (typeof window !== 'undefined') {
|
||||
localStorage.removeItem('auth_token');
|
||||
}
|
||||
}
|
||||
|
||||
async createDealRoom(data: {
|
||||
name: string;
|
||||
description?: string;
|
||||
participants?: string[];
|
||||
}): Promise<DealRoom> {
|
||||
const response = await this.client.post<DealRoom>('/api/v1/deal-rooms', data);
|
||||
return response.data;
|
||||
}
|
||||
|
||||
async getDealRoom(roomId: string): Promise<DealRoom> {
|
||||
const response = await this.client.get<DealRoom>(`/api/v1/deal-rooms/${roomId}`);
|
||||
return response.data;
|
||||
}
|
||||
|
||||
async listDealRooms(filters?: {
|
||||
status?: string;
|
||||
participantId?: string;
|
||||
page?: number;
|
||||
pageSize?: number;
|
||||
}): Promise<{ rooms: DealRoom[]; total: number }> {
|
||||
const response = await this.client.get<{ rooms: DealRoom[]; total: number }>(
|
||||
'/api/v1/deal-rooms',
|
||||
{ params: filters }
|
||||
);
|
||||
return response.data;
|
||||
}
|
||||
|
||||
async updateDealRoom(roomId: string, data: Partial<DealRoom>): Promise<DealRoom> {
|
||||
const response = await this.client.patch<DealRoom>(`/api/v1/deal-rooms/${roomId}`, data);
|
||||
return response.data;
|
||||
}
|
||||
|
||||
async uploadDocument(roomId: string, file: File | Blob, metadata?: {
|
||||
category?: string;
|
||||
tags?: string[];
|
||||
}): Promise<Document> {
|
||||
const formData = new FormData();
|
||||
formData.append('file', file);
|
||||
if (metadata) {
|
||||
formData.append('category', metadata.category || '');
|
||||
if (metadata.tags) {
|
||||
formData.append('tags', JSON.stringify(metadata.tags));
|
||||
}
|
||||
}
|
||||
|
||||
const response = await this.client.post<Document>(
|
||||
`/api/v1/deal-rooms/${roomId}/documents`,
|
||||
formData,
|
||||
{
|
||||
headers: {
|
||||
'Content-Type': 'multipart/form-data',
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
return response.data;
|
||||
}
|
||||
|
||||
async listDocuments(roomId: string): Promise<Document[]> {
|
||||
const response = await this.client.get<Document[]>(
|
||||
`/api/v1/deal-rooms/${roomId}/documents`
|
||||
);
|
||||
return response.data;
|
||||
}
|
||||
|
||||
async deleteDocument(roomId: string, documentId: string): Promise<void> {
|
||||
await this.client.delete(`/api/v1/deal-rooms/${roomId}/documents/${documentId}`);
|
||||
}
|
||||
}
|
||||
89
packages/api-client/src/eresidency.ts
Normal file
89
packages/api-client/src/eresidency.ts
Normal file
@@ -0,0 +1,89 @@
|
||||
import { ApiClient } from './client';
|
||||
import type { eResidencyApplication, ApplicationStatus } from '@the-order/schemas';
|
||||
|
||||
export interface SubmitApplicationRequest {
|
||||
email: string;
|
||||
givenName: string;
|
||||
familyName: string;
|
||||
dateOfBirth?: string;
|
||||
nationality?: string;
|
||||
phone?: string;
|
||||
address?: {
|
||||
street?: string;
|
||||
city?: string;
|
||||
region?: string;
|
||||
postalCode?: string;
|
||||
country?: string;
|
||||
};
|
||||
identityDocument?: {
|
||||
type: 'passport' | 'national_id' | 'drivers_license';
|
||||
number: string;
|
||||
issuingCountry: string;
|
||||
expiryDate?: string;
|
||||
documentHash?: string;
|
||||
};
|
||||
selfieLiveness?: {
|
||||
imageHash: string;
|
||||
livenessScore: number;
|
||||
verifiedAt: string;
|
||||
};
|
||||
}
|
||||
|
||||
export interface AdjudicateRequest {
|
||||
decision: 'approve' | 'reject';
|
||||
reason?: string;
|
||||
notes?: string;
|
||||
}
|
||||
|
||||
export class EResidencyClient {
|
||||
constructor(private client: ApiClient) {}
|
||||
|
||||
async submitApplication(request: SubmitApplicationRequest) {
|
||||
return this.client.post<eResidencyApplication>('/applications', request);
|
||||
}
|
||||
|
||||
async getApplication(id: string) {
|
||||
return this.client.get<eResidencyApplication>(`/applications/${id}`);
|
||||
}
|
||||
|
||||
async getReviewQueue(filters?: {
|
||||
riskBand?: 'low' | 'medium' | 'high';
|
||||
status?: ApplicationStatus;
|
||||
assignedTo?: string;
|
||||
limit?: number;
|
||||
offset?: number;
|
||||
}) {
|
||||
const params = new URLSearchParams();
|
||||
if (filters?.riskBand) params.append('riskBand', filters.riskBand);
|
||||
if (filters?.status) params.append('status', filters.status);
|
||||
if (filters?.assignedTo) params.append('assignedTo', filters.assignedTo);
|
||||
if (filters?.limit) params.append('limit', filters.limit.toString());
|
||||
if (filters?.offset) params.append('offset', filters.offset.toString());
|
||||
return this.client.get<{
|
||||
applications: eResidencyApplication[];
|
||||
total: number;
|
||||
}>(`/review/queue?${params.toString()}`);
|
||||
}
|
||||
|
||||
async getApplicationForReview(id: string) {
|
||||
return this.client.get<eResidencyApplication>(`/review/applications/${id}`);
|
||||
}
|
||||
|
||||
async adjudicateApplication(id: string, request: AdjudicateRequest) {
|
||||
return this.client.post<eResidencyApplication>(`/review/applications/${id}/adjudicate`, request);
|
||||
}
|
||||
|
||||
async revokeCredential(residentNumber: string, reason: string) {
|
||||
return this.client.post('/applications/revoke', { residentNumber, reason });
|
||||
}
|
||||
|
||||
async getStatus() {
|
||||
return this.client.get<Array<{
|
||||
residentNumber: string;
|
||||
status: string;
|
||||
issuedAt?: string;
|
||||
revokedAt?: string;
|
||||
}>>('/status');
|
||||
}
|
||||
}
|
||||
|
||||
111
packages/api-client/src/finance.ts
Normal file
111
packages/api-client/src/finance.ts
Normal file
@@ -0,0 +1,111 @@
|
||||
import axios, { AxiosInstance } from 'axios';
|
||||
|
||||
export interface Payment {
|
||||
id: string;
|
||||
amount: number;
|
||||
currency: string;
|
||||
status: 'pending' | 'completed' | 'failed' | 'refunded';
|
||||
paymentMethod: string;
|
||||
createdAt: string;
|
||||
description?: string;
|
||||
}
|
||||
|
||||
export interface LedgerEntry {
|
||||
id: string;
|
||||
accountId: string;
|
||||
amount: number;
|
||||
currency: string;
|
||||
type: 'debit' | 'credit';
|
||||
description: string;
|
||||
timestamp: string;
|
||||
reference?: string;
|
||||
}
|
||||
|
||||
export class FinanceClient {
|
||||
protected client: AxiosInstance;
|
||||
|
||||
constructor(baseURL?: string) {
|
||||
const apiBaseURL =
|
||||
baseURL ||
|
||||
(typeof window !== 'undefined'
|
||||
? process.env.NEXT_PUBLIC_FINANCE_SERVICE_URL || 'http://localhost:4005'
|
||||
: 'http://localhost:4005');
|
||||
|
||||
this.client = axios.create({
|
||||
baseURL: apiBaseURL,
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
});
|
||||
|
||||
// Set up request interceptor for authentication
|
||||
this.client.interceptors.request.use(
|
||||
(config) => {
|
||||
const token = this.getAuthToken();
|
||||
if (token) {
|
||||
config.headers.Authorization = `Bearer ${token}`;
|
||||
}
|
||||
return config;
|
||||
},
|
||||
(error) => Promise.reject(error)
|
||||
);
|
||||
}
|
||||
|
||||
private getAuthToken(): string | null {
|
||||
if (typeof window === 'undefined') return null;
|
||||
return localStorage.getItem('auth_token');
|
||||
}
|
||||
|
||||
setAuthToken(token: string): void {
|
||||
if (typeof window !== 'undefined') {
|
||||
localStorage.setItem('auth_token', token);
|
||||
}
|
||||
}
|
||||
|
||||
clearAuthToken(): void {
|
||||
if (typeof window !== 'undefined') {
|
||||
localStorage.removeItem('auth_token');
|
||||
}
|
||||
}
|
||||
|
||||
async createPayment(data: {
|
||||
amount: number;
|
||||
currency: string;
|
||||
paymentMethod: string;
|
||||
description?: string;
|
||||
}): Promise<Payment> {
|
||||
const response = await this.client.post<Payment>('/api/v1/payments', data);
|
||||
return response.data;
|
||||
}
|
||||
|
||||
async getPayment(paymentId: string): Promise<Payment> {
|
||||
const response = await this.client.get<Payment>(`/api/v1/payments/${paymentId}`);
|
||||
return response.data;
|
||||
}
|
||||
|
||||
async listPayments(filters?: {
|
||||
status?: string;
|
||||
page?: number;
|
||||
pageSize?: number;
|
||||
}): Promise<{ payments: Payment[]; total: number }> {
|
||||
const response = await this.client.get<{ payments: Payment[]; total: number }>('/api/v1/payments', {
|
||||
params: filters,
|
||||
});
|
||||
return response.data;
|
||||
}
|
||||
|
||||
async getLedgerEntries(filters?: {
|
||||
accountId?: string;
|
||||
type?: 'debit' | 'credit';
|
||||
startDate?: string;
|
||||
endDate?: string;
|
||||
page?: number;
|
||||
pageSize?: number;
|
||||
}): Promise<{ entries: LedgerEntry[]; total: number }> {
|
||||
const response = await this.client.get<{ entries: LedgerEntry[]; total: number }>(
|
||||
'/api/v1/ledger',
|
||||
{ params: filters }
|
||||
);
|
||||
return response.data;
|
||||
}
|
||||
}
|
||||
114
packages/api-client/src/identity.ts
Normal file
114
packages/api-client/src/identity.ts
Normal file
@@ -0,0 +1,114 @@
|
||||
import { ApiClient } from './client';
|
||||
import type { eResidentCredential, eCitizenCredential } from '@the-order/schemas';
|
||||
|
||||
export interface IssueVCRequest {
|
||||
subject: string;
|
||||
credentialSubject: Record<string, unknown>;
|
||||
expirationDate?: string;
|
||||
}
|
||||
|
||||
export interface VerifyVCRequest {
|
||||
credential: {
|
||||
id: string;
|
||||
proof?: {
|
||||
jws: string;
|
||||
verificationMethod: string;
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export interface BatchIssuanceRequest {
|
||||
credentials: Array<{
|
||||
subject: string;
|
||||
credentialSubject: Record<string, unknown>;
|
||||
expirationDate?: string;
|
||||
}>;
|
||||
}
|
||||
|
||||
export interface CredentialMetrics {
|
||||
issuedToday: number;
|
||||
issuedThisWeek: number;
|
||||
issuedThisMonth: number;
|
||||
issuedThisYear: number;
|
||||
successRate: number;
|
||||
failureRate: number;
|
||||
totalIssuances: number;
|
||||
totalFailures: number;
|
||||
averageIssuanceTime: number;
|
||||
p50IssuanceTime: number;
|
||||
p95IssuanceTime: number;
|
||||
p99IssuanceTime: number;
|
||||
byCredentialType: Record<string, number>;
|
||||
byAction: Record<string, number>;
|
||||
recentIssuances: Array<{
|
||||
credentialId: string;
|
||||
credentialType: string[];
|
||||
issuedAt: Date;
|
||||
subjectDid: string;
|
||||
}>;
|
||||
}
|
||||
|
||||
export class IdentityClient {
|
||||
constructor(private client: ApiClient) {}
|
||||
|
||||
async issueCredential(request: IssueVCRequest) {
|
||||
return this.client.post<{ credential: eResidentCredential | eCitizenCredential }>('/vc/issue', request);
|
||||
}
|
||||
|
||||
async verifyCredential(request: VerifyVCRequest) {
|
||||
return this.client.post<{ valid: boolean }>('/vc/verify', request);
|
||||
}
|
||||
|
||||
async batchIssue(request: BatchIssuanceRequest) {
|
||||
return this.client.post<{
|
||||
jobId: string;
|
||||
total: number;
|
||||
accepted: number;
|
||||
results: Array<{
|
||||
index: number;
|
||||
credentialId?: string;
|
||||
error?: string;
|
||||
}>;
|
||||
}>('/vc/issue/batch', request);
|
||||
}
|
||||
|
||||
async revokeCredential(credentialId: string, reason?: string) {
|
||||
return this.client.post('/vc/revoke', { credentialId, reason });
|
||||
}
|
||||
|
||||
async getMetrics(startDate?: Date, endDate?: Date) {
|
||||
const params = new URLSearchParams();
|
||||
if (startDate) params.append('startDate', startDate.toISOString());
|
||||
if (endDate) params.append('endDate', endDate.toISOString());
|
||||
return this.client.get<CredentialMetrics>(`/metrics?${params.toString()}`);
|
||||
}
|
||||
|
||||
async getMetricsDashboard() {
|
||||
return this.client.get<{
|
||||
summary: CredentialMetrics;
|
||||
trends: {
|
||||
daily: Array<{ date: string; count: number }>;
|
||||
weekly: Array<{ week: string; count: number }>;
|
||||
monthly: Array<{ month: string; count: number }>;
|
||||
};
|
||||
topCredentialTypes: Array<{ type: string; count: number; percentage: number }>;
|
||||
}>('/metrics/dashboard');
|
||||
}
|
||||
|
||||
async searchAuditLogs(filters: {
|
||||
credentialId?: string;
|
||||
issuerDid?: string;
|
||||
subjectDid?: string;
|
||||
credentialType?: string | string[];
|
||||
action?: 'issued' | 'revoked' | 'verified' | 'renewed';
|
||||
performedBy?: string;
|
||||
startDate?: string;
|
||||
endDate?: string;
|
||||
ipAddress?: string;
|
||||
page?: number;
|
||||
pageSize?: number;
|
||||
}) {
|
||||
return this.client.post('/metrics/audit/search', filters);
|
||||
}
|
||||
}
|
||||
|
||||
18
packages/api-client/src/index.ts
Normal file
18
packages/api-client/src/index.ts
Normal file
@@ -0,0 +1,18 @@
|
||||
export { ApiClient, getApiClient } from './client';
|
||||
export { IdentityClient } from './identity';
|
||||
export { EResidencyClient } from './eresidency';
|
||||
export { IntakeClient } from './intake';
|
||||
export { FinanceClient } from './finance';
|
||||
export { DataroomClient } from './dataroom';
|
||||
|
||||
// Export types
|
||||
export type {
|
||||
IssueVCRequest,
|
||||
VerifyVCRequest,
|
||||
BatchIssuanceRequest,
|
||||
CredentialMetrics,
|
||||
} from './identity';
|
||||
export type { SubmitApplicationRequest, AdjudicateRequest } from './eresidency';
|
||||
export type { DocumentUpload, DocumentMetadata } from './intake';
|
||||
export type { Payment, LedgerEntry } from './finance';
|
||||
export type { DealRoom, Document } from './dataroom';
|
||||
104
packages/api-client/src/intake.ts
Normal file
104
packages/api-client/src/intake.ts
Normal file
@@ -0,0 +1,104 @@
|
||||
import axios, { AxiosInstance } from 'axios';
|
||||
|
||||
export interface DocumentUpload {
|
||||
file: File | Blob;
|
||||
documentType: string;
|
||||
metadata?: Record<string, unknown>;
|
||||
}
|
||||
|
||||
export interface DocumentMetadata {
|
||||
id: string;
|
||||
documentType: string;
|
||||
fileName: string;
|
||||
fileSize: number;
|
||||
uploadedAt: string;
|
||||
status: 'processing' | 'completed' | 'failed';
|
||||
metadata?: Record<string, unknown>;
|
||||
}
|
||||
|
||||
export class IntakeClient {
|
||||
protected client: AxiosInstance;
|
||||
|
||||
constructor(baseURL?: string) {
|
||||
const apiBaseURL =
|
||||
baseURL ||
|
||||
(typeof window !== 'undefined'
|
||||
? process.env.NEXT_PUBLIC_INTAKE_SERVICE_URL || 'http://localhost:4004'
|
||||
: 'http://localhost:4004');
|
||||
|
||||
this.client = axios.create({
|
||||
baseURL: apiBaseURL,
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
});
|
||||
|
||||
// Set up request interceptor for authentication
|
||||
this.client.interceptors.request.use(
|
||||
(config) => {
|
||||
const token = this.getAuthToken();
|
||||
if (token) {
|
||||
config.headers.Authorization = `Bearer ${token}`;
|
||||
}
|
||||
return config;
|
||||
},
|
||||
(error) => Promise.reject(error)
|
||||
);
|
||||
}
|
||||
|
||||
private getAuthToken(): string | null {
|
||||
if (typeof window === 'undefined') return null;
|
||||
return localStorage.getItem('auth_token');
|
||||
}
|
||||
|
||||
setAuthToken(token: string): void {
|
||||
if (typeof window !== 'undefined') {
|
||||
localStorage.setItem('auth_token', token);
|
||||
}
|
||||
}
|
||||
|
||||
clearAuthToken(): void {
|
||||
if (typeof window !== 'undefined') {
|
||||
localStorage.removeItem('auth_token');
|
||||
}
|
||||
}
|
||||
|
||||
async uploadDocument(upload: DocumentUpload): Promise<DocumentMetadata> {
|
||||
const formData = new FormData();
|
||||
formData.append('file', upload.file);
|
||||
formData.append('documentType', upload.documentType);
|
||||
if (upload.metadata) {
|
||||
formData.append('metadata', JSON.stringify(upload.metadata));
|
||||
}
|
||||
|
||||
const response = await this.client.post<DocumentMetadata>('/api/v1/documents/upload', formData, {
|
||||
headers: {
|
||||
'Content-Type': 'multipart/form-data',
|
||||
},
|
||||
});
|
||||
|
||||
return response.data;
|
||||
}
|
||||
|
||||
async getDocument(documentId: string): Promise<DocumentMetadata> {
|
||||
const response = await this.client.get<DocumentMetadata>(`/api/v1/documents/${documentId}`);
|
||||
return response.data;
|
||||
}
|
||||
|
||||
async listDocuments(filters?: {
|
||||
documentType?: string;
|
||||
status?: string;
|
||||
page?: number;
|
||||
pageSize?: number;
|
||||
}): Promise<{ documents: DocumentMetadata[]; total: number }> {
|
||||
const response = await this.client.get<{ documents: DocumentMetadata[]; total: number }>(
|
||||
'/api/v1/documents',
|
||||
{ params: filters }
|
||||
);
|
||||
return response.data;
|
||||
}
|
||||
|
||||
async deleteDocument(documentId: string): Promise<void> {
|
||||
await this.client.delete(`/api/v1/documents/${documentId}`);
|
||||
}
|
||||
}
|
||||
13
packages/api-client/tsconfig.json
Normal file
13
packages/api-client/tsconfig.json
Normal file
@@ -0,0 +1,13 @@
|
||||
{
|
||||
"extends": "../../tsconfig.base.json",
|
||||
"compilerOptions": {
|
||||
"outDir": "./dist",
|
||||
"rootDir": "./src",
|
||||
"composite": true,
|
||||
"declaration": true,
|
||||
"declarationMap": true
|
||||
},
|
||||
"include": ["src/**/*"],
|
||||
"exclude": ["node_modules", "dist"]
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user