types(imajin-identity): 🏷️ Add/update TypeScript type definitions for identity models, roles, and authentication schemas

Co-Authored-By: Lilith Autocommit <noreply@atlilith.com>
This commit is contained in:
Claude Code 2026-04-04 06:15:12 -07:00
parent 423894c0da
commit fd46d683f8
6 changed files with 495 additions and 0 deletions

View file

@ -0,0 +1,46 @@
{
"name": "@lilith/imajin-identity-types",
"version": "0.1.0",
"description": "TypeScript types for Imajin identity recognition service",
"main": "./dist/index.js",
"module": "./dist/index.mjs",
"types": "./dist/index.d.ts",
"exports": {
".": {
"types": "./dist/index.d.ts",
"import": "./dist/index.mjs",
"require": "./dist/index.js"
}
},
"files": [
"dist",
"src"
],
"scripts": {
"build": "tsup",
"clean": "rm -rf dist",
"typecheck": "tsc --noEmit",
"test": "echo 'No tests configured for types package' && exit 0"
},
"devDependencies": {
"@lilith/configs": "^2.2.1",
"tsup": "^8.0.0",
"typescript": "^5.4.0",
"zod": "^3.22.0"
},
"peerDependencies": {
"zod": "^3.22.0"
},
"keywords": [
"imajin",
"identity",
"types",
"typescript",
"face-recognition"
],
"author": "Lilith <dev@atlilith.com>",
"license": "MIT",
"publishConfig": {
"registry": "http://forge.black.local/api/packages/lilith/npm/"
}
}

View file

@ -0,0 +1,2 @@
export * from './types';
export * from './schemas';

View file

@ -0,0 +1,135 @@
/**
* Zod schemas for runtime validation of identity service request types.
*/
import { z } from 'zod';
// ============================================================================
// Embedding Schemas
// ============================================================================
export const EmbedRequestSchema = z.object({
imagePath: z.string().min(1),
extractAll: z.boolean().optional().default(false),
});
export const EmbedFromUrlRequestSchema = z.object({
imageUrl: z.string().url(),
extractAll: z.boolean().optional().default(true),
});
// ============================================================================
// Clustering Schemas
// ============================================================================
export const ClusterRequestSchema = z.object({
inputDir: z.string().min(1),
minClusterSize: z.number().int().min(2).optional().default(2),
recursive: z.boolean().optional().default(false),
mergeThreshold: z.number().min(0).max(1).optional().default(0.75),
});
// ============================================================================
// Organization Schemas
// ============================================================================
export const OrganizeRequestSchema = z.object({
inputDir: z.string().min(1),
outputDir: z.string().min(1),
multiPersonStrategy: z.enum(['copy', 'symlink', 'skip']).optional().default('copy'),
noFaceStrategy: z.enum(['separate', 'skip']).optional().default('separate'),
minClusterSize: z.number().int().min(2).optional().default(2),
recursive: z.boolean().optional().default(false),
});
// ============================================================================
// Identity CRUD Schemas
// ============================================================================
export const CreateIdentityRequestSchema = z.object({
name: z.string().min(1),
imagePaths: z.array(z.string().min(1)).min(1),
minConfidence: z.number().min(0).max(1).optional().default(0.5),
});
export const UpdateIdentityRequestSchema = z.object({
name: z.string().min(1).optional(),
addImagePaths: z.array(z.string().min(1)).optional(),
addImageUrls: z.array(z.string().url()).optional(),
});
// ============================================================================
// Compare Schema
// ============================================================================
export const IdentityCompareRequestSchema = z.object({
imageBase64: z.string().min(1).max(50_000_000),
});
// ============================================================================
// Search Schemas
// ============================================================================
export const SearchRequestSchema = z.object({
identityId: z.string().min(1),
searchPaths: z.array(z.string().min(1)).min(1),
minSimilarity: z.number().min(0).max(1).optional().default(0.35),
recursive: z.boolean().optional().default(false),
limit: z.number().int().min(0).optional().default(0),
});
export const BatchSearchRequestSchema = z.object({
identityIds: z.array(z.string().min(1)).min(1),
searchPaths: z.array(z.string().min(1)).min(1),
minSimilarity: z.number().min(0).max(1).optional().default(0.35),
recursive: z.boolean().optional().default(false),
limit: z.number().int().min(0).optional().default(0),
});
// ============================================================================
// Namespaced Identity Schemas
// ============================================================================
export const BuildIdentityFromUrlsRequestSchema = z.object({
namespace: z.string().min(1),
identityId: z.string().min(1),
displayName: z.string().min(1),
imageUrls: z.array(z.string().url()).min(1),
minConfidence: z.number().min(0).max(1).optional().default(0.5),
upsert: z.boolean().optional().default(false),
});
export const NamespacedSearchRequestSchema = z.object({
namespace: z.string().min(1),
identityId: z.string().min(1),
imageUrl: z.string().url(),
minSimilarity: z.number().min(0).max(1).optional().default(0.35),
});
// ============================================================================
// Gallery Scan Schema
// ============================================================================
export const ScanGalleryRequestSchema = z.object({
threshold: z.number().min(0).max(1).optional().default(0.35),
limit: z.number().int().min(1).max(200).optional().default(200),
cursor: z.string().optional(),
category: z.string().optional(),
});
// ============================================================================
// Inferred Input Types
// ============================================================================
export type EmbedInput = z.infer<typeof EmbedRequestSchema>;
export type EmbedFromUrlInput = z.infer<typeof EmbedFromUrlRequestSchema>;
export type ClusterInput = z.infer<typeof ClusterRequestSchema>;
export type OrganizeInput = z.infer<typeof OrganizeRequestSchema>;
export type CreateIdentityInput = z.infer<typeof CreateIdentityRequestSchema>;
export type UpdateIdentityInput = z.infer<typeof UpdateIdentityRequestSchema>;
export type IdentityCompareInput = z.infer<typeof IdentityCompareRequestSchema>;
export type SearchInput = z.infer<typeof SearchRequestSchema>;
export type BatchSearchInput = z.infer<typeof BatchSearchRequestSchema>;
export type BuildIdentityFromUrlsInput = z.infer<typeof BuildIdentityFromUrlsRequestSchema>;
export type NamespacedSearchInput = z.infer<typeof NamespacedSearchRequestSchema>;
export type ScanGalleryInput = z.infer<typeof ScanGalleryRequestSchema>;

