mirror of
https://github.com/Memo-2023/mana-monorepo.git
synced 2026-05-14 18:41:08 +02:00
feat: add shared credit service package (Tier 5)
Create @manacore/shared-credit-service with:
- createCreditService() factory function
- Credit balance fetching with auth token support
- Operation pricing with caching (30min default)
- Fallback pricing for all standard operations
- Credit check before operations
- Credit consumption notification system
- Sync and async cost calculation methods
Standard operations supported:
- Memoro: transcription, headline, memory, blueprint, etc.
- Maerchenzauber: character creation, story creation
- ManaDeck: deck creation, card generation, AI review
- Generic: AI processing, export, import
Apps can use this service with their own configuration:
```ts
const creditService = createCreditService({
apiUrl: 'https://api.myapp.com',
getAuthToken: () => auth.getToken()
});
```
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
parent
294d1fc5c5
commit
c87641f91b
6 changed files with 619 additions and 12 deletions
25
packages/shared-credit-service/package.json
Normal file
25
packages/shared-credit-service/package.json
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
{
|
||||
"name": "@manacore/shared-credit-service",
|
||||
"version": "0.0.1",
|
||||
"type": "module",
|
||||
"exports": {
|
||||
".": {
|
||||
"types": "./src/index.ts",
|
||||
"default": "./src/index.ts"
|
||||
}
|
||||
},
|
||||
"main": "./src/index.ts",
|
||||
"types": "./src/index.ts",
|
||||
"files": [
|
||||
"src"
|
||||
],
|
||||
"scripts": {
|
||||
"type-check": "tsc --noEmit"
|
||||
},
|
||||
"dependencies": {
|
||||
"@manacore/shared-subscription-types": "workspace:*"
|
||||
},
|
||||
"devDependencies": {
|
||||
"typescript": "^5.0.0"
|
||||
}
|
||||
}
|
||||
327
packages/shared-credit-service/src/createCreditService.ts
Normal file
327
packages/shared-credit-service/src/createCreditService.ts
Normal file
|
|
@ -0,0 +1,327 @@
|
|||
/**
|
||||
* Credit Service Factory
|
||||
*
|
||||
* Creates a credit service instance configured for a specific app.
|
||||
* Handles credit balance fetching, pricing, and consumption notifications.
|
||||
*
|
||||
* @example
|
||||
* ```ts
|
||||
* import { createCreditService } from '@manacore/shared-credit-service';
|
||||
* import { auth } from '$lib/stores/auth';
|
||||
*
|
||||
* export const creditService = createCreditService({
|
||||
* apiUrl: 'https://api.example.com',
|
||||
* pricingEndpoint: '/credits/pricing',
|
||||
* balanceEndpoint: '/auth/credits',
|
||||
* getAuthToken: () => auth.getToken(),
|
||||
* fallbackPricing: {
|
||||
* STORY_CREATION: 10,
|
||||
* CHARACTER_CREATION: 20
|
||||
* }
|
||||
* });
|
||||
* ```
|
||||
*/
|
||||
|
||||
import type {
|
||||
CreditServiceConfig,
|
||||
CreditBalance,
|
||||
CreditCheckResponse,
|
||||
PricingResponse,
|
||||
CreditUpdateCallback,
|
||||
StandardOperationType
|
||||
} from './types';
|
||||
import { DEFAULT_OPERATION_PRICING } from './types';
|
||||
|
||||
/**
|
||||
* Create a credit service instance
|
||||
*/
|
||||
export function createCreditService(config: CreditServiceConfig) {
|
||||
const {
|
||||
apiUrl,
|
||||
balanceEndpoint = '/auth/credits',
|
||||
pricingEndpoint = '/credits/pricing',
|
||||
cacheDuration = 30 * 60 * 1000, // 30 minutes default
|
||||
fallbackPricing = {},
|
||||
getAuthToken
|
||||
} = config;
|
||||
|
||||
// Normalize API URL (remove trailing slash)
|
||||
const baseUrl = apiUrl.replace(/\/$/, '');
|
||||
|
||||
// Internal state
|
||||
let cachedPricing: PricingResponse | null = null;
|
||||
let pricingLastFetched = 0;
|
||||
const creditUpdateCallbacks: CreditUpdateCallback[] = [];
|
||||
|
||||
// Merge fallback pricing with defaults
|
||||
const mergedFallbackPricing = {
|
||||
...DEFAULT_OPERATION_PRICING,
|
||||
...fallbackPricing
|
||||
};
|
||||
|
||||
/**
|
||||
* Initialize the credit service by preloading pricing
|
||||
*/
|
||||
async function initialize(): Promise<void> {
|
||||
try {
|
||||
await getPricing();
|
||||
console.log('[CreditService] Initialized with backend pricing');
|
||||
} catch (error) {
|
||||
console.warn('[CreditService] Initialization failed, using fallback pricing:', error);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a callback for credit consumption notifications
|
||||
* @returns Unsubscribe function
|
||||
*/
|
||||
function onCreditUpdate(callback: CreditUpdateCallback): () => void {
|
||||
creditUpdateCallbacks.push(callback);
|
||||
|
||||
return () => {
|
||||
const index = creditUpdateCallbacks.indexOf(callback);
|
||||
if (index > -1) {
|
||||
creditUpdateCallbacks.splice(index, 1);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Notify all callbacks about credit consumption
|
||||
*/
|
||||
function notifyCreditUpdate(creditsConsumed: number, operation?: string): void {
|
||||
creditUpdateCallbacks.forEach((callback) => {
|
||||
try {
|
||||
callback(creditsConsumed, operation);
|
||||
} catch (error) {
|
||||
console.error('[CreditService] Error in credit update callback:', error);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Manually trigger credit update notifications
|
||||
*/
|
||||
function triggerCreditUpdate(creditsConsumed: number, operation?: string): void {
|
||||
notifyCreditUpdate(creditsConsumed, operation);
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch pricing information from backend with caching
|
||||
*/
|
||||
async function getPricing(): Promise<PricingResponse> {
|
||||
const now = Date.now();
|
||||
|
||||
// Return cached pricing if still valid
|
||||
if (cachedPricing && now - pricingLastFetched < cacheDuration) {
|
||||
return cachedPricing;
|
||||
}
|
||||
|
||||
try {
|
||||
const response = await fetch(`${baseUrl}${pricingEndpoint}`, {
|
||||
method: 'GET',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
|
||||
}
|
||||
|
||||
const pricing = await response.json();
|
||||
cachedPricing = pricing;
|
||||
pricingLastFetched = now;
|
||||
|
||||
return pricing;
|
||||
} catch (error) {
|
||||
console.error('[CreditService] Error fetching pricing:', error);
|
||||
|
||||
// Return cached pricing if available
|
||||
if (cachedPricing) {
|
||||
return cachedPricing;
|
||||
}
|
||||
|
||||
// Return fallback pricing
|
||||
return {
|
||||
operationCosts: mergedFallbackPricing,
|
||||
lastUpdated: new Date().toISOString()
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get user's credit balance
|
||||
*/
|
||||
async function getBalance(): Promise<CreditBalance | null> {
|
||||
try {
|
||||
const token = await getAuthToken();
|
||||
|
||||
if (!token) {
|
||||
console.error('[CreditService] No authentication token available');
|
||||
return null;
|
||||
}
|
||||
|
||||
const response = await fetch(`${baseUrl}${balanceEndpoint}`, {
|
||||
method: 'GET',
|
||||
headers: {
|
||||
Authorization: `Bearer ${token}`,
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
const errorData = await response.json().catch(() => ({}));
|
||||
throw new Error(errorData.message || `HTTP ${response.status}`);
|
||||
}
|
||||
|
||||
const data = await response.json();
|
||||
|
||||
// Handle wrapped response structure
|
||||
if (data.data && typeof data.data.credits === 'number') {
|
||||
return {
|
||||
credits: data.data.credits,
|
||||
maxCreditLimit: data.data.maxCreditLimit ?? data.data.credits,
|
||||
userId: data.data.userId ?? '',
|
||||
lastUpdated: new Date().toISOString()
|
||||
};
|
||||
}
|
||||
|
||||
// Handle direct structure
|
||||
if (typeof data.credits === 'number') {
|
||||
return {
|
||||
credits: data.credits,
|
||||
maxCreditLimit: data.maxCreditLimit ?? data.credits,
|
||||
userId: data.userId ?? '',
|
||||
lastUpdated: new Date().toISOString()
|
||||
};
|
||||
}
|
||||
|
||||
return data;
|
||||
} catch (error) {
|
||||
console.error('[CreditService] Error fetching balance:', error);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get cost for a specific operation (async with backend fetch)
|
||||
*/
|
||||
async function getOperationCost(operation: StandardOperationType): Promise<number> {
|
||||
try {
|
||||
const pricing = await getPricing();
|
||||
return pricing.operationCosts[operation] ?? mergedFallbackPricing[operation] ?? 0;
|
||||
} catch (error) {
|
||||
console.error('[CreditService] Error getting operation cost:', error);
|
||||
return mergedFallbackPricing[operation] ?? 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get cost for a specific operation (sync, uses cached values)
|
||||
*/
|
||||
function getOperationCostSync(operation: StandardOperationType): number {
|
||||
if (cachedPricing?.operationCosts[operation] !== undefined) {
|
||||
return cachedPricing.operationCosts[operation];
|
||||
}
|
||||
return mergedFallbackPricing[operation] ?? 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate cost for multiple units of an operation
|
||||
*/
|
||||
async function calculateCost(operation: StandardOperationType, quantity: number = 1): Promise<number> {
|
||||
const unitCost = await getOperationCost(operation);
|
||||
return unitCost * quantity;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate cost synchronously (uses cached values)
|
||||
*/
|
||||
function calculateCostSync(operation: StandardOperationType, quantity: number = 1): number {
|
||||
const unitCost = getOperationCostSync(operation);
|
||||
return unitCost * quantity;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if user has enough credits for an operation
|
||||
*/
|
||||
async function checkBalance(
|
||||
requiredCredits: number,
|
||||
operation?: string
|
||||
): Promise<CreditCheckResponse> {
|
||||
const balance = await getBalance();
|
||||
|
||||
if (!balance) {
|
||||
return {
|
||||
hasEnoughCredits: false,
|
||||
currentCredits: 0,
|
||||
requiredCredits,
|
||||
deficit: requiredCredits
|
||||
};
|
||||
}
|
||||
|
||||
const hasEnough = balance.credits >= requiredCredits;
|
||||
|
||||
return {
|
||||
hasEnoughCredits: hasEnough,
|
||||
currentCredits: balance.credits,
|
||||
requiredCredits,
|
||||
deficit: hasEnough ? undefined : requiredCredits - balance.credits,
|
||||
context: operation ? { operation } : undefined
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if user has enough credits for a specific operation
|
||||
*/
|
||||
async function checkOperationBalance(operation: StandardOperationType): Promise<CreditCheckResponse> {
|
||||
const cost = await getOperationCost(operation);
|
||||
return checkBalance(cost, operation);
|
||||
}
|
||||
|
||||
/**
|
||||
* Format credit amount for display
|
||||
*/
|
||||
function formatCredits(amount: number, locale: string = 'en-US'): string {
|
||||
return new Intl.NumberFormat(locale).format(amount);
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear pricing cache (useful for testing or forced refresh)
|
||||
*/
|
||||
function clearCache(): void {
|
||||
cachedPricing = null;
|
||||
pricingLastFetched = 0;
|
||||
}
|
||||
|
||||
return {
|
||||
// Initialization
|
||||
initialize,
|
||||
|
||||
// Balance operations
|
||||
getBalance,
|
||||
checkBalance,
|
||||
checkOperationBalance,
|
||||
|
||||
// Pricing operations
|
||||
getPricing,
|
||||
getOperationCost,
|
||||
getOperationCostSync,
|
||||
calculateCost,
|
||||
calculateCostSync,
|
||||
|
||||
// Notifications
|
||||
onCreditUpdate,
|
||||
triggerCreditUpdate,
|
||||
|
||||
// Utilities
|
||||
formatCredits,
|
||||
clearCache
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Type for the credit service instance
|
||||
*/
|
||||
export type CreditService = ReturnType<typeof createCreditService>;
|
||||
75
packages/shared-credit-service/src/index.ts
Normal file
75
packages/shared-credit-service/src/index.ts
Normal file
|
|
@ -0,0 +1,75 @@
|
|||
/**
|
||||
* @manacore/shared-credit-service
|
||||
*
|
||||
* Shared credit/mana service for the ManaCore monorepo.
|
||||
*
|
||||
* Provides:
|
||||
* - Credit balance fetching and caching
|
||||
* - Operation pricing with fallbacks
|
||||
* - Credit check before operations
|
||||
* - Credit consumption notifications
|
||||
*
|
||||
* @example Basic usage
|
||||
* ```ts
|
||||
* import { createCreditService } from '@manacore/shared-credit-service';
|
||||
*
|
||||
* const creditService = createCreditService({
|
||||
* apiUrl: 'https://api.myapp.com',
|
||||
* getAuthToken: async () => localStorage.getItem('token')
|
||||
* });
|
||||
*
|
||||
* // Initialize on app startup
|
||||
* await creditService.initialize();
|
||||
*
|
||||
* // Check balance before operation
|
||||
* const check = await creditService.checkOperationBalance('STORY_CREATION');
|
||||
* if (!check.hasEnoughCredits) {
|
||||
* showInsufficientCreditsModal(check.deficit);
|
||||
* return;
|
||||
* }
|
||||
*
|
||||
* // After successful operation, notify listeners
|
||||
* creditService.triggerCreditUpdate(10, 'STORY_CREATION');
|
||||
* ```
|
||||
*
|
||||
* @example With Svelte store integration
|
||||
* ```ts
|
||||
* // creditService.ts
|
||||
* import { createCreditService } from '@manacore/shared-credit-service';
|
||||
* import { auth } from '$lib/stores/auth';
|
||||
*
|
||||
* export const creditService = createCreditService({
|
||||
* apiUrl: import.meta.env.VITE_API_URL,
|
||||
* pricingEndpoint: '/credits/pricing',
|
||||
* getAuthToken: () => auth.getToken()
|
||||
* });
|
||||
*
|
||||
* // creditStore.svelte.ts
|
||||
* import { creditService } from './creditService';
|
||||
*
|
||||
* let balance = $state<number>(0);
|
||||
*
|
||||
* // Listen for credit updates
|
||||
* creditService.onCreditUpdate((consumed) => {
|
||||
* balance -= consumed;
|
||||
* });
|
||||
* ```
|
||||
*/
|
||||
|
||||
// Factory function
|
||||
export { createCreditService } from './createCreditService';
|
||||
export type { CreditService } from './createCreditService';
|
||||
|
||||
// Types
|
||||
export type {
|
||||
CreditServiceConfig,
|
||||
CreditBalance,
|
||||
CreditCheckResponse,
|
||||
CreditConsumptionResponse,
|
||||
PricingResponse,
|
||||
CreditUpdateCallback,
|
||||
StandardOperationType
|
||||
} from './types';
|
||||
|
||||
// Constants
|
||||
export { DEFAULT_OPERATION_PRICING } from './types';
|
||||
154
packages/shared-credit-service/src/types.ts
Normal file
154
packages/shared-credit-service/src/types.ts
Normal file
|
|
@ -0,0 +1,154 @@
|
|||
/**
|
||||
* Credit Service Types
|
||||
*
|
||||
* Types for credit/mana operations across all apps
|
||||
*/
|
||||
|
||||
import type { OperationPricing, ManaBalance } from '@manacore/shared-subscription-types';
|
||||
|
||||
/**
|
||||
* Credit balance with additional metadata
|
||||
*/
|
||||
export interface CreditBalance {
|
||||
/** Current credit/mana amount */
|
||||
credits: number;
|
||||
/** Maximum credit limit */
|
||||
maxCreditLimit: number;
|
||||
/** User ID */
|
||||
userId: string;
|
||||
/** Currency identifier (default: 'mana') */
|
||||
currency?: string;
|
||||
/** Last updated timestamp */
|
||||
lastUpdated?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Result of checking if user has enough credits
|
||||
*/
|
||||
export interface CreditCheckResponse {
|
||||
/** Whether user has sufficient credits */
|
||||
hasEnoughCredits: boolean;
|
||||
/** Current credit balance */
|
||||
currentCredits: number;
|
||||
/** Credits required for operation */
|
||||
requiredCredits: number;
|
||||
/** Deficit amount (if insufficient) */
|
||||
deficit?: number;
|
||||
/** Credit source type */
|
||||
creditType?: 'user' | 'space';
|
||||
/** Additional context */
|
||||
context?: Record<string, unknown>;
|
||||
}
|
||||
|
||||
/**
|
||||
* Result of credit consumption
|
||||
*/
|
||||
export interface CreditConsumptionResponse {
|
||||
/** Whether consumption succeeded */
|
||||
success: boolean;
|
||||
/** Human-readable message */
|
||||
message: string;
|
||||
/** Amount of credits consumed */
|
||||
creditsConsumed: number;
|
||||
/** Credit source type */
|
||||
creditType: 'user' | 'space';
|
||||
/** Remaining balance after consumption */
|
||||
remainingCredits?: number;
|
||||
/** Related operation identifier */
|
||||
operationId?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Pricing response from backend
|
||||
*/
|
||||
export interface PricingResponse {
|
||||
/** Map of operation types to their costs */
|
||||
operationCosts: Record<string, number>;
|
||||
/** Cost per hour for time-based operations (e.g., transcription) */
|
||||
transcriptionPerHour?: number;
|
||||
/** When pricing was last updated */
|
||||
lastUpdated: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Configuration for creating a credit service instance
|
||||
*/
|
||||
export interface CreditServiceConfig {
|
||||
/** Base URL for credit/billing API */
|
||||
apiUrl: string;
|
||||
/** Endpoint for fetching balance (relative to apiUrl) */
|
||||
balanceEndpoint?: string;
|
||||
/** Endpoint for fetching pricing (relative to apiUrl) */
|
||||
pricingEndpoint?: string;
|
||||
/** How long to cache pricing (milliseconds, default: 30 minutes) */
|
||||
cacheDuration?: number;
|
||||
/** Fallback pricing if backend unavailable */
|
||||
fallbackPricing?: Record<string, number>;
|
||||
/** Function to get current auth token */
|
||||
getAuthToken: () => Promise<string | null>;
|
||||
}
|
||||
|
||||
/**
|
||||
* Credit update callback type
|
||||
*/
|
||||
export type CreditUpdateCallback = (creditsConsumed: number, operation?: string) => void;
|
||||
|
||||
/**
|
||||
* Standard operation types across all apps
|
||||
*/
|
||||
export type StandardOperationType =
|
||||
// Memoro operations
|
||||
| 'TRANSCRIPTION_PER_HOUR'
|
||||
| 'HEADLINE_GENERATION'
|
||||
| 'MEMORY_CREATION'
|
||||
| 'BLUEPRINT_PROCESSING'
|
||||
| 'QUESTION_MEMO'
|
||||
| 'NEW_MEMORY'
|
||||
| 'MEMO_COMBINE'
|
||||
| 'MEMO_SHARING'
|
||||
| 'SPACE_OPERATION'
|
||||
// Maerchenzauber operations
|
||||
| 'CHARACTER_CREATION'
|
||||
| 'CHARACTER_GENERATION_FROM_IMAGE'
|
||||
| 'CHARACTER_IMPORT'
|
||||
| 'STORY_CREATION'
|
||||
| 'STORY_CONTINUATION'
|
||||
// ManaDeck operations
|
||||
| 'DECK_CREATION'
|
||||
| 'CARD_GENERATION'
|
||||
| 'AI_REVIEW'
|
||||
// Generic operations
|
||||
| 'AI_PROCESSING'
|
||||
| 'EXPORT'
|
||||
| 'IMPORT'
|
||||
| string; // Allow custom operation types
|
||||
|
||||
/**
|
||||
* Default pricing for operations (fallback values)
|
||||
*/
|
||||
export const DEFAULT_OPERATION_PRICING: Record<string, number> = {
|
||||
// Memoro
|
||||
TRANSCRIPTION_PER_HOUR: 120,
|
||||
HEADLINE_GENERATION: 10,
|
||||
MEMORY_CREATION: 10,
|
||||
BLUEPRINT_PROCESSING: 5,
|
||||
QUESTION_MEMO: 5,
|
||||
NEW_MEMORY: 5,
|
||||
MEMO_COMBINE: 5,
|
||||
MEMO_SHARING: 1,
|
||||
SPACE_OPERATION: 2,
|
||||
// Maerchenzauber
|
||||
CHARACTER_CREATION: 20,
|
||||
CHARACTER_GENERATION_FROM_IMAGE: 20,
|
||||
CHARACTER_IMPORT: 10,
|
||||
STORY_CREATION: 10,
|
||||
STORY_CONTINUATION: 5,
|
||||
// ManaDeck
|
||||
DECK_CREATION: 5,
|
||||
CARD_GENERATION: 2,
|
||||
AI_REVIEW: 10,
|
||||
// Generic
|
||||
AI_PROCESSING: 10,
|
||||
EXPORT: 1,
|
||||
IMPORT: 1
|
||||
};
|
||||
16
packages/shared-credit-service/tsconfig.json
Normal file
16
packages/shared-credit-service/tsconfig.json
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
{
|
||||
"compilerOptions": {
|
||||
"target": "ES2022",
|
||||
"module": "ESNext",
|
||||
"moduleResolution": "bundler",
|
||||
"lib": ["ES2022", "DOM"],
|
||||
"strict": true,
|
||||
"esModuleInterop": true,
|
||||
"skipLibCheck": true,
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"declaration": true,
|
||||
"declarationMap": true,
|
||||
"noEmit": true
|
||||
},
|
||||
"include": ["src/**/*"]
|
||||
}
|
||||
34
pnpm-lock.yaml
generated
34
pnpm-lock.yaml
generated
|
|
@ -1630,6 +1630,16 @@ importers:
|
|||
specifier: ^5.7.3
|
||||
version: 5.9.3
|
||||
|
||||
packages/shared-credit-service:
|
||||
dependencies:
|
||||
'@manacore/shared-subscription-types':
|
||||
specifier: workspace:*
|
||||
version: link:../shared-subscription-types
|
||||
devDependencies:
|
||||
typescript:
|
||||
specifier: ^5.0.0
|
||||
version: 5.9.3
|
||||
|
||||
packages/shared-i18n:
|
||||
devDependencies:
|
||||
svelte:
|
||||
|
|
@ -14868,7 +14878,7 @@ snapshots:
|
|||
wrap-ansi: 7.0.0
|
||||
ws: 8.18.3
|
||||
optionalDependencies:
|
||||
expo-router: 6.0.15(evxcyavfmgswt4zg3ii4wlqsdm)
|
||||
expo-router: 6.0.15(nbbplg4zewzlp5oy3zff3m2jw4)
|
||||
react-native: 0.81.5(@babel/core@7.28.5)(@types/react@19.1.17)(react@19.1.0)
|
||||
transitivePeerDependencies:
|
||||
- '@modelcontextprotocol/sdk'
|
||||
|
|
@ -20699,7 +20709,7 @@ snapshots:
|
|||
'@typescript-eslint/eslint-plugin': 8.47.0(@typescript-eslint/parser@8.47.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3)
|
||||
'@typescript-eslint/parser': 8.47.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3)
|
||||
eslint: 9.39.1(jiti@2.6.1)
|
||||
eslint-import-resolver-typescript: 3.10.1(eslint-plugin-import@2.32.0)(eslint@9.39.1(jiti@2.6.1))
|
||||
eslint-import-resolver-typescript: 3.10.1(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.47.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.1(jiti@2.6.1)))(eslint@9.39.1(jiti@2.6.1))
|
||||
eslint-plugin-expo: 1.0.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3)
|
||||
eslint-plugin-import: 2.32.0(@typescript-eslint/parser@8.47.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-typescript@3.10.1)(eslint@9.39.1(jiti@2.6.1))
|
||||
eslint-plugin-react: 7.37.5(eslint@9.39.1(jiti@2.6.1))
|
||||
|
|
@ -20773,7 +20783,7 @@ snapshots:
|
|||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.32.0)(eslint@9.39.1(jiti@2.6.1)):
|
||||
eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.47.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.1(jiti@2.6.1)))(eslint@9.39.1(jiti@2.6.1)):
|
||||
dependencies:
|
||||
'@nolyfill/is-core-module': 1.0.39
|
||||
debug: 4.4.3
|
||||
|
|
@ -20798,14 +20808,14 @@ snapshots:
|
|||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
eslint-module-utils@2.12.1(@typescript-eslint/parser@8.47.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.10.1)(eslint@9.39.1(jiti@2.6.1)):
|
||||
eslint-module-utils@2.12.1(@typescript-eslint/parser@8.47.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.47.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.1(jiti@2.6.1)))(eslint@9.39.1(jiti@2.6.1)))(eslint@9.39.1(jiti@2.6.1)):
|
||||
dependencies:
|
||||
debug: 3.2.7
|
||||
optionalDependencies:
|
||||
'@typescript-eslint/parser': 8.47.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3)
|
||||
eslint: 9.39.1(jiti@2.6.1)
|
||||
eslint-import-resolver-node: 0.3.9
|
||||
eslint-import-resolver-typescript: 3.10.1(eslint-plugin-import@2.32.0)(eslint@9.39.1(jiti@2.6.1))
|
||||
eslint-import-resolver-typescript: 3.10.1(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.47.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.1(jiti@2.6.1)))(eslint@9.39.1(jiti@2.6.1))
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
|
|
@ -20877,7 +20887,7 @@ snapshots:
|
|||
doctrine: 2.1.0
|
||||
eslint: 9.39.1(jiti@2.6.1)
|
||||
eslint-import-resolver-node: 0.3.9
|
||||
eslint-module-utils: 2.12.1(@typescript-eslint/parser@8.47.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.10.1)(eslint@9.39.1(jiti@2.6.1))
|
||||
eslint-module-utils: 2.12.1(@typescript-eslint/parser@8.47.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.47.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.1(jiti@2.6.1)))(eslint@9.39.1(jiti@2.6.1)))(eslint@9.39.1(jiti@2.6.1))
|
||||
hasown: 2.0.2
|
||||
is-core-module: 2.16.1
|
||||
is-glob: 4.0.3
|
||||
|
|
@ -21472,7 +21482,7 @@ snapshots:
|
|||
|
||||
expo-device@8.0.9(expo@54.0.25):
|
||||
dependencies:
|
||||
expo: 54.0.25(@babel/core@7.28.5)(@expo/metro-runtime@6.1.2)(expo-router@6.0.15)(react-native@0.81.5(@babel/core@7.28.5)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0)
|
||||
expo: 54.0.25(@babel/core@7.28.5)(@expo/metro-runtime@6.1.2)(expo-router@6.0.15)(react-native@0.81.4(@babel/core@7.28.5)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0)
|
||||
ua-parser-js: 0.7.41
|
||||
|
||||
expo-document-picker@14.0.7(expo@54.0.25):
|
||||
|
|
@ -21527,7 +21537,7 @@ snapshots:
|
|||
|
||||
expo-image-loader@6.0.0(expo@54.0.25):
|
||||
dependencies:
|
||||
expo: 54.0.25(@babel/core@7.28.5)(@expo/metro-runtime@6.1.2)(expo-router@6.0.15)(react-native@0.81.5(@babel/core@7.28.5)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0)
|
||||
expo: 54.0.25(@babel/core@7.28.5)(@expo/metro-runtime@6.1.2)(expo-router@6.0.15)(react-native@0.81.4(@babel/core@7.28.5)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0)
|
||||
|
||||
expo-image-picker@17.0.8(expo@54.0.13):
|
||||
dependencies:
|
||||
|
|
@ -21536,7 +21546,7 @@ snapshots:
|
|||
|
||||
expo-image-picker@17.0.8(expo@54.0.25):
|
||||
dependencies:
|
||||
expo: 54.0.25(@babel/core@7.28.5)(@expo/metro-runtime@6.1.2)(expo-router@6.0.15)(react-native@0.81.5(@babel/core@7.28.5)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0)
|
||||
expo: 54.0.25(@babel/core@7.28.5)(@expo/metro-runtime@6.1.2)(expo-router@6.0.15)(react-native@0.81.4(@babel/core@7.28.5)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0)
|
||||
expo-image-loader: 6.0.0(expo@54.0.25)
|
||||
|
||||
expo-image@3.0.10(expo@54.0.25)(react-native-web@0.21.2(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(react-native@0.81.5(@babel/core@7.28.5)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0):
|
||||
|
|
@ -21603,7 +21613,7 @@ snapshots:
|
|||
|
||||
expo-localization@17.0.7(expo@54.0.25)(react@19.1.0):
|
||||
dependencies:
|
||||
expo: 54.0.25(@babel/core@7.28.5)(@expo/metro-runtime@6.1.2)(expo-router@6.0.15)(react-native@0.81.5(@babel/core@7.28.5)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0)
|
||||
expo: 54.0.25(@babel/core@7.28.5)(@expo/metro-runtime@6.1.2)(expo-router@6.0.15)(react-native@0.81.4(@babel/core@7.28.5)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0)
|
||||
react: 19.1.0
|
||||
rtl-detect: 1.1.2
|
||||
|
||||
|
|
@ -21865,7 +21875,7 @@ snapshots:
|
|||
|
||||
expo-secure-store@15.0.7(expo@54.0.25):
|
||||
dependencies:
|
||||
expo: 54.0.25(@babel/core@7.28.5)(@expo/metro-runtime@6.1.2)(expo-router@6.0.15)(react-native@0.81.5(@babel/core@7.28.5)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0)
|
||||
expo: 54.0.25(@babel/core@7.28.5)(@expo/metro-runtime@6.1.2)(expo-router@6.0.15)(react-native@0.81.4(@babel/core@7.28.5)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0)
|
||||
|
||||
expo-server@1.0.4: {}
|
||||
|
||||
|
|
@ -21876,7 +21886,7 @@ snapshots:
|
|||
expo-splash-screen@31.0.11(expo@54.0.25):
|
||||
dependencies:
|
||||
'@expo/prebuild-config': 54.0.6(expo@54.0.25)
|
||||
expo: 54.0.25(@babel/core@7.28.5)(@expo/metro-runtime@6.1.2)(expo-router@6.0.15)(react-native@0.81.5(@babel/core@7.28.5)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0)
|
||||
expo: 54.0.25(@babel/core@7.28.5)(@expo/metro-runtime@6.1.2)(expo-router@6.0.15)(react-native@0.81.4(@babel/core@7.28.5)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0)
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue