anbaric 1.7.0 → 1.8.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.
Files changed (2) hide show
  1. package/README.md +176 -71
  2. package/package.json +5 -5
package/README.md CHANGED
@@ -1,98 +1,203 @@
1
1
  # anbaric
2
2
 
3
- Everything needed to write an Anbaric app, in one install. Re-exports the
4
- full app-facing surface of [`anbaric-tsapi`](https://npmjs.com/package/anbaric-tsapi)
5
- (contracts and value classes), [`anbaric-state-machine`](https://npmjs.com/package/anbaric-state-machine)
6
- (the state machine and in-memory implementations),
7
- [`anbaric-data-store`](https://npmjs.com/package/anbaric-data-store)
8
- (document and secret stores) and [`anbaric-impl-cloud`](https://npmjs.com/package/anbaric-impl-cloud)
9
- (the clients the factories switch to when deployed).
3
+ Anbaric is a Typescript framework for building stateful applications. An application is
4
+ expressed as one or more state machines: long-lived jobs move through named
5
+ states, driven by actions and transitions, with their data validated against a
6
+ schema and every change recorded in an audit trail. Alongside the state machine
7
+ the framework provides schema-validated document storage and secret storage.
8
+
9
+ Anbaric also provides a platform-as-a-service to easily deploy stateful apps built on Anbaric. The same application runs unchanged on
10
+ a developer's machine, on a server you operate, or on Anbaric Cloud, where a
11
+ single CLI command deploys it. Application code depends only on the interfaces
12
+ in this package; the framework selects in-memory or platform-backed
13
+ implementations from the environment, so no deployment detail appears in the
14
+ code.
15
+
16
+ This package (`anbaric`) is the umbrella install for writing an application. It
17
+ re-exports the app-facing surface of the underlying packages.
10
18
 
11
19
  ```bash
12
20
  npm install anbaric
13
21
  ```
14
22
 
15
- An Anbaric app is a plain Node/TypeScript ESM program. Requirements:
16
- `"type": "module"` in package.json, `main` pointing at the TypeScript entry
17
- file, run with `tsx`. Apps deployed to an Anbaric platform may currently only
18
- depend on `anbaric-*` packages.
23
+ An Anbaric application is a standard Node.js ESM program written in TypeScript:
24
+ set `"type": "module"` in `package.json`, point `main` at the TypeScript entry
25
+ file, and run it with `tsx`.
26
+
27
+ ## State machines
28
+
29
+ A **`StateMachine`** defines a workflow. It is constructed with an identifier, a
30
+ list of states, the name of the start state, and the property schema for its
31
+ jobs.
32
+
33
+ - A **`State`** is a named step. It holds a list of **actions** to run while a
34
+ job sits in that state, and a list of **transitions** to the next state.
35
+ - An **`Action`** is a unit of work. Its `run` function receives the job and
36
+ returns a `Map` of property changes: `run(job) => Promise<Map<string, any>>`.
37
+ An action does not mutate the job directly; the returned properties are
38
+ validated and applied by the machine. Each action declares the **actor** that
39
+ performs it.
40
+ - A **`Transition`** names a target state and carries a predicate over the job.
41
+ When a job is processed, the first transition whose predicate holds moves the
42
+ job to that state.
43
+ - A **`Job`** is one instance moving through the machine. It carries an
44
+ identifier, its current `state`, a `Map` of `properties`, and provenance
45
+ (`workflowId`, `startedBy`, `startedAt`, `lastUpdated`). Jobs are immutable;
46
+ each change produces a new version.
47
+ - A **`PropertyDefinition`** describes one property a job may carry: whether it
48
+ is required and how its value is validated. Every property a job holds —
49
+ including properties set by actions — must have a definition, or the change is
50
+ rejected.
51
+ - An **`Actor`** identifies who performs an operation, for authorization and
52
+ auditing. The actor types are `Code`, `Human`, `Agent` and `System`. `Code`
53
+ actions run automatically as jobs are processed; a `Human` or `Agent` actor
54
+ represents work performed by a person or an autonomous agent.
55
+
56
+ A job progresses automatically as it is processed: matching actions run, their
57
+ properties are applied, and the first satisfied transition advances the state.
58
+ This repeats until the job reaches a state from which nothing more applies.
59
+
60
+ There are three ways to influence a job:
61
+
62
+ - `startJob(properties?, actor?)` creates a job in the start state.
63
+ - `updateJob(jobId, properties, actor)` applies an explicit property change.
64
+ - `executeAction(jobId, action)` runs a single action immediately.
65
+ - Actions subscribed to a state run automatically whenever a job in that state
66
+ is processed.
67
+
68
+ Every operation is validated against the schema and written to the audit trail,
69
+ which records the resource, the actor, the interactions (create, update, state
70
+ change, delete, read), and a description of what changed.
71
+
72
+ ## Documents and secrets
73
+
74
+ For data that does not belong to a job, the framework provides two stores,
75
+ obtained from factories and used with an actor for auditing.
76
+
77
+ - **`JsonStore`** stores JSON documents in named collections, optionally
78
+ validated against a JSON Schema.
79
+ - **`SecretStore`** stores named secret strings, encrypted at rest, and never
80
+ records secret values in the audit trail.
19
81
 
20
- ## The model
82
+ ```ts
83
+ import {Human, JsonStoreFactory, SecretStoreFactory} from "anbaric";
21
84
 
22
- A **StateMachine** owns a workflow: named **States**, each with **Actions**
23
- (work that runs when a job is processed in that state) and **Transitions**
24
- (predicates deciding the next state). A **Job** moves through the machine
25
- carrying a `Map` of properties validated against **PropertyDefinitions**.
26
- Every Action declares an **Actor** (`Code`, `Human` or `Agent` — pure
27
- identity objects with `type`, `id`, `role`); `Code` actions run
28
- automatically, the other types are placeholders for human/agent work.
85
+ const actor = new Human("ada", "admin");
86
+
87
+ const customers = JsonStoreFactory.instance("customers", {
88
+ type: "object",
89
+ required: ["name"],
90
+ properties: { name: { type: "string" } },
91
+ });
92
+ await customers.create(actor, "ada", { name: "Ada" });
93
+ const record = await customers.retrieve("ada", actor);
94
+
95
+ const secrets = SecretStoreFactory.instance();
96
+ await secrets.create(actor, "api-key", "s3cr3t");
97
+ ```
98
+
99
+ ## Running and deploying
100
+
101
+ Persistence, queueing and consumers are supplied by environment-driven
102
+ factories, so the same application runs in several ways without code changes.
103
+
104
+ - **Local.** With no environment configured, every store, queue and consumer is
105
+ in-memory and jobs progress automatically. Running the program with
106
+ `npx tsx src/main.ts` is a complete local run, suitable for development and
107
+ testing.
108
+ - **Anbaric Cloud.** `anbaric deploy` packages the application (source only, no
109
+ `node_modules`) and runs it on the hosted platform. The platform installs the
110
+ application's own dependencies as it builds the image, so any npm package the
111
+ application imports works when deployed. The platform injects the configuration
112
+ that points the factories at platform-backed persistence, queueing, documents
113
+ and secrets; application code is unchanged. Authentication, job inspection and
114
+ updates are available through the CLI.
115
+ - **Self-hosted.** The [`anbaric-hosting`](https://npmjs.com/package/anbaric-hosting)
116
+ package runs the platform — the API, dispatcher, build layer and app proxy —
117
+ on infrastructure you operate, backed by Postgres.
118
+
119
+ Applications should not set the `ANBARIC_*` factory variables themselves; the
120
+ platform sets them when the application is deployed.
121
+
122
+ ## Example
29
123
 
30
124
  ```ts
31
125
  import {Action, Code, PropertyDefinition, State, StateMachine, Transition} from "anbaric";
32
126
 
33
- const flag = new PropertyDefinition("welcomeSent");
34
- flag.validation = (value) => typeof value === "boolean";
127
+ const name = new PropertyDefinition("name");
128
+ name.required = true;
129
+
35
130
  const email = new PropertyDefinition("email");
36
131
  email.required = true;
37
132
 
133
+ const welcomeSent = new PropertyDefinition("welcomeSent");
134
+ welcomeSent.validation = (value) => typeof value === "boolean";
135
+
38
136
  const sendWelcome = new Action("Send welcome email", new Code("send-welcome"));
39
- sendWelcome.run = async (job) => new Map([["welcomeSent", true]]);
137
+ sendWelcome.run = async (job) => {
138
+ // ... send the email to job.properties.get("email") ...
139
+ return new Map([["welcomeSent", true]]);
140
+ };
40
141
 
41
- const customers = new StateMachine(
142
+ const onboarding = new StateMachine(
42
143
  "customer-onboarding",
43
144
  [
44
- new State("new", [sendWelcome],
45
- [new Transition("active", job => job.properties.get("welcomeSent") === true)]),
145
+ new State("new", [sendWelcome], [
146
+ new Transition("active", (job) => job.properties.get("welcomeSent") === true),
147
+ ]),
46
148
  new State("active"),
47
149
  ],
48
150
  "new",
49
- [email, flag],
151
+ [name, email, welcomeSent],
50
152
  );
51
153
 
52
- const job = await customers.startJob(new Map([["email", "ada@example.com"]]));
53
- ```
54
-
55
- Key rules an agent must respect:
56
-
57
- - **Actions return properties, they do not mutate the job**: `run` returns a
58
- `Promise<Map<string, any>>` of property changes. Every returned property
59
- must exist in the machine's schema or the change is discarded.
60
- - **Every property a job ever carries needs a `PropertyDefinition`** —
61
- including ones actions set. Unknown properties make updates invalid.
62
- - **Three ways to influence a job**: `updateJob(jobId, properties, actor)`
63
- (explicit change, actor declared), `executeAction(jobId, action)` (run one
64
- action now, actor embedded), or subscribing actions to states (automatic on
65
- processing). All are schema-validated and audited.
66
- - **Jobs carry history**: `startedAt`, `startedBy`, `lastUpdated`, and
67
- `transitions` (`{from, to, actor}` for every state change).
68
-
69
- ## Local versus deployed
70
-
71
- Persistence, queueing and consumers come from env-driven factories. With no
72
- environment set, everything is in-memory and jobs progress automatically —
73
- `npx tsx src/main.ts` is a complete local run. On an Anbaric platform the
74
- same factories talk to the platform because it injects
75
- `ANBARIC_JOB_PERSISTENCE_TYPE=cloud`, `ANBARIC_QUEUE_TYPE=cloud`,
76
- `ANBARIC_JSON_STORE_TYPE=cloud`, `ANBARIC_SECRET_STORE_TYPE=cloud` and
77
- `ANBARIC_CLOUD_URL`. Never set these by hand in app code.
78
-
79
- Documents and secrets follow the same pattern:
80
-
81
- ```ts
82
- import {JsonStoreFactory, SecretStoreFactory} from "anbaric";
83
-
84
- const customers = JsonStoreFactory.instance("customers", {
85
- type: "object",
86
- required: ["name"],
87
- properties: { name: { type: "string" } },
88
- });
89
- await customers.save("ada", { name: "Ada" });
90
-
91
- const secrets = SecretStoreFactory.instance();
92
- await secrets.save("api-key", "s3cr3t");
154
+ const job = await onboarding.startJob(new Map([["name", "Ada"], ["email", "ada@example.com"]]));
93
155
  ```
94
156
 
95
- Per-package detail: [anbaric-tsapi](https://npmjs.com/package/anbaric-tsapi)
96
- for every contract's exact shape, [anbaric-state-machine](https://npmjs.com/package/anbaric-state-machine)
97
- for progression semantics, [anbaric-cli](https://npmjs.com/package/anbaric-cli)
98
- for deployment.
157
+ The job starts in `new`. When it is processed the `sendWelcome` action runs and
158
+ sets `welcomeSent`, and the transition then advances the job to `active`. Run
159
+ locally this happens automatically in memory; deployed, it happens on the
160
+ platform.
161
+
162
+ ## Command-line interface
163
+
164
+ The [`anbaric`](https://npmjs.com/package/anbaric-cli) CLI authenticates a
165
+ terminal, deploys applications, and inspects and drives jobs on a platform. The
166
+ principal commands are:
167
+
168
+ | Command | Purpose |
169
+ | --- | --- |
170
+ | `anbaric login` / `anbaric logout` | authorize this terminal against a platform, or revoke it |
171
+ | `anbaric configure [dir]` | set an application's name and internal port |
172
+ | `anbaric deploy [dir]` | deploy an application and wait until it is live |
173
+ | `anbaric update [dir]` | deploy over a running application without prompting |
174
+ | `anbaric apps` | list deployed applications |
175
+ | `anbaric state-machines` | list registered state machines |
176
+ | `anbaric job list [state-machine-id]` | list jobs |
177
+ | `anbaric job watch <job-id>` | follow a job's state as it changes |
178
+ | `anbaric job set-state <job-id> <state>` | move a job to a state and re-queue it |
179
+ | `anbaric job update <job-id> <key=value ...>` | change job properties and re-queue |
180
+
181
+ Every command accepts flags (such as `--environment`, `--tenant`, `--name`,
182
+ `--port`, `--yes`) that supply the answers a prompt would otherwise ask for, so
183
+ the CLI can be run non-interactively in scripts and CI. See the
184
+ [`anbaric-cli`](https://npmjs.com/package/anbaric-cli) documentation for the
185
+ full command and flag reference.
186
+
187
+ ## Packages
188
+
189
+ `anbaric` re-exports these packages; install them individually for a narrower
190
+ dependency.
191
+
192
+ - [`anbaric-tsapi`](https://npmjs.com/package/anbaric-tsapi) — the interfaces
193
+ and value classes: `Job`, `State`, `Action`, `Transition`, `Actor`,
194
+ `JobPersistence`, `JsonStore`, `SecretStore`, `Auditor`.
195
+ - [`anbaric-state-machine`](https://npmjs.com/package/anbaric-state-machine) —
196
+ the `StateMachine`, actors, and in-memory implementations.
197
+ - [`anbaric-data-store`](https://npmjs.com/package/anbaric-data-store) — the
198
+ document and secret stores.
199
+ - [`anbaric-impl-cloud`](https://npmjs.com/package/anbaric-impl-cloud) — the
200
+ clients used when an application is deployed to a platform.
201
+ - [`anbaric-cli`](https://npmjs.com/package/anbaric-cli) — the platform CLI.
202
+ - [`anbaric-hosting`](https://npmjs.com/package/anbaric-hosting) — run a
203
+ platform yourself.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "anbaric",
3
- "version": "1.7.0",
3
+ "version": "1.8.1",
4
4
  "description": "Everything needed to write an Anbaric app: state machines, jobs, document and secret stores, local in-memory implementations and the Anbaric Cloud clients",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -10,9 +10,9 @@
10
10
  "src"
11
11
  ],
12
12
  "dependencies": {
13
- "anbaric-impl-cloud": "^1.7.0",
14
- "anbaric-data-store": "^1.7.0",
15
- "anbaric-state-machine": "^1.7.0",
16
- "anbaric-tsapi": "^1.7.0"
13
+ "anbaric-impl-cloud": "^1.8.1",
14
+ "anbaric-data-store": "^1.8.1",
15
+ "anbaric-state-machine": "^1.8.1",
16
+ "anbaric-tsapi": "^1.8.1"
17
17
  }
18
18
  }