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.
- package/README.md +353 -594
- package/dist/cjs/index.js +2 -2
- package/dist/cjs/index.js.map +4 -4
- package/dist/cjs/react.js +2 -0
- package/dist/cjs/react.js.map +7 -0
- package/dist/esm/index.js +2 -2
- package/dist/esm/index.js.map +4 -4
- package/dist/esm/react.js +2 -0
- package/dist/esm/react.js.map +7 -0
- package/dist/types/__mocks__/uuid.d.ts +10 -0
- package/dist/types/__tests__/integration.test.d.ts +7 -0
- package/dist/types/agent/Agent.d.ts +77 -0
- package/dist/types/agent/__tests__/Agent.test.d.ts +1 -0
- package/dist/types/agent/__tests__/setup.d.ts +4 -0
- package/dist/types/agent/index.d.ts +7 -0
- package/dist/types/agent/types.d.ts +73 -0
- package/dist/types/crann.d.ts +1 -2
- package/dist/types/errors.d.ts +59 -0
- package/dist/types/model/crann.model.d.ts +1 -1
- package/dist/types/react/__tests__/hooks.test.d.ts +6 -0
- package/dist/types/react/hooks.d.ts +44 -0
- package/dist/types/react/index.d.ts +13 -0
- package/dist/types/react/types.d.ts +74 -0
- package/dist/types/rpc/adapter.d.ts +1 -1
- package/dist/types/rpc/types.d.ts +1 -1
- package/dist/types/store/ActionExecutor.d.ts +35 -0
- package/dist/types/store/AgentRegistry.d.ts +49 -0
- package/dist/types/store/Persistence.d.ts +59 -0
- package/dist/types/store/StateManager.d.ts +65 -0
- package/dist/types/store/Store.d.ts +188 -0
- package/dist/types/store/__tests__/ActionExecutor.test.d.ts +1 -0
- package/dist/types/store/__tests__/AgentRegistry.test.d.ts +1 -0
- package/dist/types/store/__tests__/Persistence.test.d.ts +6 -0
- package/dist/types/store/__tests__/StateManager.test.d.ts +1 -0
- package/dist/types/store/__tests__/setup.d.ts +4 -0
- package/dist/types/store/__tests__/types.test.d.ts +1 -0
- package/dist/types/store/index.d.ts +10 -0
- package/dist/types/store/types.d.ts +169 -0
- package/dist/types/transport/core/PorterAgent.d.ts +46 -0
- package/dist/types/transport/core/PorterSource.d.ts +40 -0
- package/dist/types/transport/index.d.ts +6 -0
- package/dist/types/transport/managers/AgentConnectionManager.d.ts +42 -0
- package/dist/types/transport/managers/AgentManager.d.ts +40 -0
- package/dist/types/transport/managers/AgentMessageHandler.d.ts +17 -0
- package/dist/types/transport/managers/ConnectionManager.d.ts +14 -0
- package/dist/types/transport/managers/MessageHandler.d.ts +29 -0
- package/dist/types/transport/managers/MessageQueue.d.ts +19 -0
- package/dist/types/transport/porter.model.d.ts +71 -0
- package/dist/types/transport/porter.utils.d.ts +44 -0
- package/dist/types/transport/react/index.d.ts +1 -0
- package/dist/types/transport/react/usePorter.d.ts +17 -0
- package/dist/types/utils/agent.d.ts +1 -1
- 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
|
+
}
|
|
@@ -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 "
|
|
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>>>;
|
|
@@ -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 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -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";
|