crann 1.0.49 → 2.0.2

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.
Files changed (53) hide show
  1. package/README.md +353 -594
  2. package/dist/cjs/index.js +2 -2
  3. package/dist/cjs/index.js.map +4 -4
  4. package/dist/cjs/react.js +2 -0
  5. package/dist/cjs/react.js.map +7 -0
  6. package/dist/esm/index.js +2 -2
  7. package/dist/esm/index.js.map +4 -4
  8. package/dist/esm/react.js +2 -0
  9. package/dist/esm/react.js.map +7 -0
  10. package/dist/types/__mocks__/uuid.d.ts +10 -0
  11. package/dist/types/__tests__/integration.test.d.ts +7 -0
  12. package/dist/types/agent/Agent.d.ts +77 -0
  13. package/dist/types/agent/__tests__/Agent.test.d.ts +1 -0
  14. package/dist/types/agent/__tests__/setup.d.ts +4 -0
  15. package/dist/types/agent/index.d.ts +7 -0
  16. package/dist/types/agent/types.d.ts +73 -0
  17. package/dist/types/crann.d.ts +1 -2
  18. package/dist/types/errors.d.ts +59 -0
  19. package/dist/types/model/crann.model.d.ts +1 -1
  20. package/dist/types/react/__tests__/hooks.test.d.ts +6 -0
  21. package/dist/types/react/hooks.d.ts +44 -0
  22. package/dist/types/react/index.d.ts +13 -0
  23. package/dist/types/react/types.d.ts +74 -0
  24. package/dist/types/rpc/adapter.d.ts +1 -1
  25. package/dist/types/rpc/types.d.ts +1 -1
  26. package/dist/types/store/ActionExecutor.d.ts +35 -0
  27. package/dist/types/store/AgentRegistry.d.ts +49 -0
  28. package/dist/types/store/Persistence.d.ts +59 -0
  29. package/dist/types/store/StateManager.d.ts +65 -0
  30. package/dist/types/store/Store.d.ts +188 -0
  31. package/dist/types/store/__tests__/ActionExecutor.test.d.ts +1 -0
  32. package/dist/types/store/__tests__/AgentRegistry.test.d.ts +1 -0
  33. package/dist/types/store/__tests__/Persistence.test.d.ts +6 -0
  34. package/dist/types/store/__tests__/StateManager.test.d.ts +1 -0
  35. package/dist/types/store/__tests__/setup.d.ts +4 -0
  36. package/dist/types/store/__tests__/types.test.d.ts +1 -0
  37. package/dist/types/store/index.d.ts +10 -0
  38. package/dist/types/store/types.d.ts +169 -0
  39. package/dist/types/transport/core/PorterAgent.d.ts +46 -0
  40. package/dist/types/transport/core/PorterSource.d.ts +40 -0
  41. package/dist/types/transport/index.d.ts +6 -0
  42. package/dist/types/transport/managers/AgentConnectionManager.d.ts +42 -0
  43. package/dist/types/transport/managers/AgentManager.d.ts +40 -0
  44. package/dist/types/transport/managers/AgentMessageHandler.d.ts +17 -0
  45. package/dist/types/transport/managers/ConnectionManager.d.ts +14 -0
  46. package/dist/types/transport/managers/MessageHandler.d.ts +29 -0
  47. package/dist/types/transport/managers/MessageQueue.d.ts +19 -0
  48. package/dist/types/transport/porter.model.d.ts +71 -0
  49. package/dist/types/transport/porter.utils.d.ts +44 -0
  50. package/dist/types/transport/react/index.d.ts +1 -0
  51. package/dist/types/transport/react/usePorter.d.ts +17 -0
  52. package/dist/types/utils/agent.d.ts +1 -1
  53. package/package.json +28 -2