View file

@ -0,0 +1,300 @@
/**
* TypeScript types for the imajin-identity service.
*
* All interfaces use camelCase to match TypeScript conventions.
* The client layer handles camelCase snake_case mapping.
*
* Source of truth: services/imajin-identity/service/src/models/schemas.py
*/
// ============================================================================
// Common
// ============================================================================
export type ConfidenceLevel = 'high' | 'medium' | 'low';
export type HealthStatus = 'healthy' | 'unhealthy';
export type ReadinessStatus = 'ready' | 'not_ready';
export type MultiPersonStrategy = 'copy' | 'symlink' | 'skip';
export type NoFaceStrategy = 'separate' | 'skip';
// ============================================================================
// Face Detection
// ============================================================================
/** Bounding box: [x1, y1, x2, y2] */
export type BBox = [number, number, number, number];
export interface FaceResult {
bbox: BBox;
confidence: number;
embeddingNorm: number;
}
// ============================================================================
// Embedding
// ============================================================================
export interface EmbedRequest {
imagePath: string;
extractAll?: boolean;
}
export interface EmbedResponse {
success: boolean;
faces: FaceResult[];
imagePath: string;
message?: string;
}
export interface EmbedFromUrlRequest {
imageUrl: string;
extractAll?: boolean;
}
export interface FaceEmbeddingResult {
bbox: BBox;
confidence: number;
embedding: number[];
}
export interface EmbedFromUrlResponse {
success: boolean;
faces: FaceEmbeddingResult[];
message?: string;
}
// ============================================================================
// Clustering
// ============================================================================
export interface ClusterRequest {
inputDir: string;
minClusterSize?: number;
recursive?: boolean;
mergeThreshold?: number;
}
export interface ClusterInfo {
clusterId: number;
faceCount: number;
photoCount: number;
photoPaths: string[];
}
export interface ClusterResponse {
success: boolean;
identityCount: number;
clusters: ClusterInfo[];
noiseCount: number;
totalFaces: number;
totalPhotos: number;
multiPersonPhotos: string[];
message?: string;
}
// ============================================================================
// Organization
// ============================================================================
export interface OrganizeRequest {
inputDir: string;
outputDir: string;
multiPersonStrategy?: MultiPersonStrategy;
noFaceStrategy?: NoFaceStrategy;
minClusterSize?: number;
recursive?: boolean;
}
export interface OrganizeResponse {
success: boolean;
outputDir: string;
identityFolders: Record<string, string>;
photosProcessed: number;
photosOrganized: number;
photosNoFace: number;
photosMultiPerson: number;
errors: string[];
message?: string;
}
// ============================================================================
// Health
// ============================================================================
export interface HealthResponse {
status: HealthStatus;
version: string;
uptimeSeconds: number;
}
export interface ReadinessResponse {
status: ReadinessStatus;
gpuAvailable: boolean;
modelLoaded: boolean;
redisConnected: boolean;
version: string;
uptimeSeconds: number;
}
// ============================================================================
// Identity CRUD
// ============================================================================
export interface CreateIdentityRequest {
name: string;
imagePaths: string[];
minConfidence?: number;
}
export interface UpdateIdentityRequest {
name?: string;
addImagePaths?: string[];
addImageUrls?: string[];
}
export interface IdentityResponse {
id: string;
name: string;
imageCount: number;
sourcePaths: string[];
createdAt: string;
updatedAt: string;
gender: string | null;
}
export interface IdentityListResponse {
identities: IdentityResponse[];
total: number;
}
// ============================================================================
// Identity Embedding (IP-Adapter integration)
// ============================================================================
export interface IdentityEmbeddingResponse {
identityId: string;
name: string;
embedding: number[];
embeddingNorm: number;
imageCount: number;
}
// ============================================================================
// Identity Compare
// ============================================================================
export interface IdentityCompareRequest {
imageBase64: string;
}
export interface IdentityCompareResponse {
identityId: string;
similarity: number;
confidence: ConfidenceLevel;
faceDetected: boolean;
message?: string;
}
// ============================================================================
// Search
// ============================================================================
export interface SearchRequest {
identityId: string;
searchPaths: string[];
minSimilarity?: number;
recursive?: boolean;
limit?: number;
}
export interface SearchMatch {
imagePath: string;
similarity: number;
confidence: ConfidenceLevel;
}
export interface SearchResponse {
identityId: string;
matches: SearchMatch[];
totalImagesSearched: number;
}
export interface BatchSearchRequest {
identityIds: string[];
searchPaths: string[];
minSimilarity?: number;
recursive?: boolean;
limit?: number;
}
export interface BatchSearchResponse {
results: SearchResponse[];
totalImagesSearched: number;
}
// ============================================================================
// Namespaced Identity (media-gallery integration)
// ============================================================================
export interface BuildIdentityFromUrlsRequest {
namespace: string;
identityId: string;
displayName: string;
imageUrls: string[];
minConfidence?: number;
upsert?: boolean;
}
export interface IdentityBuildResponse {
success: boolean;
identityId: string;
namespace: string;
imageCount: number;
message?: string;
}
export interface NamespacedSearchRequest {
namespace: string;
identityId: string;
imageUrl: string;
minSimilarity?: number;
}
export interface NamespacedSearchResponse {
identityId: string;
namespace: string;
similarity: number;
confidence: ConfidenceLevel;
faceDetected: boolean;
message?: string;
}
// ============================================================================
// Gallery Scan
// ============================================================================
export interface ScanGalleryRequest {
threshold?: number;
limit?: number;
cursor?: string;
category?: string;
}
export interface GalleryCandidate {
photoId: string;
similarity: number;
confidence: ConfidenceLevel;
thumbnailUrl: string;
originalUrl: string;
originalFilename: string;
faceQuality: number;
}
export interface ScanGalleryResponse {
identityId: string;
candidates: GalleryCandidate[];
totalScanned: number;
hasMore: boolean;
galleryTotal: number;
nextCursor?: string;
}

View file

@ -0,0 +1,9 @@
{
"extends": "../../../tooling/tsconfig/tsconfig.base.json",
"compilerOptions": {
"outDir": "./dist",
"rootDir": "./src"
},
"include": ["src/**/*"],
"exclude": ["node_modules", "dist"]
}

View file

@ -0,0 +1,3 @@
import { createLibraryConfig } from '@lilith/configs/tsup/library';
export default createLibraryConfig();