@mikesaintsg/core 0.0.4 → 0.0.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +37 -2
- package/dist/index.d.ts +476 -4
- package/dist/index.js +223 -199
- package/dist/index.js.map +1 -1
- package/package.json +7 -5
package/README.md
CHANGED
|
@@ -12,7 +12,8 @@
|
|
|
12
12
|
|
|
13
13
|
- ✅ **Shared Types** — Contracts used across multiple packages
|
|
14
14
|
- ✅ **Result Pattern** — Functional error handling (`ok`, `err`, `map`, `chain`)
|
|
15
|
-
- ✅ **Bridge
|
|
15
|
+
- ✅ **Bridge Classes** — Ready-to-use implementations for cross-package communication
|
|
16
|
+
- ✅ **Factory Functions** — Simple API for creating bridge instances
|
|
16
17
|
- ✅ **Adapter Interfaces** — Embedding, tool format, persistence, and policy adapters
|
|
17
18
|
- ✅ **Base Error Class** — `EcosystemError` for all package-specific errors
|
|
18
19
|
- ✅ **Content Hashing** — SHA-256 based deduplication support
|
|
@@ -141,6 +142,17 @@ const results = await bridge.execute([call1, call2, call3])
|
|
|
141
142
|
| `createFormDirtyGuard(options)` | Navigation guard for dirty forms |
|
|
142
143
|
| `createSessionPersistence(options)` | Session storage adapter |
|
|
143
144
|
|
|
145
|
+
### Bridge Classes
|
|
146
|
+
|
|
147
|
+
Implementation classes for cross-package bridges (also available via factory functions):
|
|
148
|
+
|
|
149
|
+
| Class | Factory | Description |
|
|
150
|
+
|----------------------|------------------------------|----------------------------------|
|
|
151
|
+
| `ToolCallBridge` | `createToolCallBridge()` | Executes tool calls via registry |
|
|
152
|
+
| `RetrievalTool` | `createRetrievalTool()` | Vectorstore search tool |
|
|
153
|
+
| `FormDirtyGuard` | `createFormDirtyGuard()` | Navigation guard for dirty forms |
|
|
154
|
+
| `SessionPersistence` | `createSessionPersistence()` | Session storage adapter |
|
|
155
|
+
|
|
144
156
|
### Error Handling
|
|
145
157
|
|
|
146
158
|
| Export | Description |
|
|
@@ -155,7 +167,7 @@ const results = await bridge.execute([call1, call2, call3])
|
|
|
155
167
|
| `Result<T, E>` | Success or failure union |
|
|
156
168
|
| `Ok<T>`, `Err<E>` | Result discriminants |
|
|
157
169
|
| `Unsubscribe` | Cleanup function type |
|
|
158
|
-
| `
|
|
170
|
+
| `Destroyable` | Interface for resources with cleanup |
|
|
159
171
|
| `SubscriptionToHook<T>` | Convert subscriptions to hooks |
|
|
160
172
|
| `Embedding` | Float32Array embedding vector |
|
|
161
173
|
| `ToolCall`, `ToolResult`, `ToolSchema` | Tool-related types |
|
|
@@ -286,6 +298,29 @@ const guard = createFormDirtyGuard({
|
|
|
286
298
|
router.beforeNavigate(guard)
|
|
287
299
|
```
|
|
288
300
|
|
|
301
|
+
### Using Bridge Classes Directly
|
|
302
|
+
|
|
303
|
+
```ts
|
|
304
|
+
import { ToolCallBridge, RetrievalTool, SessionPersistence } from '@mikesaintsg/core'
|
|
305
|
+
|
|
306
|
+
// Direct class instantiation (alternative to factory functions)
|
|
307
|
+
const bridge = new ToolCallBridge({
|
|
308
|
+
registry,
|
|
309
|
+
timeout: 30000,
|
|
310
|
+
})
|
|
311
|
+
|
|
312
|
+
const tool = new RetrievalTool({
|
|
313
|
+
vectorStore,
|
|
314
|
+
name: 'search',
|
|
315
|
+
description: 'Search documents',
|
|
316
|
+
})
|
|
317
|
+
|
|
318
|
+
const persistence = new SessionPersistence({
|
|
319
|
+
database,
|
|
320
|
+
storeName: 'sessions',
|
|
321
|
+
})
|
|
322
|
+
```
|
|
323
|
+
|
|
289
324
|
---
|
|
290
325
|
|
|
291
326
|
## Constants
|
package/dist/index.d.ts
CHANGED
|
@@ -3,6 +3,80 @@ export declare interface AbortableOptions {
|
|
|
3
3
|
readonly signal?: AbortSignal;
|
|
4
4
|
}
|
|
5
5
|
|
|
6
|
+
/** Activity metrics for a session */
|
|
7
|
+
export declare interface ActivityMetrics {
|
|
8
|
+
readonly activeTimeMs: number;
|
|
9
|
+
readonly idleTimeMs: number;
|
|
10
|
+
readonly awayTimeMs: number;
|
|
11
|
+
readonly interactionCount: number;
|
|
12
|
+
readonly lastInteractionAt: number;
|
|
13
|
+
readonly sessionStartedAt: number;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Activity tracker adapter interface.
|
|
18
|
+
*
|
|
19
|
+
* Tracks user engagement (active/idle/away) and dwell time per node.
|
|
20
|
+
* Implementations use browser APIs (visibility, pointer, keyboard events).
|
|
21
|
+
*/
|
|
22
|
+
export declare interface ActivityTrackerInterface extends ActivityTrackerSubscriptions, Destroyable {
|
|
23
|
+
/** Enter a node and start tracking dwell time */
|
|
24
|
+
enterNode(nodeId: string): void;
|
|
25
|
+
/** Exit current node and complete the dwell record */
|
|
26
|
+
exitNode(): DwellRecord | undefined;
|
|
27
|
+
/** Get current engagement state */
|
|
28
|
+
getEngagementState(): EngagementState;
|
|
29
|
+
/** Get current visibility state */
|
|
30
|
+
getVisibilityState(): VisibilityState;
|
|
31
|
+
/** Get current focus state */
|
|
32
|
+
getFocusState(): FocusState;
|
|
33
|
+
/** Get activity metrics summary */
|
|
34
|
+
getMetrics(): ActivityMetrics;
|
|
35
|
+
/** Get current node ID being tracked */
|
|
36
|
+
getCurrentNodeId(): string | undefined;
|
|
37
|
+
/** Get current incomplete dwell record */
|
|
38
|
+
getCurrentDwell(): PartialDwellRecord | undefined;
|
|
39
|
+
/** Get all completed dwell records */
|
|
40
|
+
getDwellHistory(): readonly DwellRecord[];
|
|
41
|
+
/** Get total active time across all dwells */
|
|
42
|
+
getTotalActiveTime(): number;
|
|
43
|
+
/** Get total idle time across all dwells */
|
|
44
|
+
getTotalIdleTime(): number;
|
|
45
|
+
/** Record an interaction (resets idle timer) */
|
|
46
|
+
recordInteraction(): void;
|
|
47
|
+
/** Reset all tracking state */
|
|
48
|
+
reset(): void;
|
|
49
|
+
/** Clear dwell history */
|
|
50
|
+
clearHistory(): void;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/** Activity tracker configuration */
|
|
54
|
+
export declare interface ActivityTrackerOptions extends SubscriptionToHook<ActivityTrackerSubscriptions> {
|
|
55
|
+
/** Idle threshold in milliseconds (default: 30000) */
|
|
56
|
+
readonly idleThreshold?: number;
|
|
57
|
+
/** Away threshold in milliseconds (default: 300000) */
|
|
58
|
+
readonly awayThreshold?: number;
|
|
59
|
+
/** Enable visibility-based tracking (default: true) */
|
|
60
|
+
readonly trackVisibility?: boolean;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/** Activity tracker subscriptions */
|
|
64
|
+
export declare interface ActivityTrackerSubscriptions {
|
|
65
|
+
/** Subscribe to engagement state changes */
|
|
66
|
+
onEngagementChange(callback: (state: EngagementState, nodeId: string) => void): Unsubscribe;
|
|
67
|
+
/** Subscribe to visibility state changes */
|
|
68
|
+
onVisibilityChange(callback: (state: VisibilityState) => void): Unsubscribe;
|
|
69
|
+
/** Subscribe to focus state changes */
|
|
70
|
+
onFocusChange(callback: (state: FocusState) => void): Unsubscribe;
|
|
71
|
+
/** Subscribe to idle warnings before state changes to away */
|
|
72
|
+
onIdleWarning(callback: (idleTimeMs: number) => void): Unsubscribe;
|
|
73
|
+
/** Subscribe to completed dwell records */
|
|
74
|
+
onDwellComplete(callback: (record: DwellRecord) => void): Unsubscribe;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/** Actor types for transition attribution */
|
|
78
|
+
export declare type Actor = 'user' | 'system' | 'automation';
|
|
79
|
+
|
|
6
80
|
/**
|
|
7
81
|
* Batch adapter interface.
|
|
8
82
|
* Controls batching behavior for bulk operations.
|
|
@@ -195,6 +269,17 @@ export declare function createSessionPersistence(options: SessionPersistenceOpti
|
|
|
195
269
|
*/
|
|
196
270
|
export declare function createToolCallBridge(options: ToolCallBridgeOptions): ToolCallBridgeInterface;
|
|
197
271
|
|
|
272
|
+
/** Decay algorithm types */
|
|
273
|
+
export declare type DecayAlgorithm = 'halflife' | 'ewma' | 'linear' | 'none';
|
|
274
|
+
|
|
275
|
+
/** Decay configuration */
|
|
276
|
+
export declare interface DecayConfig {
|
|
277
|
+
readonly algorithm: DecayAlgorithm;
|
|
278
|
+
readonly halfLifeMs?: number;
|
|
279
|
+
readonly decayFactor?: number;
|
|
280
|
+
readonly minWeight?: number;
|
|
281
|
+
}
|
|
282
|
+
|
|
198
283
|
/**
|
|
199
284
|
* Deduplication adapter interface.
|
|
200
285
|
* Determines how to handle duplicate frames based on content hash.
|
|
@@ -225,6 +310,20 @@ export declare interface Destroyable {
|
|
|
225
310
|
destroy(): void;
|
|
226
311
|
}
|
|
227
312
|
|
|
313
|
+
/** Detected intent from user input */
|
|
314
|
+
export declare type DetectedIntent = 'search' | 'question' | 'action' | 'navigation' | 'unclear';
|
|
315
|
+
|
|
316
|
+
/** Dwell record capturing time spent on a node */
|
|
317
|
+
export declare interface DwellRecord {
|
|
318
|
+
readonly nodeId: string;
|
|
319
|
+
readonly enterTime: number;
|
|
320
|
+
readonly exitTime: number;
|
|
321
|
+
readonly activeTime: number;
|
|
322
|
+
readonly idleTime: number;
|
|
323
|
+
readonly engagement: EngagementState;
|
|
324
|
+
readonly engagementScore: number;
|
|
325
|
+
}
|
|
326
|
+
|
|
228
327
|
/**
|
|
229
328
|
* @mikesaintsg/core
|
|
230
329
|
*
|
|
@@ -300,6 +399,9 @@ export declare interface EmbeddingModelMetadata {
|
|
|
300
399
|
readonly dimensions: number;
|
|
301
400
|
}
|
|
302
401
|
|
|
402
|
+
/** Engagement state for activity tracking */
|
|
403
|
+
export declare type EngagementState = 'active' | 'idle' | 'away' | 'unknown';
|
|
404
|
+
|
|
303
405
|
/** Failure result */
|
|
304
406
|
export declare interface Err<E> {
|
|
305
407
|
readonly ok: false;
|
|
@@ -326,9 +428,76 @@ export declare type ErrorCode<T extends {
|
|
|
326
428
|
readonly code: string;
|
|
327
429
|
}> = T['code'];
|
|
328
430
|
|
|
431
|
+
/** Filter options for querying events */
|
|
432
|
+
export declare interface EventFilter {
|
|
433
|
+
readonly sessionId?: string;
|
|
434
|
+
readonly actor?: Actor;
|
|
435
|
+
readonly nodeId?: string;
|
|
436
|
+
readonly from?: string;
|
|
437
|
+
readonly to?: string;
|
|
438
|
+
readonly startTime?: number;
|
|
439
|
+
readonly endTime?: number;
|
|
440
|
+
readonly namespace?: string;
|
|
441
|
+
readonly limit?: number;
|
|
442
|
+
readonly offset?: number;
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
/**
|
|
446
|
+
* Event store persistence adapter interface.
|
|
447
|
+
*
|
|
448
|
+
* Extends base persistence with event-specific storage operations.
|
|
449
|
+
* Persists transition events for audit trail and replay.
|
|
450
|
+
* Implementations: IndexedDB, OPFS, HTTP, in-memory.
|
|
451
|
+
*/
|
|
452
|
+
export declare interface EventStorePersistenceAdapterInterface extends PersistenceAdapterInterface {
|
|
453
|
+
/** Persist event(s) */
|
|
454
|
+
persist(event: TransitionEvent_2 | readonly TransitionEvent_2[]): Promise<void>;
|
|
455
|
+
/** Load events matching filter */
|
|
456
|
+
load(filter: EventFilter): Promise<readonly TransitionEvent_2[]>;
|
|
457
|
+
/** Get count of events matching filter */
|
|
458
|
+
getCount(filter?: EventFilter): Promise<number>;
|
|
459
|
+
/** Check if any events exist matching filter */
|
|
460
|
+
has(filter?: EventFilter): Promise<boolean>;
|
|
461
|
+
/**
|
|
462
|
+
* Clear events matching filter.
|
|
463
|
+
* Extends base clear() with optional filtering.
|
|
464
|
+
* Call without filter to clear all events.
|
|
465
|
+
*/
|
|
466
|
+
clear(filter?: EventFilter): Promise<void>;
|
|
467
|
+
/** Export all events for backup */
|
|
468
|
+
export(namespace?: string): Promise<readonly TransitionEvent_2[]>;
|
|
469
|
+
/** Import events (for recovery/migration) */
|
|
470
|
+
import(events: readonly TransitionEvent_2[]): Promise<void>;
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
/** Exported predictive graph for persistence */
|
|
474
|
+
export declare interface ExportedPredictiveGraph {
|
|
475
|
+
readonly version: number;
|
|
476
|
+
readonly exportedAt: number;
|
|
477
|
+
readonly modelId: string;
|
|
478
|
+
readonly namespace?: string;
|
|
479
|
+
readonly weights: readonly ExportedWeight[];
|
|
480
|
+
readonly decayConfig: DecayConfig;
|
|
481
|
+
readonly transitionCount: number;
|
|
482
|
+
readonly warmupThreshold?: number;
|
|
483
|
+
}
|
|
484
|
+
|
|
485
|
+
/** Exported weight entry */
|
|
486
|
+
export declare interface ExportedWeight {
|
|
487
|
+
readonly from: string;
|
|
488
|
+
readonly to: string;
|
|
489
|
+
readonly actor: Actor;
|
|
490
|
+
readonly weight: number;
|
|
491
|
+
readonly lastUpdated: number;
|
|
492
|
+
readonly updateCount: number;
|
|
493
|
+
}
|
|
494
|
+
|
|
329
495
|
/** Generation finish reason */
|
|
330
496
|
export declare type FinishReason = 'stop' | 'length' | 'tool_calls' | 'content_filter' | 'error';
|
|
331
497
|
|
|
498
|
+
/** Focus state for activity tracking */
|
|
499
|
+
export declare type FocusState = 'focused' | 'blurred';
|
|
500
|
+
|
|
332
501
|
/** Default form dirty guard message */
|
|
333
502
|
export declare const FORM_DIRTY_DEFAULT_MESSAGE = "You have unsaved changes. Are you sure you want to leave?";
|
|
334
503
|
|
|
@@ -341,6 +510,20 @@ export declare const FORM_DIRTY_DEFAULT_MESSAGE = "You have unsaved changes. Are
|
|
|
341
510
|
*/
|
|
342
511
|
export declare function formatScoredResult(result: ScoredResult): unknown;
|
|
343
512
|
|
|
513
|
+
/**
|
|
514
|
+
* Form dirty guard implementation.
|
|
515
|
+
* Returns a navigation guard function that prompts when form has unsaved changes.
|
|
516
|
+
*/
|
|
517
|
+
export declare class FormDirtyGuard<TFormData = unknown, TPage extends string = string> {
|
|
518
|
+
#private;
|
|
519
|
+
constructor(options: FormDirtyGuardOptions<TFormData, TPage>);
|
|
520
|
+
/**
|
|
521
|
+
* Get the navigation guard function.
|
|
522
|
+
* This is the function to register with a router.
|
|
523
|
+
*/
|
|
524
|
+
getGuard(): NavigationGuard<TPage>;
|
|
525
|
+
}
|
|
526
|
+
|
|
344
527
|
/** Form dirty guard options */
|
|
345
528
|
export declare interface FormDirtyGuardOptions<TFormData = unknown, TPage extends string = string> {
|
|
346
529
|
readonly form: FormMinimal<TFormData>;
|
|
@@ -416,6 +599,22 @@ export declare interface GenerationResult {
|
|
|
416
599
|
readonly aborted: boolean;
|
|
417
600
|
}
|
|
418
601
|
|
|
602
|
+
/** Intent detection result */
|
|
603
|
+
export declare interface IntentDetectionResult {
|
|
604
|
+
readonly original: string;
|
|
605
|
+
readonly intent: DetectedIntent;
|
|
606
|
+
readonly confidence: number;
|
|
607
|
+
readonly refinedPrompt: string;
|
|
608
|
+
readonly processingTimeMs: number;
|
|
609
|
+
readonly modelTier: ModelTier;
|
|
610
|
+
}
|
|
611
|
+
|
|
612
|
+
/** Intent detector interface */
|
|
613
|
+
export declare interface IntentDetectorInterface {
|
|
614
|
+
detect(input: string, options?: AbortableOptions): Promise<IntentDetectionResult>;
|
|
615
|
+
refine(input: string, intent: DetectedIntent, options?: AbortableOptions): Promise<string>;
|
|
616
|
+
}
|
|
617
|
+
|
|
419
618
|
/**
|
|
420
619
|
* Type guard for ecosystem errors.
|
|
421
620
|
*
|
|
@@ -599,6 +798,46 @@ export declare interface MinimalStoreAccess<T> {
|
|
|
599
798
|
clear(): Promise<void>;
|
|
600
799
|
}
|
|
601
800
|
|
|
801
|
+
/** Model info for orchestration */
|
|
802
|
+
export declare interface ModelInfo {
|
|
803
|
+
readonly tier: ModelTier;
|
|
804
|
+
readonly modelId: string;
|
|
805
|
+
readonly state: ModelLoadingState;
|
|
806
|
+
readonly loadProgress?: number;
|
|
807
|
+
readonly sizeBytes?: number;
|
|
808
|
+
readonly loadedAt?: number;
|
|
809
|
+
}
|
|
810
|
+
|
|
811
|
+
/** Model loading state */
|
|
812
|
+
export declare type ModelLoadingState = 'idle' | 'loading' | 'ready' | 'error';
|
|
813
|
+
|
|
814
|
+
/** Model orchestrator interface */
|
|
815
|
+
export declare interface ModelOrchestratorInterface extends ModelOrchestratorSubscriptions, Destroyable {
|
|
816
|
+
getModelInfo(tier: ModelTier): ModelInfo | undefined;
|
|
817
|
+
isReady(tier: ModelTier): boolean;
|
|
818
|
+
getReadyTiers(): readonly ModelTier[];
|
|
819
|
+
getActiveTier(): ModelTier | undefined;
|
|
820
|
+
getBestAvailableTier(): ModelTier | undefined;
|
|
821
|
+
preload(tier: ModelTier): Promise<void>;
|
|
822
|
+
preloadAll(): Promise<void>;
|
|
823
|
+
estimateComplexity(prompt: string): number;
|
|
824
|
+
selectTier(complexity: number): ModelTier;
|
|
825
|
+
generate(prompt: string, options?: OrchestratorGenerateOptions): Promise<OrchestratorGenerateResult>;
|
|
826
|
+
}
|
|
827
|
+
|
|
828
|
+
/** Model orchestrator subscriptions */
|
|
829
|
+
export declare interface ModelOrchestratorSubscriptions {
|
|
830
|
+
onModelStateChange(callback: (tier: ModelTier, state: ModelLoadingState) => void): Unsubscribe;
|
|
831
|
+
onModelSwitch(callback: (from: ModelTier, to: ModelTier, reason: string) => void): Unsubscribe;
|
|
832
|
+
onLoadProgress(callback: (tier: ModelTier, progress: number) => void): Unsubscribe;
|
|
833
|
+
}
|
|
834
|
+
|
|
835
|
+
/** Model selection strategy */
|
|
836
|
+
export declare type ModelSelectionStrategy = 'auto' | 'local-only' | 'api-only' | 'local-first';
|
|
837
|
+
|
|
838
|
+
/** Model tier for progressive loading */
|
|
839
|
+
export declare type ModelTier = 'fast' | 'balanced' | 'powerful';
|
|
840
|
+
|
|
602
841
|
/**
|
|
603
842
|
* Navigation guard function type.
|
|
604
843
|
* Returns true to allow navigation, false to block.
|
|
@@ -626,6 +865,27 @@ export declare interface Ok<T> {
|
|
|
626
865
|
*/
|
|
627
866
|
export declare function ok<T>(value: T): Ok<T>;
|
|
628
867
|
|
|
868
|
+
/** Model orchestrator generate options */
|
|
869
|
+
export declare interface OrchestratorGenerateOptions extends AbortableOptions {
|
|
870
|
+
readonly forceTier?: ModelTier;
|
|
871
|
+
readonly system?: string;
|
|
872
|
+
readonly tools?: readonly ToolSchema[];
|
|
873
|
+
readonly maxTokens?: number;
|
|
874
|
+
readonly temperature?: number;
|
|
875
|
+
}
|
|
876
|
+
|
|
877
|
+
/** Model orchestrator generate result */
|
|
878
|
+
export declare interface OrchestratorGenerateResult {
|
|
879
|
+
readonly text: string;
|
|
880
|
+
readonly tier: ModelTier;
|
|
881
|
+
readonly modelId: string;
|
|
882
|
+
readonly latencyMs: number;
|
|
883
|
+
readonly tokenCount?: number;
|
|
884
|
+
readonly toolCalls?: readonly ToolCall[];
|
|
885
|
+
readonly escalated?: boolean;
|
|
886
|
+
readonly escalationReason?: string;
|
|
887
|
+
}
|
|
888
|
+
|
|
629
889
|
/**
|
|
630
890
|
* Generic error data interface for package-specific errors.
|
|
631
891
|
* Packages extend this to define their error structure.
|
|
@@ -643,6 +903,39 @@ export declare interface PackageErrorData<TCode extends string> {
|
|
|
643
903
|
readonly cause?: Error;
|
|
644
904
|
}
|
|
645
905
|
|
|
906
|
+
/** Partial dwell record for in-progress tracking */
|
|
907
|
+
export declare interface PartialDwellRecord {
|
|
908
|
+
readonly nodeId: string;
|
|
909
|
+
readonly enterTime: number;
|
|
910
|
+
readonly activeTime: number;
|
|
911
|
+
readonly idleTime: number;
|
|
912
|
+
readonly engagement: EngagementState;
|
|
913
|
+
}
|
|
914
|
+
|
|
915
|
+
/**
|
|
916
|
+
* Base persistence adapter interface.
|
|
917
|
+
*
|
|
918
|
+
* Defines common operations shared by all persistence adapters.
|
|
919
|
+
* Specialized persistence adapters extend this interface with
|
|
920
|
+
* domain-specific load, save, and query methods.
|
|
921
|
+
*
|
|
922
|
+
* All persistence adapters share:
|
|
923
|
+
* - Availability checking for backend validation
|
|
924
|
+
* - Clear operation for removing all persisted data
|
|
925
|
+
*/
|
|
926
|
+
export declare interface PersistenceAdapterInterface {
|
|
927
|
+
/**
|
|
928
|
+
* Check if the persistence backend is available.
|
|
929
|
+
* Use this before operations to handle unavailable storage gracefully.
|
|
930
|
+
*/
|
|
931
|
+
isAvailable(): Promise<boolean>;
|
|
932
|
+
/**
|
|
933
|
+
* Clear all persisted data.
|
|
934
|
+
* Use with caution — this removes all data managed by this adapter.
|
|
935
|
+
*/
|
|
936
|
+
clear(): Promise<void>;
|
|
937
|
+
}
|
|
938
|
+
|
|
646
939
|
/**
|
|
647
940
|
* Priority adapter interface.
|
|
648
941
|
* Provides priority weights and comparison logic.
|
|
@@ -735,6 +1028,17 @@ export declare const RETRIEVAL_DEFAULT_LIMIT = 10;
|
|
|
735
1028
|
/** Maximum retrieval limit for retrieval tool */
|
|
736
1029
|
export declare const RETRIEVAL_MAX_LIMIT = 100;
|
|
737
1030
|
|
|
1031
|
+
/**
|
|
1032
|
+
* Retrieval tool implementation.
|
|
1033
|
+
* Provides a tool schema and handler for vectorstore search.
|
|
1034
|
+
*/
|
|
1035
|
+
export declare class RetrievalTool<TMetadata = unknown> implements RetrievalToolInterface {
|
|
1036
|
+
#private;
|
|
1037
|
+
readonly schema: ToolSchema;
|
|
1038
|
+
constructor(options: RetrievalToolOptions<TMetadata>);
|
|
1039
|
+
handler: (args: Readonly<Record<string, unknown>>) => Promise<readonly unknown[]>;
|
|
1040
|
+
}
|
|
1041
|
+
|
|
738
1042
|
/** Retrieval tool created by factory */
|
|
739
1043
|
export declare interface RetrievalToolInterface {
|
|
740
1044
|
readonly schema: ToolSchema;
|
|
@@ -811,15 +1115,38 @@ export declare interface SerializedSessionMetadata {
|
|
|
811
1115
|
readonly system?: string;
|
|
812
1116
|
}
|
|
813
1117
|
|
|
1118
|
+
/**
|
|
1119
|
+
* Session persistence implementation.
|
|
1120
|
+
* Stores and retrieves inference sessions from a database store.
|
|
1121
|
+
*/
|
|
1122
|
+
export declare class SessionPersistence implements SessionPersistenceInterface {
|
|
1123
|
+
#private;
|
|
1124
|
+
constructor(options: SessionPersistenceOptions);
|
|
1125
|
+
isAvailable(): Promise<boolean>;
|
|
1126
|
+
clear(): Promise<void>;
|
|
1127
|
+
save(id: string, session: SerializableSession): Promise<void>;
|
|
1128
|
+
load(id: string): Promise<SerializedSession | undefined>;
|
|
1129
|
+
delete(id: string): Promise<void>;
|
|
1130
|
+
list(): Promise<readonly string[]>;
|
|
1131
|
+
prune(maxAgeMs: number): Promise<number>;
|
|
1132
|
+
}
|
|
1133
|
+
|
|
814
1134
|
/**
|
|
815
1135
|
* Session persistence interface.
|
|
1136
|
+
*
|
|
1137
|
+
* Extends base persistence with session-specific storage operations.
|
|
816
1138
|
* Connects inference sessions to IndexedDB storage.
|
|
817
1139
|
*/
|
|
818
|
-
export declare interface SessionPersistenceInterface {
|
|
1140
|
+
export declare interface SessionPersistenceInterface extends PersistenceAdapterInterface {
|
|
1141
|
+
/** Save a session by ID */
|
|
819
1142
|
save(id: string, session: SerializableSession): Promise<void>;
|
|
1143
|
+
/** Load a session by ID */
|
|
820
1144
|
load(id: string): Promise<SerializedSession | undefined>;
|
|
1145
|
+
/** Delete a session by ID */
|
|
821
1146
|
delete(id: string): Promise<void>;
|
|
1147
|
+
/** List all session IDs */
|
|
822
1148
|
list(): Promise<readonly string[]>;
|
|
1149
|
+
/** Prune sessions older than maxAgeMs, returns count pruned */
|
|
823
1150
|
prune(maxAgeMs: number): Promise<number>;
|
|
824
1151
|
}
|
|
825
1152
|
|
|
@@ -853,6 +1180,71 @@ export declare interface SimilarityAdapterInterface {
|
|
|
853
1180
|
readonly name: string;
|
|
854
1181
|
}
|
|
855
1182
|
|
|
1183
|
+
/**
|
|
1184
|
+
* SSE (Server-Sent Events) event structure.
|
|
1185
|
+
* Represents a single event from an SSE stream.
|
|
1186
|
+
*/
|
|
1187
|
+
export declare interface SSEEvent {
|
|
1188
|
+
/** Event type (e.g., 'message', 'error') */
|
|
1189
|
+
readonly event?: string;
|
|
1190
|
+
/** Event data payload */
|
|
1191
|
+
readonly data: string;
|
|
1192
|
+
/** Event ID for resumption */
|
|
1193
|
+
readonly id?: string;
|
|
1194
|
+
/** Retry interval in milliseconds */
|
|
1195
|
+
readonly retry?: number;
|
|
1196
|
+
}
|
|
1197
|
+
|
|
1198
|
+
/**
|
|
1199
|
+
* SSE parser adapter interface.
|
|
1200
|
+
* Factory for creating SSE parser instances.
|
|
1201
|
+
*
|
|
1202
|
+
* **Used by server-side providers:**
|
|
1203
|
+
* - OpenAI (chat completions streaming)
|
|
1204
|
+
* - Anthropic (messages streaming)
|
|
1205
|
+
* - Other API-based providers using SSE format
|
|
1206
|
+
*
|
|
1207
|
+
* **NOT used by local providers:**
|
|
1208
|
+
* - Ollama (uses NDJSON, not SSE)
|
|
1209
|
+
* - node-llama-cpp (direct token emission)
|
|
1210
|
+
* - HuggingFace (TextStreamer callback)
|
|
1211
|
+
*
|
|
1212
|
+
* Implementations are in @mikesaintsg/adapters.
|
|
1213
|
+
*/
|
|
1214
|
+
export declare interface SSEParserAdapterInterface {
|
|
1215
|
+
/** Create a new parser instance with the given options */
|
|
1216
|
+
createParser(options: SSEParserOptions): SSEParserInterface;
|
|
1217
|
+
}
|
|
1218
|
+
|
|
1219
|
+
/**
|
|
1220
|
+
* SSE parser interface.
|
|
1221
|
+
* Stateful parser that handles chunked SSE data.
|
|
1222
|
+
*
|
|
1223
|
+
* SSE is the streaming format used by server-side LLM providers
|
|
1224
|
+
* (OpenAI, Anthropic, and other API-based services).
|
|
1225
|
+
*/
|
|
1226
|
+
export declare interface SSEParserInterface {
|
|
1227
|
+
/** Feed data chunk to parser */
|
|
1228
|
+
feed(chunk: string): void;
|
|
1229
|
+
/** Signal end of stream */
|
|
1230
|
+
end(): void;
|
|
1231
|
+
/** Reset parser state */
|
|
1232
|
+
reset(): void;
|
|
1233
|
+
}
|
|
1234
|
+
|
|
1235
|
+
/**
|
|
1236
|
+
* SSE parser options.
|
|
1237
|
+
* Callbacks for handling SSE stream events.
|
|
1238
|
+
*/
|
|
1239
|
+
export declare interface SSEParserOptions {
|
|
1240
|
+
/** Called for each parsed event */
|
|
1241
|
+
readonly onEvent: (event: SSEEvent) => void;
|
|
1242
|
+
/** Called on parse error */
|
|
1243
|
+
readonly onError?: (error: Error) => void;
|
|
1244
|
+
/** Called when stream ends */
|
|
1245
|
+
readonly onEnd?: () => void;
|
|
1246
|
+
}
|
|
1247
|
+
|
|
856
1248
|
/** Storage information (quota and usage) */
|
|
857
1249
|
export declare interface StorageInfo {
|
|
858
1250
|
readonly usage: number;
|
|
@@ -872,6 +1264,30 @@ export declare interface StoredDocument {
|
|
|
872
1264
|
readonly updatedAt?: number;
|
|
873
1265
|
}
|
|
874
1266
|
|
|
1267
|
+
/**
|
|
1268
|
+
* Streamer adapter interface for token emission.
|
|
1269
|
+
*
|
|
1270
|
+
* Streamers are the internal mechanism for emitting tokens during generation.
|
|
1271
|
+
* They bridge the gap between provider-specific streaming (SSE, local generation)
|
|
1272
|
+
* and the consumer-facing StreamHandleInterface.
|
|
1273
|
+
*
|
|
1274
|
+
* **Usage by provider type:**
|
|
1275
|
+
* - **Server-side providers** (OpenAI, Anthropic): SSE parser feeds tokens to streamer
|
|
1276
|
+
* - **Local providers** (Ollama, node-llama-cpp, HuggingFace): Direct token emission to streamer
|
|
1277
|
+
*
|
|
1278
|
+
* Implementations are in @mikesaintsg/adapters.
|
|
1279
|
+
*/
|
|
1280
|
+
export declare interface StreamerAdapterInterface {
|
|
1281
|
+
/** Subscribe to token events */
|
|
1282
|
+
onToken(callback: (token: string) => void): Unsubscribe;
|
|
1283
|
+
/** Emit a token to all subscribers */
|
|
1284
|
+
emit(token: string): void;
|
|
1285
|
+
/** Signal end of streaming */
|
|
1286
|
+
end(): void;
|
|
1287
|
+
/** Signal an error during streaming */
|
|
1288
|
+
error?(err: Error): void;
|
|
1289
|
+
}
|
|
1290
|
+
|
|
875
1291
|
/**
|
|
876
1292
|
* Stream handle interface - async iteration over tokens.
|
|
877
1293
|
* Provides streaming access to generation with abort control.
|
|
@@ -957,6 +1373,18 @@ export declare interface ToolCall {
|
|
|
957
1373
|
readonly arguments: Readonly<Record<string, unknown>>;
|
|
958
1374
|
}
|
|
959
1375
|
|
|
1376
|
+
/**
|
|
1377
|
+
* Tool call bridge implementation.
|
|
1378
|
+
* Executes tool calls against a tool registry with timeout and lifecycle hooks.
|
|
1379
|
+
*/
|
|
1380
|
+
export declare class ToolCallBridge implements ToolCallBridgeInterface {
|
|
1381
|
+
#private;
|
|
1382
|
+
constructor(options: ToolCallBridgeOptions);
|
|
1383
|
+
execute(toolCalls: ToolCall): Promise<ToolResult>;
|
|
1384
|
+
execute(toolCalls: readonly ToolCall[]): Promise<readonly ToolResult[]>;
|
|
1385
|
+
hasTool(name: string): boolean;
|
|
1386
|
+
}
|
|
1387
|
+
|
|
960
1388
|
/**
|
|
961
1389
|
* Tool call bridge interface.
|
|
962
1390
|
* Connects inference tool calls to contextprotocol tool registry.
|
|
@@ -1037,6 +1465,22 @@ export declare interface ToolSchema {
|
|
|
1037
1465
|
readonly returns?: JSONSchema7;
|
|
1038
1466
|
}
|
|
1039
1467
|
|
|
1468
|
+
/** Transition event for audit trail */
|
|
1469
|
+
declare interface TransitionEvent_2 {
|
|
1470
|
+
readonly id: string;
|
|
1471
|
+
readonly timestamp: number;
|
|
1472
|
+
readonly sessionId: string;
|
|
1473
|
+
readonly actor: Actor;
|
|
1474
|
+
readonly from: string;
|
|
1475
|
+
readonly to: string;
|
|
1476
|
+
readonly path: string;
|
|
1477
|
+
readonly dwell?: DwellRecord;
|
|
1478
|
+
readonly engagement: EngagementState;
|
|
1479
|
+
readonly namespace?: string;
|
|
1480
|
+
readonly metadata?: Readonly<Record<string, unknown>>;
|
|
1481
|
+
}
|
|
1482
|
+
export { TransitionEvent_2 as TransitionEvent }
|
|
1483
|
+
|
|
1040
1484
|
/**
|
|
1041
1485
|
* Truncation adapter interface.
|
|
1042
1486
|
* Determines which frames to remove when budget is exceeded.
|
|
@@ -1130,16 +1574,21 @@ export declare interface VectorStoreMinimal<TMetadata = unknown> {
|
|
|
1130
1574
|
|
|
1131
1575
|
/**
|
|
1132
1576
|
* VectorStore persistence adapter interface.
|
|
1577
|
+
*
|
|
1578
|
+
* Extends base persistence with document and metadata storage.
|
|
1133
1579
|
* Implemented by IndexedDB, OPFS, and HTTP adapters.
|
|
1134
1580
|
*/
|
|
1135
|
-
export declare interface VectorStorePersistenceAdapterInterface {
|
|
1581
|
+
export declare interface VectorStorePersistenceAdapterInterface extends PersistenceAdapterInterface {
|
|
1582
|
+
/** Load all stored documents */
|
|
1136
1583
|
load(): Promise<readonly StoredDocument[]>;
|
|
1584
|
+
/** Load store metadata (model info, counts) */
|
|
1137
1585
|
loadMetadata(): Promise<VectorStoreMetadata | undefined>;
|
|
1586
|
+
/** Save document(s) to storage */
|
|
1138
1587
|
save(docs: StoredDocument | readonly StoredDocument[]): Promise<void>;
|
|
1588
|
+
/** Save store metadata */
|
|
1139
1589
|
saveMetadata(metadata: VectorStoreMetadata): Promise<void>;
|
|
1590
|
+
/** Remove document(s) by ID(s) */
|
|
1140
1591
|
remove(ids: string | readonly string[]): Promise<void>;
|
|
1141
|
-
clear(): Promise<void>;
|
|
1142
|
-
isAvailable(): Promise<boolean>;
|
|
1143
1592
|
}
|
|
1144
1593
|
|
|
1145
1594
|
/** VectorStore search options */
|
|
@@ -1148,4 +1597,27 @@ export declare interface VectorStoreSearchOptions<TMetadata = unknown> {
|
|
|
1148
1597
|
readonly filter?: TMetadata;
|
|
1149
1598
|
}
|
|
1150
1599
|
|
|
1600
|
+
/** Visibility state for activity tracking */
|
|
1601
|
+
export declare type VisibilityState = 'visible' | 'hidden' | 'prerender';
|
|
1602
|
+
|
|
1603
|
+
/**
|
|
1604
|
+
* Weight persistence adapter interface.
|
|
1605
|
+
*
|
|
1606
|
+
* Extends base persistence with weight-specific storage operations.
|
|
1607
|
+
* Persists predictive graph weights for cold-start optimization.
|
|
1608
|
+
* Implementations: IndexedDB, OPFS, HTTP, in-memory.
|
|
1609
|
+
*/
|
|
1610
|
+
export declare interface WeightPersistenceAdapterInterface extends PersistenceAdapterInterface {
|
|
1611
|
+
/** Save weights snapshot */
|
|
1612
|
+
save(weights: ExportedPredictiveGraph): Promise<void>;
|
|
1613
|
+
/** Load weights by model ID */
|
|
1614
|
+
load(modelId: string): Promise<ExportedPredictiveGraph | undefined>;
|
|
1615
|
+
/** Check if weights exist for model */
|
|
1616
|
+
has(modelId: string): Promise<boolean>;
|
|
1617
|
+
/** Delete weights for model */
|
|
1618
|
+
delete(modelId: string): Promise<void>;
|
|
1619
|
+
/** List all stored model IDs */
|
|
1620
|
+
list(): Promise<readonly string[]>;
|
|
1621
|
+
}
|
|
1622
|
+
|
|
1151
1623
|
export { }
|
package/dist/index.js
CHANGED
|
@@ -1,237 +1,261 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
constructor(t, s) {
|
|
5
|
-
super(t), this.name = this.constructor.name, this.cause = s;
|
|
6
|
-
}
|
|
1
|
+
const A = 3e4, x = 10, I = 100, h = "You have unsaved changes. Are you sure you want to leave?";
|
|
2
|
+
function m(r) {
|
|
3
|
+
return { ok: !0, value: r };
|
|
7
4
|
}
|
|
8
|
-
function
|
|
9
|
-
return
|
|
5
|
+
function d(r) {
|
|
6
|
+
return { ok: !1, error: r };
|
|
10
7
|
}
|
|
11
|
-
function S(
|
|
12
|
-
return
|
|
8
|
+
function S(r) {
|
|
9
|
+
return r.ok;
|
|
13
10
|
}
|
|
14
|
-
function
|
|
15
|
-
return
|
|
11
|
+
function L(r) {
|
|
12
|
+
return !r.ok;
|
|
16
13
|
}
|
|
17
|
-
function
|
|
18
|
-
return
|
|
14
|
+
function R(r, e) {
|
|
15
|
+
return r.ok ? r.value : e;
|
|
19
16
|
}
|
|
20
|
-
function
|
|
21
|
-
|
|
17
|
+
function F(r) {
|
|
18
|
+
if (r.ok)
|
|
19
|
+
return r.value;
|
|
20
|
+
throw r.error instanceof Error ? r.error : new Error(String(r.error));
|
|
22
21
|
}
|
|
23
|
-
function
|
|
24
|
-
return
|
|
22
|
+
function M(r, e) {
|
|
23
|
+
return r.ok ? m(e(r.value)) : r;
|
|
25
24
|
}
|
|
26
|
-
function
|
|
27
|
-
|
|
28
|
-
return e.value;
|
|
29
|
-
throw e.error instanceof Error ? e.error : new Error(String(e.error));
|
|
25
|
+
function _(r, e) {
|
|
26
|
+
return r.ok ? r : d(e(r.error));
|
|
30
27
|
}
|
|
31
|
-
function
|
|
32
|
-
return
|
|
28
|
+
function D(r, e) {
|
|
29
|
+
return r.ok ? e(r.value) : r;
|
|
33
30
|
}
|
|
34
|
-
function
|
|
35
|
-
|
|
31
|
+
async function k(r) {
|
|
32
|
+
const t = new TextEncoder().encode(r), n = await crypto.subtle.digest("SHA-256", t);
|
|
33
|
+
return Array.from(new Uint8Array(n)).map((s) => s.toString(16).padStart(2, "0")).join("");
|
|
36
34
|
}
|
|
37
|
-
function
|
|
38
|
-
return
|
|
35
|
+
function f(r) {
|
|
36
|
+
return typeof r == "object" && r !== null && "id" in r && "name" in r && "arguments" in r;
|
|
39
37
|
}
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
return Array.from(new Uint8Array(a)).map((o) => o.toString(16).padStart(2, "0")).join("");
|
|
38
|
+
function E(r, e, t, n) {
|
|
39
|
+
return t.includes(r) ? !0 : n !== void 0 && !n.includes(e);
|
|
43
40
|
}
|
|
44
|
-
function
|
|
45
|
-
return typeof e == "object" && e !== null && "id" in e && "name" in e && "arguments" in e;
|
|
46
|
-
}
|
|
47
|
-
function l(e, t, s, a) {
|
|
48
|
-
return s.includes(e) ? !0 : a !== void 0 && !a.includes(t);
|
|
49
|
-
}
|
|
50
|
-
function M(e) {
|
|
41
|
+
function y(r) {
|
|
51
42
|
return {
|
|
52
|
-
content:
|
|
53
|
-
score:
|
|
54
|
-
metadata:
|
|
43
|
+
content: r.content,
|
|
44
|
+
score: r.score,
|
|
45
|
+
metadata: r.metadata
|
|
55
46
|
};
|
|
56
47
|
}
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
onAfterExecute:
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
|
|
48
|
+
class l {
|
|
49
|
+
#e;
|
|
50
|
+
#r;
|
|
51
|
+
#t;
|
|
52
|
+
#n;
|
|
53
|
+
#s;
|
|
54
|
+
constructor(e) {
|
|
55
|
+
this.#e = e.registry, this.#r = e.timeout ?? 3e4, this.#t = "onError" in e ? e.onError : void 0, this.#n = "onBeforeExecute" in e ? e.onBeforeExecute : void 0, this.#s = "onAfterExecute" in e ? e.onAfterExecute : void 0;
|
|
56
|
+
}
|
|
57
|
+
execute(e) {
|
|
58
|
+
return f(e) ? this.#i(e) : Promise.all(
|
|
59
|
+
e.map((t) => this.#i(t))
|
|
60
|
+
);
|
|
61
|
+
}
|
|
62
|
+
hasTool(e) {
|
|
63
|
+
return this.#e.has(e);
|
|
64
|
+
}
|
|
65
|
+
async #i(e) {
|
|
66
|
+
if (!this.#e.has(e.name))
|
|
68
67
|
return {
|
|
69
|
-
callId:
|
|
70
|
-
name:
|
|
68
|
+
callId: e.id,
|
|
69
|
+
name: e.name,
|
|
71
70
|
success: !1,
|
|
72
|
-
error: `Tool not found: ${
|
|
71
|
+
error: `Tool not found: ${e.name}`
|
|
73
72
|
};
|
|
74
|
-
|
|
73
|
+
this.#n?.(e);
|
|
75
74
|
try {
|
|
76
|
-
const
|
|
75
|
+
const t = new Promise((i, s) => {
|
|
77
76
|
setTimeout(() => {
|
|
78
|
-
|
|
79
|
-
},
|
|
80
|
-
}),
|
|
81
|
-
|
|
82
|
-
|
|
77
|
+
s(new Error(`Tool execution timed out after ${this.#r}ms`));
|
|
78
|
+
}, this.#r);
|
|
79
|
+
}), n = await Promise.race([
|
|
80
|
+
this.#e.execute(e.name, e.arguments),
|
|
81
|
+
t
|
|
83
82
|
]);
|
|
84
|
-
return
|
|
85
|
-
callId:
|
|
86
|
-
name:
|
|
83
|
+
return this.#s?.(e, n), {
|
|
84
|
+
callId: e.id,
|
|
85
|
+
name: e.name,
|
|
87
86
|
success: !0,
|
|
88
|
-
value:
|
|
87
|
+
value: n
|
|
89
88
|
};
|
|
90
|
-
} catch (
|
|
91
|
-
|
|
92
|
-
const
|
|
89
|
+
} catch (t) {
|
|
90
|
+
this.#t?.(t, e);
|
|
91
|
+
const n = t instanceof Error ? t.message : String(t);
|
|
93
92
|
return {
|
|
94
|
-
callId:
|
|
95
|
-
name:
|
|
93
|
+
callId: e.id,
|
|
94
|
+
name: e.name,
|
|
96
95
|
success: !1,
|
|
97
|
-
error:
|
|
96
|
+
error: n
|
|
98
97
|
};
|
|
99
98
|
}
|
|
100
99
|
}
|
|
101
|
-
return {
|
|
102
|
-
execute(r) {
|
|
103
|
-
return k(r) ? u(r) : Promise.all(
|
|
104
|
-
r.map((n) => u(n))
|
|
105
|
-
);
|
|
106
|
-
},
|
|
107
|
-
hasTool(r) {
|
|
108
|
-
return t.has(r);
|
|
109
|
-
}
|
|
110
|
-
};
|
|
111
100
|
}
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
101
|
+
class T {
|
|
102
|
+
schema;
|
|
103
|
+
#e;
|
|
104
|
+
#r;
|
|
105
|
+
#t;
|
|
106
|
+
#n;
|
|
107
|
+
#s;
|
|
108
|
+
#i;
|
|
109
|
+
constructor(e) {
|
|
110
|
+
this.#e = e.vectorStore, this.#r = e.defaultLimit ?? 10, this.#t = e.maxLimit ?? 100, this.#n = "scoreThreshold" in e ? e.scoreThreshold : void 0, this.#s = e.formatResult ?? y, this.#i = "buildFilter" in e ? e.buildFilter : void 0;
|
|
111
|
+
const t = {
|
|
112
|
+
type: "object",
|
|
113
|
+
properties: {
|
|
114
|
+
query: {
|
|
115
|
+
type: "string",
|
|
116
|
+
description: "The search query to find relevant documents"
|
|
117
|
+
},
|
|
118
|
+
limit: {
|
|
119
|
+
type: "integer",
|
|
120
|
+
description: `Maximum number of results to return (default: ${this.#r}, max: ${this.#t})`,
|
|
121
|
+
minimum: 1,
|
|
122
|
+
maximum: this.#t,
|
|
123
|
+
default: this.#r
|
|
124
|
+
},
|
|
125
|
+
...e.extendParameters
|
|
136
126
|
},
|
|
137
|
-
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
}
|
|
145
|
-
async
|
|
146
|
-
const
|
|
147
|
-
if (typeof
|
|
127
|
+
required: ["query"]
|
|
128
|
+
};
|
|
129
|
+
this.schema = {
|
|
130
|
+
name: e.name,
|
|
131
|
+
description: e.description,
|
|
132
|
+
parameters: t
|
|
133
|
+
};
|
|
134
|
+
}
|
|
135
|
+
handler = async (e) => {
|
|
136
|
+
const t = e.query;
|
|
137
|
+
if (typeof t != "string" || t.length === 0)
|
|
148
138
|
return [];
|
|
149
|
-
const
|
|
150
|
-
let
|
|
151
|
-
typeof
|
|
152
|
-
const
|
|
153
|
-
let
|
|
154
|
-
return
|
|
155
|
-
}
|
|
156
|
-
return { schema: m, handler: d };
|
|
157
|
-
}
|
|
158
|
-
function N(e) {
|
|
159
|
-
const {
|
|
160
|
-
form: t,
|
|
161
|
-
confirmFn: s,
|
|
162
|
-
message: a = D,
|
|
163
|
-
excludePages: c = [],
|
|
164
|
-
onlyFromPages: o
|
|
165
|
-
} = e;
|
|
166
|
-
return async function(r, n) {
|
|
167
|
-
return l(r, n, c, o) || !t.isDirty() ? !0 : Promise.resolve(s(a));
|
|
139
|
+
const n = e.limit;
|
|
140
|
+
let i = this.#r;
|
|
141
|
+
typeof n == "number" && Number.isInteger(n) && (i = Math.min(Math.max(1, n), this.#t));
|
|
142
|
+
const s = this.#i?.(e), a = s !== void 0 ? { limit: i, filter: s } : { limit: i }, o = await this.#e.search(t, a);
|
|
143
|
+
let c = o;
|
|
144
|
+
return this.#n !== void 0 && (c = o.filter((u) => u.score >= this.#n)), c.map(this.#s);
|
|
168
145
|
};
|
|
169
146
|
}
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
async load(r) {
|
|
199
|
-
return o.get(r);
|
|
200
|
-
},
|
|
201
|
-
async delete(r) {
|
|
202
|
-
await o.remove(r);
|
|
203
|
-
},
|
|
204
|
-
async list() {
|
|
205
|
-
return (await o.all()).map((n) => n.id);
|
|
206
|
-
},
|
|
207
|
-
async prune(r) {
|
|
208
|
-
return u(r);
|
|
147
|
+
class g {
|
|
148
|
+
#e;
|
|
149
|
+
#r;
|
|
150
|
+
#t;
|
|
151
|
+
#n;
|
|
152
|
+
#s;
|
|
153
|
+
constructor(e) {
|
|
154
|
+
this.#e = e.form, this.#r = e.confirmFn, this.#t = e.message ?? h, this.#n = e.excludePages ?? [], this.#s = "onlyFromPages" in e ? e.onlyFromPages : void 0;
|
|
155
|
+
}
|
|
156
|
+
/**
|
|
157
|
+
* Get the navigation guard function.
|
|
158
|
+
* This is the function to register with a router.
|
|
159
|
+
*/
|
|
160
|
+
getGuard() {
|
|
161
|
+
return async (e, t) => E(e, t, this.#n, this.#s) || !this.#e.isDirty() ? !0 : Promise.resolve(this.#r(this.#t));
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
class w {
|
|
165
|
+
#e;
|
|
166
|
+
#r;
|
|
167
|
+
constructor(e) {
|
|
168
|
+
this.#e = e.database.store(e.storeName), this.#r = "onSaveError" in e ? e.onSaveError : void 0, e.autoprune !== void 0 && e.autoprune > 0 && this.prune(e.autoprune);
|
|
169
|
+
}
|
|
170
|
+
async isAvailable() {
|
|
171
|
+
try {
|
|
172
|
+
return await this.#e.all(), !0;
|
|
173
|
+
} catch {
|
|
174
|
+
return !1;
|
|
209
175
|
}
|
|
210
|
-
}
|
|
176
|
+
}
|
|
177
|
+
async clear() {
|
|
178
|
+
await this.#e.clear();
|
|
179
|
+
}
|
|
180
|
+
async save(e, t) {
|
|
181
|
+
try {
|
|
182
|
+
const n = {
|
|
183
|
+
id: e,
|
|
184
|
+
messages: [...t.getMessages()],
|
|
185
|
+
metadata: t.getMetadata(),
|
|
186
|
+
updatedAt: Date.now()
|
|
187
|
+
};
|
|
188
|
+
await this.#e.set(n, e);
|
|
189
|
+
} catch (n) {
|
|
190
|
+
throw this.#r?.(n, e), n;
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
async load(e) {
|
|
194
|
+
return this.#e.get(e);
|
|
195
|
+
}
|
|
196
|
+
async delete(e) {
|
|
197
|
+
await this.#e.remove(e);
|
|
198
|
+
}
|
|
199
|
+
async list() {
|
|
200
|
+
return (await this.#e.all()).map((t) => t.id);
|
|
201
|
+
}
|
|
202
|
+
async prune(e) {
|
|
203
|
+
const n = Date.now() - e, i = await this.#e.all();
|
|
204
|
+
let s = 0;
|
|
205
|
+
for (const a of i)
|
|
206
|
+
a.updatedAt < n && (await this.#e.remove(a.id), s++);
|
|
207
|
+
return s;
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
class v extends Error {
|
|
211
|
+
/** Original error that caused this one */
|
|
212
|
+
cause;
|
|
213
|
+
constructor(e, t) {
|
|
214
|
+
super(e), this.name = this.constructor.name, this.cause = t;
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
function P(r) {
|
|
218
|
+
return r instanceof v;
|
|
219
|
+
}
|
|
220
|
+
function b(r) {
|
|
221
|
+
return new l(r);
|
|
222
|
+
}
|
|
223
|
+
function p(r) {
|
|
224
|
+
return new T(r);
|
|
225
|
+
}
|
|
226
|
+
function B(r) {
|
|
227
|
+
return new g(r).getGuard();
|
|
228
|
+
}
|
|
229
|
+
function G(r) {
|
|
230
|
+
return new w(r);
|
|
211
231
|
}
|
|
212
232
|
export {
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
S as
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
233
|
+
A as BRIDGE_DEFAULT_TIMEOUT,
|
|
234
|
+
v as EcosystemError,
|
|
235
|
+
h as FORM_DIRTY_DEFAULT_MESSAGE,
|
|
236
|
+
g as FormDirtyGuard,
|
|
237
|
+
x as RETRIEVAL_DEFAULT_LIMIT,
|
|
238
|
+
I as RETRIEVAL_MAX_LIMIT,
|
|
239
|
+
T as RetrievalTool,
|
|
240
|
+
w as SessionPersistence,
|
|
241
|
+
l as ToolCallBridge,
|
|
242
|
+
D as chain,
|
|
243
|
+
k as computeContentHash,
|
|
244
|
+
B as createFormDirtyGuard,
|
|
245
|
+
p as createRetrievalTool,
|
|
246
|
+
G as createSessionPersistence,
|
|
247
|
+
b as createToolCallBridge,
|
|
248
|
+
d as err,
|
|
249
|
+
y as formatScoredResult,
|
|
250
|
+
P as isEcosystemError,
|
|
251
|
+
L as isErr,
|
|
252
|
+
S as isOk,
|
|
253
|
+
f as isToolCall,
|
|
254
|
+
M as map,
|
|
255
|
+
_ as mapErr,
|
|
256
|
+
m as ok,
|
|
257
|
+
E as shouldSkipFormGuard,
|
|
258
|
+
R as unwrap,
|
|
259
|
+
F as unwrapOrThrow
|
|
236
260
|
};
|
|
237
261
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sources":["../src/errors.ts","../src/helpers.ts","../src/constants.ts","../src/factories.ts"],"sourcesContent":["/**\n * @mikesaintsg/core\n *\n * Base error class and utilities for the ecosystem.\n */\n// ============================================================================\n// Base Ecosystem Error\n// ============================================================================\n/**\n * Base error class for all ecosystem errors.\n * All package-specific errors should extend this class.\n *\n * @example\n * ```ts\n * class StorageError extends EcosystemError {\n * readonly code: StorageErrorCode\n *\n * constructor(code: StorageErrorCode, message: string, cause?: Error) {\n * super(message, cause)\n * this.code = code\n * }\n * }\n * ```\n */\nexport abstract class EcosystemError extends Error {\n\t/** Error code for programmatic handling */\n\tabstract readonly code: string\n\t/** Original error that caused this one */\n\toverride readonly cause: Error | undefined\n\n\tconstructor(message: string, cause?: Error) {\n\t\tsuper(message)\n\t\tthis.name = this.constructor.name\n\t\tthis.cause = cause\n\t}\n}\n/**\n * Type guard for ecosystem errors.\n *\n * @param error - The value to check\n * @returns True if the error is an EcosystemError\n *\n * @example\n * ```ts\n * try {\n * await someOperation()\n * } catch (error) {\n * if (isEcosystemError(error)) {\n * console.log('Code:', error.code)\n * }\n * }\n * ```\n */\nexport function isEcosystemError(error: unknown): error is EcosystemError {\n\treturn error instanceof EcosystemError\n}\n","/**\r\n * @mikesaintsg/core\r\n *\r\n * Helper functions and type guards.\r\n */\r\n\r\nimport type { Ok, Err, Result, ContentHash, ScoredResult } from './types.js'\r\n\r\n// ============================================================================\r\n// Result Pattern Helpers\r\n// ============================================================================\r\n\r\n/**\r\n * Create a success result.\r\n *\r\n * @param value - The success value\r\n * @returns An Ok result containing the value\r\n *\r\n * @example\r\n * ```ts\r\n * const result = ok(42)\r\n * // result.ok === true\r\n * // result.value === 42\r\n * ```\r\n */\r\nexport function ok<T>(value: T): Ok<T> {\r\n\treturn { ok: true, value }\r\n}\r\n\r\n/**\r\n * Create a failure result.\r\n *\r\n * @param error - The error value\r\n * @returns An Err result containing the error\r\n *\r\n * @example\r\n * ```ts\r\n * const result = err('NOT_FOUND')\r\n * // result.ok === false\r\n * // result.error === 'NOT_FOUND'\r\n * ```\r\n */\r\nexport function err<E>(error: E): Err<E> {\r\n\treturn { ok: false, error }\r\n}\r\n\r\n/**\r\n * Check if a result is a success.\r\n *\r\n * @param result - The result to check\r\n * @returns True if the result is Ok, false otherwise\r\n *\r\n * @example\r\n * ```ts\r\n * const result: Result<number, string> = ok(42)\r\n * if (isOk(result)) {\r\n * console.log(result.value) // TypeScript knows result is Ok<number>\r\n * }\r\n * ```\r\n */\r\nexport function isOk<T, E>(result: Result<T, E>): result is Ok<T> {\r\n\treturn result.ok === true\r\n}\r\n\r\n/**\r\n * Check if a result is a failure.\r\n *\r\n * @param result - The result to check\r\n * @returns True if the result is Err, false otherwise\r\n *\r\n * @example\r\n * ```ts\r\n * const result: Result<number, string> = err('NOT_FOUND')\r\n * if (isErr(result)) {\r\n * console.log(result.error) // TypeScript knows result is Err<string>\r\n * }\r\n * ```\r\n */\r\nexport function isErr<T, E>(result: Result<T, E>): result is Err<E> {\r\n\treturn !result.ok\r\n}\r\n\r\n/**\r\n * Unwrap a result, returning the value or a default.\r\n *\r\n * @param result - The result to unwrap\r\n * @param defaultValue - Value to return if result is an error\r\n * @returns The success value or the default value\r\n *\r\n * @example\r\n * ```ts\r\n * const value = unwrap(ok(42), 0) // 42\r\n * const fallback = unwrap(err('oops'), 0) // 0\r\n * ```\r\n */\r\nexport function unwrap<T, E>(result: Result<T, E>, defaultValue: T): T {\r\n\treturn result.ok ? result.value : defaultValue\r\n}\r\n\r\n/**\r\n * Unwrap a result, throwing if it's an error.\r\n *\r\n * @param result - The result to unwrap\r\n * @returns The success value\r\n * @throws The error if result is Err\r\n *\r\n * @example\r\n * ```ts\r\n * const value = unwrapOrThrow(ok(42)) // 42\r\n * unwrapOrThrow(err(new Error('oops'))) // throws Error('oops')\r\n * ```\r\n */\r\nexport function unwrapOrThrow<T, E>(result: Result<T, E>): T {\r\n\tif (result.ok) {\r\n\t\treturn result.value\r\n\t}\r\n\tif (result.error instanceof Error) {\r\n\t\tthrow result.error\r\n\t}\r\n\tthrow new Error(String(result.error))\r\n}\r\n\r\n/**\r\n * Map a function over a success value.\r\n *\r\n * @param result - The result to map over\r\n * @param fn - Function to apply to the success value\r\n * @returns A new result with the mapped value, or the original error\r\n *\r\n * @example\r\n * ```ts\r\n * const doubled = map(ok(5), x => x * 2) // ok(10)\r\n * const failed = map(err('oops'), x => x * 2) // err('oops')\r\n * ```\r\n */\r\nexport function map<T, U, E>(\r\n\tresult: Result<T, E>,\r\n\tfn: (value: T) => U,\r\n): Result<U, E> {\r\n\treturn result.ok ? ok(fn(result.value)) : result\r\n}\r\n\r\n/**\r\n * Map a function over an error value.\r\n *\r\n * @param result - The result to map over\r\n * @param fn - Function to apply to the error value\r\n * @returns A new result with the mapped error, or the original value\r\n *\r\n * @example\r\n * ```ts\r\n * const wrapped = mapErr(err('oops'), e => new Error(e)) // err(Error('oops'))\r\n * const unchanged = mapErr(ok(42), e => new Error(e)) // ok(42)\r\n * ```\r\n */\r\nexport function mapErr<T, E, F>(\r\n\tresult: Result<T, E>,\r\n\tfn: (error: E) => F,\r\n): Result<T, F> {\r\n\treturn result.ok ? result : err(fn(result.error))\r\n}\r\n\r\n/**\r\n * Chain results (flatMap). Apply a function that returns a Result to a success value.\r\n *\r\n * @param result - The result to chain\r\n * @param fn - Function returning a new Result\r\n * @returns The result of applying fn, or the original error\r\n *\r\n * @example\r\n * ```ts\r\n * const parsed = chain(ok('42'), s => {\r\n * const n = parseInt(s, 10)\r\n * return isNaN(n) ? err('PARSE_ERROR') : ok(n)\r\n * })\r\n * // parsed = ok(42)\r\n * ```\r\n */\r\nexport function chain<T, U, E>(\r\n\tresult: Result<T, E>,\r\n\tfn: (value: T) => Result<U, E>,\r\n): Result<U, E> {\r\n\treturn result.ok ? fn(result.value) : result\r\n}\r\n\r\n// ============================================================================\r\n// Content Hashing Helpers\r\n// ============================================================================\r\n\r\n/**\r\n * Compute a SHA-256 content hash for text.\r\n *\r\n * @param text - The text to hash\r\n * @returns A hex string content hash\r\n *\r\n * @example\r\n * ```ts\r\n * const hash = await computeContentHash('Hello, world!')\r\n * // hash = 'a591a6d40bf420404a011733cfb7b190d62c65bf0bcda32b57b277d9ad9f146e'\r\n * ```\r\n */\r\nexport async function computeContentHash(text: string): Promise<ContentHash> {\r\n\tconst encoder = new TextEncoder()\r\n\tconst data = encoder.encode(text)\r\n\tconst hashBuffer = await crypto.subtle.digest('SHA-256', data)\r\n\tconst hashArray = Array.from(new Uint8Array(hashBuffer))\r\n\treturn hashArray.map(b => b.toString(16).padStart(2, '0')).join('')\r\n}\r\n\r\n// ============================================================================\r\n// Bridge Helpers\r\n// ============================================================================\r\n\r\n/**\r\n * Check if a value is a single ToolCall (not an array).\r\n *\r\n * @param value - Value to check\r\n * @returns True if the value is a single ToolCall\r\n */\r\nexport function isToolCall(value: unknown): value is { id: string; name: string; arguments: unknown } {\r\n\treturn (\r\n\t\ttypeof value === 'object' &&\r\n\t\tvalue !== null &&\r\n\t\t'id' in value &&\r\n\t\t'name' in value &&\r\n\t\t'arguments' in value\r\n\t)\r\n}\r\n\r\n/**\r\n * Determine if form dirty guard should be skipped for a navigation.\r\n *\r\n * @param to - Target page\r\n * @param from - Source page\r\n * @param excludePages - Pages to exclude from guard\r\n * @param onlyFromPages - Only guard from these pages (if specified)\r\n * @returns True if guard should be skipped\r\n */\r\nexport function shouldSkipFormGuard<TPage extends string>(\r\n\tto: TPage,\r\n\tfrom: TPage,\r\n\texcludePages: readonly TPage[],\r\n\tonlyFromPages: readonly TPage[] | undefined,\r\n): boolean {\r\n\t// Skip if navigating to excluded page\r\n\tif (excludePages.includes(to)) {\r\n\t\treturn true\r\n\t}\r\n\r\n\t// Skip if from page is not in onlyFromPages (if specified)\r\n\treturn onlyFromPages !== undefined && !onlyFromPages.includes(from)\r\n}\r\n\r\n/**\r\n * Default result formatter for retrieval tools.\r\n * Returns content, score, and metadata.\r\n *\r\n * @param result - Scored result to format\r\n * @returns Formatted result object\r\n */\r\nexport function formatScoredResult(result: ScoredResult): unknown {\r\n\treturn {\r\n\t\tcontent: result.content,\r\n\t\tscore: result.score,\r\n\t\tmetadata: result.metadata,\r\n\t}\r\n}\r\n","/**\r\n * @mikesaintsg/core\r\n *\r\n * Shared constants for the core library.\r\n */\r\n\r\n// ============================================================================\r\n// Bridge Constants\r\n// ============================================================================\r\n\r\n/** Default timeout for bridge operations in milliseconds */\r\nexport const BRIDGE_DEFAULT_TIMEOUT = 30000\r\n\r\n/** Default retrieval limit for retrieval tool */\r\nexport const RETRIEVAL_DEFAULT_LIMIT = 10\r\n\r\n/** Maximum retrieval limit for retrieval tool */\r\nexport const RETRIEVAL_MAX_LIMIT = 100\r\n\r\n/** Default form dirty guard message */\r\nexport const FORM_DIRTY_DEFAULT_MESSAGE = 'You have unsaved changes. Are you sure you want to leave?'\r\n","/**\n * @mikesaintsg/core\n *\n * Factory functions for creating bridge instances.\n */\n\nimport type {\n\tToolCall,\n\tToolResult,\n\tToolCallBridgeOptions,\n\tToolCallBridgeInterface,\n\tRetrievalToolOptions,\n\tRetrievalToolInterface,\n\tToolSchema,\n\tJSONSchema7,\n\tFormDirtyGuardOptions,\n\tNavigationGuard,\n\tSessionPersistenceOptions,\n\tSessionPersistenceInterface,\n\tSerializableSession,\n\tSerializedSession,\n} from './types.js'\nimport {\n\tBRIDGE_DEFAULT_TIMEOUT,\n\tRETRIEVAL_DEFAULT_LIMIT,\n\tRETRIEVAL_MAX_LIMIT,\n\tFORM_DIRTY_DEFAULT_MESSAGE,\n} from './constants.js'\nimport {\n\tisToolCall,\n\tshouldSkipFormGuard,\n\tformatScoredResult,\n} from './helpers.js'\n\n// ============================================================================\n// Tool Call Bridge Factory\n// ============================================================================\n\n/**\n * Create a tool call bridge.\n *\n * @param options - Bridge configuration options\n * @returns A tool call bridge instance\n *\n * @example\n * ```ts\n * import { createToolRegistry } from '@mikesaintsg/contextprotocol'\n * import { createToolCallBridge } from '@mikesaintsg/core'\n *\n * const registry = createToolRegistry()\n * registry.register(weatherTool)\n *\n * const bridge = createToolCallBridge({\n * registry,\n * timeout: 30000,\n * onError: (error, toolCall) => console.error(`Tool ${toolCall.name} failed:`, error),\n * })\n *\n * // Execute tool calls from LLM response\n * const results = await bridge.execute(response.toolCalls)\n * ```\n */\nexport function createToolCallBridge(\n\toptions: ToolCallBridgeOptions,\n): ToolCallBridgeInterface {\n\tconst {\n\t\tregistry,\n\t\ttimeout = BRIDGE_DEFAULT_TIMEOUT,\n\t\tonError,\n\t\tonBeforeExecute,\n\t\tonAfterExecute,\n\t} = options\n\n\tasync function executeWithTimeout(toolCall: ToolCall): Promise<ToolResult> {\n\t\t// Check if tool exists\n\t\tif (!registry.has(toolCall.name)) {\n\t\t\treturn {\n\t\t\t\tcallId: toolCall.id,\n\t\t\t\tname: toolCall.name,\n\t\t\t\tsuccess: false,\n\t\t\t\terror: `Tool not found: ${toolCall.name}`,\n\t\t\t}\n\t\t}\n\n\t\t// Call lifecycle hook\n\t\tonBeforeExecute?.(toolCall)\n\n\t\ttry {\n\t\t\t// Create timeout promise\n\t\t\tconst timeoutPromise = new Promise<never>((_, reject) => {\n\t\t\t\tsetTimeout(() => {\n\t\t\t\t\treject(new Error(`Tool execution timed out after ${timeout}ms`))\n\t\t\t\t}, timeout)\n\t\t\t})\n\n\t\t\t// Execute tool with timeout\n\t\t\tconst value = await Promise.race([\n\t\t\t\tregistry.execute(toolCall.name, toolCall.arguments),\n\t\t\t\ttimeoutPromise,\n\t\t\t])\n\n\t\t\t// Call lifecycle hook\n\t\t\tonAfterExecute?.(toolCall, value)\n\n\t\t\treturn {\n\t\t\t\tcallId: toolCall.id,\n\t\t\t\tname: toolCall.name,\n\t\t\t\tsuccess: true,\n\t\t\t\tvalue,\n\t\t\t}\n\t\t} catch (error) {\n\t\t\t// Call error hook\n\t\t\tonError?.(error, toolCall)\n\n\t\t\tconst errorMessage = error instanceof Error\n\t\t\t\t? error.message\n\t\t\t\t: String(error)\n\n\t\t\treturn {\n\t\t\t\tcallId: toolCall.id,\n\t\t\t\tname: toolCall.name,\n\t\t\t\tsuccess: false,\n\t\t\t\terror: errorMessage,\n\t\t\t}\n\t\t}\n\t}\n\n\treturn {\n\t\texecute(toolCallOrCalls: ToolCall | readonly ToolCall[]) {\n\t\t\tif (isToolCall(toolCallOrCalls)) {\n\t\t\t\treturn executeWithTimeout(toolCallOrCalls)\n\t\t\t}\n\t\t\treturn Promise.all(\n\t\t\t\t(toolCallOrCalls).map(tc => executeWithTimeout(tc)),\n\t\t\t)\n\t\t},\n\n\t\thasTool(name: string): boolean {\n\t\t\treturn registry.has(name)\n\t\t},\n\t} as ToolCallBridgeInterface\n}\n\n// ============================================================================\n// Retrieval Tool Factory\n// ============================================================================\n\n/**\n * Create a retrieval tool for use with contextprotocol tool registry.\n *\n * @param options - Retrieval tool configuration options\n * @returns A tool schema and handler for registration\n *\n * @example\n * ```ts\n * import { createVectorStore } from '@mikesaintsg/vectorstore'\n * import { createToolRegistry } from '@mikesaintsg/contextprotocol'\n * import { createRetrievalTool } from '@mikesaintsg/core'\n *\n * const vectorStore = createVectorStore({ ... })\n * const registry = createToolRegistry()\n *\n * const { schema, handler } = createRetrievalTool({\n * vectorStore,\n * name: 'search_docs',\n * description: 'Search documentation for relevant information',\n * defaultLimit: 5,\n * scoreThreshold: 0.7,\n * })\n *\n * registry.register({ ...schema, execute: handler })\n * ```\n */\nexport function createRetrievalTool<TMetadata = unknown>(\n\toptions: RetrievalToolOptions<TMetadata>,\n): RetrievalToolInterface {\n\tconst {\n\t\tvectorStore,\n\t\tname,\n\t\tdescription,\n\t\tdefaultLimit = RETRIEVAL_DEFAULT_LIMIT,\n\t\tmaxLimit = RETRIEVAL_MAX_LIMIT,\n\t\tscoreThreshold,\n\t\tformatResult = formatScoredResult,\n\t\textendParameters = {},\n\t\tbuildFilter,\n\t} = options\n\n\t// Build tool schema parameters\n\tconst parameters: JSONSchema7 = {\n\t\ttype: 'object',\n\t\tproperties: {\n\t\t\tquery: {\n\t\t\t\ttype: 'string',\n\t\t\t\tdescription: 'The search query to find relevant documents',\n\t\t\t},\n\t\t\tlimit: {\n\t\t\t\ttype: 'integer',\n\t\t\t\tdescription: `Maximum number of results to return (default: ${defaultLimit}, max: ${maxLimit})`,\n\t\t\t\tminimum: 1,\n\t\t\t\tmaximum: maxLimit,\n\t\t\t\tdefault: defaultLimit,\n\t\t\t},\n\t\t\t...extendParameters,\n\t\t},\n\t\trequired: ['query'],\n\t}\n\n\tconst schema: ToolSchema = {\n\t\tname,\n\t\tdescription,\n\t\tparameters,\n\t}\n\n\tasync function handler(\n\t\targs: Readonly<Record<string, unknown>>,\n\t): Promise<readonly unknown[]> {\n\t\tconst query = args.query\n\t\tif (typeof query !== 'string' || query.length === 0) {\n\t\t\treturn []\n\t\t}\n\n\t\tconst requestedLimit = args.limit\n\t\tlet limit = defaultLimit\n\t\tif (typeof requestedLimit === 'number' && Number.isInteger(requestedLimit)) {\n\t\t\tlimit = Math.min(Math.max(1, requestedLimit), maxLimit)\n\t\t}\n\n\t\t// Build filter if provided\n\t\tconst filter = buildFilter?.(args)\n\n\t\t// Search vectorstore - only include filter if defined\n\t\tconst searchOptions = filter !== undefined\n\t\t\t? { limit, filter }\n\t\t\t: { limit }\n\t\tconst results = await vectorStore.search(query, searchOptions)\n\n\t\t// Filter by score threshold\n\t\tlet filteredResults = results\n\t\tif (scoreThreshold !== undefined) {\n\t\t\tfilteredResults = results.filter(r => r.score >= scoreThreshold)\n\t\t}\n\n\t\t// Format results\n\t\treturn filteredResults.map(formatResult)\n\t}\n\n\treturn { schema, handler }\n}\n\n// ============================================================================\n// Form Dirty Guard Factory\n// ============================================================================\n\n/**\n * Create a navigation guard that prevents leaving when form is dirty.\n *\n * @param options - Form dirty guard configuration options\n * @returns A navigation guard function\n *\n * @example\n * ```ts\n * import { createForm } from '@mikesaintsg/form'\n * import { createFormDirtyGuard } from '@mikesaintsg/core'\n *\n * const form = createForm({ ... })\n *\n * const guard = createFormDirtyGuard({\n * form,\n * confirmFn: (message) => window.confirm(message),\n * message: 'You have unsaved changes. Continue?',\n * excludePages: ['settings'],\n * })\n *\n * // Use with router\n * router.beforeNavigate(guard)\n * ```\n */\nexport function createFormDirtyGuard<TFormData = unknown, TPage extends string = string>(\n\toptions: FormDirtyGuardOptions<TFormData, TPage>,\n): NavigationGuard<TPage> {\n\tconst {\n\t\tform,\n\t\tconfirmFn,\n\t\tmessage = FORM_DIRTY_DEFAULT_MESSAGE,\n\t\texcludePages = [],\n\t\tonlyFromPages,\n\t} = options\n\n\treturn async function guard(to: TPage, from: TPage): Promise<boolean> {\n\t\t// Check if we should skip guard for this navigation\n\t\tif (shouldSkipFormGuard(to, from, excludePages, onlyFromPages)) {\n\t\t\treturn true\n\t\t}\n\n\t\t// If form is not dirty, allow navigation\n\t\tif (!form.isDirty()) {\n\t\t\treturn true\n\t\t}\n\n\t\t// Form is dirty, ask for confirmation\n\t\treturn Promise.resolve(confirmFn(message))\n\t}\n}\n\n// ============================================================================\n// Session Persistence Factory\n// ============================================================================\n\n/**\n * Create a session persistence adapter for storing inference sessions.\n *\n * @param options - Session persistence configuration options\n * @returns A session persistence instance\n *\n * @example\n * ```ts\n * import { createDatabase } from '@mikesaintsg/indexeddb'\n * import { createSessionPersistence } from '@mikesaintsg/core'\n *\n * const db = await createDatabase({ name: 'sessions' })\n * const persistence = createSessionPersistence({\n * database: db,\n * storeName: 'chat_sessions',\n * autoprune: 7 * 24 * 60 * 60 * 1000, // 7 days\n * })\n *\n * // Save session\n * await persistence.save('session-1', session)\n *\n * // Load session\n * const savedSession = await persistence.load('session-1')\n * ```\n */\nexport function createSessionPersistence(\n\toptions: SessionPersistenceOptions,\n): SessionPersistenceInterface {\n\tconst {\n\t\tdatabase,\n\t\tstoreName,\n\t\tautoprune,\n\t\tonSaveError,\n\t} = options\n\n\tconst store = database.store<SerializedSession>(storeName)\n\n\tasync function pruneOldSessions(maxAgeMs: number): Promise<number> {\n\t\tconst now = Date.now()\n\t\tconst cutoff = now - maxAgeMs\n\n\t\tconst allSessions = await store.all()\n\t\tlet prunedCount = 0\n\n\t\tfor (const session of allSessions) {\n\t\t\tif (session.updatedAt < cutoff) {\n\t\t\t\tawait store.remove(session.id)\n\t\t\t\tprunedCount++\n\t\t\t}\n\t\t}\n\n\t\treturn prunedCount\n\t}\n\n\t// Auto-prune on creation if configured\n\tif (autoprune !== undefined && autoprune > 0) {\n\t\tvoid pruneOldSessions(autoprune)\n\t}\n\n\treturn {\n\t\tasync save(id: string, session: SerializableSession): Promise<void> {\n\t\t\ttry {\n\t\t\t\tconst serialized: SerializedSession = {\n\t\t\t\t\tid,\n\t\t\t\t\tmessages: [...session.getMessages()],\n\t\t\t\t\tmetadata: session.getMetadata(),\n\t\t\t\t\tupdatedAt: Date.now(),\n\t\t\t\t}\n\n\t\t\t\tawait store.set(serialized, id)\n\t\t\t} catch (error) {\n\t\t\t\tonSaveError?.(error, id)\n\t\t\t\tthrow error\n\t\t\t}\n\t\t},\n\n\t\tasync load(id: string): Promise<SerializedSession | undefined> {\n\t\t\treturn store.get(id)\n\t\t},\n\n\t\tasync delete(id: string): Promise<void> {\n\t\t\tawait store.remove(id)\n\t\t},\n\n\t\tasync list(): Promise<readonly string[]> {\n\t\t\tconst allSessions = await store.all()\n\t\t\treturn allSessions.map(s => s.id)\n\t\t},\n\n\t\tasync prune(maxAgeMs: number): Promise<number> {\n\t\t\treturn pruneOldSessions(maxAgeMs)\n\t\t},\n\t}\n}\n"],"names":["EcosystemError","message","cause","isEcosystemError","error","ok","value","err","isOk","result","isErr","unwrap","defaultValue","unwrapOrThrow","map","fn","mapErr","chain","computeContentHash","text","data","hashBuffer","b","isToolCall","shouldSkipFormGuard","to","from","excludePages","onlyFromPages","formatScoredResult","BRIDGE_DEFAULT_TIMEOUT","RETRIEVAL_DEFAULT_LIMIT","RETRIEVAL_MAX_LIMIT","FORM_DIRTY_DEFAULT_MESSAGE","createToolCallBridge","options","registry","timeout","onError","onBeforeExecute","onAfterExecute","executeWithTimeout","toolCall","timeoutPromise","_","reject","errorMessage","toolCallOrCalls","tc","name","createRetrievalTool","vectorStore","description","defaultLimit","maxLimit","scoreThreshold","formatResult","extendParameters","buildFilter","parameters","schema","handler","args","query","requestedLimit","limit","filter","searchOptions","results","filteredResults","r","createFormDirtyGuard","form","confirmFn","createSessionPersistence","database","storeName","autoprune","onSaveError","store","pruneOldSessions","maxAgeMs","cutoff","allSessions","prunedCount","session","id","serialized","s"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","sources":["../src/constants.ts","../src/helpers.ts","../src/core/bridges/ToolCallBridge.ts","../src/core/bridges/RetrievalTool.ts","../src/core/bridges/FormDirtyGuard.ts","../src/core/bridges/SessionPersistence.ts","../src/errors.ts","../src/factories.ts"],"sourcesContent":["/**\r\n * @mikesaintsg/core\r\n *\r\n * Shared constants for the core library.\r\n */\r\n\r\n// ============================================================================\r\n// Bridge Constants\r\n// ============================================================================\r\n\r\n/** Default timeout for bridge operations in milliseconds */\r\nexport const BRIDGE_DEFAULT_TIMEOUT = 30000\r\n\r\n/** Default retrieval limit for retrieval tool */\r\nexport const RETRIEVAL_DEFAULT_LIMIT = 10\r\n\r\n/** Maximum retrieval limit for retrieval tool */\r\nexport const RETRIEVAL_MAX_LIMIT = 100\r\n\r\n/** Default form dirty guard message */\r\nexport const FORM_DIRTY_DEFAULT_MESSAGE = 'You have unsaved changes. Are you sure you want to leave?'\r\n","/**\r\n * @mikesaintsg/core\r\n *\r\n * Helper functions and type guards.\r\n */\r\n\r\nimport type { Ok, Err, Result, ContentHash, ScoredResult } from './types.js'\r\n\r\n// ============================================================================\r\n// Result Pattern Helpers\r\n// ============================================================================\r\n\r\n/**\r\n * Create a success result.\r\n *\r\n * @param value - The success value\r\n * @returns An Ok result containing the value\r\n *\r\n * @example\r\n * ```ts\r\n * const result = ok(42)\r\n * // result.ok === true\r\n * // result.value === 42\r\n * ```\r\n */\r\nexport function ok<T>(value: T): Ok<T> {\r\n\treturn { ok: true, value }\r\n}\r\n\r\n/**\r\n * Create a failure result.\r\n *\r\n * @param error - The error value\r\n * @returns An Err result containing the error\r\n *\r\n * @example\r\n * ```ts\r\n * const result = err('NOT_FOUND')\r\n * // result.ok === false\r\n * // result.error === 'NOT_FOUND'\r\n * ```\r\n */\r\nexport function err<E>(error: E): Err<E> {\r\n\treturn { ok: false, error }\r\n}\r\n\r\n/**\r\n * Check if a result is a success.\r\n *\r\n * @param result - The result to check\r\n * @returns True if the result is Ok, false otherwise\r\n *\r\n * @example\r\n * ```ts\r\n * const result: Result<number, string> = ok(42)\r\n * if (isOk(result)) {\r\n * console.log(result.value) // TypeScript knows result is Ok<number>\r\n * }\r\n * ```\r\n */\r\nexport function isOk<T, E>(result: Result<T, E>): result is Ok<T> {\r\n\treturn result.ok\r\n}\r\n\r\n/**\r\n * Check if a result is a failure.\r\n *\r\n * @param result - The result to check\r\n * @returns True if the result is Err, false otherwise\r\n *\r\n * @example\r\n * ```ts\r\n * const result: Result<number, string> = err('NOT_FOUND')\r\n * if (isErr(result)) {\r\n * console.log(result.error) // TypeScript knows result is Err<string>\r\n * }\r\n * ```\r\n */\r\nexport function isErr<T, E>(result: Result<T, E>): result is Err<E> {\r\n\treturn !result.ok\r\n}\r\n\r\n/**\r\n * Unwrap a result, returning the value or a default.\r\n *\r\n * @param result - The result to unwrap\r\n * @param defaultValue - Value to return if result is an error\r\n * @returns The success value or the default value\r\n *\r\n * @example\r\n * ```ts\r\n * const value = unwrap(ok(42), 0) // 42\r\n * const fallback = unwrap(err('oops'), 0) // 0\r\n * ```\r\n */\r\nexport function unwrap<T, E>(result: Result<T, E>, defaultValue: T): T {\r\n\treturn result.ok ? result.value : defaultValue\r\n}\r\n\r\n/**\r\n * Unwrap a result, throwing if it's an error.\r\n *\r\n * @param result - The result to unwrap\r\n * @returns The success value\r\n * @throws The error if result is Err\r\n *\r\n * @example\r\n * ```ts\r\n * const value = unwrapOrThrow(ok(42)) // 42\r\n * unwrapOrThrow(err(new Error('oops'))) // throws Error('oops')\r\n * ```\r\n */\r\nexport function unwrapOrThrow<T, E>(result: Result<T, E>): T {\r\n\tif (result.ok) {\r\n\t\treturn result.value\r\n\t}\r\n\tif (result.error instanceof Error) {\r\n\t\tthrow result.error\r\n\t}\r\n\tthrow new Error(String(result.error))\r\n}\r\n\r\n/**\r\n * Map a function over a success value.\r\n *\r\n * @param result - The result to map over\r\n * @param fn - Function to apply to the success value\r\n * @returns A new result with the mapped value, or the original error\r\n *\r\n * @example\r\n * ```ts\r\n * const doubled = map(ok(5), x => x * 2) // ok(10)\r\n * const failed = map(err('oops'), x => x * 2) // err('oops')\r\n * ```\r\n */\r\nexport function map<T, U, E>(\r\n\tresult: Result<T, E>,\r\n\tfn: (value: T) => U,\r\n): Result<U, E> {\r\n\treturn result.ok ? ok(fn(result.value)) : result\r\n}\r\n\r\n/**\r\n * Map a function over an error value.\r\n *\r\n * @param result - The result to map over\r\n * @param fn - Function to apply to the error value\r\n * @returns A new result with the mapped error, or the original value\r\n *\r\n * @example\r\n * ```ts\r\n * const wrapped = mapErr(err('oops'), e => new Error(e)) // err(Error('oops'))\r\n * const unchanged = mapErr(ok(42), e => new Error(e)) // ok(42)\r\n * ```\r\n */\r\nexport function mapErr<T, E, F>(\r\n\tresult: Result<T, E>,\r\n\tfn: (error: E) => F,\r\n): Result<T, F> {\r\n\treturn result.ok ? result : err(fn(result.error))\r\n}\r\n\r\n/**\r\n * Chain results (flatMap). Apply a function that returns a Result to a success value.\r\n *\r\n * @param result - The result to chain\r\n * @param fn - Function returning a new Result\r\n * @returns The result of applying fn, or the original error\r\n *\r\n * @example\r\n * ```ts\r\n * const parsed = chain(ok('42'), s => {\r\n * const n = parseInt(s, 10)\r\n * return isNaN(n) ? err('PARSE_ERROR') : ok(n)\r\n * })\r\n * // parsed = ok(42)\r\n * ```\r\n */\r\nexport function chain<T, U, E>(\r\n\tresult: Result<T, E>,\r\n\tfn: (value: T) => Result<U, E>,\r\n): Result<U, E> {\r\n\treturn result.ok ? fn(result.value) : result\r\n}\r\n\r\n// ============================================================================\r\n// Content Hashing Helpers\r\n// ============================================================================\r\n\r\n/**\r\n * Compute a SHA-256 content hash for text.\r\n *\r\n * @param text - The text to hash\r\n * @returns A hex string content hash\r\n *\r\n * @example\r\n * ```ts\r\n * const hash = await computeContentHash('Hello, world!')\r\n * // hash = 'a591a6d40bf420404a011733cfb7b190d62c65bf0bcda32b57b277d9ad9f146e'\r\n * ```\r\n */\r\nexport async function computeContentHash(text: string): Promise<ContentHash> {\r\n\tconst encoder = new TextEncoder()\r\n\tconst data = encoder.encode(text)\r\n\tconst hashBuffer = await crypto.subtle.digest('SHA-256', data)\r\n\tconst hashArray = Array.from(new Uint8Array(hashBuffer))\r\n\treturn hashArray.map(b => b.toString(16).padStart(2, '0')).join('')\r\n}\r\n\r\n// ============================================================================\r\n// Bridge Helpers\r\n// ============================================================================\r\n\r\n/**\r\n * Check if a value is a single ToolCall (not an array).\r\n *\r\n * @param value - Value to check\r\n * @returns True if the value is a single ToolCall\r\n */\r\nexport function isToolCall(value: unknown): value is { id: string; name: string; arguments: unknown } {\r\n\treturn (\r\n\t\ttypeof value === 'object' &&\r\n\t\tvalue !== null &&\r\n\t\t'id' in value &&\r\n\t\t'name' in value &&\r\n\t\t'arguments' in value\r\n\t)\r\n}\r\n\r\n/**\r\n * Determine if form dirty guard should be skipped for a navigation.\r\n *\r\n * @param to - Target page\r\n * @param from - Source page\r\n * @param excludePages - Pages to exclude from guard\r\n * @param onlyFromPages - Only guard from these pages (if specified)\r\n * @returns True if guard should be skipped\r\n */\r\nexport function shouldSkipFormGuard<TPage extends string>(\r\n\tto: TPage,\r\n\tfrom: TPage,\r\n\texcludePages: readonly TPage[],\r\n\tonlyFromPages: readonly TPage[] | undefined,\r\n): boolean {\r\n\t// Skip if navigating to excluded page\r\n\tif (excludePages.includes(to)) {\r\n\t\treturn true\r\n\t}\r\n\r\n\t// Skip if from page is not in onlyFromPages (if specified)\r\n\treturn onlyFromPages !== undefined && !onlyFromPages.includes(from)\r\n}\r\n\r\n/**\r\n * Default result formatter for retrieval tools.\r\n * Returns content, score, and metadata.\r\n *\r\n * @param result - Scored result to format\r\n * @returns Formatted result object\r\n */\r\nexport function formatScoredResult(result: ScoredResult): unknown {\r\n\treturn {\r\n\t\tcontent: result.content,\r\n\t\tscore: result.score,\r\n\t\tmetadata: result.metadata,\r\n\t}\r\n}\r\n","/**\n * @mikesaintsg/core\n *\n * Tool call bridge implementation.\n * Connects inference tool calls to contextprotocol tool registry.\n */\n\nimport type {\n\tToolCall,\n\tToolResult,\n\tToolCallBridgeOptions,\n\tToolCallBridgeInterface,\n\tToolRegistryMinimal,\n} from '../../types.js'\nimport { BRIDGE_DEFAULT_TIMEOUT } from '../../constants.js'\nimport { isToolCall } from '../../helpers.js'\n\n/**\n * Tool call bridge implementation.\n * Executes tool calls against a tool registry with timeout and lifecycle hooks.\n */\nexport class ToolCallBridge implements ToolCallBridgeInterface {\n\treadonly #registry: ToolRegistryMinimal\n\treadonly #timeout: number\n\treadonly #onError: ((error: unknown, toolCall: ToolCall) => void) | undefined\n\treadonly #onBeforeExecute: ((toolCall: ToolCall) => void) | undefined\n\treadonly #onAfterExecute: ((toolCall: ToolCall, result: unknown) => void) | undefined\n\n\tconstructor(options: ToolCallBridgeOptions) {\n\t\tthis.#registry = options.registry\n\t\tthis.#timeout = options.timeout ?? BRIDGE_DEFAULT_TIMEOUT\n\t\tthis.#onError = 'onError' in options ? options.onError : undefined\n\t\tthis.#onBeforeExecute = 'onBeforeExecute' in options ? options.onBeforeExecute : undefined\n\t\tthis.#onAfterExecute = 'onAfterExecute' in options ? options.onAfterExecute : undefined\n\t}\n\n\texecute(toolCalls: ToolCall): Promise<ToolResult>\n\texecute(toolCalls: readonly ToolCall[]): Promise<readonly ToolResult[]>\n\texecute(toolCallOrCalls: ToolCall | readonly ToolCall[]): Promise<ToolResult | readonly ToolResult[]> {\n\t\tif (isToolCall(toolCallOrCalls)) {\n\t\t\treturn this.#executeWithTimeout(toolCallOrCalls)\n\t\t}\n\t\treturn Promise.all(\n\t\t\ttoolCallOrCalls.map(tc => this.#executeWithTimeout(tc)),\n\t\t)\n\t}\n\n\thasTool(name: string): boolean {\n\t\treturn this.#registry.has(name)\n\t}\n\n\tasync #executeWithTimeout(toolCall: ToolCall): Promise<ToolResult> {\n\t\t// Check if tool exists\n\t\tif (!this.#registry.has(toolCall.name)) {\n\t\t\treturn {\n\t\t\t\tcallId: toolCall.id,\n\t\t\t\tname: toolCall.name,\n\t\t\t\tsuccess: false,\n\t\t\t\terror: `Tool not found: ${toolCall.name}`,\n\t\t\t}\n\t\t}\n\n\t\t// Call lifecycle hook\n\t\tthis.#onBeforeExecute?.(toolCall)\n\n\t\ttry {\n\t\t\t// Create timeout promise\n\t\t\tconst timeoutPromise = new Promise<never>((_, reject) => {\n\t\t\t\tsetTimeout(() => {\n\t\t\t\t\treject(new Error(`Tool execution timed out after ${this.#timeout}ms`))\n\t\t\t\t}, this.#timeout)\n\t\t\t})\n\n\t\t\t// Execute tool with timeout\n\t\t\tconst value = await Promise.race([\n\t\t\t\tthis.#registry.execute(toolCall.name, toolCall.arguments),\n\t\t\t\ttimeoutPromise,\n\t\t\t])\n\n\t\t\t// Call lifecycle hook\n\t\t\tthis.#onAfterExecute?.(toolCall, value)\n\n\t\t\treturn {\n\t\t\t\tcallId: toolCall.id,\n\t\t\t\tname: toolCall.name,\n\t\t\t\tsuccess: true,\n\t\t\t\tvalue,\n\t\t\t}\n\t\t} catch (error) {\n\t\t\t// Call error hook\n\t\t\tthis.#onError?.(error, toolCall)\n\n\t\t\tconst errorMessage = error instanceof Error\n\t\t\t\t? error.message\n\t\t\t\t: String(error)\n\n\t\t\treturn {\n\t\t\t\tcallId: toolCall.id,\n\t\t\t\tname: toolCall.name,\n\t\t\t\tsuccess: false,\n\t\t\t\terror: errorMessage,\n\t\t\t}\n\t\t}\n\t}\n}\n","/**\n * @mikesaintsg/core\n *\n * Retrieval tool implementation.\n * Creates a tool for vectorstore search that can be registered with contextprotocol.\n */\n\nimport type {\n\tRetrievalToolOptions,\n\tRetrievalToolInterface,\n\tToolSchema,\n\tJSONSchema7,\n\tVectorStoreMinimal,\n} from '../../types.js'\nimport {\n\tRETRIEVAL_DEFAULT_LIMIT,\n\tRETRIEVAL_MAX_LIMIT,\n} from '../../constants.js'\nimport { formatScoredResult } from '../../helpers.js'\n\n/**\n * Retrieval tool implementation.\n * Provides a tool schema and handler for vectorstore search.\n */\nexport class RetrievalTool<TMetadata = unknown> implements RetrievalToolInterface {\n\treadonly schema: ToolSchema\n\treadonly #vectorStore: VectorStoreMinimal<TMetadata>\n\treadonly #defaultLimit: number\n\treadonly #maxLimit: number\n\treadonly #scoreThreshold: number | undefined\n\treadonly #formatResult: (result: { id: string; content: string; score: number; metadata?: Readonly<Record<string, unknown>> }) => unknown\n\treadonly #buildFilter: ((params: Readonly<Record<string, unknown>>) => TMetadata | undefined) | undefined\n\n\tconstructor(options: RetrievalToolOptions<TMetadata>) {\n\t\tthis.#vectorStore = options.vectorStore\n\t\tthis.#defaultLimit = options.defaultLimit ?? RETRIEVAL_DEFAULT_LIMIT\n\t\tthis.#maxLimit = options.maxLimit ?? RETRIEVAL_MAX_LIMIT\n\t\tthis.#scoreThreshold = 'scoreThreshold' in options ? options.scoreThreshold : undefined\n\t\tthis.#formatResult = options.formatResult ?? formatScoredResult\n\t\tthis.#buildFilter = 'buildFilter' in options ? options.buildFilter : undefined\n\n\t\t// Build tool schema parameters\n\t\tconst parameters: JSONSchema7 = {\n\t\t\ttype: 'object',\n\t\t\tproperties: {\n\t\t\t\tquery: {\n\t\t\t\t\ttype: 'string',\n\t\t\t\t\tdescription: 'The search query to find relevant documents',\n\t\t\t\t},\n\t\t\t\tlimit: {\n\t\t\t\t\ttype: 'integer',\n\t\t\t\t\tdescription: `Maximum number of results to return (default: ${this.#defaultLimit}, max: ${this.#maxLimit})`,\n\t\t\t\t\tminimum: 1,\n\t\t\t\t\tmaximum: this.#maxLimit,\n\t\t\t\t\tdefault: this.#defaultLimit,\n\t\t\t\t},\n\t\t\t\t...options.extendParameters,\n\t\t\t},\n\t\t\trequired: ['query'],\n\t\t}\n\n\t\tthis.schema = {\n\t\t\tname: options.name,\n\t\t\tdescription: options.description,\n\t\t\tparameters,\n\t\t}\n\t}\n\n\thandler = async(args: Readonly<Record<string, unknown>>): Promise<readonly unknown[]> => {\n\t\tconst query = args.query\n\t\tif (typeof query !== 'string' || query.length === 0) {\n\t\t\treturn []\n\t\t}\n\n\t\tconst requestedLimit = args.limit\n\t\tlet limit = this.#defaultLimit\n\t\tif (typeof requestedLimit === 'number' && Number.isInteger(requestedLimit)) {\n\t\t\tlimit = Math.min(Math.max(1, requestedLimit), this.#maxLimit)\n\t\t}\n\n\t\t// Build filter if provided\n\t\tconst filter = this.#buildFilter?.(args)\n\n\t\t// Search vectorstore - only include filter if defined\n\t\tconst searchOptions = filter !== undefined\n\t\t\t? { limit, filter }\n\t\t\t: { limit }\n\t\tconst results = await this.#vectorStore.search(query, searchOptions)\n\n\t\t// Filter by score threshold\n\t\tlet filteredResults = results\n\t\tif (this.#scoreThreshold !== undefined) {\n\t\t\tfilteredResults = results.filter(r => r.score >= this.#scoreThreshold!)\n\t\t}\n\n\t\t// Format results\n\t\treturn filteredResults.map(this.#formatResult)\n\t}\n}\n","/**\n * @mikesaintsg/core\n *\n * Form dirty guard implementation.\n * Navigation guard that prevents leaving when form is dirty.\n */\n\nimport type {\n\tFormDirtyGuardOptions,\n\tNavigationGuard,\n\tFormMinimal,\n} from '../../types.js'\nimport { FORM_DIRTY_DEFAULT_MESSAGE } from '../../constants.js'\nimport { shouldSkipFormGuard } from '../../helpers.js'\n\n/**\n * Form dirty guard implementation.\n * Returns a navigation guard function that prompts when form has unsaved changes.\n */\nexport class FormDirtyGuard<TFormData = unknown, TPage extends string = string> {\n\treadonly #form: FormMinimal<TFormData>\n\treadonly #confirmFn: (message: string) => Promise<boolean> | boolean\n\treadonly #message: string\n\treadonly #excludePages: readonly TPage[]\n\treadonly #onlyFromPages: readonly TPage[] | undefined\n\n\tconstructor(options: FormDirtyGuardOptions<TFormData, TPage>) {\n\t\tthis.#form = options.form\n\t\tthis.#confirmFn = options.confirmFn\n\t\tthis.#message = options.message ?? FORM_DIRTY_DEFAULT_MESSAGE\n\t\tthis.#excludePages = options.excludePages ?? []\n\t\tthis.#onlyFromPages = 'onlyFromPages' in options ? options.onlyFromPages : undefined\n\t}\n\n\t/**\n\t * Get the navigation guard function.\n\t * This is the function to register with a router.\n\t */\n\tgetGuard(): NavigationGuard<TPage> {\n\t\treturn async(to: TPage, from: TPage): Promise<boolean> => {\n\t\t\t// Check if we should skip guard for this navigation\n\t\t\tif (shouldSkipFormGuard(to, from, this.#excludePages, this.#onlyFromPages)) {\n\t\t\t\treturn true\n\t\t\t}\n\n\t\t\t// If form is not dirty, allow navigation\n\t\t\tif (!this.#form.isDirty()) {\n\t\t\t\treturn true\n\t\t\t}\n\n\t\t\t// Form is dirty, ask for confirmation\n\t\t\treturn Promise.resolve(this.#confirmFn(this.#message))\n\t\t}\n\t}\n}\n","/**\n * @mikesaintsg/core\n *\n * Session persistence implementation.\n * Connects inference sessions to IndexedDB storage.\n */\n\nimport type {\n\tSessionPersistenceOptions,\n\tSessionPersistenceInterface,\n\tSerializableSession,\n\tSerializedSession,\n\tMinimalStoreAccess,\n} from '../../types.js'\n\n/**\n * Session persistence implementation.\n * Stores and retrieves inference sessions from a database store.\n */\nexport class SessionPersistence implements SessionPersistenceInterface {\n\treadonly #store: MinimalStoreAccess<SerializedSession>\n\treadonly #onSaveError: ((error: unknown, sessionId: string) => void) | undefined\n\n\tconstructor(options: SessionPersistenceOptions) {\n\t\tthis.#store = options.database.store<SerializedSession>(options.storeName)\n\t\tthis.#onSaveError = 'onSaveError' in options ? options.onSaveError : undefined\n\n\t\t// Auto-prune on creation if configured\n\t\tif (options.autoprune !== undefined && options.autoprune > 0) {\n\t\t\tvoid this.prune(options.autoprune)\n\t\t}\n\t}\n\n\tasync isAvailable(): Promise<boolean> {\n\t\ttry {\n\t\t\t// Try to access the store to verify availability\n\t\t\tawait this.#store.all()\n\t\t\treturn true\n\t\t} catch {\n\t\t\treturn false\n\t\t}\n\t}\n\n\tasync clear(): Promise<void> {\n\t\tawait this.#store.clear()\n\t}\n\n\tasync save(id: string, session: SerializableSession): Promise<void> {\n\t\ttry {\n\t\t\tconst serialized: SerializedSession = {\n\t\t\t\tid,\n\t\t\t\tmessages: [...session.getMessages()],\n\t\t\t\tmetadata: session.getMetadata(),\n\t\t\t\tupdatedAt: Date.now(),\n\t\t\t}\n\n\t\t\tawait this.#store.set(serialized, id)\n\t\t} catch (error) {\n\t\t\tthis.#onSaveError?.(error, id)\n\t\t\tthrow error\n\t\t}\n\t}\n\n\tasync load(id: string): Promise<SerializedSession | undefined> {\n\t\treturn this.#store.get(id)\n\t}\n\n\tasync delete(id: string): Promise<void> {\n\t\tawait this.#store.remove(id)\n\t}\n\n\tasync list(): Promise<readonly string[]> {\n\t\tconst allSessions = await this.#store.all()\n\t\treturn allSessions.map(s => s.id)\n\t}\n\n\tasync prune(maxAgeMs: number): Promise<number> {\n\t\tconst now = Date.now()\n\t\tconst cutoff = now - maxAgeMs\n\n\t\tconst allSessions = await this.#store.all()\n\t\tlet prunedCount = 0\n\n\t\tfor (const session of allSessions) {\n\t\t\tif (session.updatedAt < cutoff) {\n\t\t\t\tawait this.#store.remove(session.id)\n\t\t\t\tprunedCount++\n\t\t\t}\n\t\t}\n\n\t\treturn prunedCount\n\t}\n}\n","/**\r\n * @mikesaintsg/core\r\n *\r\n * Base error class and utilities for the ecosystem.\r\n */\r\n// ============================================================================\r\n// Base Ecosystem Error\r\n// ============================================================================\r\n/**\r\n * Base error class for all ecosystem errors.\r\n * All package-specific errors should extend this class.\r\n *\r\n * @example\r\n * ```ts\r\n * class StorageError extends EcosystemError {\r\n * readonly code: StorageErrorCode\r\n *\r\n * constructor(code: StorageErrorCode, message: string, cause?: Error) {\r\n * super(message, cause)\r\n * this.code = code\r\n * }\r\n * }\r\n * ```\r\n */\r\nexport abstract class EcosystemError extends Error {\r\n\t/** Error code for programmatic handling */\r\n\tabstract readonly code: string\r\n\t/** Original error that caused this one */\r\n\toverride readonly cause: Error | undefined\r\n\r\n\tconstructor(message: string, cause?: Error) {\r\n\t\tsuper(message)\r\n\t\tthis.name = this.constructor.name\r\n\t\tthis.cause = cause\r\n\t}\r\n}\r\n/**\r\n * Type guard for ecosystem errors.\r\n *\r\n * @param error - The value to check\r\n * @returns True if the error is an EcosystemError\r\n *\r\n * @example\r\n * ```ts\r\n * try {\r\n * await someOperation()\r\n * } catch (error) {\r\n * if (isEcosystemError(error)) {\r\n * console.log('Code:', error.code)\r\n * }\r\n * }\r\n * ```\r\n */\r\nexport function isEcosystemError(error: unknown): error is EcosystemError {\r\n\treturn error instanceof EcosystemError\r\n}\r\n","/**\r\n * @mikesaintsg/core\r\n *\r\n * Factory functions for creating bridge instances.\r\n */\r\n\r\nimport type {\r\n\tToolCallBridgeOptions,\r\n\tToolCallBridgeInterface,\r\n\tRetrievalToolOptions,\r\n\tRetrievalToolInterface,\r\n\tFormDirtyGuardOptions,\r\n\tNavigationGuard,\r\n\tSessionPersistenceOptions,\r\n\tSessionPersistenceInterface,\r\n} from './types.js'\r\nimport {\r\n\tToolCallBridge,\r\n\tRetrievalTool,\r\n\tFormDirtyGuard,\r\n\tSessionPersistence,\r\n} from './core/index.js'\r\n\r\n// ============================================================================\r\n// Tool Call Bridge Factory\r\n// ============================================================================\r\n\r\n/**\r\n * Create a tool call bridge.\r\n *\r\n * @param options - Bridge configuration options\r\n * @returns A tool call bridge instance\r\n *\r\n * @example\r\n * ```ts\r\n * import { createToolRegistry } from '@mikesaintsg/contextprotocol'\r\n * import { createToolCallBridge } from '@mikesaintsg/core'\r\n *\r\n * const registry = createToolRegistry()\r\n * registry.register(weatherTool)\r\n *\r\n * const bridge = createToolCallBridge({\r\n * registry,\r\n * timeout: 30000,\r\n * onError: (error, toolCall) => console.error(`Tool ${toolCall.name} failed:`, error),\r\n * })\r\n *\r\n * // Execute tool calls from LLM response\r\n * const results = await bridge.execute(response.toolCalls)\r\n * ```\r\n */\r\nexport function createToolCallBridge(\r\n\toptions: ToolCallBridgeOptions,\r\n): ToolCallBridgeInterface {\r\n\treturn new ToolCallBridge(options)\r\n}\r\n\r\n// ============================================================================\r\n// Retrieval Tool Factory\r\n// ============================================================================\r\n\r\n/**\r\n * Create a retrieval tool for use with contextprotocol tool registry.\r\n *\r\n * @param options - Retrieval tool configuration options\r\n * @returns A tool schema and handler for registration\r\n *\r\n * @example\r\n * ```ts\r\n * import { createVectorStore } from '@mikesaintsg/vectorstore'\r\n * import { createToolRegistry } from '@mikesaintsg/contextprotocol'\r\n * import { createRetrievalTool } from '@mikesaintsg/core'\r\n *\r\n * const vectorStore = createVectorStore({ ... })\r\n * const registry = createToolRegistry()\r\n *\r\n * const { schema, handler } = createRetrievalTool({\r\n * vectorStore,\r\n * name: 'search_docs',\r\n * description: 'Search documentation for relevant information',\r\n * defaultLimit: 5,\r\n * scoreThreshold: 0.7,\r\n * })\r\n *\r\n * registry.register({ ...schema, execute: handler })\r\n * ```\r\n */\r\nexport function createRetrievalTool<TMetadata = unknown>(\r\n\toptions: RetrievalToolOptions<TMetadata>,\r\n): RetrievalToolInterface {\r\n\treturn new RetrievalTool(options)\r\n}\r\n\r\n// ============================================================================\r\n// Form Dirty Guard Factory\r\n// ============================================================================\r\n\r\n/**\r\n * Create a navigation guard that prevents leaving when form is dirty.\r\n *\r\n * @param options - Form dirty guard configuration options\r\n * @returns A navigation guard function\r\n *\r\n * @example\r\n * ```ts\r\n * import { createForm } from '@mikesaintsg/form'\r\n * import { createFormDirtyGuard } from '@mikesaintsg/core'\r\n *\r\n * const form = createForm({ ... })\r\n *\r\n * const guard = createFormDirtyGuard({\r\n * form,\r\n * confirmFn: (message) => window.confirm(message),\r\n * message: 'You have unsaved changes. Continue?',\r\n * excludePages: ['settings'],\r\n * })\r\n *\r\n * // Use with router\r\n * router.beforeNavigate(guard)\r\n * ```\r\n */\r\nexport function createFormDirtyGuard<TFormData = unknown, TPage extends string = string>(\r\n\toptions: FormDirtyGuardOptions<TFormData, TPage>,\r\n): NavigationGuard<TPage> {\r\n\tconst guard = new FormDirtyGuard(options)\r\n\treturn guard.getGuard()\r\n}\r\n\r\n// ============================================================================\r\n// Session Persistence Factory\r\n// ============================================================================\r\n\r\n/**\r\n * Create a session persistence adapter for storing inference sessions.\r\n *\r\n * @param options - Session persistence configuration options\r\n * @returns A session persistence instance\r\n *\r\n * @example\r\n * ```ts\r\n * import { createDatabase } from '@mikesaintsg/indexeddb'\r\n * import { createSessionPersistence } from '@mikesaintsg/core'\r\n *\r\n * const db = await createDatabase({ name: 'sessions' })\r\n * const persistence = createSessionPersistence({\r\n * database: db,\r\n * storeName: 'chat_sessions',\r\n * autoprune: 7 * 24 * 60 * 60 * 1000, // 7 days\r\n * })\r\n *\r\n * // Save session\r\n * await persistence.save('session-1', session)\r\n *\r\n * // Load session\r\n * const savedSession = await persistence.load('session-1')\r\n * ```\r\n */\r\nexport function createSessionPersistence(\r\n\toptions: SessionPersistenceOptions,\r\n): SessionPersistenceInterface {\r\n\treturn new SessionPersistence(options)\r\n}\r\n"],"names":["BRIDGE_DEFAULT_TIMEOUT","RETRIEVAL_DEFAULT_LIMIT","RETRIEVAL_MAX_LIMIT","FORM_DIRTY_DEFAULT_MESSAGE","ok","value","err","error","isOk","result","isErr","unwrap","defaultValue","unwrapOrThrow","map","fn","mapErr","chain","computeContentHash","text","data","hashBuffer","b","isToolCall","shouldSkipFormGuard","to","from","excludePages","onlyFromPages","formatScoredResult","ToolCallBridge","#registry","#timeout","#onError","#onBeforeExecute","#onAfterExecute","options","toolCallOrCalls","#executeWithTimeout","tc","name","toolCall","timeoutPromise","_","reject","errorMessage","RetrievalTool","#vectorStore","#defaultLimit","#maxLimit","#scoreThreshold","#formatResult","#buildFilter","parameters","args","query","requestedLimit","limit","filter","searchOptions","results","filteredResults","r","FormDirtyGuard","#form","#confirmFn","#message","#excludePages","#onlyFromPages","SessionPersistence","#store","#onSaveError","id","session","serialized","s","maxAgeMs","cutoff","allSessions","prunedCount","EcosystemError","message","cause","isEcosystemError","createToolCallBridge","createRetrievalTool","createFormDirtyGuard","createSessionPersistence"],"mappings":"AAWO,MAAMA,IAAyB,KAGzBC,IAA0B,IAG1BC,IAAsB,KAGtBC,IAA6B;ACKnC,SAASC,EAAMC,GAAiB;AACtC,SAAO,EAAE,IAAI,IAAM,OAAAA,EAAA;AACpB;AAeO,SAASC,EAAOC,GAAkB;AACxC,SAAO,EAAE,IAAI,IAAO,OAAAA,EAAA;AACrB;AAgBO,SAASC,EAAWC,GAAuC;AACjE,SAAOA,EAAO;AACf;AAgBO,SAASC,EAAYD,GAAwC;AACnE,SAAO,CAACA,EAAO;AAChB;AAeO,SAASE,EAAaF,GAAsBG,GAAoB;AACtE,SAAOH,EAAO,KAAKA,EAAO,QAAQG;AACnC;AAeO,SAASC,EAAoBJ,GAAyB;AAC5D,MAAIA,EAAO;AACV,WAAOA,EAAO;AAEf,QAAIA,EAAO,iBAAiB,QACrBA,EAAO,QAER,IAAI,MAAM,OAAOA,EAAO,KAAK,CAAC;AACrC;AAeO,SAASK,EACfL,GACAM,GACe;AACf,SAAON,EAAO,KAAKL,EAAGW,EAAGN,EAAO,KAAK,CAAC,IAAIA;AAC3C;AAeO,SAASO,EACfP,GACAM,GACe;AACf,SAAON,EAAO,KAAKA,IAASH,EAAIS,EAAGN,EAAO,KAAK,CAAC;AACjD;AAkBO,SAASQ,EACfR,GACAM,GACe;AACf,SAAON,EAAO,KAAKM,EAAGN,EAAO,KAAK,IAAIA;AACvC;AAkBA,eAAsBS,EAAmBC,GAAoC;AAE5E,QAAMC,IADU,IAAI,YAAA,EACC,OAAOD,CAAI,GAC1BE,IAAa,MAAM,OAAO,OAAO,OAAO,WAAWD,CAAI;AAE7D,SADkB,MAAM,KAAK,IAAI,WAAWC,CAAU,CAAC,EACtC,IAAI,CAAAC,MAAKA,EAAE,SAAS,EAAE,EAAE,SAAS,GAAG,GAAG,CAAC,EAAE,KAAK,EAAE;AACnE;AAYO,SAASC,EAAWlB,GAA2E;AACrG,SACC,OAAOA,KAAU,YACjBA,MAAU,QACV,QAAQA,KACR,UAAUA,KACV,eAAeA;AAEjB;AAWO,SAASmB,EACfC,GACAC,GACAC,GACAC,GACU;AAEV,SAAID,EAAa,SAASF,CAAE,IACpB,KAIDG,MAAkB,UAAa,CAACA,EAAc,SAASF,CAAI;AACnE;AASO,SAASG,EAAmBpB,GAA+B;AACjE,SAAO;AAAA,IACN,SAASA,EAAO;AAAA,IAChB,OAAOA,EAAO;AAAA,IACd,UAAUA,EAAO;AAAA,EAAA;AAEnB;ACrPO,MAAMqB,EAAkD;AAAA,EACrDC;AAAA,EACAC;AAAA,EACAC;AAAA,EACAC;AAAA,EACAC;AAAA,EAET,YAAYC,GAAgC;AAC3C,SAAKL,KAAYK,EAAQ,UACzB,KAAKJ,KAAWI,EAAQ,WAAW,KACnC,KAAKH,KAAW,aAAaG,IAAUA,EAAQ,UAAU,QACzD,KAAKF,KAAmB,qBAAqBE,IAAUA,EAAQ,kBAAkB,QACjF,KAAKD,KAAkB,oBAAoBC,IAAUA,EAAQ,iBAAiB;AAAA,EAC/E;AAAA,EAIA,QAAQC,GAA8F;AACrG,WAAId,EAAWc,CAAe,IACtB,KAAKC,GAAoBD,CAAe,IAEzC,QAAQ;AAAA,MACdA,EAAgB,IAAI,CAAAE,MAAM,KAAKD,GAAoBC,CAAE,CAAC;AAAA,IAAA;AAAA,EAExD;AAAA,EAEA,QAAQC,GAAuB;AAC9B,WAAO,KAAKT,GAAU,IAAIS,CAAI;AAAA,EAC/B;AAAA,EAEA,MAAMF,GAAoBG,GAAyC;AAElE,QAAI,CAAC,KAAKV,GAAU,IAAIU,EAAS,IAAI;AACpC,aAAO;AAAA,QACN,QAAQA,EAAS;AAAA,QACjB,MAAMA,EAAS;AAAA,QACf,SAAS;AAAA,QACT,OAAO,mBAAmBA,EAAS,IAAI;AAAA,MAAA;AAKzC,SAAKP,KAAmBO,CAAQ;AAEhC,QAAI;AAEH,YAAMC,IAAiB,IAAI,QAAe,CAACC,GAAGC,MAAW;AACxD,mBAAW,MAAM;AAChB,UAAAA,EAAO,IAAI,MAAM,kCAAkC,KAAKZ,EAAQ,IAAI,CAAC;AAAA,QACtE,GAAG,KAAKA,EAAQ;AAAA,MACjB,CAAC,GAGK3B,IAAQ,MAAM,QAAQ,KAAK;AAAA,QAChC,KAAK0B,GAAU,QAAQU,EAAS,MAAMA,EAAS,SAAS;AAAA,QACxDC;AAAA,MAAA,CACA;AAGD,kBAAKP,KAAkBM,GAAUpC,CAAK,GAE/B;AAAA,QACN,QAAQoC,EAAS;AAAA,QACjB,MAAMA,EAAS;AAAA,QACf,SAAS;AAAA,QACT,OAAApC;AAAA,MAAA;AAAA,IAEF,SAASE,GAAO;AAEf,WAAK0B,KAAW1B,GAAOkC,CAAQ;AAE/B,YAAMI,IAAetC,aAAiB,QACnCA,EAAM,UACN,OAAOA,CAAK;AAEf,aAAO;AAAA,QACN,QAAQkC,EAAS;AAAA,QACjB,MAAMA,EAAS;AAAA,QACf,SAAS;AAAA,QACT,OAAOI;AAAA,MAAA;AAAA,IAET;AAAA,EACD;AACD;AChFO,MAAMC,EAAqE;AAAA,EACxE;AAAA,EACAC;AAAA,EACAC;AAAA,EACAC;AAAA,EACAC;AAAA,EACAC;AAAA,EACAC;AAAA,EAET,YAAYhB,GAA0C;AACrD,SAAKW,KAAeX,EAAQ,aAC5B,KAAKY,KAAgBZ,EAAQ,gBAAgB,IAC7C,KAAKa,KAAYb,EAAQ,YAAY,KACrC,KAAKc,KAAkB,oBAAoBd,IAAUA,EAAQ,iBAAiB,QAC9E,KAAKe,KAAgBf,EAAQ,gBAAgBP,GAC7C,KAAKuB,KAAe,iBAAiBhB,IAAUA,EAAQ,cAAc;AAGrE,UAAMiB,IAA0B;AAAA,MAC/B,MAAM;AAAA,MACN,YAAY;AAAA,QACX,OAAO;AAAA,UACN,MAAM;AAAA,UACN,aAAa;AAAA,QAAA;AAAA,QAEd,OAAO;AAAA,UACN,MAAM;AAAA,UACN,aAAa,iDAAiD,KAAKL,EAAa,UAAU,KAAKC,EAAS;AAAA,UACxG,SAAS;AAAA,UACT,SAAS,KAAKA;AAAA,UACd,SAAS,KAAKD;AAAA,QAAA;AAAA,QAEf,GAAGZ,EAAQ;AAAA,MAAA;AAAA,MAEZ,UAAU,CAAC,OAAO;AAAA,IAAA;AAGnB,SAAK,SAAS;AAAA,MACb,MAAMA,EAAQ;AAAA,MACd,aAAaA,EAAQ;AAAA,MACrB,YAAAiB;AAAA,IAAA;AAAA,EAEF;AAAA,EAEA,UAAU,OAAMC,MAAyE;AACxF,UAAMC,IAAQD,EAAK;AACnB,QAAI,OAAOC,KAAU,YAAYA,EAAM,WAAW;AACjD,aAAO,CAAA;AAGR,UAAMC,IAAiBF,EAAK;AAC5B,QAAIG,IAAQ,KAAKT;AACjB,IAAI,OAAOQ,KAAmB,YAAY,OAAO,UAAUA,CAAc,MACxEC,IAAQ,KAAK,IAAI,KAAK,IAAI,GAAGD,CAAc,GAAG,KAAKP,EAAS;AAI7D,UAAMS,IAAS,KAAKN,KAAeE,CAAI,GAGjCK,IAAgBD,MAAW,SAC9B,EAAE,OAAAD,GAAO,QAAAC,EAAA,IACT,EAAE,OAAAD,EAAA,GACCG,IAAU,MAAM,KAAKb,GAAa,OAAOQ,GAAOI,CAAa;AAGnE,QAAIE,IAAkBD;AACtB,WAAI,KAAKV,OAAoB,WAC5BW,IAAkBD,EAAQ,OAAO,CAAAE,MAAKA,EAAE,SAAS,KAAKZ,EAAgB,IAIhEW,EAAgB,IAAI,KAAKV,EAAa;AAAA,EAC9C;AACD;AC/EO,MAAMY,EAAmE;AAAA,EACtEC;AAAA,EACAC;AAAA,EACAC;AAAA,EACAC;AAAA,EACAC;AAAA,EAET,YAAYhC,GAAkD;AAC7D,SAAK4B,KAAQ5B,EAAQ,MACrB,KAAK6B,KAAa7B,EAAQ,WAC1B,KAAK8B,KAAW9B,EAAQ,WAAWjC,GACnC,KAAKgE,KAAgB/B,EAAQ,gBAAgB,CAAA,GAC7C,KAAKgC,KAAiB,mBAAmBhC,IAAUA,EAAQ,gBAAgB;AAAA,EAC5E;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,WAAmC;AAClC,WAAO,OAAMX,GAAWC,MAEnBF,EAAoBC,GAAIC,GAAM,KAAKyC,IAAe,KAAKC,EAAc,KAKrE,CAAC,KAAKJ,GAAM,YACR,KAID,QAAQ,QAAQ,KAAKC,GAAW,KAAKC,EAAQ,CAAC;AAAA,EAEvD;AACD;ACnCO,MAAMG,EAA0D;AAAA,EAC7DC;AAAA,EACAC;AAAA,EAET,YAAYnC,GAAoC;AAC/C,SAAKkC,KAASlC,EAAQ,SAAS,MAAyBA,EAAQ,SAAS,GACzE,KAAKmC,KAAe,iBAAiBnC,IAAUA,EAAQ,cAAc,QAGjEA,EAAQ,cAAc,UAAaA,EAAQ,YAAY,KACrD,KAAK,MAAMA,EAAQ,SAAS;AAAA,EAEnC;AAAA,EAEA,MAAM,cAAgC;AACrC,QAAI;AAEH,mBAAM,KAAKkC,GAAO,IAAA,GACX;AAAA,IACR,QAAQ;AACP,aAAO;AAAA,IACR;AAAA,EACD;AAAA,EAEA,MAAM,QAAuB;AAC5B,UAAM,KAAKA,GAAO,MAAA;AAAA,EACnB;AAAA,EAEA,MAAM,KAAKE,GAAYC,GAA6C;AACnE,QAAI;AACH,YAAMC,IAAgC;AAAA,QACrC,IAAAF;AAAA,QACA,UAAU,CAAC,GAAGC,EAAQ,aAAa;AAAA,QACnC,UAAUA,EAAQ,YAAA;AAAA,QAClB,WAAW,KAAK,IAAA;AAAA,MAAI;AAGrB,YAAM,KAAKH,GAAO,IAAII,GAAYF,CAAE;AAAA,IACrC,SAASjE,GAAO;AACf,iBAAKgE,KAAehE,GAAOiE,CAAE,GACvBjE;AAAA,IACP;AAAA,EACD;AAAA,EAEA,MAAM,KAAKiE,GAAoD;AAC9D,WAAO,KAAKF,GAAO,IAAIE,CAAE;AAAA,EAC1B;AAAA,EAEA,MAAM,OAAOA,GAA2B;AACvC,UAAM,KAAKF,GAAO,OAAOE,CAAE;AAAA,EAC5B;AAAA,EAEA,MAAM,OAAmC;AAExC,YADoB,MAAM,KAAKF,GAAO,IAAA,GACnB,IAAI,CAAAK,MAAKA,EAAE,EAAE;AAAA,EACjC;AAAA,EAEA,MAAM,MAAMC,GAAmC;AAE9C,UAAMC,IADM,KAAK,IAAA,IACID,GAEfE,IAAc,MAAM,KAAKR,GAAO,IAAA;AACtC,QAAIS,IAAc;AAElB,eAAWN,KAAWK;AACrB,MAAIL,EAAQ,YAAYI,MACvB,MAAM,KAAKP,GAAO,OAAOG,EAAQ,EAAE,GACnCM;AAIF,WAAOA;AAAA,EACR;AACD;ACpEO,MAAeC,UAAuB,MAAM;AAAA;AAAA,EAIhC;AAAA,EAElB,YAAYC,GAAiBC,GAAe;AAC3C,UAAMD,CAAO,GACb,KAAK,OAAO,KAAK,YAAY,MAC7B,KAAK,QAAQC;AAAA,EACd;AACD;AAkBO,SAASC,EAAiB5E,GAAyC;AACzE,SAAOA,aAAiByE;AACzB;ACJO,SAASI,EACfhD,GAC0B;AAC1B,SAAO,IAAIN,EAAeM,CAAO;AAClC;AAgCO,SAASiD,EACfjD,GACyB;AACzB,SAAO,IAAIU,EAAcV,CAAO;AACjC;AA8BO,SAASkD,EACflD,GACyB;AAEzB,SADc,IAAI2B,EAAe3B,CAAO,EAC3B,SAAA;AACd;AA+BO,SAASmD,EACfnD,GAC8B;AAC9B,SAAO,IAAIiC,EAAmBjC,CAAO;AACtC;"}
|
package/package.json
CHANGED
|
@@ -1,13 +1,15 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mikesaintsg/core",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.6",
|
|
4
4
|
"type": "module",
|
|
5
|
-
"description": "
|
|
5
|
+
"description": "Shared types, contracts, and bridge functions for the @mikesaintsg ecosystem. Zero runtime dependencies.",
|
|
6
6
|
"keywords": [
|
|
7
7
|
"typescript",
|
|
8
|
-
"
|
|
8
|
+
"types",
|
|
9
|
+
"contracts",
|
|
10
|
+
"bridge",
|
|
11
|
+
"result-pattern",
|
|
9
12
|
"type-safe",
|
|
10
|
-
"promise-based",
|
|
11
13
|
"zero-dependencies"
|
|
12
14
|
],
|
|
13
15
|
"author": "Mike Garcia",
|
|
@@ -55,7 +57,7 @@
|
|
|
55
57
|
"eslint": "^9.39.2",
|
|
56
58
|
"jiti": "^2.6.1",
|
|
57
59
|
"typescript": "^5.9.3",
|
|
58
|
-
"typescript-eslint": "^8.53.
|
|
60
|
+
"typescript-eslint": "^8.53.1",
|
|
59
61
|
"vite": "^7.3.1",
|
|
60
62
|
"vite-plugin-dts": "^4.5.4",
|
|
61
63
|
"vite-plugin-singlefile": "^2.3.0",
|