@@ -0,0 +1,59 @@
1
+ /**
2
+ * Crann Error Classes
3
+ *
4
+ * Custom error types for better debugging and error handling.
5
+ */
6
+ /**
7
+ * Base error class for all Crann errors.
8
+ */
9
+ export declare class CrannError extends Error {
10
+ constructor(message: string);
11
+ }
12
+ /**
13
+ * Thrown when there's an issue with the config schema.
14
+ */
15
+ export declare class ConfigError extends CrannError {
16
+ readonly field?: string | undefined;
17
+ constructor(message: string, field?: string | undefined);
18
+ }
19
+ /**
20
+ * Thrown when a store or agent has been destroyed/disconnected.
21
+ */
22
+ export declare class LifecycleError extends CrannError {
23
+ readonly storeName: string;
24
+ readonly entity: "store" | "agent";
25
+ constructor(storeName: string, entity: "store" | "agent");
26
+ }
27
+ /**
28
+ * Thrown when there's a connection issue.
29
+ */
30
+ export declare class ConnectionError extends CrannError {
31
+ readonly storeName: string;
32
+ readonly reason?: string | undefined;
33
+ constructor(message: string, storeName: string, reason?: string | undefined);
34
+ }
35
+ /**
36
+ * Thrown when an action execution fails.
37
+ */
38
+ export declare class ActionError extends CrannError {
39
+ readonly actionName: string;
40
+ readonly storeName: string;
41
+ readonly reason: string;
42
+ constructor(actionName: string, storeName: string, reason: string);
43
+ }
44
+ /**
45
+ * Thrown when action validation fails.
46
+ */
47
+ export declare class ValidationError extends CrannError {
48
+ readonly actionName: string;
49
+ readonly storeName: string;
50
+ readonly reason: string;
51
+ constructor(actionName: string, storeName: string, reason: string);
52
+ }
53
+ /**
54
+ * Thrown when there's a storage key collision.
55
+ */
56
+ export declare class StorageCollisionError extends CrannError {
57
+ readonly storeName: string;
58
+ constructor(storeName: string);
59
+ }
@@ -1,4 +1,4 @@
1
- import { AgentInfo, BrowserLocation } from "porter-source";
1
+ import { AgentInfo, BrowserLocation } from "../transport";
2
2
  export declare const Partition: {
3
3
  Instance: "instance";
4
4
  Service: "service";
@@ -0,0 +1,6 @@
1
+ /**
2
+ * React Hooks Tests
3
+ *
4
+ * Tests for the Crann React integration hooks.
5
+ */
6
+ export {};
@@ -0,0 +1,44 @@
1
+ /**
2
+ * Crann React Hooks Implementation
3
+ *
4
+ * Provides React hooks for connecting to and using a Crann store.
5
+ */
6
+ import type { ConfigSchema, ValidatedConfig } from "../store/types";
7
+ import type { CrannHooks, CreateCrannHooksOptions } from "./types";
8
+ /**
9
+ * Creates a set of React hooks for a Crann store.
10
+ *
11
+ * This is the main entry point for React integration. Call once at module
12
+ * level with your config, then use the returned hooks in your components.
13
+ *
14
+ * @param config - Validated config from createConfig()
15
+ * @param options - Optional hook options
16
+ * @returns Object containing all Crann React hooks
17
+ *
18
+ * @example
19
+ * // hooks.ts
20
+ * import { createConfig } from 'crann';
21
+ * import { createCrannHooks } from 'crann/react';
22
+ *
23
+ * const config = createConfig({
24
+ * name: 'myFeature',
25
+ * count: { default: 0 },
26
+ * actions: {
27
+ * increment: { handler: async (ctx) => ctx.setState({ count: ctx.state.count + 1 }) },
28
+ * },
29
+ * });
30
+ *
31
+ * export const { useCrannState, useCrannActions, useCrannReady } = createCrannHooks(config);
32
+ *
33
+ * // MyComponent.tsx
34
+ * function Counter() {
35
+ * const count = useCrannState(s => s.count);
36
+ * const { increment } = useCrannActions();
37
+ * const isReady = useCrannReady();
38
+ *
39
+ * if (!isReady) return <div>Loading...</div>;
40
+ *
41
+ * return <button onClick={() => increment()}>Count: {count}</button>;
42
+ * }
43
+ */
44
+ export declare function createCrannHooks<TConfig extends ConfigSchema>(config: ValidatedConfig<TConfig>, options?: CreateCrannHooksOptions): CrannHooks<TConfig>;
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Crann React Integration
3
+ *
4
+ * Provides React hooks for connecting to and using a Crann store.
5
+ *
6
+ * @example
7
+ * import { createCrannHooks } from 'crann/react';
8
+ * import { config } from './config';
9
+ *
10
+ * export const { useCrannState, useCrannActions, useCrannReady } = createCrannHooks(config);
11
+ */
12
+ export { createCrannHooks } from "./hooks";
13
+ export type { CrannHooks, CreateCrannHooksOptions, UseCrannStateSelector, UseCrannStateTuple, } from "./types";
@@ -0,0 +1,74 @@
1
+ /**
2
+ * Crann React Integration Types
3
+ */
4
+ import type { ConfigSchema, DerivedState, DerivedActions } from "../store/types";
5
+ import type { AgentAPI } from "../agent/types";
6
+ /**
7
+ * Return type of the useCrannState hook when using a selector.
8
+ */
9
+ export type UseCrannStateSelector<TConfig extends ConfigSchema, TSelected> = TSelected;
10
+ /**
11
+ * Return type of the useCrannState hook when using a key.
12
+ * Returns [value, setValue] tuple like useState.
13
+ */
14
+ export type UseCrannStateTuple<TConfig extends ConfigSchema, K extends keyof DerivedState<TConfig>> = [
15
+ DerivedState<TConfig>[K],
16
+ (value: DerivedState<TConfig>[K]) => Promise<void>
17
+ ];
18
+ /**
19
+ * Options for creating Crann hooks.
20
+ */
21
+ export type CreateCrannHooksOptions = {
22
+ /** Enable debug logging */
23
+ debug?: boolean;
24
+ };
25
+ /**
26
+ * The hooks object returned by createCrannHooks.
27
+ */
28
+ export interface CrannHooks<TConfig extends ConfigSchema> {
29
+ /**
30
+ * Hook to read state with a selector function.
31
+ * Re-renders only when selected value changes.
32
+ *
33
+ * @example
34
+ * const count = useCrannState(s => s.count);
35
+ */
36
+ useCrannState<TSelected>(selector: (state: DerivedState<TConfig>) => TSelected): TSelected;
37
+ /**
38
+ * Hook to read and write a specific state key.
39
+ * Returns [value, setValue] tuple like useState.
40
+ *
41
+ * @example
42
+ * const [count, setCount] = useCrannState('count');
43
+ */
44
+ useCrannState<K extends keyof DerivedState<TConfig>>(key: K): UseCrannStateTuple<TConfig, K>;
45
+ /**
46
+ * Hook to get typed action methods.
47
+ * Actions are stable references that won't cause re-renders.
48
+ *
49
+ * @example
50
+ * const { increment, fetchUser } = useCrannActions();
51
+ */
52
+ useCrannActions(): DerivedActions<TConfig>;
53
+ /**
54
+ * Hook to check connection status.
55
+ * Re-renders when connection status changes.
56
+ *
57
+ * @example
58
+ * const isReady = useCrannReady();
59
+ * if (!isReady) return <Loading />;
60
+ */
61
+ useCrannReady(): boolean;
62
+ /**
63
+ * Optional provider for dependency injection (useful for testing).
64
+ * Not required for normal usage.
65
+ */
66
+ CrannProvider: React.FC<{
67
+ agent?: AgentAPI<TConfig>;
68
+ children: React.ReactNode;
69
+ }>;
70
+ /**
71
+ * Get the current agent instance (for advanced usage).
72
+ */
73
+ useAgent(): AgentAPI<TConfig> | null;
74
+ }
@@ -1,3 +1,3 @@
1
- import { source, connect } from "porter-source";
1
+ import { source, connect } from "../transport";
2
2
  import { ActionDefinition, AnyConfig, DerivedState, SetStateFunction } from "../model/crann.model";
3
3
  export declare function createCrannRPCAdapter<TConfig extends AnyConfig>(stateGetter: () => DerivedState<TConfig>, actions: Record<string, ActionDefinition<DerivedState<TConfig>, any[], any>>, porter?: ReturnType<typeof source> | ReturnType<typeof connect>, setState?: SetStateFunction<DerivedState<TConfig>>): import("./types").RemoteCallable<Record<string, ActionDefinition<DerivedState<TConfig>, any[], any>>>;
@@ -1,4 +1,4 @@
1
- import { BrowserLocation } from "porter-source";
1
+ import { BrowserLocation } from "../transport";
2
2
  export type MessageMap = {
3
3
  call: {
4
4
  id: string;
@@ -0,0 +1,35 @@
1
+ /**
2
+ * ActionExecutor - Executes RPC actions
3
+ *
4
+ * Responsibilities:
5
+ * - Execute action handlers with context object
6
+ * - Validate action arguments
7
+ * - Handle errors
8
+ */
9
+ import type { AgentInfo } from "../transport";
10
+ import { ConfigSchema, ValidatedConfig, DerivedState } from "./types";
11
+ export declare class ActionExecutor<TConfig extends ConfigSchema> {
12
+ private readonly config;
13
+ private readonly getState;
14
+ private readonly setState;
15
+ constructor(config: ValidatedConfig<TConfig>, getState: () => DerivedState<TConfig>, setState: (state: Partial<DerivedState<TConfig>>, agentId: string) => Promise<void>);
16
+ /**
17
+ * Execute an action by name.
18
+ *
19
+ * @param actionName - The name of the action to execute
20
+ * @param args - Arguments to pass to the action handler
21
+ * @param agentInfo - Info about the calling agent
22
+ * @returns The result of the action handler
23
+ * @throws {ActionError} If the action doesn't exist or fails
24
+ * @throws {ValidationError} If action validation fails
25
+ */
26
+ execute(actionName: string, args: unknown[], agentInfo: AgentInfo): Promise<unknown>;
27
+ /**
28
+ * Check if an action exists.
29
+ */
30
+ hasAction(actionName: string): boolean;
31
+ /**
32
+ * Get list of available action names.
33
+ */
34
+ getActionNames(): string[];
35
+ }
@@ -0,0 +1,49 @@
1
+ /**
2
+ * AgentRegistry - Tracks connected agents
3
+ *
4
+ * Responsibilities:
5
+ * - Maintain registry of connected agents
6
+ * - Provide query capabilities
7
+ * - Clean up on disconnect
8
+ */
9
+ import type { AgentInfo } from "../transport";
10
+ import { AgentConnectionInfo } from "./types";
11
+ export declare class AgentRegistry {
12
+ private readonly agents;
13
+ /**
14
+ * Register a new agent connection.
15
+ */
16
+ add(agentInfo: AgentInfo): AgentConnectionInfo;
17
+ /**
18
+ * Unregister an agent.
19
+ */
20
+ remove(agentId: string): boolean;
21
+ /**
22
+ * Get agent info by ID.
23
+ */
24
+ get(agentId: string): AgentConnectionInfo | undefined;
25
+ /**
26
+ * Get all connected agents.
27
+ */
28
+ getAll(): AgentConnectionInfo[];
29
+ /**
30
+ * Query agents by criteria.
31
+ */
32
+ query(criteria: {
33
+ context?: string;
34
+ tabId?: number;
35
+ frameId?: number;
36
+ }): AgentConnectionInfo[];
37
+ /**
38
+ * Check if an agent is registered.
39
+ */
40
+ has(agentId: string): boolean;
41
+ /**
42
+ * Get the number of connected agents.
43
+ */
44
+ get size(): number;
45
+ /**
46
+ * Clear all agents.
47
+ */
48
+ clear(): void;
49
+ }
@@ -0,0 +1,59 @@
1
+ /**
2
+ * Persistence - Handles chrome.storage operations
3
+ *
4
+ * Responsibilities:
5
+ * - Hydrate state from storage on startup
6
+ * - Persist state changes to storage
7
+ * - Manage storage key structure: crann:{name}:v{version}:{key}
8
+ */
9
+ import { ConfigSchema, ValidatedConfig, DerivedSharedState, StoreOptions } from "./types";
10
+ export declare class Persistence<TConfig extends ConfigSchema> {
11
+ private readonly config;
12
+ private readonly options;
13
+ constructor(config: ValidatedConfig<TConfig>, options?: StoreOptions);
14
+ /**
15
+ * Build a storage key with the structured format.
16
+ * Format: crann:{name}:v{version}:{key}
17
+ */
18
+ private buildKey;
19
+ /**
20
+ * Parse a storage key to extract components.
21
+ */
22
+ private parseKey;
23
+ /**
24
+ * Get the metadata key for this store.
25
+ * Format: crann:{name}:__meta
26
+ */
27
+ private getMetaKey;
28
+ /**
29
+ * Hydrate state from chrome.storage.
30
+ * Only loads keys that exist in the current config.
31
+ */
32
+ hydrate(): Promise<Partial<DerivedSharedState<TConfig>>>;
33
+ /**
34
+ * Persist state changes to storage.
35
+ * Only persists keys with persist: 'local' or 'session'.
36
+ */
37
+ persist(state: Partial<DerivedSharedState<TConfig>>): Promise<void>;
38
+ /**
39
+ * Clear all persisted data for this store.
40
+ */
41
+ clearAll(): Promise<void>;
42
+ private updateMetadata;
43
+ }
44
+ /**
45
+ * Find and remove orphaned Crann data from storage.
46
+ *
47
+ * @example
48
+ * const removed = await clearOrphanedData({
49
+ * keepStores: ['myFeature', 'otherStore'],
50
+ * dryRun: true,
51
+ * });
52
+ */
53
+ export declare function clearOrphanedData(options: {
54
+ keepStores: string[];
55
+ dryRun?: boolean;
56
+ }): Promise<{
57
+ keys: string[];
58
+ count: number;
59
+ }>;
@@ -0,0 +1,65 @@
1
+ /**
2
+ * StateManager - Handles in-memory state operations
3
+ *
4
+ * Responsibilities:
5
+ * - Maintain shared state and per-agent state
6
+ * - Handle state updates with change detection
7
+ * - Initialize default values from config
8
+ */
9
+ import { ConfigSchema, ValidatedConfig, DerivedState, DerivedSharedState, DerivedAgentState } from "./types";
10
+ import { Persistence } from "./Persistence";
11
+ export declare class StateManager<TConfig extends ConfigSchema> {
12
+ private readonly config;
13
+ private readonly persistence;
14
+ private sharedState;
15
+ private readonly agentStates;
16
+ private readonly defaultSharedState;
17
+ private readonly defaultAgentState;
18
+ constructor(config: ValidatedConfig<TConfig>, persistence: Persistence<TConfig>);
19
+ /**
20
+ * Get the full derived state (shared only, from store perspective).
21
+ */
22
+ getState(): DerivedState<TConfig>;
23
+ /**
24
+ * Get shared state only.
25
+ */
26
+ getSharedState(): DerivedSharedState<TConfig>;
27
+ /**
28
+ * Get agent-scoped state for a specific agent.
29
+ */
30
+ getAgentState(agentId: string): DerivedAgentState<TConfig>;
31
+ /**
32
+ * Get full state for an agent (shared + agent-scoped).
33
+ */
34
+ getFullStateForAgent(agentId: string): DerivedState<TConfig>;
35
+ /**
36
+ * Update state, separating shared and agent-scoped changes.
37
+ * Returns the changes that were actually applied.
38
+ */
39
+ setState(state: Partial<DerivedState<TConfig>>, agentId?: string): {
40
+ sharedChanges: Partial<DerivedSharedState<TConfig>>;
41
+ agentChanges: Partial<DerivedAgentState<TConfig>>;
42
+ };
43
+ /**
44
+ * Update agent-scoped state only.
45
+ */
46
+ setAgentState(agentId: string, state: Partial<DerivedAgentState<TConfig>>): void;
47
+ /**
48
+ * Hydrate shared state from storage.
49
+ */
50
+ hydrateSharedState(state: Partial<DerivedSharedState<TConfig>>): void;
51
+ /**
52
+ * Initialize state for a new agent.
53
+ */
54
+ initializeAgentState(agentId: string): void;
55
+ /**
56
+ * Remove state for a disconnected agent.
57
+ */
58
+ removeAgentState(agentId: string): void;
59
+ /**
60
+ * Clear all state back to defaults.
61
+ */
62
+ clear(): void;
63
+ private buildDefaultSharedState;
64
+ private buildDefaultAgentState;
65
+ }
@@ -0,0 +1,188 @@
1
+ /**
2
+ * Crann v2 Store
3
+ *
4
+ * The central state hub that runs in the service worker.
5
+ * This is NOT a singleton - each call to createStore() returns a new instance.
6
+ */
7
+ import type { BrowserLocation } from "../transport";
8
+ import { ConfigSchema, ValidatedConfig, StoreOptions, DerivedState, DerivedSharedState, DerivedAgentState, StateChangeListener, AgentConnectionInfo } from "./types";
9
+ export declare class Store<TConfig extends ConfigSchema> {
10
+ private readonly config;
11
+ private readonly options;
12
+ private readonly porter;
13
+ private readonly stateManager;
14
+ private readonly persistence;
15
+ private readonly agentRegistry;
16
+ private readonly actionExecutor;
17
+ private readonly stateChangeListeners;
18
+ private readonly agentConnectListeners;
19
+ private readonly agentDisconnectListeners;
20
+ private isDestroyed;
21
+ constructor(config: ValidatedConfig<TConfig>, options?: StoreOptions);
22
+ /**
23
+ * Get the current shared state (state visible to all agents).
24
+ *
25
+ * @returns A snapshot of the current shared state
26
+ * @throws {LifecycleError} If the store has been destroyed
27
+ *
28
+ * @example
29
+ * const state = store.getState();
30
+ * console.log(state.count);
31
+ */
32
+ getState(): DerivedState<TConfig>;
33
+ /**
34
+ * Get agent-scoped state for a specific agent.
35
+ *
36
+ * @param agentId - The unique identifier of the agent
37
+ * @returns The agent-scoped state for the specified agent
38
+ * @throws {LifecycleError} If the store has been destroyed
39
+ *
40
+ * @example
41
+ * store.onAgentConnect((agent) => {
42
+ * const agentState = store.getAgentState(agent.id);
43
+ * });
44
+ */
45
+ getAgentState(agentId: string): DerivedAgentState<TConfig>;
46
+ /**
47
+ * Update shared state. Changes are persisted and broadcast to all agents.
48
+ *
49
+ * @param state - Partial state to merge with current shared state
50
+ * @throws {LifecycleError} If the store has been destroyed
51
+ *
52
+ * @example
53
+ * await store.setState({ count: 5 });
54
+ */
55
+ setState(state: Partial<DerivedSharedState<TConfig>>): Promise<void>;
56
+ /**
57
+ * Update state for a specific agent. Can include both shared and agent-scoped state.
58
+ *
59
+ * @param state - Partial state to merge
60
+ * @param agentId - The agent to update (for agent-scoped state)
61
+ * @throws {LifecycleError} If the store has been destroyed
62
+ *
63
+ * @example
64
+ * await store.setState({ count: 5, agentData: 'custom' }, agentId);
65
+ */
66
+ setState(state: Partial<DerivedState<TConfig>>, agentId: string): Promise<void>;
67
+ /**
68
+ * Update agent-scoped state for a specific agent.
69
+ *
70
+ * @param agentId - The unique identifier of the agent
71
+ * @param state - Partial agent-scoped state to merge
72
+ * @throws {LifecycleError} If the store has been destroyed
73
+ *
74
+ * @example
75
+ * await store.setAgentState(agentId, { agentData: 'custom' });
76
+ */
77
+ setAgentState(agentId: string, state: Partial<DerivedAgentState<TConfig>>): Promise<void>;
78
+ /**
79
+ * Clear all state back to defaults and remove persisted data.
80
+ *
81
+ * @throws {LifecycleError} If the store has been destroyed
82
+ *
83
+ * @example
84
+ * await store.clear();
85
+ */
86
+ clear(): Promise<void>;
87
+ /**
88
+ * Subscribe to state changes. Called whenever state is updated.
89
+ *
90
+ * @param listener - Callback receiving (state, changes, agent?)
91
+ * @returns Unsubscribe function
92
+ * @throws {LifecycleError} If the store has been destroyed
93
+ *
94
+ * @example
95
+ * const unsubscribe = store.subscribe((state, changes, agent) => {
96
+ * console.log('State changed:', changes);
97
+ * });
98
+ * // Later: unsubscribe();
99
+ */
100
+ subscribe(listener: StateChangeListener<TConfig>): () => void;
101
+ /**
102
+ * Register callback for when an agent connects.
103
+ *
104
+ * @param callback - Called with agent connection info
105
+ * @returns Unsubscribe function
106
+ * @throws {LifecycleError} If the store has been destroyed
107
+ *
108
+ * @example
109
+ * store.onAgentConnect((agent) => {
110
+ * console.log(`Agent ${agent.id} connected from tab ${agent.tabId}`);
111
+ * });
112
+ */
113
+ onAgentConnect(callback: (agent: AgentConnectionInfo) => void): () => void;
114
+ /**
115
+ * Register callback for when an agent disconnects.
116
+ *
117
+ * @param callback - Called with agent connection info
118
+ * @returns Unsubscribe function
119
+ * @throws {LifecycleError} If the store has been destroyed
120
+ *
121
+ * @example
122
+ * store.onAgentDisconnect((agent) => {
123
+ * console.log(`Agent ${agent.id} disconnected`);
124
+ * });
125
+ */
126
+ onAgentDisconnect(callback: (agent: AgentConnectionInfo) => void): () => void;
127
+ /**
128
+ * Get all connected agents, optionally filtered by location.
129
+ *
130
+ * @param query - Optional filter by context, tabId, frameId
131
+ * @returns Array of connected agent info
132
+ * @throws {LifecycleError} If the store has been destroyed
133
+ *
134
+ * @example
135
+ * const allAgents = store.getAgents();
136
+ * const contentScripts = store.getAgents({ context: 'contentscript' });
137
+ * const tab42Agents = store.getAgents({ tabId: 42 });
138
+ */
139
+ getAgents(query?: Partial<BrowserLocation>): AgentConnectionInfo[];
140
+ /**
141
+ * Destroy the store and clean up all resources.
142
+ * After calling this, the store cannot be used. Use for testing or HMR cleanup.
143
+ *
144
+ * @param options.clearPersisted - If true, also clears persisted storage data
145
+ *
146
+ * @example
147
+ * // In tests
148
+ * afterEach(() => {
149
+ * store.destroy({ clearPersisted: true });
150
+ * });
151
+ */
152
+ destroy(options?: {
153
+ clearPersisted?: boolean;
154
+ }): void;
155
+ private setupMessageHandlers;
156
+ private setupRpcHandlers;
157
+ private hydrate;
158
+ private notifyStateChange;
159
+ private assertNotDestroyed;
160
+ }
161
+ /**
162
+ * Create a new Crann store instance.
163
+ *
164
+ * This should be called in your service worker/background script.
165
+ * Each call creates a new, independent store instance (no singleton).
166
+ *
167
+ * @param config - Validated config from createConfig()
168
+ * @param options - Optional store options
169
+ * @param options.debug - Enable debug logging
170
+ * @param options.migrate - Migration function for schema version changes
171
+ * @returns A new Store instance
172
+ *
173
+ * @example
174
+ * // background.ts
175
+ * import { createConfig, createStore } from 'crann';
176
+ *
177
+ * const config = createConfig({
178
+ * name: 'myFeature',
179
+ * count: { default: 0, persist: 'local' },
180
+ * });
181
+ *
182
+ * const store = createStore(config, { debug: true });
183
+ *
184
+ * store.subscribe((state, changes) => {
185
+ * console.log('State changed:', changes);
186
+ * });
187
+ */
188
+ export declare function createStore<TConfig extends ConfigSchema>(config: ValidatedConfig<TConfig>, options?: StoreOptions): Store<TConfig>;
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Persistence Tests
3
+ *
4
+ * Tests for the Persistence module which handles chrome.storage operations.
5
+ */
6
+ export {};
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,4 @@
1
+ /**
2
+ * Jest setup for store tests
3
+ * Mocks browser extension APIs
4
+ */
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Crann v2 Store Module
3
+ *
4
+ * This module provides the new Store implementation for v2.
5
+ */
6
+ export { Store, createStore } from "./Store";
7
+ export { createConfig } from "./types";
8
+ export { clearOrphanedData } from "./Persistence";
9
+ export type { ConfigSchema, ValidatedConfig, StateItemDefinition, ActionDefinition, ActionsDefinition, ActionContext, ActionHandler, DerivedState, DerivedSharedState, DerivedAgentState, DerivedActions, StateChanges, StateChangeListener, StoreOptions, AgentOptions, ConnectionStatus, AgentConnectionInfo, ScopeType, PersistType, } from "./types";
10
+ export { Scope, Persist } from "./types";