@onereach/state-machine-service 1.0.0-framework.11

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 ADDED
@@ -0,0 +1,3 @@
1
+ # @onereach/state-machine-service
2
+
3
+ This package defines high level service for using State Machine
@@ -0,0 +1,130 @@
1
+ import { StateMachineRuntime } from "@onereach/state-machine-runtime";
2
+ import { InstanceWatchOptions, LoadedStateMachineInstance, StateMachineInstanceChange, StateMachineInstanceReference, StateMachineInstanceStore, StateTemplateReference } from "@onereach/state-machine-store";
3
+ //#region src/types.d.ts
4
+ interface CreateInstanceOptions {
5
+ id: string;
6
+ template: StateTemplateReference;
7
+ state?: Record<string, unknown>;
8
+ metadata?: Record<string, unknown>;
9
+ }
10
+ type ManagedExecutionResult<TOutput = unknown> = {
11
+ kind: 'query';
12
+ output: TOutput;
13
+ /**
14
+ * Instance as loaded.
15
+ *
16
+ * No persisted change occurred.
17
+ */
18
+ instance: LoadedStateMachineInstance;
19
+ } | {
20
+ kind: 'mutation';
21
+ output: TOutput;
22
+ /**
23
+ * Newly persisted instance revision.
24
+ */
25
+ instance: LoadedStateMachineInstance;
26
+ };
27
+ interface StateMachineServiceOptions {
28
+ /**
29
+ * Require safe optimistic concurrency for mutations.
30
+ *
31
+ * @default true
32
+ */
33
+ requireSafeMutationPersistence?: boolean;
34
+ }
35
+ //#endregion
36
+ //#region src/index.d.ts
37
+ declare class StateMachineService<TContext> {
38
+ /**
39
+ * A map of prepared state machine instances.
40
+ */
41
+ private readonly prepared;
42
+ /**
43
+ * The state machine instance store.
44
+ */
45
+ private readonly instances;
46
+ /**
47
+ * The state machine runtime.
48
+ */
49
+ private readonly runtime;
50
+ /**
51
+ * Whether to require safe mutation persistence.
52
+ */
53
+ private readonly requireSafeMutationPersistence;
54
+ constructor(instances: StateMachineInstanceStore, runtime: StateMachineRuntime<TContext>, options?: StateMachineServiceOptions);
55
+ /**
56
+ * Prepare a state machine instance for execution.
57
+ *
58
+ * @param instance - The loaded state machine instance.
59
+ * @returns The prepared state machine instance.
60
+ */
61
+ private prepare;
62
+ /**
63
+ * Create a new state machine instance.
64
+ *
65
+ * @param options - The options for creating the state machine instance.
66
+ * @returns The created state machine instance.
67
+ */
68
+ create(options: CreateInstanceOptions): Promise<LoadedStateMachineInstance>;
69
+ /**
70
+ * Load a state machine instance.
71
+ *
72
+ * @param reference - The reference to the state machine instance.
73
+ * @returns The loaded state machine instance.
74
+ */
75
+ load(reference: StateMachineInstanceReference): Promise<LoadedStateMachineInstance | undefined>;
76
+ /**
77
+ * Require a state machine instance.
78
+ *
79
+ * @param reference - The reference to the state machine instance.
80
+ * @returns The loaded state machine instance.
81
+ */
82
+ require(reference: StateMachineInstanceReference): Promise<LoadedStateMachineInstance>;
83
+ /**
84
+ * Delete a state machine instance.
85
+ *
86
+ * @param reference - The reference to the state machine instance.
87
+ * @returns True if the instance was deleted, false otherwise.
88
+ */
89
+ delete(reference: StateMachineInstanceReference): Promise<boolean>;
90
+ /**
91
+ * Save the state of a state machine instance.
92
+ *
93
+ * @param reference - The reference to the state machine instance.
94
+ * @param state - The state to save.
95
+ * @returns The saved state machine instance.
96
+ */
97
+ saveState(reference: StateMachineInstanceReference, state: Record<string, unknown>): Promise<LoadedStateMachineInstance>;
98
+ /**
99
+ * Execute a function on a state machine instance.
100
+ *
101
+ * @param reference - The reference to the state machine instance.
102
+ * @param functionName - The name of the function to execute.
103
+ * @param input - The input to the function.
104
+ * @param context - The context to use for the execution.
105
+ * @returns The result of the execution.
106
+ */
107
+ execute<TOutput = unknown>(reference: StateMachineInstanceReference, functionName: string, input: unknown, context: TContext): Promise<ManagedExecutionResult<TOutput>>;
108
+ /**
109
+ * Watch a state machine instance for changes.
110
+ *
111
+ * @param reference - The reference to the state machine instance.
112
+ * @param options - The options for watching the state machine instance.
113
+ * @returns An async iterable of state machine instance changes.
114
+ */
115
+ watch(reference: StateMachineInstanceReference, options?: InstanceWatchOptions): AsyncIterable<StateMachineInstanceChange>;
116
+ /**
117
+ * Subscribe to a state machine instance for changes.
118
+ *
119
+ * @param reference - The reference to the state machine instance.
120
+ * @param listener - The listener to call when the state machine instance changes.
121
+ * @param options - The options for subscribing to the state machine instance.
122
+ * @returns A function to unsubscribe from the state machine instance.
123
+ */
124
+ subscribe(reference: StateMachineInstanceReference, listener: (change: StateMachineInstanceChange) => void | Promise<void>, options?: InstanceWatchOptions & {
125
+ onError?: (error: unknown) => void;
126
+ }): () => void;
127
+ }
128
+ //#endregion
129
+ export { type CreateInstanceOptions, type ManagedExecutionResult, StateMachineService, type StateMachineServiceOptions };
130
+ //# sourceMappingURL=index.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.mts","names":[],"sources":["../src/types.ts","../src/index.ts"],"mappings":";;;UAEiB;EACf;EACA,UAAU;EACV,QAAQ;EACR,WAAW;;KAGD,uBAAuB;EAE7B;EAEA,QAAQ;;;;;;EAOR,UAAU;;EAGV;EAEA,QAAQ;;;;EAKR,UAAU;;UAGC;;;;;;EAMf;;;;cC1BW,oBAAoB;;;;mBAId;;;;mBAKA;;;;mBAKA;;;;mBAKA;EAGf,YAAA,WAAW,2BACX,SAAS,oBAAoB,WAC7B,UAAS;;;;;;;UAaH;;;;;;;EAoCK,OAAO,SAAS,wBAAwB,QAAQ;;;;;;;EAUhD,KAAK,WAAW,gCAAgC,QAAQ;;;;;;;EAUxD,QAAQ,WAAW,gCAAgC,QAAQ;;;;;;;EAU3D,OAAO,WAAW,gCAAgC;;;;;;;;EAalD,UACX,WAAW,+BACX,OAAO,0BACN,QAAQ;;;;;;;;;;EAyBE,QAAQ,mBACnB,WAAW,+BACX,sBACA,gBACA,SAAS,WACR,QAAQ,uBAAuB;;;;;;;;EA+D3B,MACL,WAAW,+BAEX,UAAU,uBACT,cAAc;;;;;;;;;EAYV,UACL,WAAW,+BACX,WAAW,QAAQ,sCAAsC,eACzD,UAAS;IACP,WAAW"}
package/dist/index.mjs ADDED
@@ -0,0 +1,2 @@
1
+ import{UnknownFunctionError as e}from"@onereach/state-machine-runtime";import{UnsafeConcurrencyError as t,hasSafeConditionalWrites as n}from"@onereach/state-machine-store";var r=class{prepared=new Map;instances;runtime;requireSafeMutationPersistence;constructor(e,t,n={}){this.instances=e,this.runtime=t,this.requireSafeMutationPersistence=n.requireSafeMutationPersistence??!0}prepare(e){let t=[e.template.definition.id,e.template.revision].join(`:`),n=this.prepared.get(t);return n||(n=this.runtime.prepare({definition:e.template.definition,validators:e.template.validators}),this.prepared.set(t,n)),n}async create(e){return this.instances.create(e)}async load(e){return this.instances.load(e)}async require(e){return this.instances.require(e)}async delete(e){let t=await this.instances.require(e);return this.instances.delete(t)}async saveState(e,t){let n=await this.instances.require(e);return this.instances.saveState(n,t)}async execute(r,i,a,o){let s=await this.instances.require(r),c=this.prepare(s),l=c.getFunction(i);if(!l)throw new e(i);if(l.kind===`mutation`&&this.requireSafeMutationPersistence&&!n(this.instances.capabilities))throw new t(this.instances.capabilities.concurrency);let u=await c.execute(i,a,s.instance.state,o);if(u.kind===`query`)return{kind:`query`,output:u.output,instance:s};let d=await this.instances.saveState(s,u.state);return{kind:`mutation`,output:u.output,instance:d}}watch(e,t){return this.instances.watch(e,t)}subscribe(e,t,n={}){return this.instances.subscribe(e,t,n)}};export{r as StateMachineService};
2
+ //# sourceMappingURL=index.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.mjs","names":[],"sources":["../src/index.ts"],"sourcesContent":["import { StateMachineRuntime, UnknownFunctionError } from '@onereach/state-machine-runtime';\nimport type { PreparedStateTemplate } from '@onereach/state-machine-runtime';\nimport type {\n StateMachineInstanceChange,\n StateMachineInstanceReference,\n StateMachineInstanceStore,\n LoadedStateMachineInstance,\n InstanceWatchOptions,\n} from '@onereach/state-machine-store';\nimport { hasSafeConditionalWrites, UnsafeConcurrencyError } from '@onereach/state-machine-store';\n\nimport type { CreateInstanceOptions, ManagedExecutionResult, StateMachineServiceOptions } from './types.ts';\n\nexport class StateMachineService<TContext> {\n /**\n * A map of prepared state machine instances.\n */\n private readonly prepared = new Map<string, PreparedStateTemplate<TContext>>();\n\n /**\n * The state machine instance store.\n */\n private readonly instances: StateMachineInstanceStore;\n\n /**\n * The state machine runtime.\n */\n private readonly runtime: StateMachineRuntime<TContext>;\n\n /**\n * Whether to require safe mutation persistence.\n */\n private readonly requireSafeMutationPersistence: boolean;\n\n constructor(\n instances: StateMachineInstanceStore,\n runtime: StateMachineRuntime<TContext>,\n options: StateMachineServiceOptions = {},\n ) {\n this.instances = instances;\n this.runtime = runtime;\n this.requireSafeMutationPersistence = options.requireSafeMutationPersistence ?? true;\n }\n\n /**\n * Prepare a state machine instance for execution.\n *\n * @param instance - The loaded state machine instance.\n * @returns The prepared state machine instance.\n */\n private prepare(instance: LoadedStateMachineInstance): PreparedStateTemplate<TContext> {\n /**\n * Template revision is immutable identity for our cache.\n */\n const key = [instance.template.definition.id, instance.template.revision].join(':');\n\n let prepared = this.prepared.get(key);\n\n if (!prepared) {\n prepared = this.runtime.prepare({\n definition: instance.template.definition,\n validators: instance.template.validators,\n });\n\n this.prepared.set(key, prepared);\n }\n\n return prepared;\n }\n\n /*\n ------------------------------------------------------------------------\n */\n /*\n Lifecycle\n */\n /*\n ------------------------------------------------------------------------\n */\n\n /**\n * Create a new state machine instance.\n *\n * @param options - The options for creating the state machine instance.\n * @returns The created state machine instance.\n */\n public async create(options: CreateInstanceOptions): Promise<LoadedStateMachineInstance> {\n return this.instances.create(options);\n }\n\n /**\n * Load a state machine instance.\n *\n * @param reference - The reference to the state machine instance.\n * @returns The loaded state machine instance.\n */\n public async load(reference: StateMachineInstanceReference): Promise<LoadedStateMachineInstance | undefined> {\n return this.instances.load(reference);\n }\n\n /**\n * Require a state machine instance.\n *\n * @param reference - The reference to the state machine instance.\n * @returns The loaded state machine instance.\n */\n public async require(reference: StateMachineInstanceReference): Promise<LoadedStateMachineInstance> {\n return this.instances.require(reference);\n }\n\n /**\n * Delete a state machine instance.\n *\n * @param reference - The reference to the state machine instance.\n * @returns True if the instance was deleted, false otherwise.\n */\n public async delete(reference: StateMachineInstanceReference): Promise<boolean> {\n const loaded = await this.instances.require(reference);\n\n return this.instances.delete(loaded);\n }\n\n /**\n * Save the state of a state machine instance.\n *\n * @param reference - The reference to the state machine instance.\n * @param state - The state to save.\n * @returns The saved state machine instance.\n */\n public async saveState(\n reference: StateMachineInstanceReference,\n state: Record<string, unknown>,\n ): Promise<LoadedStateMachineInstance> {\n const loaded = await this.instances.require(reference);\n\n return this.instances.saveState(loaded, state);\n }\n\n /*\n ------------------------------------------------------------------------\n */\n /*\n Execution\n */\n /*\n ------------------------------------------------------------------------\n */\n\n /**\n * Execute a function on a state machine instance.\n *\n * @param reference - The reference to the state machine instance.\n * @param functionName - The name of the function to execute.\n * @param input - The input to the function.\n * @param context - The context to use for the execution.\n * @returns The result of the execution.\n */\n public async execute<TOutput = unknown>(\n reference: StateMachineInstanceReference,\n functionName: string,\n input: unknown,\n context: TContext,\n ): Promise<ManagedExecutionResult<TOutput>> {\n const loaded = await this.instances.require(reference);\n const prepared = this.prepare(loaded);\n const functionDefinition = prepared.getFunction(functionName);\n\n if (!functionDefinition) throw new UnknownFunctionError(functionName);\n\n /*\n * Fail before executing mutation code.\n *\n * This is important because implementation may perform\n * external side effects through context.\n */\n if (\n functionDefinition.kind === 'mutation' &&\n this.requireSafeMutationPersistence &&\n !hasSafeConditionalWrites(this.instances.capabilities)\n ) {\n throw new UnsafeConcurrencyError(this.instances.capabilities.concurrency);\n }\n\n const result = await prepared.execute(functionName, input, loaded.instance.state, context);\n\n if (result.kind === 'query') {\n return {\n kind: 'query',\n output: result.output as TOutput,\n instance: loaded,\n };\n }\n\n /**\n * Compare-and-swap happens here.\n *\n * If another process changed the instance after our load,\n * saveState throws RevisionConflictError.\n */\n const persisted = await this.instances.saveState(loaded, result.state);\n\n return {\n kind: 'mutation',\n output: result.output as TOutput,\n instance: persisted,\n };\n }\n\n /*\n ------------------------------------------------------------------------\n */\n /*\n Change notifications\n */\n /*\n ------------------------------------------------------------------------\n */\n\n /**\n * Watch a state machine instance for changes.\n *\n * @param reference - The reference to the state machine instance.\n * @param options - The options for watching the state machine instance.\n * @returns An async iterable of state machine instance changes.\n */\n public watch(\n reference: StateMachineInstanceReference,\n\n options?: InstanceWatchOptions,\n ): AsyncIterable<StateMachineInstanceChange> {\n return this.instances.watch(reference, options);\n }\n\n /**\n * Subscribe to a state machine instance for changes.\n *\n * @param reference - The reference to the state machine instance.\n * @param listener - The listener to call when the state machine instance changes.\n * @param options - The options for subscribing to the state machine instance.\n * @returns A function to unsubscribe from the state machine instance.\n */\n public subscribe(\n reference: StateMachineInstanceReference,\n listener: (change: StateMachineInstanceChange) => void | Promise<void>,\n options: InstanceWatchOptions & {\n onError?: (error: unknown) => void;\n } = {},\n ): () => void {\n return this.instances.subscribe(reference, listener, options);\n }\n}\n\nexport type * from './types.ts';\n"],"mappings":"4KAaA,IAAa,EAAb,KAA2C,CAIzC,SAA4B,IAAI,IAKhC,UAKA,QAKA,+BAEA,YACE,EACA,EACA,EAAsC,CAAC,EACvC,CACA,KAAK,UAAY,EACjB,KAAK,QAAU,EACf,KAAK,+BAAiC,EAAQ,gCAAkC,EAClF,CAQA,QAAgB,EAAuE,CAIrF,IAAM,EAAM,CAAC,EAAS,SAAS,WAAW,GAAI,EAAS,SAAS,QAAQ,CAAC,CAAC,KAAK,GAAG,EAE9E,EAAW,KAAK,SAAS,IAAI,CAAG,EAWpC,OATK,IACH,EAAW,KAAK,QAAQ,QAAQ,CAC9B,WAAY,EAAS,SAAS,WAC9B,WAAY,EAAS,SAAS,UAChC,CAAC,EAED,KAAK,SAAS,IAAI,EAAK,CAAQ,GAG1B,CACT,CAkBA,MAAa,OAAO,EAAqE,CACvF,OAAO,KAAK,UAAU,OAAO,CAAO,CACtC,CAQA,MAAa,KAAK,EAA2F,CAC3G,OAAO,KAAK,UAAU,KAAK,CAAS,CACtC,CAQA,MAAa,QAAQ,EAA+E,CAClG,OAAO,KAAK,UAAU,QAAQ,CAAS,CACzC,CAQA,MAAa,OAAO,EAA4D,CAC9E,IAAM,EAAS,MAAM,KAAK,UAAU,QAAQ,CAAS,EAErD,OAAO,KAAK,UAAU,OAAO,CAAM,CACrC,CASA,MAAa,UACX,EACA,EACqC,CACrC,IAAM,EAAS,MAAM,KAAK,UAAU,QAAQ,CAAS,EAErD,OAAO,KAAK,UAAU,UAAU,EAAQ,CAAK,CAC/C,CAqBA,MAAa,QACX,EACA,EACA,EACA,EAC0C,CAC1C,IAAM,EAAS,MAAM,KAAK,UAAU,QAAQ,CAAS,EAC/C,EAAW,KAAK,QAAQ,CAAM,EAC9B,EAAqB,EAAS,YAAY,CAAY,EAE5D,GAAI,CAAC,EAAoB,MAAM,IAAI,EAAqB,CAAY,EAQpE,GACE,EAAmB,OAAS,YAC5B,KAAK,gCACL,CAAC,EAAyB,KAAK,UAAU,YAAY,EAErD,MAAM,IAAI,EAAuB,KAAK,UAAU,aAAa,WAAW,EAG1E,IAAM,EAAS,MAAM,EAAS,QAAQ,EAAc,EAAO,EAAO,SAAS,MAAO,CAAO,EAEzF,GAAI,EAAO,OAAS,QAClB,MAAO,CACL,KAAM,QACN,OAAQ,EAAO,OACf,SAAU,CACZ,EASF,IAAM,EAAY,MAAM,KAAK,UAAU,UAAU,EAAQ,EAAO,KAAK,EAErE,MAAO,CACL,KAAM,WACN,OAAQ,EAAO,OACf,SAAU,CACZ,CACF,CAmBA,MACE,EAEA,EAC2C,CAC3C,OAAO,KAAK,UAAU,MAAM,EAAW,CAAO,CAChD,CAUA,UACE,EACA,EACA,EAEI,CAAC,EACO,CACZ,OAAO,KAAK,UAAU,UAAU,EAAW,EAAU,CAAO,CAC9D,CACF"}
package/package.json ADDED
@@ -0,0 +1,48 @@
1
+ {
2
+ "name": "@onereach/state-machine-service",
3
+ "version": "1.0.0-framework.11",
4
+ "description": "State Machine high-level API for most applications",
5
+ "keywords": [
6
+ "onereach",
7
+ "toolkit",
8
+ "state-machine"
9
+ ],
10
+ "author": "OneReach Development Team <dev.team@onereach.ai>",
11
+ "license": "Apache-2.0",
12
+ "type": "module",
13
+ "publishConfig": {
14
+ "access": "public"
15
+ },
16
+ "files": [
17
+ "dist",
18
+ "!dist/metafile*.json"
19
+ ],
20
+ "devDependencies": {
21
+ "@arethetypeswrong/core": "^0.18.5",
22
+ "@onereach/state-machine-core": "1.0.0-framework.10",
23
+ "@onereach/state-machine-driver-memory": "1.0.0-framework.10",
24
+ "@onereach/state-machine-validation-ajv": "1.0.0-framework.10",
25
+ "@types/source-map-support": "^0.5.10",
26
+ "publint": "^0.3.24",
27
+ "rollup-plugin-visualizer": "^7.1.1",
28
+ "tsdown": "^0.22.14",
29
+ "typescript": "^6.0.3"
30
+ },
31
+ "dependencies": {
32
+ "@onereach/state-machine-runtime": "1.0.0-framework.11",
33
+ "@onereach/state-machine-store": "1.0.0-framework.10"
34
+ },
35
+ "exports": {
36
+ ".": "./dist/index.mjs",
37
+ "./package.json": "./package.json"
38
+ },
39
+ "scripts": {
40
+ "build": "tsdown --config tsdown.config.mts",
41
+ "build:visualize": "VISUALIZE=1 pnpm build",
42
+ "preversion_": "pnpm build && pnpm test",
43
+ "publish:rc": "pnpm version prerelease --preid rc && pnpm publish --tag rc",
44
+ "test": "pnpm run unit",
45
+ "unit": "vitest run",
46
+ "preversion": "pnpm build"
47
+ }
48
+ }