anbaric-tsapi 1.0.0

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/package.json ADDED
@@ -0,0 +1,20 @@
1
+ {
2
+ "name": "anbaric-tsapi",
3
+ "version": "1.0.0",
4
+ "description": "These are the shared libraries - types, classes, etc - that both the public state-machine and hosting services share",
5
+ "license": "MIT",
6
+ "author": "chris@anbaric.ai",
7
+ "type": "module",
8
+ "main": "src/index.ts",
9
+ "types": "src/index.ts",
10
+ "scripts": {
11
+ "test": "vitest run"
12
+ },
13
+ "devDependencies": {
14
+ "@types/node": "^26.2.0",
15
+ "typescript": "^7.0.2"
16
+ },
17
+ "files": [
18
+ "src"
19
+ ]
20
+ }
@@ -0,0 +1,25 @@
1
+ import {Actor} from "../actors/Actor";
2
+ import {Job} from "../jobs/Job";
3
+
4
+ type CodeRun = (job : Job) => Promise<Map<string, any>>;
5
+
6
+ class Action {
7
+
8
+ readonly id : string;
9
+ name : string;
10
+ description : string;
11
+ actor : Actor;
12
+
13
+ constructor(name : string, actor : Actor, description : string = "", id : string = crypto.randomUUID()) {
14
+ this.name = name;
15
+ this.actor = actor;
16
+ this.description = description;
17
+ this.id = id;
18
+ }
19
+
20
+ predicate = (_job : Job) => true;
21
+ run : CodeRun = async (_job : Job) => new Map();
22
+
23
+ }
24
+
25
+ export { Action }
@@ -0,0 +1,11 @@
1
+ type ActorType = "HUMAN" | "CODE" | "AGENT";
2
+
3
+ interface Actor {
4
+
5
+ type : ActorType;
6
+ id : string;
7
+ role : string;
8
+
9
+ }
10
+
11
+ export type { Actor, ActorType }
@@ -0,0 +1,6 @@
1
+ type QueueMessage = {
2
+ jobId : string,
3
+ workflowId : string,
4
+ };
5
+
6
+ export type { QueueMessage }
@@ -0,0 +1,53 @@
1
+ type JsonSchema = {
2
+ type? : "object" | "array" | "string" | "number" | "integer" | "boolean" | "null",
3
+ properties? : Record<string, JsonSchema>,
4
+ required? : Array<string>,
5
+ items? : JsonSchema,
6
+ enum? : Array<any>,
7
+ };
8
+
9
+ const jsonTypeOf = (value : any) : string => {
10
+ if (value === null) return "null";
11
+ if (Array.isArray(value)) return "array";
12
+ if (typeof value === "number") return Number.isInteger(value) ? "integer" : "number";
13
+ return typeof value;
14
+ };
15
+
16
+ const matchesType = (value : any, expected : string) : boolean => {
17
+ const actual = jsonTypeOf(value);
18
+ return expected === "number" ? actual === "number" || actual === "integer" : actual === expected;
19
+ };
20
+
21
+ const isPlainObject = (value : any) : boolean => jsonTypeOf(value) === "object";
22
+
23
+ const validateDocument = (document : any, schema : JsonSchema, path : string = "$") : Array<string> => {
24
+ const violations : Array<string> = [];
25
+
26
+ if (schema.type && !matchesType(document, schema.type)) {
27
+ violations.push(`${path} should be ${schema.type} but was ${jsonTypeOf(document)}`);
28
+ return violations;
29
+ }
30
+
31
+ if (schema.enum && !schema.enum.some(allowed => JSON.stringify(allowed) === JSON.stringify(document))) {
32
+ violations.push(`${path} must be one of ${JSON.stringify(schema.enum)}`);
33
+ }
34
+
35
+ if (isPlainObject(document)) {
36
+ for (const key of schema.required ?? []) {
37
+ if (!(key in document)) violations.push(`${path}.${key} is required`);
38
+ }
39
+ for (const [key, propertySchema] of Object.entries(schema.properties ?? {})) {
40
+ if (key in document) violations.push(...validateDocument(document[key], propertySchema, `${path}.${key}`));
41
+ }
42
+ }
43
+
44
+ if (Array.isArray(document) && schema.items) {
45
+ document.forEach((item, index) =>
46
+ violations.push(...validateDocument(item, schema.items!, `${path}[${index}]`)));
47
+ }
48
+
49
+ return violations;
50
+ };
51
+
52
+ export { validateDocument };
53
+ export type { JsonSchema };
@@ -0,0 +1,10 @@
1
+ interface JsonStore {
2
+
3
+ save(id : string, document : any) : Promise<void>;
4
+ retrieve(id : string) : Promise<any>;
5
+ delete(id : string) : Promise<void>;
6
+ list(pageSize? : number, page? : number) : Promise<Array<any>>;
7
+
8
+ }
9
+
10
+ export { JsonStore }
@@ -0,0 +1,50 @@
1
+ import {Transition} from "../transitions/Transition";
2
+ import {JobTransition} from "./JobTransition";
3
+
4
+ class Job {
5
+
6
+ readonly id : string;
7
+ private state: string;
8
+ properties : Map<string, any>;
9
+ readonly workflowId? : string;
10
+ readonly startedAt : Date;
11
+ readonly startedBy : string;
12
+ lastUpdated : Date;
13
+ readonly transitions : Array<JobTransition>;
14
+
15
+ constructor(id : string, properties : Map<string, any> = new Map(), initialState: string, workflowId? : string,
16
+ startedBy : string = "system", startedAt : Date = new Date(),
17
+ lastUpdated : Date = startedAt, transitions : Array<JobTransition> = []) {
18
+ this.id = id;
19
+ this.properties = properties;
20
+ this.state = initialState;
21
+ this.workflowId = workflowId;
22
+ this.startedBy = startedBy;
23
+ this.startedAt = startedAt;
24
+ this.lastUpdated = lastUpdated;
25
+ this.transitions = transitions;
26
+ }
27
+
28
+ private setState(stateId : string) : void {
29
+ this.state = stateId;
30
+ }
31
+
32
+ get stateId() : string | undefined {
33
+ return this.state;
34
+ }
35
+
36
+ transition(transition : Transition, actor : string = this.workflowId ?? "state-machine") : boolean {
37
+
38
+ if (transition.predicate(this)) {
39
+ this.transitions.push({ from: this.state, to: transition.to, actor });
40
+ this.setState(transition.to);
41
+ this.lastUpdated = new Date();
42
+ return true;
43
+ }
44
+
45
+ return false;
46
+ }
47
+
48
+ }
49
+
50
+ export { Job }
@@ -0,0 +1,13 @@
1
+ import {Job} from "./Job";
2
+
3
+ interface JobPersistence {
4
+
5
+ save(job : Job) : Promise<void>;
6
+ retrieve(id : string) : Promise<Job>;
7
+ delete(id : string) : Promise<void>;
8
+ list(pageSize? : number, page? : number) : Promise<Array<Job>>;
9
+ updateProperties(id : string, properties : Map<string, any>) : Promise<void>;
10
+
11
+ }
12
+
13
+ export { JobPersistence }
@@ -0,0 +1,35 @@
1
+ import {Job} from "./Job";
2
+ import {JobTransition} from "./JobTransition";
3
+
4
+ type SerializedJob = {
5
+ id : string,
6
+ state : string,
7
+ properties : Record<string, any>,
8
+ workflowId? : string,
9
+ startedAt? : string,
10
+ startedBy? : string,
11
+ lastUpdated? : string,
12
+ transitions? : Array<JobTransition>,
13
+ };
14
+
15
+ const serializeJob = (job : Job) : SerializedJob => ({
16
+ id: job.id,
17
+ state: job.stateId!,
18
+ properties: Object.fromEntries(job.properties),
19
+ workflowId: job.workflowId,
20
+ startedAt: job.startedAt.toISOString(),
21
+ startedBy: job.startedBy,
22
+ lastUpdated: job.lastUpdated.toISOString(),
23
+ transitions: job.transitions,
24
+ });
25
+
26
+ const deserializeJob = (serialized : SerializedJob) : Job => {
27
+ const startedAt = serialized.startedAt ? new Date(serialized.startedAt) : new Date();
28
+ return new Job(serialized.id, new Map(Object.entries(serialized.properties)), serialized.state,
29
+ serialized.workflowId, serialized.startedBy ?? "system", startedAt,
30
+ serialized.lastUpdated ? new Date(serialized.lastUpdated) : startedAt,
31
+ serialized.transitions ?? []);
32
+ };
33
+
34
+ export { serializeJob, deserializeJob };
35
+ export type { SerializedJob };
@@ -0,0 +1,7 @@
1
+ type JobTransition = {
2
+ from : string,
3
+ to : string,
4
+ actor : string,
5
+ };
6
+
7
+ export type { JobTransition }
@@ -0,0 +1,12 @@
1
+ class PropertyDefinition {
2
+
3
+ id : string;
4
+ required : boolean = false;
5
+ validation : (arg0: any) => boolean = (value : any) => true;
6
+
7
+ constructor(id : string) {
8
+ this.id = id;
9
+ }
10
+ }
11
+
12
+ export { PropertyDefinition }
@@ -0,0 +1,10 @@
1
+ interface SecretStore {
2
+
3
+ save(name : string, value : string) : Promise<void>;
4
+ retrieve(name : string) : Promise<string>;
5
+ delete(name : string) : Promise<void>;
6
+ list() : Promise<Array<string>>;
7
+
8
+ }
9
+
10
+ export { SecretStore }
@@ -0,0 +1,8 @@
1
+ interface Consumer {
2
+
3
+ subscribe(workflowId : string, processJob : (jobId : string) => Promise<void>) : void;
4
+ cleanUp() : Promise<void>;
5
+
6
+ }
7
+
8
+ export { Consumer }
@@ -0,0 +1,22 @@
1
+ import {QueueMessage} from "../cloud/QueueMessage";
2
+
3
+ interface Queue {
4
+
5
+ enqueue(jobId : string, workflowId : string) : Promise<void>;
6
+ schedule(jobId : string, workflowId : string, due : Date) : Promise<void>;
7
+
8
+ }
9
+
10
+ interface Dequeue extends Queue {
11
+
12
+ dequeueSome() : Promise<Array<QueueMessage>>;
13
+
14
+ }
15
+
16
+ const Dequeue = {
17
+ supports(queue : Queue) : queue is Dequeue {
18
+ return "dequeueSome" in queue;
19
+ },
20
+ };
21
+
22
+ export { Queue, Dequeue }
@@ -0,0 +1,22 @@
1
+ import {Action} from "../actions/Action";
2
+ import {Transition} from "../transitions/Transition";
3
+
4
+ class State {
5
+
6
+ readonly id : string;
7
+ actions : Array<Action>;
8
+ transitions : Array<Transition>;
9
+
10
+ constructor(id : string, actions : Array<Action> = [], transitions : Array<Transition> = []) {
11
+ this.id = id;
12
+ this.actions = actions;
13
+ this.transitions = transitions;
14
+ }
15
+
16
+ subscribe(action : Action) : void {
17
+ this.actions.push(action);
18
+ }
19
+
20
+ }
21
+
22
+ export { State }
@@ -0,0 +1,13 @@
1
+ import {Job} from "../jobs/Job";
2
+
3
+ class Transition {
4
+ to: string;
5
+ predicate: (job: Job) => boolean;
6
+
7
+ constructor(to: string, predicate: (job: Job) => boolean) {
8
+ this.to = to;
9
+ this.predicate = predicate;
10
+ }
11
+ }
12
+
13
+ export { Transition }
package/src/index.ts ADDED
@@ -0,0 +1,15 @@
1
+ export * from "./api/jobs/Job";
2
+ export * from "./api/jobs/JobPersistence"
3
+ export * from "./api/jobs/JobSerialization"
4
+ export * from "./api/jobs/JobTransition"
5
+ export * from "./api/jobs/PropertyDefinition"
6
+ export * from "./api/states/State"
7
+ export * from "./api/actions/Action"
8
+ export * from "./api/transitions/Transition"
9
+ export * from "./api/actors/Actor"
10
+ export * from "./api/documents/JsonStore"
11
+ export * from "./api/secrets/SecretStore"
12
+ export * from "./api/documents/JsonSchema"
13
+ export * from "./api/state-machine/Queue"
14
+ export * from "./api/state-machine/Consumer"
15
+ export * from "./api/cloud/QueueMessage"