coremachine 1.0.0 → 1.0.1
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/dist/index.d.ts +80 -0
- package/dist/index.js +120 -0
- package/package.json +1 -1
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import Hypercore from "hypercore";
|
|
2
|
+
import { Duplex } from "streamx";
|
|
3
|
+
export type MachineConfig<TContext extends Record<string, any> = Record<string, any>, TStates extends Record<string, StateConfig<TContext>> = Record<string, StateConfig<TContext>>> = {
|
|
4
|
+
initial: keyof TStates;
|
|
5
|
+
context: TContext;
|
|
6
|
+
states: TStates;
|
|
7
|
+
};
|
|
8
|
+
export type StateConfig<TContext extends Record<string, any>> = {
|
|
9
|
+
on: Record<string, TransitionConfig<TContext>>;
|
|
10
|
+
};
|
|
11
|
+
export type TransitionConfig<TContext extends Record<string, any>> = {
|
|
12
|
+
target: string;
|
|
13
|
+
action: (ctx: TContext, ...args: any[]) => void | Promise<void>;
|
|
14
|
+
};
|
|
15
|
+
export type ExtractContext<T> = T extends MachineConfig<infer C, any> ? C : never;
|
|
16
|
+
export type ExtractStates<T> = T extends MachineConfig<any, infer S> ? keyof S : never;
|
|
17
|
+
type ExtractActions<T> = T extends MachineConfig<any, infer S> ? S extends Record<string, {
|
|
18
|
+
on: Record<infer E, any>;
|
|
19
|
+
}> ? E : never : never;
|
|
20
|
+
type ExtractActionParams<T, E extends string> = T extends MachineConfig<any, infer S> ? {
|
|
21
|
+
[K in keyof S]: S[K] extends {
|
|
22
|
+
on: Record<E, {
|
|
23
|
+
action: (ctx: any, ...args: infer P) => any;
|
|
24
|
+
}>;
|
|
25
|
+
} ? P extends [infer First, ...any[]] ? First : undefined : never;
|
|
26
|
+
}[keyof S] : never;
|
|
27
|
+
type ExtractActionSignatures<T> = T extends MachineConfig<any, infer S> ? {
|
|
28
|
+
[K in ExtractActions<T>]: ExtractActionParams<T, K extends string ? K : never> extends never ? undefined : ExtractActionParams<T, K extends string ? K : never>;
|
|
29
|
+
} : never;
|
|
30
|
+
export declare function createMachine<TContext extends Record<string, any>, TStates extends Record<string, StateConfig<TContext>>>(config: MachineConfig<TContext, TStates> & {
|
|
31
|
+
initial: keyof TStates;
|
|
32
|
+
context: TContext;
|
|
33
|
+
states: TStates;
|
|
34
|
+
}): MachineConfig<TContext, TStates>;
|
|
35
|
+
export declare function inferActions<T extends MachineConfig<any, any>>(machine: T): ExtractActionSignatures<T>;
|
|
36
|
+
export type Infer<T extends MachineConfig<any, any>> = ReturnType<typeof inferActions<T>>;
|
|
37
|
+
export type ActionMessage<T extends MachineConfig<any, any>> = {
|
|
38
|
+
[E in ExtractActions<T> & string]: ExtractActionParams<T, E> extends never ? {
|
|
39
|
+
action: E;
|
|
40
|
+
value?: undefined;
|
|
41
|
+
} : undefined extends ExtractActionParams<T, E> ? {
|
|
42
|
+
action: E;
|
|
43
|
+
value?: ExtractActionParams<T, E>;
|
|
44
|
+
} : {
|
|
45
|
+
action: E;
|
|
46
|
+
value: ExtractActionParams<T, E>;
|
|
47
|
+
};
|
|
48
|
+
}[ExtractActions<T> & string];
|
|
49
|
+
export type StateMessage<T extends MachineConfig<any, any>> = {
|
|
50
|
+
state: ExtractStates<T>;
|
|
51
|
+
context: ExtractContext<T>;
|
|
52
|
+
};
|
|
53
|
+
interface CoremachineOptions {
|
|
54
|
+
eager?: boolean;
|
|
55
|
+
}
|
|
56
|
+
export declare class Coremachine<T extends MachineConfig<any, any>> extends Duplex<ActionMessage<T>, StateMessage<T>> {
|
|
57
|
+
private _core;
|
|
58
|
+
private _machine;
|
|
59
|
+
private _state;
|
|
60
|
+
private _context;
|
|
61
|
+
private _currentIndex;
|
|
62
|
+
private _eager;
|
|
63
|
+
constructor(core: Hypercore, machine: T, opts?: CoremachineOptions);
|
|
64
|
+
_open(cb: (err?: Error | null) => void): void;
|
|
65
|
+
_write(chunk: ActionMessage<T>, cb: (err?: Error | null) => void): void;
|
|
66
|
+
_read(cb: (err?: Error | null) => void): void;
|
|
67
|
+
_destroy(cb: (err?: Error | null) => void): void;
|
|
68
|
+
action<E extends ExtractActions<T>>(action: E, value?: ExtractActionParams<T, E extends string ? E : never>): Promise<{
|
|
69
|
+
state: ExtractStates<T>;
|
|
70
|
+
context: ExtractContext<T>;
|
|
71
|
+
}>;
|
|
72
|
+
forward(): Promise<void>;
|
|
73
|
+
backward(): Promise<void>;
|
|
74
|
+
truncate(newLength: number): any;
|
|
75
|
+
get state(): ExtractStates<T>;
|
|
76
|
+
get context(): ExtractContext<T>;
|
|
77
|
+
get isEmpty(): boolean;
|
|
78
|
+
getAvailableActions(): Array<ExtractActions<T>>;
|
|
79
|
+
}
|
|
80
|
+
export {};
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
import { Duplex } from "streamx";
|
|
2
|
+
// Improved createMachine function with better type inference
|
|
3
|
+
export function createMachine(config) {
|
|
4
|
+
return config;
|
|
5
|
+
}
|
|
6
|
+
// Utility function to infer action types and payloads
|
|
7
|
+
export function inferActions(machine) {
|
|
8
|
+
const result = {};
|
|
9
|
+
// Collect all action names from all states
|
|
10
|
+
for (const stateName in machine.states) {
|
|
11
|
+
const state = machine.states[stateName];
|
|
12
|
+
for (const action in state.on) {
|
|
13
|
+
result[action] = undefined; // Placeholder for type inference
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
return result;
|
|
17
|
+
}
|
|
18
|
+
export class Coremachine extends Duplex {
|
|
19
|
+
constructor(core, machine, opts = {}) {
|
|
20
|
+
super();
|
|
21
|
+
this._currentIndex = null;
|
|
22
|
+
this._eager = false;
|
|
23
|
+
this._core = core;
|
|
24
|
+
this._machine = machine;
|
|
25
|
+
this._state = machine.initial;
|
|
26
|
+
this._context = structuredClone(machine.context);
|
|
27
|
+
this._eager = Boolean(opts.eager);
|
|
28
|
+
}
|
|
29
|
+
_open(cb) {
|
|
30
|
+
this._core
|
|
31
|
+
.ready()
|
|
32
|
+
.then(async () => {
|
|
33
|
+
if (this._core.length > 0) {
|
|
34
|
+
const lastState = await this._core.get(this._core.length - 1);
|
|
35
|
+
this._state = lastState.state;
|
|
36
|
+
this._context = lastState.context;
|
|
37
|
+
const currentState = this._machine.states[this._state];
|
|
38
|
+
if (currentState?.on.start?.target) {
|
|
39
|
+
this._state = currentState.on.start.target;
|
|
40
|
+
}
|
|
41
|
+
if (currentState?.on.start?.action) {
|
|
42
|
+
await currentState.on.start.action(this._context, this._state);
|
|
43
|
+
}
|
|
44
|
+
if (this._eager) {
|
|
45
|
+
// @ts-ignore
|
|
46
|
+
this.push({ state: this._state, context: this._context });
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
cb();
|
|
50
|
+
})
|
|
51
|
+
.catch(cb);
|
|
52
|
+
}
|
|
53
|
+
_write(chunk, cb) {
|
|
54
|
+
this.action(chunk.action, chunk.value).then(() => cb(), cb);
|
|
55
|
+
}
|
|
56
|
+
_read(cb) {
|
|
57
|
+
cb();
|
|
58
|
+
}
|
|
59
|
+
_destroy(cb) {
|
|
60
|
+
this._core.close().then(() => cb(), cb);
|
|
61
|
+
}
|
|
62
|
+
async action(action, value) {
|
|
63
|
+
const currentState = this._machine.states[this._state];
|
|
64
|
+
const transition = currentState?.on[action] ||
|
|
65
|
+
this._machine.states.all?.[action];
|
|
66
|
+
if (!transition) {
|
|
67
|
+
throw new Error(`Invalid action: ${String(action)} for state ${this._state}`);
|
|
68
|
+
}
|
|
69
|
+
const oldState = structuredClone(this._context);
|
|
70
|
+
await transition.action(this._context, value);
|
|
71
|
+
await this._core.append({
|
|
72
|
+
state: transition.target || this._state,
|
|
73
|
+
context: this._context,
|
|
74
|
+
});
|
|
75
|
+
this._state = transition.target || this._state;
|
|
76
|
+
if (transition.target) {
|
|
77
|
+
// @ts-ignore
|
|
78
|
+
this.push({ state: this._state, context: this._context });
|
|
79
|
+
}
|
|
80
|
+
return { state: this._state, context: this._context };
|
|
81
|
+
}
|
|
82
|
+
async forward() {
|
|
83
|
+
const newIndex = this._currentIndex === null
|
|
84
|
+
? this._core.length - 2
|
|
85
|
+
: this._currentIndex + 1;
|
|
86
|
+
if (this._core.length > newIndex && newIndex < this._core.length) {
|
|
87
|
+
const nextState = await this._core.get(newIndex);
|
|
88
|
+
this._state = nextState.state;
|
|
89
|
+
this._context = nextState.context;
|
|
90
|
+
this._currentIndex = newIndex;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
async backward() {
|
|
94
|
+
const newIndex = this._currentIndex === null
|
|
95
|
+
? this._core.length - 2
|
|
96
|
+
: this._currentIndex - 1;
|
|
97
|
+
if (this._core.length > newIndex && newIndex >= 0) {
|
|
98
|
+
const lastState = await this._core.get(newIndex);
|
|
99
|
+
this._state = lastState.state;
|
|
100
|
+
this._context = lastState.context;
|
|
101
|
+
this._currentIndex = newIndex;
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
truncate(newLength) {
|
|
105
|
+
return this._core.truncate(newLength);
|
|
106
|
+
}
|
|
107
|
+
get state() {
|
|
108
|
+
return this._state;
|
|
109
|
+
}
|
|
110
|
+
get context() {
|
|
111
|
+
return this._context;
|
|
112
|
+
}
|
|
113
|
+
get isEmpty() {
|
|
114
|
+
return this._core.length === 0;
|
|
115
|
+
}
|
|
116
|
+
getAvailableActions() {
|
|
117
|
+
const currentState = this._machine.states[this._state];
|
|
118
|
+
return Object.keys(currentState?.on || {});
|
|
119
|
+
}
|
|
120
|
+
}
|