@mikesaintsg/core 0.0.4 → 0.0.5

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 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 Functions** — Connect packages without circular dependencies
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
- | `DestroyFn` | Resource cleanup function |
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,54 @@ export declare interface AbortableOptions {
3
3
  readonly signal?: AbortSignal;
4
4
  }
5
5
 
6
+ /**
7
+ * Activity tracker adapter interface.
8
+ *
9
+ * Tracks user engagement (active/idle/away) and dwell time per node.
10
+ * Implementations use browser APIs (visibility, pointer, keyboard events).
11
+ */
12
+ export declare interface ActivityTrackerInterface extends ActivityTrackerSubscriptions, Destroyable {
13
+ /** Enter a node and start tracking dwell time */
14
+ enterNode(nodeId: string): void;
15
+ /** Exit current node and complete the dwell record */
16
+ exitNode(): DwellRecord | undefined;
17
+ /** Get current engagement state */
18
+ getEngagementState(): EngagementState;
19
+ /** Get current node ID being tracked */
20
+ getCurrentNodeId(): string | undefined;
21
+ /** Get current incomplete dwell record */
22
+ getCurrentDwell(): PartialDwellRecord | undefined;
23
+ /** Get all completed dwell records */
24
+ getDwellHistory(): readonly DwellRecord[];
25
+ /** Get total active time across all dwells */
26
+ getTotalActiveTime(): number;
27
+ /** Get total idle time across all dwells */
28
+ getTotalIdleTime(): number;
29
+ /** Clear dwell history */
30
+ clearHistory(): void;
31
+ }
32
+
33
+ /** Activity tracker configuration */
34
+ export declare interface ActivityTrackerOptions extends SubscriptionToHook<ActivityTrackerSubscriptions> {
35
+ /** Idle threshold in milliseconds (default: 30000) */
36
+ readonly idleThreshold?: number;
37
+ /** Away threshold in milliseconds (default: 300000) */
38
+ readonly awayThreshold?: number;
39
+ /** Enable visibility-based tracking (default: true) */
40
+ readonly trackVisibility?: boolean;
41
+ }
42
+
43
+ /** Activity tracker subscriptions */
44
+ export declare interface ActivityTrackerSubscriptions {
45
+ /** Subscribe to engagement state changes */
46
+ onEngagementChange(callback: (state: EngagementState, nodeId: string) => void): Unsubscribe;
47
+ /** Subscribe to completed dwell records */
48
+ onDwellComplete(callback: (record: DwellRecord) => void): Unsubscribe;
49
+ }
50
+
51
+ /** Actor types for transition attribution */
52
+ export declare type Actor = 'user' | 'system' | 'automation';
53
+
6
54
  /**
7
55
  * Batch adapter interface.
8
56
  * Controls batching behavior for bulk operations.
@@ -195,6 +243,17 @@ export declare function createSessionPersistence(options: SessionPersistenceOpti
195
243
  */
196
244
  export declare function createToolCallBridge(options: ToolCallBridgeOptions): ToolCallBridgeInterface;
197
245
 
246
+ /** Decay algorithm types */
247
+ export declare type DecayAlgorithm = 'halflife' | 'ewma' | 'linear' | 'none';
248
+
249
+ /** Decay configuration */
250
+ export declare interface DecayConfig {
251
+ readonly algorithm: DecayAlgorithm;
252
+ readonly halfLifeMs?: number;
253
+ readonly decayFactor?: number;
254
+ readonly minWeight?: number;
255
+ }
256
+
198
257
  /**
199
258
  * Deduplication adapter interface.
200
259
  * Determines how to handle duplicate frames based on content hash.
@@ -225,6 +284,17 @@ export declare interface Destroyable {
225
284
  destroy(): void;
226
285
  }
227
286
 
287
+ /** Dwell record capturing time spent on a node */
288
+ export declare interface DwellRecord {
289
+ readonly nodeId: string;
290
+ readonly enterTime: number;
291
+ readonly exitTime: number;
292
+ readonly activeTime: number;
293
+ readonly idleTime: number;
294
+ readonly engagement: EngagementState;
295
+ readonly engagementScore: number;
296
+ }
297
+
228
298
  /**
229
299
  * @mikesaintsg/core
230
300
  *
@@ -300,6 +370,9 @@ export declare interface EmbeddingModelMetadata {
300
370
  readonly dimensions: number;
301
371
  }
302
372
 
373
+ /** Engagement state for activity tracking */
374
+ export declare type EngagementState = 'active' | 'idle' | 'away' | 'unknown';
375
+
303
376
  /** Failure result */
304
377
  export declare interface Err<E> {
305
378
  readonly ok: false;
@@ -326,6 +399,70 @@ export declare type ErrorCode<T extends {
326
399
  readonly code: string;
327
400
  }> = T['code'];
328
401
 
402
+ /** Filter options for querying events */
403
+ export declare interface EventFilter {
404
+ readonly sessionId?: string;
405
+ readonly actor?: Actor;
406
+ readonly nodeId?: string;
407
+ readonly from?: string;
408
+ readonly to?: string;
409
+ readonly startTime?: number;
410
+ readonly endTime?: number;
411
+ readonly namespace?: string;
412
+ readonly limit?: number;
413
+ readonly offset?: number;
414
+ }
415
+
416
+ /**
417
+ * Event store persistence adapter interface.
418
+ *
419
+ * Extends base persistence with event-specific storage operations.
420
+ * Persists transition events for audit trail and replay.
421
+ * Implementations: IndexedDB, OPFS, HTTP, in-memory.
422
+ */
423
+ export declare interface EventStorePersistenceAdapterInterface extends PersistenceAdapterInterface {
424
+ /** Persist event(s) */
425
+ persist(event: TransitionEvent_2 | readonly TransitionEvent_2[]): Promise<void>;
426
+ /** Load events matching filter */
427
+ load(filter: EventFilter): Promise<readonly TransitionEvent_2[]>;
428
+ /** Get count of events matching filter */
429
+ getCount(filter?: EventFilter): Promise<number>;
430
+ /** Check if any events exist matching filter */
431
+ has(filter?: EventFilter): Promise<boolean>;
432
+ /**
433
+ * Clear events matching filter.
434
+ * Extends base clear() with optional filtering.
435
+ * Call without filter to clear all events.
436
+ */
437
+ clear(filter?: EventFilter): Promise<void>;
438
+ /** Export all events for backup */
439
+ export(namespace?: string): Promise<readonly TransitionEvent_2[]>;
440
+ /** Import events (for recovery/migration) */
441
+ import(events: readonly TransitionEvent_2[]): Promise<void>;
442
+ }
443
+
444
+ /** Exported predictive graph for persistence */
445
+ export declare interface ExportedPredictiveGraph {
446
+ readonly version: number;
447
+ readonly exportedAt: number;
448
+ readonly modelId: string;
449
+ readonly namespace?: string;
450
+ readonly weights: readonly ExportedWeight[];
451
+ readonly decayConfig: DecayConfig;
452
+ readonly transitionCount: number;
453
+ readonly warmupThreshold?: number;
454
+ }
455
+
456
+ /** Exported weight entry */
457
+ export declare interface ExportedWeight {
458
+ readonly from: string;
459
+ readonly to: string;
460
+ readonly actor: Actor;
461
+ readonly weight: number;
462
+ readonly lastUpdated: number;
463
+ readonly updateCount: number;
464
+ }
465
+
329
466
  /** Generation finish reason */
330
467
  export declare type FinishReason = 'stop' | 'length' | 'tool_calls' | 'content_filter' | 'error';
331
468
 
@@ -341,6 +478,20 @@ export declare const FORM_DIRTY_DEFAULT_MESSAGE = "You have unsaved changes. Are
341
478
  */
342
479
  export declare function formatScoredResult(result: ScoredResult): unknown;
343
480
 
481
+ /**
482
+ * Form dirty guard implementation.
483
+ * Returns a navigation guard function that prompts when form has unsaved changes.
484
+ */
485
+ export declare class FormDirtyGuard<TFormData = unknown, TPage extends string = string> {
486
+ #private;
487
+ constructor(options: FormDirtyGuardOptions<TFormData, TPage>);
488
+ /**
489
+ * Get the navigation guard function.
490
+ * This is the function to register with a router.
491
+ */
492
+ getGuard(): NavigationGuard<TPage>;
493
+ }
494
+
344
495
  /** Form dirty guard options */
345
496
  export declare interface FormDirtyGuardOptions<TFormData = unknown, TPage extends string = string> {
346
497
  readonly form: FormMinimal<TFormData>;
@@ -643,6 +794,39 @@ export declare interface PackageErrorData<TCode extends string> {
643
794
  readonly cause?: Error;
644
795
  }
645
796
 
797
+ /** Partial dwell record for in-progress tracking */
798
+ export declare interface PartialDwellRecord {
799
+ readonly nodeId: string;
800
+ readonly enterTime: number;
801
+ readonly activeTime: number;
802
+ readonly idleTime: number;
803
+ readonly engagement: EngagementState;
804
+ }
805
+
806
+ /**
807
+ * Base persistence adapter interface.
808
+ *
809
+ * Defines common operations shared by all persistence adapters.
810
+ * Specialized persistence adapters extend this interface with
811
+ * domain-specific load, save, and query methods.
812
+ *
813
+ * All persistence adapters share:
814
+ * - Availability checking for backend validation
815
+ * - Clear operation for removing all persisted data
816
+ */
817
+ export declare interface PersistenceAdapterInterface {
818
+ /**
819
+ * Check if the persistence backend is available.
820
+ * Use this before operations to handle unavailable storage gracefully.
821
+ */
822
+ isAvailable(): Promise<boolean>;
823
+ /**
824
+ * Clear all persisted data.
825
+ * Use with caution — this removes all data managed by this adapter.
826
+ */
827
+ clear(): Promise<void>;
828
+ }
829
+
646
830
  /**
647
831
  * Priority adapter interface.
648
832
  * Provides priority weights and comparison logic.
@@ -735,6 +919,17 @@ export declare const RETRIEVAL_DEFAULT_LIMIT = 10;
735
919
  /** Maximum retrieval limit for retrieval tool */
736
920
  export declare const RETRIEVAL_MAX_LIMIT = 100;
737
921
 
922
+ /**
923
+ * Retrieval tool implementation.
924
+ * Provides a tool schema and handler for vectorstore search.
925
+ */
926
+ export declare class RetrievalTool<TMetadata = unknown> implements RetrievalToolInterface {
927
+ #private;
928
+ readonly schema: ToolSchema;
929
+ constructor(options: RetrievalToolOptions<TMetadata>);
930
+ handler: (args: Readonly<Record<string, unknown>>) => Promise<readonly unknown[]>;
931
+ }
932
+
738
933
  /** Retrieval tool created by factory */
739
934
  export declare interface RetrievalToolInterface {
740
935
  readonly schema: ToolSchema;
@@ -811,15 +1006,38 @@ export declare interface SerializedSessionMetadata {
811
1006
  readonly system?: string;
812
1007
  }
813
1008
 
1009
+ /**
1010
+ * Session persistence implementation.
1011
+ * Stores and retrieves inference sessions from a database store.
1012
+ */
1013
+ export declare class SessionPersistence implements SessionPersistenceInterface {
1014
+ #private;
1015
+ constructor(options: SessionPersistenceOptions);
1016
+ isAvailable(): Promise<boolean>;
1017
+ clear(): Promise<void>;
1018
+ save(id: string, session: SerializableSession): Promise<void>;
1019
+ load(id: string): Promise<SerializedSession | undefined>;
1020
+ delete(id: string): Promise<void>;
1021
+ list(): Promise<readonly string[]>;
1022
+ prune(maxAgeMs: number): Promise<number>;
1023
+ }
1024
+
814
1025
  /**
815
1026
  * Session persistence interface.
1027
+ *
1028
+ * Extends base persistence with session-specific storage operations.
816
1029
  * Connects inference sessions to IndexedDB storage.
817
1030
  */
818
- export declare interface SessionPersistenceInterface {
1031
+ export declare interface SessionPersistenceInterface extends PersistenceAdapterInterface {
1032
+ /** Save a session by ID */
819
1033
  save(id: string, session: SerializableSession): Promise<void>;
1034
+ /** Load a session by ID */
820
1035
  load(id: string): Promise<SerializedSession | undefined>;
1036
+ /** Delete a session by ID */
821
1037
  delete(id: string): Promise<void>;
1038
+ /** List all session IDs */
822
1039
  list(): Promise<readonly string[]>;
1040
+ /** Prune sessions older than maxAgeMs, returns count pruned */
823
1041
  prune(maxAgeMs: number): Promise<number>;
824
1042
  }
825
1043
 
@@ -853,6 +1071,71 @@ export declare interface SimilarityAdapterInterface {
853
1071
  readonly name: string;
854
1072
  }
855
1073
 
1074
+ /**
1075
+ * SSE (Server-Sent Events) event structure.
1076
+ * Represents a single event from an SSE stream.
1077
+ */
1078
+ export declare interface SSEEvent {
1079
+ /** Event type (e.g., 'message', 'error') */
1080
+ readonly event?: string;
1081
+ /** Event data payload */
1082
+ readonly data: string;
1083
+ /** Event ID for resumption */
1084
+ readonly id?: string;
1085
+ /** Retry interval in milliseconds */
1086
+ readonly retry?: number;
1087
+ }
1088
+
1089
+ /**
1090
+ * SSE parser adapter interface.
1091
+ * Factory for creating SSE parser instances.
1092
+ *
1093
+ * **Used by server-side providers:**
1094
+ * - OpenAI (chat completions streaming)
1095
+ * - Anthropic (messages streaming)
1096
+ * - Other API-based providers using SSE format
1097
+ *
1098
+ * **NOT used by local providers:**
1099
+ * - Ollama (uses NDJSON, not SSE)
1100
+ * - node-llama-cpp (direct token emission)
1101
+ * - HuggingFace (TextStreamer callback)
1102
+ *
1103
+ * Implementations are in @mikesaintsg/adapters.
1104
+ */
1105
+ export declare interface SSEParserAdapterInterface {
1106
+ /** Create a new parser instance with the given options */
1107
+ createParser(options: SSEParserOptions): SSEParserInterface;
1108
+ }
1109
+
1110
+ /**
1111
+ * SSE parser interface.
1112
+ * Stateful parser that handles chunked SSE data.
1113
+ *
1114
+ * SSE is the streaming format used by server-side LLM providers
1115
+ * (OpenAI, Anthropic, and other API-based services).
1116
+ */
1117
+ export declare interface SSEParserInterface {
1118
+ /** Feed data chunk to parser */
1119
+ feed(chunk: string): void;
1120
+ /** Signal end of stream */
1121
+ end(): void;
1122
+ /** Reset parser state */
1123
+ reset(): void;
1124
+ }
1125
+
1126
+ /**
1127
+ * SSE parser options.
1128
+ * Callbacks for handling SSE stream events.
1129
+ */
1130
+ export declare interface SSEParserOptions {
1131
+ /** Called for each parsed event */
1132
+ readonly onEvent: (event: SSEEvent) => void;
1133
+ /** Called on parse error */
1134
+ readonly onError?: (error: Error) => void;
1135
+ /** Called when stream ends */
1136
+ readonly onEnd?: () => void;
1137
+ }
1138
+
856
1139
  /** Storage information (quota and usage) */
857
1140
  export declare interface StorageInfo {
858
1141
  readonly usage: number;
@@ -872,6 +1155,30 @@ export declare interface StoredDocument {
872
1155
  readonly updatedAt?: number;
873
1156
  }
874
1157
 
1158
+ /**
1159
+ * Streamer adapter interface for token emission.
1160
+ *
1161
+ * Streamers are the internal mechanism for emitting tokens during generation.
1162
+ * They bridge the gap between provider-specific streaming (SSE, local generation)
1163
+ * and the consumer-facing StreamHandleInterface.
1164
+ *
1165
+ * **Usage by provider type:**
1166
+ * - **Server-side providers** (OpenAI, Anthropic): SSE parser feeds tokens to streamer
1167
+ * - **Local providers** (Ollama, node-llama-cpp, HuggingFace): Direct token emission to streamer
1168
+ *
1169
+ * Implementations are in @mikesaintsg/adapters.
1170
+ */
1171
+ export declare interface StreamerAdapterInterface {
1172
+ /** Subscribe to token events */
1173
+ onToken(callback: (token: string) => void): Unsubscribe;
1174
+ /** Emit a token to all subscribers */
1175
+ emit(token: string): void;
1176
+ /** Signal end of streaming */
1177
+ end(): void;
1178
+ /** Signal an error during streaming */
1179
+ error?(err: Error): void;
1180
+ }
1181
+
875
1182
  /**
876
1183
  * Stream handle interface - async iteration over tokens.
877
1184
  * Provides streaming access to generation with abort control.
@@ -957,6 +1264,18 @@ export declare interface ToolCall {
957
1264
  readonly arguments: Readonly<Record<string, unknown>>;
958
1265
  }
959
1266
 
1267
+ /**
1268
+ * Tool call bridge implementation.
1269
+ * Executes tool calls against a tool registry with timeout and lifecycle hooks.
1270
+ */
1271
+ export declare class ToolCallBridge implements ToolCallBridgeInterface {
1272
+ #private;
1273
+ constructor(options: ToolCallBridgeOptions);
1274
+ execute(toolCalls: ToolCall): Promise<ToolResult>;
1275
+ execute(toolCalls: readonly ToolCall[]): Promise<readonly ToolResult[]>;
1276
+ hasTool(name: string): boolean;
1277
+ }
1278
+
960
1279
  /**
961
1280
  * Tool call bridge interface.
962
1281
  * Connects inference tool calls to contextprotocol tool registry.
@@ -1037,6 +1356,22 @@ export declare interface ToolSchema {
1037
1356
  readonly returns?: JSONSchema7;
1038
1357
  }
1039
1358
 
1359
+ /** Transition event for audit trail */
1360
+ declare interface TransitionEvent_2 {
1361
+ readonly id: string;
1362
+ readonly timestamp: number;
1363
+ readonly sessionId: string;
1364
+ readonly actor: Actor;
1365
+ readonly from: string;
1366
+ readonly to: string;
1367
+ readonly path: string;
1368
+ readonly dwell?: DwellRecord;
1369
+ readonly engagement: EngagementState;
1370
+ readonly namespace?: string;
1371
+ readonly metadata?: Readonly<Record<string, unknown>>;
1372
+ }
1373
+ export { TransitionEvent_2 as TransitionEvent }
1374
+
1040
1375
  /**
1041
1376
  * Truncation adapter interface.
1042
1377
  * Determines which frames to remove when budget is exceeded.
@@ -1130,16 +1465,21 @@ export declare interface VectorStoreMinimal<TMetadata = unknown> {
1130
1465
 
1131
1466
  /**
1132
1467
  * VectorStore persistence adapter interface.
1468
+ *
1469
+ * Extends base persistence with document and metadata storage.
1133
1470
  * Implemented by IndexedDB, OPFS, and HTTP adapters.
1134
1471
  */
1135
- export declare interface VectorStorePersistenceAdapterInterface {
1472
+ export declare interface VectorStorePersistenceAdapterInterface extends PersistenceAdapterInterface {
1473
+ /** Load all stored documents */
1136
1474
  load(): Promise<readonly StoredDocument[]>;
1475
+ /** Load store metadata (model info, counts) */
1137
1476
  loadMetadata(): Promise<VectorStoreMetadata | undefined>;
1477
+ /** Save document(s) to storage */
1138
1478
  save(docs: StoredDocument | readonly StoredDocument[]): Promise<void>;
1479
+ /** Save store metadata */
1139
1480
  saveMetadata(metadata: VectorStoreMetadata): Promise<void>;
1481
+ /** Remove document(s) by ID(s) */
1140
1482
  remove(ids: string | readonly string[]): Promise<void>;
1141
- clear(): Promise<void>;
1142
- isAvailable(): Promise<boolean>;
1143
1483
  }
1144
1484
 
1145
1485
  /** VectorStore search options */
@@ -1148,4 +1488,24 @@ export declare interface VectorStoreSearchOptions<TMetadata = unknown> {
1148
1488
  readonly filter?: TMetadata;
1149
1489
  }
1150
1490
 
1491
+ /**
1492
+ * Weight persistence adapter interface.
1493
+ *
1494
+ * Extends base persistence with weight-specific storage operations.
1495
+ * Persists predictive graph weights for cold-start optimization.
1496
+ * Implementations: IndexedDB, OPFS, HTTP, in-memory.
1497
+ */
1498
+ export declare interface WeightPersistenceAdapterInterface extends PersistenceAdapterInterface {
1499
+ /** Save weights snapshot */
1500
+ save(weights: ExportedPredictiveGraph): Promise<void>;
1501
+ /** Load weights by model ID */
1502
+ load(modelId: string): Promise<ExportedPredictiveGraph | undefined>;
1503
+ /** Check if weights exist for model */
1504
+ has(modelId: string): Promise<boolean>;
1505
+ /** Delete weights for model */
1506
+ delete(modelId: string): Promise<void>;
1507
+ /** List all stored model IDs */
1508
+ list(): Promise<readonly string[]>;
1509
+ }
1510
+
1151
1511
  export { }
package/dist/index.js CHANGED
@@ -1,237 +1,261 @@
1
- class A extends Error {
2
- /** Original error that caused this one */
3
- cause;
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 b(e) {
9
- return e instanceof A;
5
+ function d(r) {
6
+ return { ok: !1, error: r };
10
7
  }
11
- function S(e) {
12
- return { ok: !0, value: e };
8
+ function S(r) {
9
+ return r.ok;
13
10
  }
14
- function I(e) {
15
- return { ok: !1, error: e };
11
+ function L(r) {
12
+ return !r.ok;
16
13
  }
17
- function F(e) {
18
- return e.ok === !0;
14
+ function R(r, e) {
15
+ return r.ok ? r.value : e;
19
16
  }
20
- function P(e) {
21
- return !e.ok;
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 q(e, t) {
24
- return e.ok ? e.value : t;
22
+ function M(r, e) {
23
+ return r.ok ? m(e(r.value)) : r;
25
24
  }
26
- function U(e) {
27
- if (e.ok)
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 B(e, t) {
32
- return e.ok ? S(t(e.value)) : e;
28
+ function D(r, e) {
29
+ return r.ok ? e(r.value) : r;
33
30
  }
34
- function G(e, t) {
35
- return e.ok ? e : I(t(e.error));
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 O(e, t) {
38
- return e.ok ? t(e.value) : e;
35
+ function f(r) {
36
+ return typeof r == "object" && r !== null && "id" in r && "name" in r && "arguments" in r;
39
37
  }
40
- async function $(e) {
41
- const s = new TextEncoder().encode(e), a = await crypto.subtle.digest("SHA-256", s);
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 k(e) {
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: e.content,
53
- score: e.score,
54
- metadata: e.metadata
43
+ content: r.content,
44
+ score: r.score,
45
+ metadata: r.metadata
55
46
  };
56
47
  }
57
- const R = 3e4, L = 10, _ = 100, D = "You have unsaved changes. Are you sure you want to leave?";
58
- function j(e) {
59
- const {
60
- registry: t,
61
- timeout: s = R,
62
- onError: a,
63
- onBeforeExecute: c,
64
- onAfterExecute: o
65
- } = e;
66
- async function u(r) {
67
- if (!t.has(r.name))
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: r.id,
70
- name: r.name,
68
+ callId: e.id,
69
+ name: e.name,
71
70
  success: !1,
72
- error: `Tool not found: ${r.name}`
71
+ error: `Tool not found: ${e.name}`
73
72
  };
74
- c?.(r);
73
+ this.#n?.(e);
75
74
  try {
76
- const n = new Promise((f, m) => {
75
+ const t = new Promise((i, s) => {
77
76
  setTimeout(() => {
78
- m(new Error(`Tool execution timed out after ${s}ms`));
79
- }, s);
80
- }), i = await Promise.race([
81
- t.execute(r.name, r.arguments),
82
- n
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 o?.(r, i), {
85
- callId: r.id,
86
- name: r.name,
83
+ return this.#s?.(e, n), {
84
+ callId: e.id,
85
+ name: e.name,
87
86
  success: !0,
88
- value: i
87
+ value: n
89
88
  };
90
- } catch (n) {
91
- a?.(n, r);
92
- const i = n instanceof Error ? n.message : String(n);
89
+ } catch (t) {
90
+ this.#t?.(t, e);
91
+ const n = t instanceof Error ? t.message : String(t);
93
92
  return {
94
- callId: r.id,
95
- name: r.name,
93
+ callId: e.id,
94
+ name: e.name,
96
95
  success: !1,
97
- error: i
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
- function H(e) {
113
- const {
114
- vectorStore: t,
115
- name: s,
116
- description: a,
117
- defaultLimit: c = L,
118
- maxLimit: o = _,
119
- scoreThreshold: u,
120
- formatResult: r = M,
121
- extendParameters: n = {},
122
- buildFilter: i
123
- } = e, f = {
124
- type: "object",
125
- properties: {
126
- query: {
127
- type: "string",
128
- description: "The search query to find relevant documents"
129
- },
130
- limit: {
131
- type: "integer",
132
- description: `Maximum number of results to return (default: ${c}, max: ${o})`,
133
- minimum: 1,
134
- maximum: o,
135
- default: c
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
- ...n
138
- },
139
- required: ["query"]
140
- }, m = {
141
- name: s,
142
- description: a,
143
- parameters: f
144
- };
145
- async function d(h) {
146
- const y = h.query;
147
- if (typeof y != "string" || y.length === 0)
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 p = h.limit;
150
- let E = c;
151
- typeof p == "number" && Number.isInteger(p) && (E = Math.min(Math.max(1, p), o));
152
- const w = i?.(h), v = w !== void 0 ? { limit: E, filter: w } : { limit: E }, g = await t.search(y, v);
153
- let T = g;
154
- return u !== void 0 && (T = g.filter((x) => x.score >= u)), T.map(r);
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
- function V(e) {
171
- const {
172
- database: t,
173
- storeName: s,
174
- autoprune: a,
175
- onSaveError: c
176
- } = e, o = t.store(s);
177
- async function u(r) {
178
- const i = Date.now() - r, f = await o.all();
179
- let m = 0;
180
- for (const d of f)
181
- d.updatedAt < i && (await o.remove(d.id), m++);
182
- return m;
183
- }
184
- return a !== void 0 && a > 0 && u(a), {
185
- async save(r, n) {
186
- try {
187
- const i = {
188
- id: r,
189
- messages: [...n.getMessages()],
190
- metadata: n.getMetadata(),
191
- updatedAt: Date.now()
192
- };
193
- await o.set(i, r);
194
- } catch (i) {
195
- throw c?.(i, r), i;
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
- R as BRIDGE_DEFAULT_TIMEOUT,
214
- A as EcosystemError,
215
- D as FORM_DIRTY_DEFAULT_MESSAGE,
216
- L as RETRIEVAL_DEFAULT_LIMIT,
217
- _ as RETRIEVAL_MAX_LIMIT,
218
- O as chain,
219
- $ as computeContentHash,
220
- N as createFormDirtyGuard,
221
- H as createRetrievalTool,
222
- V as createSessionPersistence,
223
- j as createToolCallBridge,
224
- I as err,
225
- M as formatScoredResult,
226
- b as isEcosystemError,
227
- P as isErr,
228
- F as isOk,
229
- k as isToolCall,
230
- B as map,
231
- G as mapErr,
232
- S as ok,
233
- l as shouldSkipFormGuard,
234
- q as unwrap,
235
- U as unwrapOrThrow
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":"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"}
package/package.json CHANGED
@@ -1,13 +1,15 @@
1
1
  {
2
2
  "name": "@mikesaintsg/core",
3
- "version": "0.0.4",
3
+ "version": "0.0.5",
4
4
  "type": "module",
5
- "description": "Type-safe FileSystem wrapper with full TypeScript support. Zero runtime dependencies.",
5
+ "description": "Shared types, contracts, and bridge functions for the @mikesaintsg ecosystem. Zero runtime dependencies.",
6
6
  "keywords": [
7
7
  "typescript",
8
- "browser",
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.0",
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",